Skip to content

Commit

Permalink
Add support for a 'dark mode' to mkdocs theme
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
waylan and oprypin committed Mar 16, 2024
1 parent 694a602 commit a836155
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 19 deletions.
Binary file added docs/img/color_mode_toggle_menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/img/mkdocs.png
Binary file not shown.
Binary file added docs/img/mkdocs_theme_dark_mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/mkdocs_theme_light_mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 31 additions & 13 deletions docs/user-guide/choosing-your-theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,45 @@ theme:
The default theme, which was built as a custom [Bootstrap] theme, supports almost
every feature of MkDocs.
![mkdocs](../img/mkdocs.png)
<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`.

![color mode toggle menu](../img/color_mode_toggle_menu.png)

* **`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.
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions mkdocs/tests/config/config_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,16 @@ def test_theme(self, mytheme, custom):
'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,
'analytics': {'gtag': None},
'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},
Expand Down Expand Up @@ -190,6 +193,8 @@ def test_theme(self, mytheme, custom):
'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',
Expand All @@ -199,6 +204,7 @@ def test_theme(self, mytheme, custom):
'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},
Expand Down
3 changes: 3 additions & 0 deletions mkdocs/tests/theme_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ def test_simple_theme(self):
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',
Expand Down
38 changes: 35 additions & 3 deletions mkdocs/themes/mkdocs/base.html
Original file line number Diff line number Diff line change
@@ -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">
Expand All @@ -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">
Expand Down Expand Up @@ -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">
Expand Down Expand Up @@ -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>
Expand Down
71 changes: 68 additions & 3 deletions mkdocs/themes/mkdocs/js/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ function applyTopPadding() {
}

$(document).ready(function() {

applyTopPadding();

var search_term = getSearchTerm(),
$search_modal = $('#mkdocs_search_modal'),
$keyboard_modal = $('#mkdocs_keyboard_modal');
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -267,3 +266,69 @@ var keyCodes = {
221: '&rsqb;',
222: '&apos;',
};

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);
});
});
3 changes: 3 additions & 0 deletions mkdocs/themes/mkdocs/mkdocs_theme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a836155

Please sign in to comment.