chore: 2 big design passes to harmonize and fix stuff
This commit is contained in:
1 parent
67b3ff03d0
commit
5e05b606a7
43 files changed
+2167
-4183
No files matched your search
+85
-165
@@ -1,167 +1,87 @@
|
||||
# Foundations
|
||||
|
||||
Token source files (copy them into `web/src/theme/` in the Nuxt UI foundation slice, which then becomes the live source):
|
||||
|
||||
- `source/tokens/renewcms.css`: `@theme`, `:root`, `.dark` and the `.article-content` scale
|
||||
- `source/tokens/ui.config.ts`: Nuxt UI color aliases, icons and component `ui` overrides
|
||||
- `source/tokens/vite.config.ts`: the `@nuxt/ui/vite` plugin setup
|
||||
- `source/tokens/tokens.json`: the same values as data
|
||||
- `source/brand/favicon.svg`: the mark, dark-aware
|
||||
|
||||
Extracted from `source/RenewCMS Foundations.dc.html`:
|
||||
|
||||
## Ledger foundations
|
||||
|
||||
Everything below is generated from one set of files: tokens/renewcms.css (Tailwind @theme , :root , .dark , article content styles), tokens/ui.config.ts (Nuxt UI colors, icons and component overrides) and tokens/vite.config.ts . The tables on this page read those files, so they can't drift.
|
||||
|
||||
### Logo
|
||||
|
||||
The mark is a white R on a black square, drawn on a 16-pixel grid so it stays sharp as a favicon. It keeps the same geometry at every size. In dark mode the black square gets a 1 px #444 edge so it doesn't disappear into the background. The wordmark pairs the mark with RenewCMS in Plex Sans Semibold, with the text set at 0.6× the mark's height.
|
||||
|
||||
RenewCMS
|
||||
|
||||
16
|
||||
|
||||
32
|
||||
|
||||
64
|
||||
|
||||
128, app icon source for 180 / 512
|
||||
|
||||
Articles · RenewCMS
|
||||
|
||||
RenewCMS
|
||||
|
||||
16
|
||||
|
||||
32
|
||||
|
||||
64
|
||||
|
||||
128
|
||||
|
||||
Articles · RenewCMS
|
||||
|
||||
Favicon file: brand/favicon.svg . The 1 px edge switches on with prefers-color-scheme: dark . Keep clear space of at least half the mark's height around it. The R is never recolored or placed on sand.
|
||||
|
||||
### Color scales
|
||||
|
||||
Seven Tailwind color scales, each mapped to a Nuxt UI alias. The ink, chalk and sand scales are built on your brand values. The four semantic scales are new and deliberately muted: evenly spaced oklch lightness steps with low chroma, so they sit comfortably next to ink and sand.
|
||||
|
||||
### Theme variables
|
||||
|
||||
Every --ui-* variable Nuxt UI reads, for both themes. Surfaces are white. The #fafafa brand background is the page canvas behind them. The theme follows the system setting until the owner picks Light or Dark from the user menu, and that choice is stored by Nuxt UI's color mode.
|
||||
|
||||
Variable Used for Light Dark
|
||||
|
||||
### Contrast checks
|
||||
|
||||
Pair Needs Light Dark
|
||||
|
||||
### Typography
|
||||
|
||||
The interface uses IBM Plex Sans in three weights: 400, 500 and 600. IDs, paths, counters and code are set in IBM Plex Mono. Sizes replace Tailwind's text-* defaults. On screens narrower than md , form fields use 16 px so iOS doesn't zoom in when a field gets focus.
|
||||
|
||||
Before and after: the Rue Verte kitchen
|
||||
|
||||
GET /v1/article/12 · 8 412 / 10 000
|
||||
|
||||
font-mono · 13px / 20px · 400 Code, paths, IDs, counters
|
||||
|
||||
Article content uses a separate scale in Source Serif 4, applied through the .article-content class. The editor surface and the preview both use it, so what the owner writes looks like what a public site would roughly show. The measure is capped at 42 rem, about 70 characters per line.
|
||||
|
||||
Choosing lime plaster for old stone walls
|
||||
|
||||
Cement traps moisture in solid walls. Lime lets the stone breathe, which is why we strip it back on almost every farmhouse we take on .
|
||||
|
||||
What we use
|
||||
|
||||
Hot-mixed lime for the base coat
|
||||
|
||||
Hair or fibre for the scratch coat
|
||||
|
||||
A thin lime putty finish
|
||||
|
||||
Drying time
|
||||
|
||||
It sets slowly, and that is the point.
|
||||
|
||||
Before you start
|
||||
|
||||
Strip loose material back to sound stone.
|
||||
|
||||
Wet the wall the evening before.
|
||||
|
||||
Article image
|
||||
|
||||
The north wall after the second coat.
|
||||
|
||||
Element md and up Below md, spacing
|
||||
|
||||
### Spacing, radius and density
|
||||
|
||||
Spacing uses Tailwind's 4 px base unit unchanged. Radius is 0 everywhere: setting --ui-radius: 0rem flattens every component that derives its corners from it, and rounded-none overrides cover the few that hard-code rounded-full . The density is compact on desktop. On touch screens, every tap target is at least 44 px.
|
||||
|
||||
Control Height and use
|
||||
|
||||
size="sm" 28 px · table row actions, toolbar buttons in the editor
|
||||
|
||||
size="md" 32 px · default on desktop: buttons, inputs, selects, tabs
|
||||
|
||||
size="lg" 40 px · auth forms, primary actions in dialogs
|
||||
|
||||
size="xl" 44 px · everything below md, via a responsive size prop
|
||||
|
||||
Table row 44 px on desktop, 64 px cards on mobile
|
||||
|
||||
Gutters 16 px on mobile, 24 px on desktop; sidebar 224 px, collapses to 56 px
|
||||
|
||||
### Borders and elevation
|
||||
|
||||
Most surfaces are flat and separated by hairlines. Shadows appear only on things that float above the page.
|
||||
|
||||
Hairline 1 px --ui-border . Cards, table edges, sidebar and top bar dividers. Decorative, so no contrast requirement.
|
||||
|
||||
Search by title
|
||||
|
||||
Control edge 1 px --ui-border-accented . Inputs, selects, checkboxes, outline buttons. 3.6:1 on white.
|
||||
|
||||
New article
|
||||
|
||||
Focus ring 2 px --ui-primary outline with a 2 px offset, shown only on :focus-visible . Nuxt UI's default, kept.
|
||||
|
||||
Edit
|
||||
|
||||
Unpublish
|
||||
|
||||
Popover --shadow-popover . Dropdown menus, selects, toasts. In dark mode it becomes a darker shadow plus the hairline.
|
||||
|
||||
Modal --shadow-modal over a 40% chalk-950 overlay. Modals and slideovers.
|
||||
|
||||
Layer z Contents
|
||||
|
||||
Breakpoint Min What changes
|
||||
|
||||
### Motion
|
||||
|
||||
Motion is there to show where something came from or that something is working. It is short and never decorative.
|
||||
|
||||
120 ms --duration-fast · ease-standard Hover and pressed colors, focus ring, the counter turning to warning, the switch thumb.
|
||||
|
||||
180 ms --duration-base · ease-enter / ease-exit Dropdowns and tooltips (fade plus a 4 px shift), the tab indicator, toasts sliding in, SaveStatus crossfades.
|
||||
|
||||
240 ms --duration-slow · ease-enter / ease-exit Modals (fade plus scale from 0.98), slideovers (slide from the edge), sidebar collapse.
|
||||
|
||||
Never animates Route changes, table rows sorting or filtering, numbers counting up, the logo, editor text, and anything that runs on page load.
|
||||
|
||||
Reduced motion With prefers-reduced-motion: reduce , every transition and animation completes instantly, skeletons stop pulsing and become flat blocks, and toasts appear without sliding. The one exception is the spinner on the automatic verification screen. It keeps turning, slowed to 1.6 s per rotation, because it is the only sign that work is happening.
|
||||
|
||||
### Icons
|
||||
|
||||
Lucide through Iconify, using Nuxt UI's i-lucide-* classes. Icons are 16 px next to 13–14 px text and 20 px on mobile top bars. They are always paired with a visible label or an aria-label . Each icon maps to one meaning: Eye is only ever show password, and Preview uses Book Open.
|
||||
|
||||
### Where Nuxt UI defaults bend
|
||||
|
||||
### Files
|
||||
|
||||
Ready to paste into the repository. They follow its code style: tabs, no semicolons, single quotes and no comments. The CSS goes in src/assets/main.css and the config in src/theme/ui.config.ts . Add class="isolate" to the app root, as Nuxt UI requires.
|
||||
Tokens only. No raw hex or rgb in any frame. The one exception is the brand mark SVG (`#111` and `#fff` fills). Radius is 0 everywhere (no `border-radius` is declared in any frame).
|
||||
|
||||
## New tokens (do not exist in the app yet)
|
||||
`tokens/renewcms.css` defines no `--rc-*` token. The frames use the ones below. They are **new**. Add them to the app's CSS, light values in `:root` and dark values in `.dark`. No `--ui-*` token is changed.
|
||||
|
||||
| Name | Light | Dark | Used by |
|
||||
|---|---|---|---|
|
||||
| `--rc-sand` | #e8dfd1 | #d4c5b0 | Selected nav item (parent and child), selected table row and media card, current paginator page, pressed filter card, avatars, account chip, "In this article" tag, drag-drop fill |
|
||||
| `--rc-on-sand` | #111111 | #111111 | Text and icons on `--rc-sand`. Never use `--ui-text-muted` or white on sand |
|
||||
| `--rc-success-soft` | #eaefea | #1f241f | Success badge, success alert and toast icon ground |
|
||||
| `--rc-info-soft` | #ebeef0 | #202428 | Info badge, info alert, "variants" badge, duplicate badge |
|
||||
| `--rc-warning-soft` | #f0ede6 | #2a251e | Warning badge and alert, "Unused" badge |
|
||||
| `--rc-error-soft` | #f3eae9 | #2c201f | Error badge and alert, failed-actions card |
|
||||
| `--rc-overlay` | rgb(10 10 10 / 0.4) | rgb(0 0 0 / 0.6) | Dialog, sheet and slide-over scrim; crop mask |
|
||||
| `--rc-shadow-pop` | 0 4px 16px rgb(17 17 17 / 0.08), 0 1px 2px rgb(17 17 17 / 0.06) | 0 4px 16px rgb(0 0 0 / 0.5) | Menus, popovers, toasts. Same as `--shadow-popover` |
|
||||
| `--rc-shadow-modal` | 0 16px 48px rgb(17 17 17 / 0.18) | 0 16px 48px rgb(0 0 0 / 0.6) | Dialogs, sheets, slide-overs. Same as `--shadow-modal` |
|
||||
| `--rc-canvas` | #ecebe8 | #1c1c1c | Design boards only. Not for the app |
|
||||
|
||||
Implementers may alias `--rc-shadow-pop` and `--rc-shadow-modal` to the existing `--shadow-popover` and `--shadow-modal`. The Nuxt UI `UAlert`/`UBadge` `soft` variants can map to the four `-soft` tokens.
|
||||
|
||||
## Contrast (computed, AA: text 4.5:1, UI components 3:1)
|
||||
Light | dark. Computed with the WCAG relative luminance formula from the token values above and the `--ui-*` values in the board root.
|
||||
|
||||
| Pair | Light | Dark | Result |
|
||||
|---|---|---|---|
|
||||
| Success, info, warning, error on their `-soft` ground (badges, alerts) | 6.7 / 6.9 / 7.1 / 7.3 | 8.7 / 8.4 / 8.1 / 8.1 | Pass |
|
||||
| Neutral badge: `--ui-text-toned` on `--ui-bg-elevated` | 8.7 | 10.9 | Pass |
|
||||
| Chip, selected row, current page: `--rc-on-sand` on `--rc-sand` | 14.3 | 11.2 | Pass |
|
||||
| Neutral chip: `--ui-text-highlighted` on `--ui-bg-accented` | 14.9 | 15.2 | Pass |
|
||||
| Toast title on `--ui-bg` | 18.9 | 18.1 | Pass |
|
||||
| Toast body `--ui-text-toned` / `--ui-text-muted` on `--ui-bg` | 9.7 / 5.7 | 11.8 / 6.6 | Pass |
|
||||
| Banner (offline): `--ui-text-inverted` on `--ui-bg-inverted` | 18.9 | 18.1 | Pass |
|
||||
| Table text `--ui-text` on `--ui-bg`; on hover `--ui-bg-elevated` | 15.9; 14.2 | 14.9; 13.7 | Pass |
|
||||
| Table header and hover meta: `--ui-text-muted` on `--ui-bg-elevated` | 5.1 | 6.1 | Pass |
|
||||
| Tab selected / unselected / count | 18.9 / 9.7 / 5.7 | 18.1 / 11.8 / 6.6 | Pass |
|
||||
| Segmented: selected `--ui-bg` on `--ui-primary`; unselected `--ui-text-toned` on `--ui-bg` | 18.9; 9.7 | 18.1; 11.8 | Pass |
|
||||
| Placeholder `--ui-text-muted` on `--ui-bg` | 5.7 | 6.6 | Pass |
|
||||
| `--ui-text-muted` on `--rc-sand` | 4.3 | 1.7 | **Fails.** Never place muted text on sand. Frames use `--rc-on-sand` |
|
||||
| `--ui-text-dimmed` on `--ui-bg` | 2.8 | 3.3 | **Fails.** Not used for text. Allowed for disabled icons and decorative strokes |
|
||||
| Disabled controls at 40% opacity (label on `--ui-bg`) | 2.6 | 3.7 | Exempt (inactive component). Never carry information only in a disabled label |
|
||||
| Disabled table row at 55% opacity | not computed | not computed | Exempt (inactive) |
|
||||
| UI: `--ui-border-accented` on `--ui-bg` (input, checkbox, segmented, secondary button borders) | 3.6 | 3.3 | Pass (3:1) |
|
||||
| UI: focus ring `--ui-primary` on `--ui-bg` | 18.9 | 18.1 | Pass |
|
||||
| UI: `--rc-sand` fill against `--ui-bg` | 1.3 | 11.2 | **Fails in light** as the only indicator |
|
||||
| UI: `--ui-border` on `--ui-bg` | 1.3 | 1.5 | Decorative only (card and table lines). Never the only boundary of a control |
|
||||
|
||||
Fixes applied (token swaps):
|
||||
- Current page in the paginator: border changed from `--rc-sand` to `--ui-primary` (18.9 / 18.1) so the state does not rely on a 1.3:1 fill.
|
||||
- Selected media cards and rows keep `--ui-primary` outline with the sand fill (already so).
|
||||
- Selected nav items still rely on the sand fill plus weight 500 and `aria-current="page"`. The fill alone is 1.3:1 in light; the weight change and the programmatic state carry the information. This is accepted and recorded here, not "fixed".
|
||||
- Rule added: `--ui-text-muted` is never used on `--rc-sand`.
|
||||
Not computed: hover and active backgrounds of every control against every text colour; the states-matrix uses combinations already listed above.
|
||||
|
||||
## One value per role (spacing, radius, type, icons)
|
||||
Sweep of the frames (`AppFrame`, `ActivityFrame`, `MediaFrame`, `VariantsFrame`, `IntegrationPage`, `IntegrationImages`, `ApiKeysPage`, `CodeSnippet`, `AuthCard`). "Found" is what was drawn before pass 2.
|
||||
|
||||
| Role | Found | Value now (desktop / mobile) |
|
||||
|---|---|---|
|
||||
| Page padding | 32 px (Home, Users, Settings, Integration, API keys), 24 px (Media, Activity, Variants); mobile 20 16 or 16 | 24 px / 16 px. Extra bottom padding only to clear a fixed bar (88 or 96 px) |
|
||||
| Section gap on a page | 20, 28 (Home, Settings), 16 elsewhere | 16 px |
|
||||
| Card padding | 16 px and 20 px | 16 px |
|
||||
| Card inner gap | 8, 12, 14, 16 | 12 px (6 px between a label and its control, 8 px between buttons) |
|
||||
| Banner and alert padding | 10 12, 12 14 | 12 14 |
|
||||
| Radius | none declared | 0 |
|
||||
| Page title | 28/36 (Home, Integration, API keys), 24/32 (Variants), 20/28 (rest) | 20/28, weight 600, same on mobile |
|
||||
| Section heading (reference pages) | 18/26 | 18/26 |
|
||||
| Card title | 14/22, 15/22, 15/24 | 15/24, weight 600 |
|
||||
| Sub heading | 14/22 | 14/22 |
|
||||
| Dialog title | 16/24 | 16/24 |
|
||||
| Stat figure | 28/36 (Home), 24/32 (Activity), 22/36 (Variants mobile) | 24/32, mobile 22/32 |
|
||||
| Error and 404 page title | 24/32 | 24/32 (unchanged) |
|
||||
| Editor article title | 18/26 | 18/26 (own role) |
|
||||
| Body text | 13/20 | 13/20 |
|
||||
| Small and meta text | 12/18 | 12/18 |
|
||||
| Icon in text and buttons | 16 (91), 14 (87), 12 (20), 13 (1), 18, 20, 22, 28 | 16 px. 14 px inside compact controls and badges (12 px in badges). 20 px in the mobile top bar. 18 px in mobile list rows and sheet rows. The 13 px icon became 14. Auth card (22) and the empty-state glyph (28) stay as illustration sizes |
|
||||
| Control height (button, input, select) | 28, 32, 40 (inputs in API keys, Integration, Images) | 32 px / 44 px. Inline row buttons 28 px on desktop, 44 px on mobile. The 40 px inputs became 32 / 44 |
|
||||
| Dialog | top offset 120 and 140, centered (export), padding 20 | width 460 (560 wide, 640 crop), 140 px from the top, header 20 24 0, body 20 24 0, footer 20 24 |
|
||||
| Table row | 40, 48, 56 | 48 px; media rows 56 px (thumbnail); mobile 56 px |
|
||||
|
||||
## Pairings
|
||||
- Selected rows use `--rc-sand` with `--rc-on-sand` text and icon in both themes. Hover, focus-visible and active on a selected row keep sand. Focus adds a 2 px `--ui-primary` outline.
|
||||
- Child selected: the parent row is not filled. It uses `--ui-text-highlighted`, weight 500, chevron down.
|
||||
- Focus-visible: 2 px `--ui-primary`, offset 2 px (inset -2 px for tabs, segmented controls and rows).
|
||||
- Disabled: 40% opacity (table rows 55%).
|
||||
- Hover, active and the rest: board "States matrix: controls" (`StatesMatrix.dc.html`). Hover and active tokens: primary button hover `--ui-text`, active `--ui-text-toned`; secondary and ghost hover `--ui-bg-elevated`, active `--ui-bg-accented`; destructive hover opacity 0.85, active 0.75; input hover border `--ui-text-muted`, focus border `--ui-primary`.
|
||||
Reference in new issue
Block a user