mdcms/docs/claude-design.md
Claude 737049f19e
Add configurable nav section toggle icons
Two new top-level theme.yml keys — nav-section-expand-icon and
nav-section-collapse-icon — replace the hardcoded arrow_right/arrow_drop_down
used on collapsible nav sections. Defaults preserve existing behaviour.

Eight new icon SVGs added to app/assets/icons/:
  keyboard_arrow_right / keyboard_arrow_down     (chevrons)
  keyboard_double_arrow_right / keyboard_double_arrow_down
  expand_content / collapse_content              (corner arrows)
  add / minimize                                 (plus/minus)

All eight added to STANDARD_ICONS so fetch-deps bundles them correctly.
CLAUDE.md key reference and docs/claude-design.md updated with the full
icon catalogue, pairing guidance, and style notes for Claude Design.

https://claude.ai/code/session_01NQKywehSj8Ku4yKhwB4VNB
2026-05-18 15:08:59 +00:00

309 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# mdcms theme authoring guide for Claude Design
This document explains the `theme.yml` format so that Claude Design can produce
complete, correct theme files that render well in all nav configurations and in
both light and dark mode.
---
## Full theme.yml structure
```yaml
# mdcms v0.4 | DO NOT REMOVE THIS COMMENT
# mdcms theme — <theme name>
# ──────────────────────────────────
# Colours
# ──────────────────────────────────
light:
accent: "#2563EB" # brand colour; used for links, active nav border, accents
background: "#FFFFFF" # main content area background
nav-background: "#F8FAFC" # sidebar/nav panel background
text: "#1E293B" # body text
text-muted: "#64748B" # secondary text, captions
nav-link: "#1E293B" # inactive nav link text
nav-link-active: "#2563EB" # active (current page) nav link text
nav-section-heading: "#64748B" # nav section label text (uppercase, small)
nav-sitename: "#1E293B" # site name in sidebar header
nav-description: "#64748B" # site description below the site name
nav-toggle: "#64748B" # dark/light mode toggle button
# divider: "#CBD5E1" # omit to auto-derive via color-mix(background, text)
dark:
accent: "#60A5FA"
background: "#0F172A"
nav-background: "#1E293B"
text: "#F1F5F9"
text-muted: "#94A3B8"
nav-link: "#E2E8F0"
nav-link-active: "#60A5FA"
nav-section-heading: "#94A3B8"
nav-sitename: "#E2E8F0"
nav-description: "#94A3B8"
nav-toggle: "#94A3B8"
# divider: "#334155" # omit to auto-derive via color-mix(background, text)
# ──────────────────────────────────
# Semantic colours
# colours-semantic applies to both modes.
# colours-semantic-dark overrides for dark mode only.
# ──────────────────────────────────
colours-semantic:
info: "#2563EB"
warning: "#D97706"
success: "#16A34A"
error: "#DC2626"
colours-semantic-dark:
info: "#60A5FA"
warning: "#F59E0B"
success: "#34D399"
error: "#F87171"
# ──────────────────────────────────
# Callout defaults
# primary-colour → left border and icon
# background-colour → tinted background (rendered at ~8% opacity)
# ──────────────────────────────────
callouts:
info:
icon: info
primary-colour: "#2563EB"
background-colour: "#2563EB"
warning:
icon: warning
primary-colour: "#D97706"
background-colour: "#D97706"
success:
icon: success
primary-colour: "#16A34A"
background-colour: "#16A34A"
error:
icon: error
primary-colour: "#DC2626"
background-colour: "#DC2626"
# ──────────────────────────────────
# Typography
# Format: "provider:Font Name:weight" (provider: bunny | google)
# ──────────────────────────────────
font-body: "bunny:IBM Plex Sans:400"
font-heading: "bunny:IBM Plex Sans:700"
font-size: 1.0 # unitless multiplier (1.0 = 16px base)
line-height: 1.7 # unitless multiplier
# ──────────────────────────────────
# Nav section toggle icons
# expand-icon: shown when section is collapsed
# collapse-icon: shown when section is expanded
# ──────────────────────────────────
nav-section-expand-icon: arrow_right # default
nav-section-collapse-icon: arrow_drop_down # default
# ──────────────────────────────────
# Layout
# ──────────────────────────────────
main-width: 80em
nav-width: 20em
```
---
## Nav section toggle icons
Sections with `pagesvisibility: hidden` in `nav.yml` are collapsible. The
expand and collapse icons are set independently at the top level of `theme.yml`
(not inside `light:` or `dark:` — they are not per-mode).
| Key | Default | Shown when |
|---|---|---|
| `nav-section-expand-icon` | `arrow_right` | section is collapsed |
| `nav-section-collapse-icon` | `arrow_drop_down` | section is expanded |
**Available pairs and their character:**
| Expand icon | Collapse icon | Character |
|---|---|---|
| `arrow_right` | `arrow_drop_down` | Solid filled triangles — compact, classic |
| `keyboard_arrow_right` | `keyboard_arrow_down` | Chevrons (/˅) — lighter, more modern |
| `keyboard_double_arrow_right` | `keyboard_double_arrow_down` | Double chevrons (»/⌄) — emphatic |
| `expand_content` | `collapse_content` | Corner-arrows — editorial, spatial |
| `add` | `minimize` | Plus/minus — very minimal, utilitarian |
Mix and match freely — the expand and collapse icons do not have to come from
the same pair, but keeping them visually related (same weight and style)
usually reads better.
**Matching icon style to nav style:** bold high-contrast themes (filled
triangle, plus/minus) suit designs with strong typographic weight. Lighter
themes pair better with chevrons. Editorial or magazine-style designs work
well with `expand_content`/`collapse_content`.
---
## Nav colour keys: when to set them
There are six nav colour keys divided into two groups:
**Nav links and labels** — control the navigation list itself:
- `nav-link` — inactive link text (defaults to `text`)
- `nav-link-active` — active/current page link text (defaults to `accent`)
- `nav-section-heading` — uppercase section labels (defaults to `text-muted`)
**Sidebar header elements** — control the branding area above the nav list:
- `nav-sitename` — site name (defaults to `nav-link`)
- `nav-description` — subtitle below the site name (defaults to `nav-section-heading`)
- `nav-toggle` — dark/light mode toggle button (defaults to `nav-section-heading`)
### When the defaults are fine
On themes where `nav-background` is a neutral near-white (light mode) or
near-black (dark mode), `text` and `text-muted` read well against the nav
background. All six keys can be omitted and the fallback chain works correctly.
### When to set the keys explicitly
Set all six keys whenever `nav-background` is anything other than a neutral:
any saturated brand colour (red, navy, forest green, teal), any noticeably
dark sidebar in an otherwise light design, or any light-but-tinted background.
The two groups can be set independently. On a subtly tinted nav where the
link defaults look fine but the site name needs slightly more weight or a
different shade, set only the header keys (`nav-sitename`, `nav-description`,
`nav-toggle`) and leave the nav link keys to their defaults.
**Rule of thumb:** if `nav-background` has saturation above ~20 % or lightness
below 30 % (dark sidebar) or differs from `background` by more than a slight
tint, set all six explicitly for that mode.
### Pattern: accent-coloured nav (e.g. brand red, navy, forest green)
```yaml
light:
accent: "#D00C33"
nav-background: "#D00C33" # same as accent — all nav keys must be set
nav-link: "#FFFFFF"
nav-link-active: "#FFFFFF"
nav-section-heading: "rgba(255,255,255,0.65)"
nav-sitename: "#FFFFFF"
nav-description: "rgba(255,255,255,0.65)"
nav-toggle: "rgba(255,255,255,0.65)"
dark:
accent: "#D00C33"
nav-background: "#000000"
nav-link: "#E2E2E2"
nav-link-active: "#FFFFFF"
nav-section-heading: "#888888"
nav-sitename: "#FFFFFF"
nav-description: "#888888"
nav-toggle: "#888888"
```
### Pattern: dark nav in light mode (sidebar darker than content)
```yaml
light:
nav-background: "#1E293B"
nav-link: "#CBD5E1"
nav-link-active: "#FFFFFF"
nav-section-heading: "#64748B"
nav-sitename: "#FFFFFF"
nav-description: "#64748B"
nav-toggle: "#64748B"
```
### Pattern: transparent / very light nav (default behaviour)
When `nav-background` is a light neutral, the defaults work fine.
You can omit `nav-link`, `nav-link-active`, and `nav-section-heading`
and the renderer will fall back to `text`, `accent`, and `text-muted`.
---
## Semantic colours and dark mode
`colours-semantic` values are applied globally (both modes). The callout
background is rendered at ~8% opacity, so a colour that looks fine on white
can wash out on a dark background — or conversely, a colour bright enough for
dark mode may be too vivid on white.
The solution is `colours-semantic-dark`: it overrides semantic colours in dark
mode only. Typical approach:
- **`colours-semantic`** — choose saturated but not neon values that work on white
- **`colours-semantic-dark`** — use lighter, more luminous variants of the same hues
```yaml
colours-semantic:
info: "#1D4ED8" # deep blue — strong on white
warning: "#B45309" # amber — strong on white
success: "#15803D" # green — strong on white
error: "#B91C1C" # red — strong on white
colours-semantic-dark:
info: "#93C5FD" # light blue — visible on dark background
warning: "#FCD34D" # light amber
success: "#6EE7B7" # light green
error: "#FCA5A5" # light red/pink
```
Match `callouts` `primary-colour` / `background-colour` values to
`colours-semantic` (light mode callout values), since the callout block
uses its own per-callout colour settings rather than the semantic variables.
---
## Legibility analysis
Before finalising any theme — and especially when refactoring an existing one —
work through every colour pairing in the design and check that text is
readable against its background.
**Pairs to check:**
| Text | Background |
|---|---|
| `text` | `background` |
| `text-muted` | `background` |
| `nav-link` | `nav-background` |
| `nav-link-active` | `nav-background` |
| `nav-section-heading` | `nav-background` |
| `nav-sitename` | `nav-background` |
| `nav-description` | `nav-background` |
| `nav-toggle` | `nav-background` |
| `accent` | `background` (used for inline links in content) |
| `colours-semantic.*` | `background` (callout borders and tinted backgrounds) |
| `colours-semantic-dark.*` | dark `background` |
**WCAG contrast targets:**
- Body text (`text`) on `background`: aim for **7:1** (AAA). Never go below 4.5:1 (AA).
- Secondary text (`text-muted`, `nav-section-heading`, `nav-description`): minimum **3:1**, aim for 4.5:1.
- Nav links and site name: minimum **4.5:1** against `nav-background`.
- Active/hover states: minimum **3:1** (they are reinforced by other visual cues).
**Common failure modes to look for:**
- A saturated accent on a white background can be vibrant but low-contrast — reds and oranges are frequent offenders.
- `text-muted` on a tinted or coloured background often falls below 3:1.
- Dark-mode `text-muted` on a near-black background is easy to get wrong when porting from a light-mode palette.
- `nav-description` and `nav-toggle` are small and low-weight, so they need more contrast than the minimum to feel comfortable — lean toward the higher targets for these.
When a pairing is marginal, adjust the lighter or darker of the two values by enough to clear the target. Do not simply accept values that are close to failing.
---
## Checklist before finalising a theme
- [ ] All six nav colour keys (`nav-link`, `nav-link-active`, `nav-section-heading`,
`nav-sitename`, `nav-description`, `nav-toggle`) set for both `light` and
`dark` whenever `nav-background` is non-neutral
- [ ] All nav colours contrast against `nav-background` (WCAG AA minimum; see Legibility analysis above)
- [ ] `text` on `background` meets 7:1 (AAA); never below 4.5:1
- [ ] `text-muted` and header element colours meet at least 3:1; aim for 4.5:1
- [ ] `accent` on `background` meets 4.5:1 (used for inline links)
- [ ] `colours-semantic-dark` provided with lighter variants of each colour
- [ ] `callouts` `primary-colour` matches `colours-semantic` values for consistency
- [ ] `divider` omitted unless the auto-derived value looks wrong (check hr and table borders)
- [ ] Dark mode `background` is not pure `#000000` unless intentional (use `#0A0A0A`+)
- [ ] `font-size` between `0.85` and `1.15`; `line-height` between `1.5` and `1.9`
- [ ] Version comment on line 1: `# mdcms v0.4 | DO NOT REMOVE THIS COMMENT`