Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,23 @@ uv pip install intility-bifrost-mkdocs

## Usage

Add `intility-bifrost` to your `mkdocs.yml` plugins:
Set the theme to `material` and add `intility-bifrost` to your `mkdocs.yml` plugins:

```yaml
theme:
name: material
palette:
- scheme: light
primary: &bifrost_theme teal # Options: teal, purple, pink, yellow
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: dark
primary: *bifrost_theme
toggle:
icon: material/brightness-4
name: Switch to light mode

plugins:
- intility-bifrost
- search
```

The `&bifrost_theme` anchor sets the color once and reuses it for both modes.
That's the whole setup. The plugin configures the markdown extensions, theme
features, fonts, icons, and a light/dark palette toggle for you.

To pick a different theme color, set a version badge, or build navigation from
`.nav.yml` files, see the
**[Quick Start](https://intility.github.io/bifrost-mkdocs/)** in the docs.

## What it provides

Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ See the [Feature Showcase](showcase/index.md) for a live demonstration of every

3. **Start writing docs.** The plugin configures the markdown extensions, theme features, fonts, and icons for you.

That's all you need. Everything else (markdown extensions, theme features, fonts, icons) is injected automatically and can be overridden by setting it yourself. Add a [color scheme and dark-mode toggle](#change-the-color-scheme) when you want them.
That's all you need. Everything else (markdown extensions, theme features, fonts, icons, and a teal light/dark palette toggle) is injected automatically and can be overridden by setting it yourself. To use a [different color](#change-the-color-scheme), set your own `palette`.

## Overriding Defaults

Expand All @@ -36,7 +36,7 @@ markdown_extensions:

### Change the Color Scheme

Add a `palette` to your theme config. This sets the Bifrost theme color and enables the light/dark mode toggle:
The plugin injects a teal light/dark palette by default. To use a different color, set your own `palette` (this also lets you customize the toggle icons and labels):

```yaml
theme:
Expand All @@ -54,7 +54,7 @@ theme:
name: Switch to light mode
```

The `&bifrost_theme` anchor defines the color once and reuses it for both modes. Without a palette the site still works; it just uses the default color and has no mode toggle.
The `&bifrost_theme` anchor defines the color once and reuses it for both modes. A user-defined `palette` replaces the injected default entirely, so include both modes if you want to keep the toggle.

### Version Badge

Expand Down
14 changes: 0 additions & 14 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@ theme:
language: en
logo: assets/bifrost-logo.svg
favicon: assets/bifrost-logo.svg
palette:
- scheme: light
primary: &bifrost_theme teal # Options: teal, purple, pink, yellow
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: dark
primary: *bifrost_theme
toggle:
icon: material/brightness-4
name: Switch to light mode

plugins:
- intility-bifrost
Expand All @@ -36,6 +25,3 @@ plugins:
- git-revision-date-localized:
enable_creation_date: true
type: timeago

# Navigation is defined with awesome-nav via .nav.yml files in docs/ and
# docs/showcase/ instead of an explicit nav: block here.
38 changes: 38 additions & 0 deletions src/intility_bifrost_mkdocs/plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import copy
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -64,6 +65,32 @@
"content.tabs.link",
]

# ---------------------------------------------------------------------------
# Default palette: a light/dark toggle on the teal theme.
# ---------------------------------------------------------------------------
# Mirrors the quick start in the docs so the minimal config (just the plugin)
# ships with a working light/dark toggle. `scheme` uses light/dark rather than
# Material's default/slate; bifrost-theme.js maps those onto Bifrost's
# light/dark classes and Bifrost's cascade layers handle the colors.
DEFAULT_PALETTE: list[dict[str, Any]] = [
{
"scheme": "light",
"primary": "teal",
"toggle": {
"icon": "material/brightness-7",
"name": "Switch to dark mode",
},
},
{
"scheme": "dark",
"primary": "teal",
"toggle": {
"icon": "material/brightness-4",
"name": "Switch to light mode",
},
},
]

# ---------------------------------------------------------------------------
# Fonts (Bifrost branding).
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -188,6 +215,16 @@ def _inject_theme_features(config: MkDocsConfig) -> None:
config.theme["features"] = features


def _inject_palette(config: MkDocsConfig) -> None:
"""Set a default light/dark palette (with toggle) if the user hasn't.

Gives the minimal config a working light/dark toggle. A user-defined
``palette`` (even a single-entry one) is left untouched.
"""
if not config.theme.get("palette"):
config.theme["palette"] = copy.deepcopy(DEFAULT_PALETTE)


def _inject_theme_settings(config: MkDocsConfig) -> None:
"""Set Bifrost fonts and admonition icons when the user hasn't customized them."""
# Fonts: Bifrost styles all text (vendored Satoshi) and code (system
Expand Down Expand Up @@ -315,6 +352,7 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig:
# Inject sensible defaults (never overwrites user-provided config).
_inject_markdown_extensions(config)
_inject_theme_features(config)
_inject_palette(config)
_inject_theme_settings(config)
_inject_extra_javascript(config)

Expand Down
41 changes: 41 additions & 0 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
DEFAULT_ADMONITION_ICONS,
DEFAULT_EXTENSIONS,
DEFAULT_FEATURES,
DEFAULT_PALETTE,
DEFAULT_TOP_ICON,
IntilityBifrostPlugin,
_build_layer_bootstrap_css,
Expand Down Expand Up @@ -259,6 +260,46 @@ def test_user_top_icon_preserved():
assert result.theme["icon"]["top"] == "material/arrow-up"


# ---------------------------------------------------------------------------
# Palette
# ---------------------------------------------------------------------------


def test_default_palette_injected():
"""The minimal config should get a light/dark palette with a toggle."""
plugin = IntilityBifrostPlugin()
config = _minimal_config()

result = plugin.on_config(config)

palette = result.theme["palette"]
assert [entry["scheme"] for entry in palette] == ["light", "dark"]
assert all("toggle" in entry for entry in palette)


def test_user_palette_preserved():
"""A user-provided palette should not be overwritten."""
plugin = IntilityBifrostPlugin()
config = _minimal_config()

config.theme["palette"] = [{"scheme": "slate", "primary": "purple"}]

result = plugin.on_config(config)

assert result.theme["palette"] == [{"scheme": "slate", "primary": "purple"}]


def test_default_palette_not_shared_across_configs():
"""Injected palette must be a copy, not the shared module constant."""
plugin = IntilityBifrostPlugin()
config = _minimal_config()

result = plugin.on_config(config)
result.theme["palette"][0]["primary"] = "pink"

assert DEFAULT_PALETTE[0]["primary"] == "teal"


# ---------------------------------------------------------------------------
# Extra JavaScript
# ---------------------------------------------------------------------------
Expand Down