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
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,40 @@ Keep a Changelog change-type headings, so a consumer reads only the
sections that affect its template. Version numbers follow the
`MAJOR.MINOR.PATCH` policy described in [the README](README.md#versioning).

## Unreleased

### shared

- The brand assets are the **ClumL company mark**, replacing a
`brand.svg` that was the Clumit Security product logo — one consumer's
product, shipped to every consumer. A project documenting a different
product would have published another product's branding.
- `brand.svg` now carries **white** lettering, for the site header, which
sits on the primary-coloured bar. Anything rendering it on a light
background needs `brand-print.svg` instead.
- Added `brand-print.svg`, the black-lettering variant the PDF cover
uses, and `brand-symbol.svg`, the cube alone. A wordmark scaled to a
16-pixel tab icon is unreadable; the cube is not.

### manual

- `theme.favicon` points at `theme/brand-symbol.svg` rather than the
wordmark.

### api-reference

- `theme.favicon` points at `theme/brand-symbol.svg` rather than the
wordmark.

### scripts

- `fetch-theme.sh` installs all three brand assets.
- `build-docs-pdf.sh` takes the cover logo from `brand-print.svg`, and
accepts `extra.pdf.cover_logo` — a path relative to `docs_dir` — so a
project documenting a product with its own mark can put it on the
cover. A path that does not resolve is an error rather than a silent
fall back to the company mark.

## [0.2.0] - 2026-08-08

### manual
Expand Down
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ templates/ Template assets grouped by document type
release-notes/ (planned)
shared/ Assets shared across all templates
fonts/ Roboto and Pretendard web fonts
brand.svg Brand logo
brand.svg ClumL wordmark, white lettering (site header)
brand-print.svg ClumL wordmark, black lettering (PDF cover)
brand-symbol.svg ClumL cube alone (favicon)
styles/ Base CSS
samples/ Per-template sample sites for previewing
index.html Landing page linking to all samples
Expand Down Expand Up @@ -190,6 +192,8 @@ It downloads the release named in `docs/theme.toml` and installs:
| `shared/styles/base.css` | `docs/theme/styles/base.css` |
| `shared/fonts/` | `docs/theme/fonts/` |
| `shared/brand.svg` | `docs/theme/brand.svg` |
| `shared/brand-print.svg` | `docs/theme/brand-print.svg` |
| `shared/brand-symbol.svg` | `docs/theme/brand-symbol.svg` |
| `scripts/build-docs-pdf.sh` | `docs/theme/build-docs-pdf.sh` |

The install directory must not be dot-prefixed: MkDocs drops every
Expand Down Expand Up @@ -253,6 +257,37 @@ default, and a consumer that needs its own `i18n` languages redefines
the whole `plugins` list (which replaces the default wholesale), as the
sample sites do.

### Branding

The theme ships the **ClumL company mark** in three variants, because one
file cannot serve all three places. `brand.svg` has white lettering for
the site header, which sits on the primary-coloured bar. `brand-print.svg`
has black lettering for the PDF cover, which sits on white paper.
`brand-symbol.svg` is the cube alone: a wordmark scaled to a 16-pixel tab
icon is unreadable, and the cube is not. The base wires all three, so a
project documenting something ClumL publishes needs no branding config at
all.

A project documenting a product with its own mark overrides them. Commit
the product's assets under `docs/` — **not** under `docs/theme/`, which
is covered by the `.meta` digest and reverted on the next installer run:

```yaml
theme:
logo: assets/product-logo.svg
favicon: assets/product-symbol.svg

extra:
pdf:
cover_logo: assets/product-logo-print.svg
```

`theme` is a mapping, so those two keys merge into the base rather than
replacing it — the palette, fonts, and features it defines all survive.
`extra.pdf.cover_logo` is a path relative to `docs_dir`; a path that does
not resolve is an error rather than a silent fall back to the company
mark, which would otherwise ship a cover branded with the wrong name.

The base already wires `extra_css` to the installed stylesheets (base,
lists, and PDF guardrails, plus `api.css` for the api-reference
template), so you do not list them yourself. To review the full set of
Expand Down
21 changes: 18 additions & 3 deletions scripts/build-docs-pdf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,24 @@ if cover_subtitle is not None:
if toc_title is not None:
options["toc_title"] = toc_title

brand_svg = os.path.join(theme_dir, "brand.svg")
if os.path.isfile(brand_svg):
options["cover_logo"] = brand_svg
# The cover sits on white paper, so it needs the black-lettering variant.
# theme/brand.svg is the white-lettering one the site header uses; putting
# that on the cover renders an invisible logo and nothing downstream would
# report it. A consumer documenting a product with its own mark points
# extra.pdf.cover_logo at it, relative to docs_dir.
cover_logo = text("cover_logo")
if cover_logo is not None:
docs_dir = str(data.get("docs_dir") or "docs")
cover_logo = os.path.join(root, docs_dir, cover_logo)
if not os.path.isfile(cover_logo):
fail(f"{config_path}: 'extra.pdf.cover_logo' does not exist at "
f"{cover_logo}")
else:
cover_logo = os.path.join(theme_dir, "brand-print.svg")
if not os.path.isfile(cover_logo):
fail(f"{cover_logo} is missing; the installed theme is incomplete. "
"Re-run ./scripts/fetch-theme.sh.")
options["cover_logo"] = cover_logo

# cover_tagline is not a mkdocs-with-pdf option. The plugin seeds the
# cover template context from `extra` and never overwrites this name, so
Expand Down
14 changes: 10 additions & 4 deletions scripts/fetch-theme.sh
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,16 @@ def stage(src, staging, template, template_dir, label):
fail(f"shared/fonts/ not found in {label}")
copy_tree(shared_fonts, os.path.join(staging, "fonts"))

brand = os.path.join(src, "shared", "brand.svg")
if not os.path.isfile(brand):
fail(f"shared/brand.svg not found in {label}")
copy_file(brand, os.path.join(staging, "brand.svg"))
# brand.svg carries white lettering for the site header, which sits on
# the primary-coloured bar; brand-print.svg is the black-lettering
# variant the PDF cover needs on white paper; brand-symbol.svg is the
# cube alone, which is the only one of the three that stays legible at
# favicon size.
for name in ("brand.svg", "brand-print.svg", "brand-symbol.svg"):
asset = os.path.join(src, "shared", name)
if not os.path.isfile(asset):
fail(f"shared/{name} not found in {label}")
copy_file(asset, os.path.join(staging, name))

pdf_script = os.path.join(src, "scripts", "build-docs-pdf.sh")
if not os.path.isfile(pdf_script):
Expand Down
1 change: 1 addition & 0 deletions shared/brand-print.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions shared/brand-symbol.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading