mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Refine header emphasis, field-on-layer treatment, and narrow-pane control collapse
This commit is contained in:
@@ -94,15 +94,16 @@ and size is a relationship of 8 (with 2/4 as fine sub-steps):
|
||||
Color is expressed as **roles**, never raw hexes, so themes can repaint the whole
|
||||
UI by swapping one set of values. Borrowed from Carbon's layering model:
|
||||
|
||||
| Role token | Meaning |
|
||||
| ---------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `--bg` | App canvas (lowest layer) |
|
||||
| `--layer-01` / `--layer-02` | Raised surfaces (panels, cards, popovers) — elevation by lightness step, not shadow |
|
||||
| `--border` / `--border-strong` | Subtle and prominent separators |
|
||||
| `--text` / `--text-secondary` / `--text-placeholder` | Text hierarchy |
|
||||
| `--accent` / `--accent-hover` / `--accent-contrast` | The expressive accent — **swappable**; UI must never hardcode a hue |
|
||||
| `--focus` | Focus-ring color (defaults to `--accent`) |
|
||||
| `--support-error / -success / -warning / -info` | Status only — color = meaning |
|
||||
| Role token | Meaning |
|
||||
| ---------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| `--bg` | App canvas (lowest layer) |
|
||||
| `--layer-01` / `--layer-02` | Raised surfaces (panels, cards, popovers) — elevation by lightness step, not shadow |
|
||||
| `--border` / `--border-strong` | Subtle and prominent separators |
|
||||
| `--text` / `--text-secondary` / `--text-placeholder` | Text hierarchy |
|
||||
| `--accent` / `--accent-hover` / `--accent-contrast` | The expressive accent — **swappable**; UI must never hardcode a hue |
|
||||
| `--accent-soft` / `--accent-soft-hover` | Low-emphasis accent **wash** (accent mixed into `--bg`) for a tinted-but-quiet surface |
|
||||
| `--focus` | Focus-ring color (defaults to `--accent`) |
|
||||
| `--support-error / -success / -warning / -info` | Status only — color = meaning |
|
||||
|
||||
- **Neutrals** use the Carbon gray ramp (`#f4f4f4 … #161616`) — accessible and
|
||||
legible. **Accent and theming are open**: the default accent is **deep teal**
|
||||
@@ -113,6 +114,17 @@ UI by swapping one set of values. Borrowed from Carbon's layering model:
|
||||
warning `#f1c21b`, info `#0043ce` — tuned per theme for contrast.
|
||||
- **Contrast:** target WCAG AA (4.5:1 text, 3:1 large/UI). Accent-on-`--bg` and
|
||||
text-on-`--accent` must both pass for any shipped theme.
|
||||
- **Soft accent is derived, not hardcoded.** `--accent-soft` /
|
||||
`--accent-soft-hover` are `color-mix(in srgb, var(--accent) 12–20%, var(--bg))`,
|
||||
so the wash follows whatever accent + theme is active rather than carrying a
|
||||
per-accent value. Use it for a surface that should be _noticed_ without competing
|
||||
with a primary action (the header's **Donate** button).
|
||||
- **Field-on-layer (Carbon layering).** A field is a layer _on top of_ the surface
|
||||
it sits on — so it steps **toward `--bg`**, never to a darker gray. On the white
|
||||
canvas and on a `--layer-01` panel alike, an input reads as **`--bg` fill +
|
||||
`--border-strong` outline**, not a `--layer-02` fill. Stacking a darker-gray field
|
||||
on a gray panel (canvas → `--layer-01` panel → `--layer-02` field) muddies into
|
||||
three indistinct grays — the bug this rule prevents (the snippet metadata panel).
|
||||
|
||||
### 3.4 Shape & elevation
|
||||
|
||||
@@ -138,9 +150,19 @@ UI by swapping one set of values. Borrowed from Carbon's layering model:
|
||||
## 4. Component conventions
|
||||
|
||||
- **Buttons:** square, 32px (compact) / 40px (default) tall. Variants: **primary**
|
||||
(filled `--accent`), **secondary** (bordered), **ghost** (text-only),
|
||||
**danger** (filled `--support-error`). 600-weight label. Clear hover/active and
|
||||
a visible focus ring.
|
||||
(filled `--accent`), **secondary** (bordered), **ghost** (text-only, borderless),
|
||||
**soft-accent** (ghost on an `--accent-soft` wash — a low-emphasis solicitation,
|
||||
e.g. Donate), **danger** (filled `--support-error`). 600-weight label. Clear
|
||||
hover/active and a visible focus ring.
|
||||
- **Emphasis hierarchy (Carbon button/usage).** A region carries **one**
|
||||
high-emphasis (primary) button at most; everything else is lower emphasis. In
|
||||
toolbars/headers full of utilities, the utilities go **ghost** so they recede
|
||||
behind the work area and read as a row of equals — only the genuine call to
|
||||
action is filled. Worked examples: the **editor toolbar** (Publish is the lone
|
||||
primary; Extract/Revert are secondary, and collapse to icons when narrow — see
|
||||
[arch 10 §8](10-interaction-and-feedback.md)), and the **header** (Datasets /
|
||||
Import / Export / About are ghost; a divider then sets off the soft-accent Donate
|
||||
and the ghost theme toggle).
|
||||
- **Hover is variant-specific:** filled buttons (primary/danger) **darken**
|
||||
(`--accent-hover` / a slight brightness drop); outlined/ghost buttons **gain a
|
||||
fill one elevation step above their surface** — on `--bg` → `--layer-01`, on a
|
||||
@@ -150,8 +172,10 @@ UI by swapping one set of values. Borrowed from Carbon's layering model:
|
||||
must step its hover fill up to match.
|
||||
- **Focus ring:** a 2px `--focus` outline (offset 1–2px). Always visible on
|
||||
keyboard focus — accessibility is non-negotiable (principle 4).
|
||||
- **Fields** (text, textarea, select, search): square, 1px `--border`, `--layer-01`
|
||||
fill, accent border + focus ring on focus. Mono font for spec/JSON inputs.
|
||||
- **Fields** (text, textarea, select, search): square, 1px `--border-strong`,
|
||||
**`--bg` fill** (field-on-layer, §3.3 — white on the canvas _and_ on a
|
||||
`--layer-01` panel; never a darker-gray fill), accent border + focus ring on
|
||||
focus. Mono font for spec/JSON inputs.
|
||||
- **List rows** (snippet library): compact, full-row hover (`--layer-01`),
|
||||
active row marked by an accent left-border + `--layer-01` fill, secondary
|
||||
metadata in `--text-secondary`. Row-level actions reveal on hover.
|
||||
@@ -232,15 +256,32 @@ Carbon and drawn `fill: currentColor`.
|
||||
|
||||
**Core set** — recurring, cross-surface:
|
||||
|
||||
| Meaning | Carbon glyph | Form | Surfaces |
|
||||
| -------------------- | --------------- | --------------------- | ------------------------------------------------- |
|
||||
| Close / dismiss | `Close` (✕) | icon-only ⭐ | `ModalShell`, `Toaster` |
|
||||
| Theme → dark | `Asleep` (moon) | icon-only ⭐ | `ThemeToggle` (shown when light) |
|
||||
| Theme → light | `Light` (sun) | icon-only ⭐ | `ThemeToggle` (shown when dark) |
|
||||
| References a dataset | `DataTable` | icon + text | Library row marker, Linked-datasets list |
|
||||
| Add / create-new | `Add` | icon + text | Library "Create New Snippet", Datasets "New …" |
|
||||
| Delete | `TrashCan` | icon-only ⭐ (danger) | Library row delete¹ — text "Delete" in the panel² |
|
||||
| Unpublished draft | (CSS dot) | status-glyph | Library row (paired with a hidden label) |
|
||||
| Meaning | Carbon glyph | Form | Surfaces |
|
||||
| -------------------- | --------------- | ------------------------ | -------------------------------------------------------------------------------------------- |
|
||||
| Close / dismiss | `Close` (✕) | icon-only ⭐ | `ModalShell`, `Toaster` |
|
||||
| Theme → dark | `Asleep` (moon) | icon-only ⭐ | `ThemeToggle` (shown when light) |
|
||||
| Theme → light | `Light` (sun) | icon-only ⭐ | `ThemeToggle` (shown when dark) |
|
||||
| References a dataset | `DataTable` | icon + text | Library row marker, Linked-datasets list, header **Datasets**, editor **Extract**⁴ |
|
||||
| Add / create-new | `Add` | icon + text → icon-only⁴ | Library "Create New Snippet" (collapses to "+" when the pane is narrow), Datasets "New …" |
|
||||
| Delete | `TrashCan` | icon-only ⭐ (danger) | Library row delete¹ — text "Delete" in the panel² |
|
||||
| Import workspace | `Upload` | icon + text | Header **Import** (a file is brought into the app) |
|
||||
| Export workspace | `Download` | icon + text | Header **Export** (the workspace is written out) |
|
||||
| About / information | `Information` | icon + text | Header **About** |
|
||||
| Revert draft | `Reset` | icon + text → icon-only⁴ | Editor toolbar **Revert** (restore last published) |
|
||||
| Live search | `Search` | icon-in-field⁵ | Library search box (leading magnifier; the input's `aria-label`/placeholder names the field) |
|
||||
| Settings (gear) | `Settings` | icon-only ⭐ | Per-pane settings disclosures (Editor, Preview, Library dates) |
|
||||
| Unpublished draft | (CSS dot) | status-glyph | Library row (paired with a hidden label) |
|
||||
|
||||
**Pane-toggle set** — the one **custom** sub-family (not single Carbon glyphs): a
|
||||
panel frame with one of three regions filled, where the filled bar's _position_
|
||||
encodes which pane it toggles. Icon-only by design — position is the meaning — each
|
||||
carrying an `aria-label`:
|
||||
|
||||
| Meaning | Glyph | Form | Surface |
|
||||
| ------------------- | ------------------------------ | ------------ | ----------------- |
|
||||
| Toggle library pane | panel frame, **left** filled | icon-only ⭐ | `PaneToggleStrip` |
|
||||
| Toggle editor pane | panel frame, **centre** filled | icon-only ⭐ | `PaneToggleStrip` |
|
||||
| Toggle preview pane | panel frame, **right** filled | icon-only ⭐ | `PaneToggleStrip` |
|
||||
|
||||
**Status set** — Carbon's **filled** notification glyphs, one per severity. Unlike
|
||||
the outline UI set, these are coloured **by status** (not by surrounding text) and
|
||||
@@ -257,23 +298,37 @@ notifications/validation as they arrive):
|
||||
| Success | `CheckmarkFilled` | `--support-success` | `Toaster` (success) |
|
||||
| Info | `InformationFilled` | `--support-info` | `Toaster` (info) |
|
||||
|
||||
**Scoped set** — registered (glyph reserved) but single-surface and **not yet
|
||||
implemented**:
|
||||
**Scoped set** — single-surface, glyph **reserved** in the ledger but **not yet in
|
||||
the `Icon` registry**:
|
||||
|
||||
| Meaning | Carbon glyph | Form | Surface / note |
|
||||
| ---------------- | ------------------ | ----------- | ----------------------------------------------------- |
|
||||
| Swap / transpose | `ArrowsHorizontal` | icon + text | Chart Builder "Swap X/Y" — one button; icon is polish |
|
||||
| Meaning | Carbon glyph | Form | Surface / note |
|
||||
| ---------------- | ------------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Swap / transpose | `ArrowsHorizontal` | icon + text | Chart Builder "Swap X/Y" — the button **ships** today with an interim Unicode `⇄`, not a registry `Icon`. `ArrowsHorizontal` stays reserved here so the meaning is claimed; promote the button to it (add the `IconName` + glyph) when polishing the swap. |
|
||||
|
||||
⭐ = **icon-only set**: close + theme (truly universal), plus **delete** as a
|
||||
deliberate destructive-row exception — a dense, repeated list action where a label
|
||||
would cost more than it gives. ✕ means **close only**; delete is `TrashCan`, never
|
||||
✕ (that collision is exactly what one-glyph-one-meaning forbids).
|
||||
⭐ = **icon-only set** (the glyph alone names the control, via `aria-label`): the
|
||||
**universal** glyphs `close` + `theme`; the conventional disclosure/affordance
|
||||
glyphs `settings` (gear) and the **pane-toggle** trio (position is the meaning);
|
||||
and **delete** as a deliberate destructive-row exception — a dense, repeated list
|
||||
action where a label would cost more than it gives. `search` is _not_ ⭐: its
|
||||
magnifier is a decorative lead-in to a labelled input (footnote ⁵), not a control
|
||||
named by the glyph. ✕ means **close only**; delete is `TrashCan`, never ✕ (that
|
||||
collision is exactly what one-glyph-one-meaning forbids). Admitting a glyph to ⭐ is
|
||||
a contract change (§5.1 rule 4), not a per-component call.
|
||||
|
||||
¹ Row delete is hover/focus-revealed and reddens on hover/focus (arch 10 — reveal &
|
||||
destructive-intent rules). ² "Duplicate" and "Delete" in the detail panel stay
|
||||
**text** (label-first; lower frequency, not a dense row). ³ The raw warning yellow
|
||||
fails contrast on light surfaces, so the warning glyph uses `--support-warning-fg`
|
||||
(darkened amber; the yellow `--toast-accent` stays on the decorative border).
|
||||
(darkened amber; the yellow `--toast-accent` stays on the decorative border). ⁴
|
||||
**Responsive collapse**, not membership in the icon-only set: these are icon+text
|
||||
that _shed the label_ under width pressure (the editor toolbar's secondary actions,
|
||||
and the library's standalone Create CTA, when the pane is narrow — [arch 10
|
||||
§8](10-interaction-and-feedback.md)), keeping the accessible name in
|
||||
`aria-label`/`title`. A degradation that preserves the name is distinct from a
|
||||
permanent icon-only control (§5.1 rule 4), so it isn't a closed-set change. ⁵
|
||||
**Icon-in-field**: a decorative leading glyph _inside_ a labelled control — the
|
||||
search input's magnifier is `aria-hidden`, and the input itself carries the
|
||||
accessible name. Not icon-only (the control is named by its label, not the glyph).
|
||||
|
||||
### 5.3 Size
|
||||
|
||||
|
||||
Reference in New Issue
Block a user