mirror of
https://github.com/mkdocs/mkdocs.git
synced 2026-03-27 01:48:30 +07:00
Add support for a 'dark mode' to mkdocs theme
Also add an optional toggle button for it. Three new config options have been added: 1. 'color_mode' which can be set to one of 'light', 'dark', or 'auto'. Default is 'light' for backward compatability. The 'auto' color mode will check the system settings and automaticaly switch to light or dark mode on page load or when the system's color mode changes. 2. 'hljs_style_dark': the Highlight.js theme to use in 'dark_mode'. Default is 'github-dark' which matches the light mode default of 'github'. The preexisting config option 'hljs_style' is used for 'light' mode. 3. 'user_color_mode_toggle': Allow users to select their prefered color mode (light, dark, auto) from within the browser and save their preference for future page loads. The new config option 'user_color_mode_toggle' (default: 'False') can be enabled to display a toggle menu in the nav bar. The default value of the toggle menu on first load is the value set to 'color_mode'. MkDocs' own documentation is now configured with 'color_mode: auto'. Co-authored-by: Oleh Prypin <oleh@pryp.in>
This commit is contained in:
committed by
Oleh Prypin
parent
694a6028f6
commit
a836155549
BIN
docs/img/color_mode_toggle_menu.png
Normal file
BIN
docs/img/color_mode_toggle_menu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 77 KiB |
BIN
docs/img/mkdocs_theme_dark_mode.png
Normal file
BIN
docs/img/mkdocs_theme_dark_mode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
BIN
docs/img/mkdocs_theme_light_mode.png
Normal file
BIN
docs/img/mkdocs_theme_light_mode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
@@ -21,17 +21,45 @@ theme:
|
||||
The default theme, which was built as a custom [Bootstrap] theme, supports almost
|
||||
every feature of MkDocs.
|
||||
|
||||

|
||||
<div id="mkdocs-theme-images" class="carousel slide carousel-fade" data-bs-ride="carousel">
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img src="../../img/mkdocs_theme_light_mode.png" class="d-block w-100" alt="MkDocs theme in light mode">
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="../../img/mkdocs_theme_dark_mode.png" class="d-block w-100" alt="MkDocs theme in dark mode">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
In addition to the default [theme configuration options][theme], the `mkdocs` theme
|
||||
supports the following options:
|
||||
|
||||
* **`color_mode`**: Set the default color mode for the theme to one of `light`,
|
||||
`dark`, or `auto`. The `auto` mode will switch to `light` or `dark` based on
|
||||
the system configuration of the user's device. Default: `light`.
|
||||
|
||||
* **`user_color_mode_toggle`**: Enable a toggle menu in the navigation bar
|
||||
which allows users to select their preferred `color_mode` (light, dark, auto)
|
||||
from within the browser and save their preference for future page loads. The
|
||||
default selection of the toggle menu on first page load is the value set to
|
||||
`color_mode`. Default: `false`.
|
||||
|
||||

|
||||
|
||||
* **`nav_style`**: Adjust the visual style of the top navigation bar. Set to
|
||||
one of `primary`, `dark` or `light`. Default: `primary`. This option is
|
||||
independent of the `color_mode` option and must be defined separately.
|
||||
|
||||
* **`highlightjs`**: Enables highlighting of source code in code blocks using
|
||||
the [highlight.js] JavaScript library. Default: `True`.
|
||||
|
||||
* **`hljs_style`**: The highlight.js library provides 79 different [styles]
|
||||
* **`hljs_style`**: The highlight.js library provides many different [styles]
|
||||
(color variations) for highlighting source code in code blocks. Set this to
|
||||
the name of the desired style. Default: `github`.
|
||||
the name of the desired style when in `light` mode. Default: `github`.
|
||||
|
||||
* **`hljs_style_dark`**: Set this to the name of the desired highlight.js
|
||||
style when in `dark` mode. Default: `github_dark`.
|
||||
|
||||
* **`hljs_languages`**: By default, highlight.js only supports 23 common
|
||||
languages. List additional languages here to include support for them.
|
||||
@@ -91,16 +119,6 @@ supports the following options:
|
||||
* **`navigation_depth`**: The maximum depth of the navigation tree in the
|
||||
sidebar. Default: `2`.
|
||||
|
||||
* **`nav_style`**: This adjusts the visual style for the top navigation bar; by
|
||||
default, this is set to `primary` (the default), but it can also be set to
|
||||
`dark` or `light`.
|
||||
|
||||
```yaml
|
||||
theme:
|
||||
name: mkdocs
|
||||
nav_style: dark
|
||||
```
|
||||
|
||||
* **`locale`**{ #mkdocs-locale }: The locale (language/location) used to
|
||||
build the theme. If your locale is not yet supported, it will fall back
|
||||
to the default.
|
||||
|
||||
@@ -8,6 +8,8 @@ edit_uri: blob/master/docs/
|
||||
|
||||
theme:
|
||||
name: mkdocs
|
||||
color_mode: auto
|
||||
user_color_mode_toggle: true
|
||||
locale: en
|
||||
analytics: {gtag: 'G-274394082'}
|
||||
highlightjs: true
|
||||
|
||||
@@ -105,6 +105,8 @@ class ConfigTests(unittest.TestCase):
|
||||
'static_templates': ['404.html', 'sitemap.xml'],
|
||||
'vars': {
|
||||
'name': 'mkdocs',
|
||||
'color_mode': 'light',
|
||||
'user_color_mode_toggle': False,
|
||||
'locale': parse_locale('en'),
|
||||
'include_search_page': False,
|
||||
'search_index_only': False,
|
||||
@@ -112,6 +114,7 @@ class ConfigTests(unittest.TestCase):
|
||||
'highlightjs': True,
|
||||
'hljs_style': 'github',
|
||||
'hljs_languages': [],
|
||||
'hljs_style_dark': 'github-dark',
|
||||
'navigation_depth': 2,
|
||||
'nav_style': 'primary',
|
||||
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83},
|
||||
@@ -190,6 +193,8 @@ class ConfigTests(unittest.TestCase):
|
||||
'static_templates': ['404.html', 'sitemap.xml', 'foo.html'],
|
||||
'vars': {
|
||||
'name': 'mkdocs',
|
||||
'color_mode': 'light',
|
||||
'user_color_mode_toggle': False,
|
||||
'locale': parse_locale('fr'),
|
||||
'show_sidebar': False,
|
||||
'some_var': 'bar',
|
||||
@@ -199,6 +204,7 @@ class ConfigTests(unittest.TestCase):
|
||||
'highlightjs': True,
|
||||
'hljs_style': 'github',
|
||||
'hljs_languages': [],
|
||||
'hljs_style_dark': 'github-dark',
|
||||
'navigation_depth': 2,
|
||||
'nav_style': 'primary',
|
||||
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83},
|
||||
|
||||
@@ -25,12 +25,15 @@ class ThemeTests(unittest.TestCase):
|
||||
dict(theme),
|
||||
{
|
||||
'name': 'mkdocs',
|
||||
'color_mode': 'light',
|
||||
'user_color_mode_toggle': False,
|
||||
'locale': parse_locale('en'),
|
||||
'include_search_page': False,
|
||||
'search_index_only': False,
|
||||
'analytics': {'gtag': None},
|
||||
'highlightjs': True,
|
||||
'hljs_style': 'github',
|
||||
'hljs_style_dark': 'github-dark',
|
||||
'hljs_languages': [],
|
||||
'navigation_depth': 2,
|
||||
'nav_style': 'primary',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ config.theme.locale|default('en') }}" data-bs-theme="light">
|
||||
<html lang="{{ config.theme.locale|default('en') }}" data-bs-theme="{{ config.theme.color_mode }}">
|
||||
<head>
|
||||
{%- block site_meta %}
|
||||
<meta charset="utf-8">
|
||||
@@ -24,7 +24,8 @@
|
||||
<link href="{{ 'css/v4-font-face.min.css'|url }}" rel="stylesheet">
|
||||
<link href="{{ 'css/base.css'|url }}" rel="stylesheet">
|
||||
{%- if config.theme.highlightjs %}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/{{ config.theme.hljs_style }}.min.css">
|
||||
<link id="hljs-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/{{ config.theme.hljs_style }}.min.css" {% if config.theme.color_mode != "light" %}disabled{% endif %}>
|
||||
<link id="hljs-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/{{ config.theme.hljs_style_dark }}.min.css" {% if config.theme.color_mode != "dark" %}disabled{% endif %}>
|
||||
{%- endif %}
|
||||
{%- for path in config.extra_css %}
|
||||
<link href="{{ path|url }}" rel="stylesheet">
|
||||
@@ -108,7 +109,7 @@
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
<ul class="nav navbar-nav ms-md-auto">
|
||||
{%- block search_button %}
|
||||
{%- if 'search' in config.plugins %}
|
||||
<li class="nav-item">
|
||||
@@ -167,6 +168,37 @@
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- if config.theme.user_color_mode_toggle %}
|
||||
<li class="nav-item dropdown">
|
||||
<button id="theme-menu" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme" class="nav-link dropdown-toggle">
|
||||
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||
<span class="d-lg-none ms-2">Toggle theme</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="{% if config.theme.color_mode == 'light' %}true{% else %}false{% endif %}">
|
||||
<i class="fa-solid fa-sun fa-fw"></i>
|
||||
<span class="ms-2">Light</span>
|
||||
<i class="fa-solid fa-check ms-auto{% if config.theme.color_mode != 'light' %} d-none{% endif %}"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="{% if config.theme.color_mode == 'dark' %}true{% else %}false{% endif %}">
|
||||
<i class="fa-solid fa-moon fa-fw"></i>
|
||||
<span class="ms-2">Dark</span>
|
||||
<i class="fa-solid fa-check ms-auto{% if config.theme.color_mode != 'dark' %} d-none{% endif %}"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="{% if config.theme.color_mode == 'auto' %}true{% else %}false{% endif %}">
|
||||
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||
<span class="ms-2">Auto</span>
|
||||
<i class="fa-solid fa-check ms-auto{% if config.theme.color_mode != 'auto' %} d-none{% endif %}"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{%- endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,9 +19,6 @@ function applyTopPadding() {
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
applyTopPadding();
|
||||
|
||||
var search_term = getSearchTerm(),
|
||||
$search_modal = $('#mkdocs_search_modal'),
|
||||
$keyboard_modal = $('#mkdocs_keyboard_modal');
|
||||
@@ -139,6 +136,8 @@ $(document).ready(function() {
|
||||
$(this).find('.dropdown-submenu > a').removeClass('open');
|
||||
$(this).find('.dropdown-menu .dropdown-menu').removeClass('show');
|
||||
});
|
||||
|
||||
applyTopPadding();
|
||||
});
|
||||
|
||||
$(window).on('resize', applyTopPadding);
|
||||
@@ -267,3 +266,69 @@ var keyCodes = {
|
||||
221: ']',
|
||||
222: ''',
|
||||
};
|
||||
|
||||
function setColorMode(mode) {
|
||||
// Switch between light/dark theme. `mode` is a string value of either 'dark' or 'light'.
|
||||
var hljs_light = document.getElementById('hljs-light'),
|
||||
hljs_dark = document.getElementById('hljs-dark');
|
||||
document.documentElement.setAttribute('data-bs-theme', mode);
|
||||
if (mode == 'dark') {
|
||||
hljs_light.disabled = true;
|
||||
hljs_dark.disabled = false;
|
||||
} else {
|
||||
hljs_dark.disabled = true;
|
||||
hljs_light.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function updateModeToggle(mode) {
|
||||
// Update icon and toggle checkmarks of color mode selector.
|
||||
var menu = document.getElementById('theme-menu');
|
||||
document.querySelectorAll('[data-bs-theme-value]')
|
||||
.forEach(function(toggle) {
|
||||
if (mode == toggle.getAttribute('data-bs-theme-value')) {
|
||||
toggle.setAttribute('aria-pressed', 'true');
|
||||
toggle.lastElementChild.classList.remove('d-none');
|
||||
menu.firstElementChild.setAttribute('class', toggle.firstElementChild.getAttribute('class'));
|
||||
} else {
|
||||
toggle.setAttribute('aria-pressed', 'false');
|
||||
toggle.lastElementChild.classList.add('d-none');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onSystemColorSchemeChange(event) {
|
||||
// Update site color mode to match system color mode.
|
||||
setColorMode(event.matches ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
var mql = window.matchMedia('(prefers-color-scheme: dark)'),
|
||||
defaultMode = document.documentElement.getAttribute('data-bs-theme'),
|
||||
storedMode = localStorage.getItem('mkdocs-colormode');
|
||||
if (storedMode && storedMode != 'auto') {
|
||||
setColorMode(storedMode);
|
||||
updateModeToggle(storedMode);
|
||||
} else if (storedMode == 'auto' || defaultMode == 'auto') {
|
||||
setColorMode(mql.matches ? 'dark' : 'light');
|
||||
updateModeToggle('auto');
|
||||
mql.addEventListener('change', onSystemColorSchemeChange);
|
||||
} else {
|
||||
setColorMode(defaultMode);
|
||||
updateModeToggle(defaultMode);
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]')
|
||||
.forEach(function(toggle) {
|
||||
toggle.addEventListener('click', function (e) {
|
||||
var mode = e.currentTarget.getAttribute('data-bs-theme-value');
|
||||
localStorage.setItem('mkdocs-colormode', mode);
|
||||
if (mode == 'auto') {
|
||||
setColorMode(mql.matches ? 'dark' : 'light');
|
||||
mql.addEventListener('change', onSystemColorSchemeChange);
|
||||
} else {
|
||||
setColorMode(mode);
|
||||
mql.removeEventListener('change', onSystemColorSchemeChange);
|
||||
}
|
||||
updateModeToggle(mode);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,9 +11,12 @@ search_index_only: false
|
||||
highlightjs: true
|
||||
hljs_languages: []
|
||||
hljs_style: github
|
||||
hljs_style_dark: github-dark
|
||||
|
||||
navigation_depth: 2
|
||||
nav_style: primary
|
||||
color_mode: light
|
||||
user_color_mode_toggle: false
|
||||
|
||||
analytics:
|
||||
gtag: null
|
||||
|
||||
Reference in New Issue
Block a user