mirror of
https://github.com/kbenestad/mdcms.git
synced 2026-06-18 15:24:32 +00:00
Add nav-sitename, nav-description, nav-toggle colour keys
Separates sidebar header colours from nav link colours. The three new keys control the site name, site description, and dark/light toggle independently, each cascading from the nearest nav variable (nav-sitename → nav-link, nav-description and nav-toggle → nav-section-heading) so existing themes are unaffected. Enables Claude Design to fine-tune sidebar header legibility on saturated or bold nav backgrounds without having to override the nav link colours, and vice versa. CSS selectors and applyThemeYml() updated; app/theme.yml, CLAUDE.md, and docs/claude-design.md updated with full key reference and pattern examples. https://claude.ai/code/session_01NQKywehSj8Ku4yKhwB4VNB
This commit is contained in:
parent
1d76226311
commit
f4a41ed3ae
4 changed files with 77 additions and 31 deletions
|
|
@ -233,6 +233,9 @@ Presentational config separate from `config.yml`. Controls accent colour, dark/l
|
||||||
| `nav-link` | `--nav-link-colour` | falls back to `text` |
|
| `nav-link` | `--nav-link-colour` | falls back to `text` |
|
||||||
| `nav-link-active` | `--nav-link-active-colour` | falls back to `accent` |
|
| `nav-link-active` | `--nav-link-active-colour` | falls back to `accent` |
|
||||||
| `nav-section-heading` | `--nav-section-heading-colour` | falls back to `text-muted` |
|
| `nav-section-heading` | `--nav-section-heading-colour` | falls back to `text-muted` |
|
||||||
|
| `nav-sitename` | `--nav-sitename-colour` | falls back to `nav-link` |
|
||||||
|
| `nav-description` | `--nav-description-colour` | falls back to `nav-section-heading` |
|
||||||
|
| `nav-toggle` | `--nav-toggle-colour` | falls back to `nav-section-heading` |
|
||||||
| `divider` | `--divider` | `color-mix(in srgb, background 85%, text)` |
|
| `divider` | `--divider` | `color-mix(in srgb, background 85%, text)` |
|
||||||
|
|
||||||
**When to use nav-link keys:** When `nav-background` matches or is very close to `accent`, the default behaviour (active link coloured with `accent`) makes links invisible. Set `nav-link`, `nav-link-active`, and `nav-section-heading` explicitly so all three are legible against `nav-background`. Example: a red nav background needs white (`#FFFFFF`) for all three nav colour keys.
|
**When to use nav-link keys:** When `nav-background` matches or is very close to `accent`, the default behaviour (active link coloured with `accent`) makes links invisible. Set `nav-link`, `nav-link-active`, and `nav-section-heading` explicitly so all three are legible against `nav-background`. Example: a red nav background needs white (`#FFFFFF`) for all three nav colour keys.
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ if ('serviceWorker' in navigator) {
|
||||||
--nav-link-colour: var(--nav-font-colour);
|
--nav-link-colour: var(--nav-font-colour);
|
||||||
--nav-link-active-colour: var(--accent);
|
--nav-link-active-colour: var(--accent);
|
||||||
--nav-section-heading-colour: var(--font-colour-muted);
|
--nav-section-heading-colour: var(--font-colour-muted);
|
||||||
|
--nav-sitename-colour: var(--nav-link-colour);
|
||||||
|
--nav-description-colour: var(--nav-section-heading-colour);
|
||||||
|
--nav-toggle-colour: var(--nav-section-heading-colour);
|
||||||
--nav-active-bg: rgba(var(--accent-rgb), 0.10);
|
--nav-active-bg: rgba(var(--accent-rgb), 0.10);
|
||||||
--nav-hover-bg: rgba(var(--accent-rgb), 0.05);
|
--nav-hover-bg: rgba(var(--accent-rgb), 0.05);
|
||||||
--font-colour: #1E293B;
|
--font-colour: #1E293B;
|
||||||
|
|
@ -91,6 +94,9 @@ if ('serviceWorker' in navigator) {
|
||||||
--bg-nav: #1E293B;
|
--bg-nav: #1E293B;
|
||||||
--nav-font-colour: #E2E8F0;
|
--nav-font-colour: #E2E8F0;
|
||||||
--nav-link-colour: var(--nav-font-colour);
|
--nav-link-colour: var(--nav-font-colour);
|
||||||
|
--nav-sitename-colour: var(--nav-link-colour);
|
||||||
|
--nav-description-colour: var(--nav-section-heading-colour);
|
||||||
|
--nav-toggle-colour: var(--nav-section-heading-colour);
|
||||||
--nav-link-active-colour: var(--accent);
|
--nav-link-active-colour: var(--accent);
|
||||||
--nav-section-heading-colour: var(--font-colour-muted);
|
--nav-section-heading-colour: var(--font-colour-muted);
|
||||||
--nav-active-bg: rgba(96, 165, 250, 0.15);
|
--nav-active-bg: rgba(96, 165, 250, 0.15);
|
||||||
|
|
@ -196,14 +202,14 @@ body {
|
||||||
font-family: var(--font-title);
|
font-family: var(--font-title);
|
||||||
font-weight: var(--font-title-weight);
|
font-weight: var(--font-title-weight);
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
color: var(--nav-link-colour, var(--font-colour));
|
color: var(--nav-sitename-colour);
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.sidebar-sitename:hover { color: var(--nav-link-active-colour, var(--accent)); }
|
.sidebar-sitename:hover { color: var(--nav-link-active-colour, var(--accent)); }
|
||||||
|
|
||||||
.sidebar-description { font-size: 0.8rem; color: var(--nav-section-heading-colour, var(--font-colour-muted)); margin-top: 0.25rem; line-height: 1.4; }
|
.sidebar-description { font-size: 0.8rem; color: var(--nav-description-colour); margin-top: 0.25rem; line-height: 1.4; }
|
||||||
|
|
||||||
/* Search */
|
/* Search */
|
||||||
.search-container { padding: 0.75rem 1.25rem; flex-shrink: 0; }
|
.search-container { padding: 0.75rem 1.25rem; flex-shrink: 0; }
|
||||||
|
|
@ -341,9 +347,9 @@ body {
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.4rem 0.6rem;
|
padding: 0.4rem 0.6rem;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--nav-section-heading-colour, var(--font-colour-muted));
|
color: var(--nav-toggle-colour);
|
||||||
background: none;
|
background: none;
|
||||||
border: 1px solid color-mix(in srgb, var(--bg-nav) 70%, var(--nav-link-colour, var(--font-colour)));
|
border: 1px solid color-mix(in srgb, var(--bg-nav) 70%, var(--nav-toggle-colour));
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: var(--font-body);
|
font-family: var(--font-body);
|
||||||
|
|
@ -351,7 +357,7 @@ body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.theme-toggle:hover { color: var(--nav-link-colour, var(--font-colour)); border-color: var(--nav-section-heading-colour, var(--font-colour-muted)); }
|
.theme-toggle:hover { color: var(--nav-link-colour, var(--font-colour)); border-color: var(--nav-toggle-colour); }
|
||||||
.theme-toggle svg { width: 16px; height: 16px; flex-shrink: 0; }
|
.theme-toggle svg { width: 16px; height: 16px; flex-shrink: 0; }
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════
|
/* ═══════════════════════════════════════════
|
||||||
|
|
@ -1259,6 +1265,9 @@ body {
|
||||||
if (m['nav-link']) vars.push(`--nav-link-colour: ${m['nav-link']}`);
|
if (m['nav-link']) vars.push(`--nav-link-colour: ${m['nav-link']}`);
|
||||||
if (m['nav-link-active']) vars.push(`--nav-link-active-colour: ${m['nav-link-active']}`);
|
if (m['nav-link-active']) vars.push(`--nav-link-active-colour: ${m['nav-link-active']}`);
|
||||||
if (m['nav-section-heading']) vars.push(`--nav-section-heading-colour: ${m['nav-section-heading']}`);
|
if (m['nav-section-heading']) vars.push(`--nav-section-heading-colour: ${m['nav-section-heading']}`);
|
||||||
|
if (m['nav-sitename']) vars.push(`--nav-sitename-colour: ${m['nav-sitename']}`);
|
||||||
|
if (m['nav-description']) vars.push(`--nav-description-colour: ${m['nav-description']}`);
|
||||||
|
if (m['nav-toggle']) vars.push(`--nav-toggle-colour: ${m['nav-toggle']}`);
|
||||||
if (m['divider']) vars.push(`--divider: ${m['divider']}`);
|
if (m['divider']) vars.push(`--divider: ${m['divider']}`);
|
||||||
if (vars.length) modeCss += `:root[data-theme="${mode}"] { ${vars.join('; ')}; }\n`;
|
if (vars.length) modeCss += `:root[data-theme="${mode}"] { ${vars.join('; ')}; }\n`;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ light:
|
||||||
# nav-link: "#1E293B" # inactive nav link text (defaults to text)
|
# nav-link: "#1E293B" # inactive nav link text (defaults to text)
|
||||||
# nav-link-active: "#2563EB" # active nav link text (defaults to accent)
|
# nav-link-active: "#2563EB" # active nav link text (defaults to accent)
|
||||||
# nav-section-heading: "#64748B" # nav section label text (defaults to text-muted)
|
# nav-section-heading: "#64748B" # nav section label text (defaults to text-muted)
|
||||||
|
# nav-sitename: "#1E293B" # site name in sidebar header (defaults to nav-link)
|
||||||
|
# nav-description: "#64748B" # site description in sidebar header (defaults to nav-section-heading)
|
||||||
|
# nav-toggle: "#64748B" # dark/light mode toggle (defaults to nav-section-heading)
|
||||||
# divider: "#CBD5E1" # border/hr colour (defaults to color-mix of background + text)
|
# divider: "#CBD5E1" # border/hr colour (defaults to color-mix of background + text)
|
||||||
|
|
||||||
dark:
|
dark:
|
||||||
|
|
@ -26,6 +29,9 @@ dark:
|
||||||
# nav-link: "#E2E8F0" # inactive nav link text (defaults to text)
|
# nav-link: "#E2E8F0" # inactive nav link text (defaults to text)
|
||||||
# nav-link-active: "#60A5FA" # active nav link text (defaults to accent)
|
# nav-link-active: "#60A5FA" # active nav link text (defaults to accent)
|
||||||
# nav-section-heading: "#94A3B8" # nav section label text (defaults to text-muted)
|
# nav-section-heading: "#94A3B8" # nav section label text (defaults to text-muted)
|
||||||
|
# nav-sitename: "#E2E8F0" # site name in sidebar header (defaults to nav-link)
|
||||||
|
# nav-description: "#94A3B8" # site description in sidebar header (defaults to nav-section-heading)
|
||||||
|
# nav-toggle: "#94A3B8" # dark/light mode toggle (defaults to nav-section-heading)
|
||||||
# divider: "#334155" # border/hr colour (defaults to color-mix of background + text)
|
# divider: "#334155" # border/hr colour (defaults to color-mix of background + text)
|
||||||
|
|
||||||
# ──────────────────────────────────
|
# ──────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,13 @@ light:
|
||||||
nav-background: "#F8FAFC" # sidebar/nav panel background
|
nav-background: "#F8FAFC" # sidebar/nav panel background
|
||||||
text: "#1E293B" # body text
|
text: "#1E293B" # body text
|
||||||
text-muted: "#64748B" # secondary text, captions
|
text-muted: "#64748B" # secondary text, captions
|
||||||
nav-link: "#1E293B" # inactive nav link text
|
nav-link: "#1E293B" # inactive nav link text
|
||||||
nav-link-active: "#2563EB" # active (current page) nav link text
|
nav-link-active: "#2563EB" # active (current page) nav link text
|
||||||
nav-section-heading: "#64748B" # nav section label text (uppercase, small)
|
nav-section-heading: "#64748B" # nav section label text (uppercase, small)
|
||||||
# divider: "#CBD5E1" # omit to auto-derive via color-mix(background, text)
|
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:
|
dark:
|
||||||
accent: "#60A5FA"
|
accent: "#60A5FA"
|
||||||
|
|
@ -35,7 +38,10 @@ dark:
|
||||||
nav-link: "#E2E8F0"
|
nav-link: "#E2E8F0"
|
||||||
nav-link-active: "#60A5FA"
|
nav-link-active: "#60A5FA"
|
||||||
nav-section-heading: "#94A3B8"
|
nav-section-heading: "#94A3B8"
|
||||||
# divider: "#334155" # omit to auto-derive via color-mix(background, text)
|
nav-sitename: "#E2E8F0"
|
||||||
|
nav-description: "#94A3B8"
|
||||||
|
nav-toggle: "#94A3B8"
|
||||||
|
# divider: "#334155" # omit to auto-derive via color-mix(background, text)
|
||||||
|
|
||||||
# ──────────────────────────────────
|
# ──────────────────────────────────
|
||||||
# Semantic colours
|
# Semantic colours
|
||||||
|
|
@ -95,38 +101,53 @@ nav-width: 20em
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Critical rule: nav contrast
|
## Nav colour keys: when to set them
|
||||||
|
|
||||||
The renderer defaults `nav-link-active` to `accent` and `nav-link` to `text`.
|
There are six nav colour keys divided into two groups:
|
||||||
When `nav-background` and `accent` share the same hue (or are very close),
|
|
||||||
active nav links become invisible — the coloured text disappears into a
|
|
||||||
coloured background.
|
|
||||||
|
|
||||||
The nav colour keys also control the **site name, site description, and
|
**Nav links and labels** — control the navigation list itself:
|
||||||
dark/light mode toggle** — all three live inside the sidebar and inherit from
|
- `nav-link` — inactive link text (defaults to `text`)
|
||||||
the same variables. On muted or neutral nav backgrounds the content-area
|
- `nav-link-active` — active/current page link text (defaults to `accent`)
|
||||||
fallbacks (`text`, `text-muted`) are fine. On any saturated or bold nav
|
- `nav-section-heading` — uppercase section labels (defaults to `text-muted`)
|
||||||
background the contrast between `text` and `text-muted` is likely too low for
|
|
||||||
these elements to remain legible, so all three nav colour keys must be set
|
|
||||||
explicitly.
|
|
||||||
|
|
||||||
**Rule of thumb:** if `nav-background` has a saturation above roughly 20 % or
|
**Sidebar header elements** — control the branding area above the nav list:
|
||||||
a lightness below 30 % (dark sidebar) or above 85 % (near-white sidebar that
|
- `nav-sitename` — site name (defaults to `nav-link`)
|
||||||
differs noticeably from the page background), set `nav-link`,
|
- `nav-description` — subtitle below the site name (defaults to `nav-section-heading`)
|
||||||
`nav-link-active`, and `nav-section-heading` explicitly for that mode.
|
- `nav-toggle` — dark/light mode toggle button (defaults to `nav-section-heading`)
|
||||||
|
|
||||||
**Always set all three nav colour keys explicitly** whenever `nav-background`
|
### When the defaults are fine
|
||||||
is anything other than a neutral near-white (light) or near-black (dark).
|
|
||||||
|
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)
|
### Pattern: accent-coloured nav (e.g. brand red, navy, forest green)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
light:
|
light:
|
||||||
accent: "#D00C33"
|
accent: "#D00C33"
|
||||||
nav-background: "#D00C33" # same as accent — nav links MUST be overridden
|
nav-background: "#D00C33" # same as accent — all nav keys must be set
|
||||||
nav-link: "#FFFFFF"
|
nav-link: "#FFFFFF"
|
||||||
nav-link-active: "#FFFFFF"
|
nav-link-active: "#FFFFFF"
|
||||||
nav-section-heading: "rgba(255,255,255,0.65)"
|
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:
|
dark:
|
||||||
accent: "#D00C33"
|
accent: "#D00C33"
|
||||||
|
|
@ -134,6 +155,9 @@ dark:
|
||||||
nav-link: "#E2E2E2"
|
nav-link: "#E2E2E2"
|
||||||
nav-link-active: "#FFFFFF"
|
nav-link-active: "#FFFFFF"
|
||||||
nav-section-heading: "#888888"
|
nav-section-heading: "#888888"
|
||||||
|
nav-sitename: "#FFFFFF"
|
||||||
|
nav-description: "#888888"
|
||||||
|
nav-toggle: "#888888"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pattern: dark nav in light mode (sidebar darker than content)
|
### Pattern: dark nav in light mode (sidebar darker than content)
|
||||||
|
|
@ -144,6 +168,9 @@ light:
|
||||||
nav-link: "#CBD5E1"
|
nav-link: "#CBD5E1"
|
||||||
nav-link-active: "#FFFFFF"
|
nav-link-active: "#FFFFFF"
|
||||||
nav-section-heading: "#64748B"
|
nav-section-heading: "#64748B"
|
||||||
|
nav-sitename: "#FFFFFF"
|
||||||
|
nav-description: "#64748B"
|
||||||
|
nav-toggle: "#64748B"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pattern: transparent / very light nav (default behaviour)
|
### Pattern: transparent / very light nav (default behaviour)
|
||||||
|
|
@ -189,9 +216,10 @@ uses its own per-callout colour settings rather than the semantic variables.
|
||||||
|
|
||||||
## Checklist before finalising a theme
|
## Checklist before finalising a theme
|
||||||
|
|
||||||
- [ ] `nav-link`, `nav-link-active`, `nav-section-heading` specified for both
|
- [ ] All six nav colour keys (`nav-link`, `nav-link-active`, `nav-section-heading`,
|
||||||
`light` and `dark` whenever `nav-background` is non-neutral
|
`nav-sitename`, `nav-description`, `nav-toggle`) set for both `light` and
|
||||||
- [ ] All three nav link colours contrast against `nav-background` (WCAG AA minimum)
|
`dark` whenever `nav-background` is non-neutral
|
||||||
|
- [ ] All nav colours contrast against `nav-background` (WCAG AA minimum)
|
||||||
- [ ] `colours-semantic-dark` provided with lighter variants of each colour
|
- [ ] `colours-semantic-dark` provided with lighter variants of each colour
|
||||||
- [ ] `callouts` `primary-colour` matches `colours-semantic` values for consistency
|
- [ ] `callouts` `primary-colour` matches `colours-semantic` values for consistency
|
||||||
- [ ] `divider` omitted unless the auto-derived value looks wrong (check hr and table borders)
|
- [ ] `divider` omitted unless the auto-derived value looks wrong (check hr and table borders)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue