page title
:ini:`PROJECT_BRIEF` If set, appended in a thinner font to
:ini:`PROJECT_NAME`
+:ini:`PROJECT_LOGO` URL of an image file to use as a log in the top
+ navbar. Default is none.
:ini:`OUTPUT_DIRECTORY` Used to discover where Doxygen generates the
files
:ini:`XML_OUTPUT` Used to discover where Doxygen puts the
:py:`"My Python Project"` is used.
:py:`PROJECT_SUBTITLE: str` Project subtitle. If set, appended in a
thinner font to :py:`PROJECT_TITLE`.
+:py:`PROJECT_LOGO: str` URL of an image to use as a log in the top
+ navbar. Default is none.
:py:`MAIN_PROJECT_URL: str` If set and :py:`PROJECT_SUBTITLE` is also
set, then :py:`PROJECT_TITLE` in the top
navbar will link to this URL and
default_config = {
'PROJECT_NAME': ['My Project'],
+ 'PROJECT_LOGO': [''],
'OUTPUT_DIRECTORY': [''],
'XML_OUTPUT': ['xml'],
'HTML_OUTPUT': ['html'],
# String values that we want
for i in ['PROJECT_NAME',
'PROJECT_BRIEF',
+ 'PROJECT_LOGO',
'OUTPUT_DIRECTORY',
'HTML_OUTPUT',
'XML_OUTPUT',
f.write(b'\n')
# Copy all referenced files
- for i in state.images + state.doxyfile['HTML_EXTRA_STYLESHEET'] + state.doxyfile['HTML_EXTRA_FILES'] + ([state.doxyfile['M_FAVICON'][0]] if state.doxyfile['M_FAVICON'] else []) + ([] if state.doxyfile['M_SEARCH_DISABLED'] else ['search.js']):
+ for i in state.images + state.doxyfile['HTML_EXTRA_STYLESHEET'] + state.doxyfile['HTML_EXTRA_FILES'] + ([state.doxyfile['PROJECT_LOGO']] if state.doxyfile['PROJECT_LOGO'] else []) + ([state.doxyfile['M_FAVICON'][0]] if state.doxyfile['M_FAVICON'] else []) + ([] if state.doxyfile['M_SEARCH_DISABLED'] else ['search.js']):
# Skip absolute URLs
if urllib.parse.urlparse(i).netloc: continue
default_config = {
'PROJECT_TITLE': 'My Python Project',
'PROJECT_SUBTITLE': None,
+ 'PROJECT_LOGO': None,
'MAIN_PROJECT_URL': None,
'INPUT': None,
'OUTPUT': 'output',
f.write(b'\n')
# Copy referenced files
- for i in config['STYLESHEETS'] + config['EXTRA_FILES'] + ([config['FAVICON'][0]] if config['FAVICON'] else []) + list(state.external_data) + ([] if config['SEARCH_DISABLED'] else ['search.js']):
+ for i in config['STYLESHEETS'] + config['EXTRA_FILES'] + ([config['PROJECT_LOGO']] if config['PROJECT_LOGO'] else []) + ([config['FAVICON'][0]] if config['FAVICON'] else []) + list(state.external_data) + ([] if config['SEARCH_DISABLED'] else ['search.js']):
# Skip absolute URLs
if urllib.parse.urlparse(i).netloc: continue
<div class="m-row">
{% if M_MAIN_PROJECT_URL and PROJECT_BRIEF %}
<span id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">
- <a href="{{ M_MAIN_PROJECT_URL }}">{{ PROJECT_NAME }}</a> <span class="m-breadcrumb">|</span> <a href="index.html" class="m-thin">{{ PROJECT_BRIEF }}</a>
+ <a href="{{ M_MAIN_PROJECT_URL }}">{% if PROJECT_LOGO %}<img src="{{ PROJECT_LOGO|basename_or_url|e }}" />{% endif %}{{ PROJECT_NAME }}</a> <span class="m-breadcrumb">|</span> <a href="index.html" class="m-thin">{{ PROJECT_BRIEF }}</a>
</span>
{% else %}
- <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">{{ PROJECT_NAME }}{% if PROJECT_BRIEF %} <span class="m-thin">{{ PROJECT_BRIEF }}</span>{% endif %}</a>
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">{% if PROJECT_LOGO %}<img src="{{ PROJECT_LOGO|basename_or_url|e }}" />{% endif %}{{ PROJECT_NAME }}{% if PROJECT_BRIEF %} <span class="m-thin">{{ PROJECT_BRIEF }}</span>{% endif %}</a>
{% endif %}
{% if M_LINKS_NAVBAR1 or M_LINKS_NAVBAR2 or not M_SEARCH_DISABLED %}
<div class="m-col-t-4 m-hide-m m-text-right m-nopadr">
<div class="m-row">
{% if MAIN_PROJECT_URL and PROJECT_TITLE %}
<span id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">
- <a href="{{ MAIN_PROJECT_URL }}">{{ PROJECT_TITLE }}</a> <span class="m-breadcrumb">|</span> <a href="{{ 'index'|path_to_url }}" class="m-thin">{{ PROJECT_SUBTITLE }}</a>
+ <a href="{{ MAIN_PROJECT_URL }}">{% if PROJECT_LOGO %}<img src="{{ PROJECT_LOGO|format_url|e }}" />{% endif %}{{ PROJECT_TITLE }}</a> <span class="m-breadcrumb">|</span> <a href="{{ 'index'|path_to_url }}" class="m-thin">{{ PROJECT_SUBTITLE }}</a>
</span>
{% else %}
- <a href="{{ 'index'|path_to_url }}" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">{{ PROJECT_TITLE }}{% if PROJECT_SUBTITLE %} <span class="m-thin">{{ PROJECT_SUBTITLE }}</span>{% endif %}</a>
+ <a href="{{ 'index'|path_to_url }}" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">{% if PROJECT_LOGO %}<img src="{{ PROJECT_LOGO|format_url|e }}" />{% endif %}{{ PROJECT_TITLE }}{% if PROJECT_SUBTITLE %} <span class="m-thin">{{ PROJECT_SUBTITLE }}</span>{% endif %}</a>
{% endif %}
{% if LINKS_NAVBAR1 or LINKS_NAVBAR2 or not SEARCH_DISABLED %}
<div class="m-col-t-4 m-hide-m m-text-right m-nopadr">
--- /dev/null
+XML_OUTPUT =
+PROJECT_NAME = "Your Brand"
+PROJECT_LOGO = mosra.jpg
+
+##! M_PAGE_FINE_PRINT =
+##! M_THEME_COLOR =
+##! M_FAVICON =
+##! M_LINKS_NAVBAR1 =
+##! M_LINKS_NAVBAR2 =
+##! M_SEARCH_DISABLED = YES
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>Your Brand</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m"><img src="mosra.jpg" />Your Brand</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ Your Brand
+ </h1>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.14">
+ <compounddef id="indexpage" kind="page">
+ <compoundname>index</compoundname>
+ <title>Your Brand</title>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ </compounddef>
+</doxygen>
--- /dev/null
+../../../site/content/static/mosra.jpg
\ No newline at end of file
--- /dev/null
+XML_OUTPUT =
+PROJECT_NAME = "Your Brand"
+PROJECT_LOGO = mosra.jpg
+PROJECT_BRIEF = docs
+
+##! M_PAGE_FINE_PRINT =
+##! M_THEME_COLOR =
+##! M_FAVICON =
+##! M_LINKS_NAVBAR1 =
+##! M_LINKS_NAVBAR2 =
+##! M_SEARCH_DISABLED = YES
+##! M_MAIN_PROJECT_URL = http://your.brand
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>Your Brand docs</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <span id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">
+ <a href="http://your.brand"><img src="mosra.jpg" />Your Brand</a> <span class="m-breadcrumb">|</span> <a href="index.html" class="m-thin">docs</a>
+ </span>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ Your Brand
+ </h1>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.14">
+ <compounddef id="indexpage" kind="page">
+ <compoundname>index</compoundname>
+ <title>Your Brand</title>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ </compounddef>
+</doxygen>
--- /dev/null
+../../../site/content/static/mosra.jpg
\ No newline at end of file
'M_THEME_COLOR': '#22272e',
'OUTPUT_DIRECTORY': '',
'PROJECT_BRIEF': 'is cool',
+ 'PROJECT_LOGO': '',
'PROJECT_NAME': 'My Pet Project',
'SHOW_INCLUDE_FILES': True,
'XML_OUTPUT': 'xml'
self.run_doxygen(wildcard='indexpage.xml')
self.assertEqual(*self.actual_expected_contents('index.html'))
+class NavbarProjectLogo(BaseTestCase):
+ def __init__(self, *args, **kwargs):
+ super().__init__(__file__, 'navbar_project_logo', *args, **kwargs)
+
+ def test(self):
+ self.run_doxygen(wildcard='indexpage.xml')
+ self.assertEqual(*self.actual_expected_contents('index.html'))
+
+class NavbarProjectLogoMainProjectUrl(BaseTestCase):
+ def __init__(self, *args, **kwargs):
+ super().__init__(__file__, 'navbar_project_logo_main_project_url', *args, **kwargs)
+
+ def test(self):
+ self.run_doxygen(wildcard='indexpage.xml')
+ self.assertEqual(*self.actual_expected_contents('index.html'))
+
class SearchBinary(BaseTestCase):
def __init__(self, *args, **kwargs):
super().__init__(__file__, 'search_binary', *args, **kwargs)
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>My Python Project | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m"><img src="mosra.jpg" />My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ My Python Project
+ </h1>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+../../../site/content/static/mosra.jpg
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>My Python Project | My Python Project docs</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <span id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">
+ <a href="http://your.brand"><img src="mosra.jpg" />My Python Project</a> <span class="m-breadcrumb">|</span> <a href="index.html" class="m-thin">docs</a>
+ </span>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ My Python Project
+ </h1>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+../../../site/content/static/mosra.jpg
\ No newline at end of file
self.assertEqual(*self.actual_expected_contents('index.html'))
self.assertTrue(os.path.exists(os.path.join(self.path, 'output', 'search-v1.js')))
self.assertEqual(*self.actual_expected_contents('opensearch.xml'))
+
+class ProjectLogo(BaseTestCase):
+ def test(self):
+ self.run_python({
+ 'PROJECT_LOGO': 'mosra.jpg',
+ })
+ self.assertEqual(*self.actual_expected_contents('index.html'))
+
+class ProjectLogoMainProjectUrl(BaseTestCase):
+ def test(self):
+ self.run_python({
+ 'PROJECT_LOGO': 'mosra.jpg',
+ 'PROJECT_SUBTITLE': 'docs',
+ 'MAIN_PROJECT_URL': 'http://your.brand'
+ })
+ self.assertEqual(*self.actual_expected_contents('index.html'))
<div class="m-container">
<div class="m-row">
<a href="{{ SITEURL }}/" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m{% if page and page.landing and page.cover and page.hide_navbar_brand == 'True' %} m-navbar-brand-hidden{% endif %}">
- {%- if M_SITE_LOGO %}<img src="{{ M_SITE_LOGO|e }}" />{% endif -%}
+ {%- if M_SITE_LOGO %}<img src="{{ M_SITE_LOGO|format_siteurl|e }}" />{% endif -%}
{{- (M_SITE_LOGO_TEXT or SITENAME)|e -}}
</a>
{% if M_LINKS_NAVBAR1 or M_LINKS_NAVBAR2 %}
--- /dev/null
+<!DOCTYPE html>
+<html lang="en" prefix="og: http://ogp.me/ns#">
+<head>
+ <meta charset="UTF-8" />
+ <title>Brand Logo | A Pelican Blog</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i" />
+ <link rel="stylesheet" href="static/m-dark.css" />
+ <link rel="canonical" href="pages/brand-logo.html" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta property="og:site_name" content="A Pelican Blog" />
+ <meta property="og:title" content="Brand Logo" />
+ <meta name="twitter:title" content="Brand Logo" />
+ <meta property="og:url" content="pages/brand-logo.html" />
+ <meta name="twitter:card" content="summary" />
+ <meta property="og:type" content="page" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="./" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m"><img src="mosra.jpg" />A Pelican Blog</a>
+ </div>
+ </div>
+</nav></header>
+<main>
+<article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>Brand Logo</h1>
+ </div>
+ </div>
+ </div>
+</article>
+</main>
+</body>
+</html>
--- /dev/null
+Brand Logo
+##########
+
+:save_as: index.html
--- /dev/null
+../../../site/content/static/mosra.jpg
\ No newline at end of file
# different og:url but nothing else.
self.assertEqual(*self.actual_expected_contents('index.html'))
self.assertEqual(*self.actual_expected_contents('archives.html'))
+
+class BrandLogo(MinimalTestCase):
+ def __init__(self, *args, **kwargs):
+ super().__init__(__file__, 'brand_logo', *args, **kwargs)
+
+ def test(self):
+ self.run_pelican({
+ # This is the minimal that's required. Not even the M_THEME_COLOR
+ # is required.
+ 'THEME': '.',
+ 'PLUGIN_PATHS': ['../plugins'],
+ 'PLUGINS': ['m.htmlsanity'],
+ 'THEME_STATIC_DIR': 'static',
+ 'M_CSS_FILES': ['https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i',
+ 'static/m-dark.css'],
+ 'M_SITE_LOGO': 'mosra.jpg',
+ 'STATIC_PATHS': ['mosra.jpg'],
+ 'ARTICLE_PATHS': ['articles'], # doesn't exist
+ # Supplying empty index.html to avoid excessive hello world markup
+ # we don't need
+ 'PAGE_PATHS': ['.'],
+ 'M_FINE_PRINT': ''})
+
+ # The archives and index page should be exactly the same
+ self.assertEqual(*self.actual_expected_contents('index.html'))