Restructures into apps/ssp + apps/behandelportal (two Angular projects) plus libs/shared + libs/beheer (cross-app libraries), replacing WP-61's separate sibling repo. That split had already produced real drift: a hand-vendored copy of the backend's OpenAPI doc, a shared/ui+layout tree forked and silently diverging (7 files), and beheer + the styles.scss token bridge duplicated byte-for-byte across both repos. - git mv the SSP's src/app/* into apps/ssp/; fold shared/, beheer/, environments/, the Storybook docs/*.mdx, and styles.scss into libs/shared + libs/beheer (all confirmed identical between the two repos before merging). auth stays deliberately duplicated per ADR-0002 (actor-specific, expected to diverge) - amended there. - One generated API client (libs/shared), no more vendored swagger.json. - .dependency-cruiser split into a base factory + one config per app, and Storybook into .storybook-ssp/.storybook-behandelportal - both forced by the @auth/* alias resolving to different directories per app. - SiteHeaderComponent/ShellComponent gained HEADER_NAV_ITEMS/ HEADER_ADMIN_LINKS/DEBUG_PANEL injection tokens so each app supplies its own nav/admin-links/dev-panel instead of one being hardcoded. - CLAUDE.md, ARCHITECTURE.md, dependencies.md, and ADR-0002 updated; WP-67 backlog entry documents the full decision trail. npm run ci green (lint, dep:check x2, 360 tests across ssp/ behandelportal/shared/beheer, both localized builds, backend tests, snippet + api-client drift); both dev servers, both Storybook instances, and docker compose verified working. The old sibling repo (/home/eho/repos/behandelportal) is left untouched, not deleted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
101 lines
3.8 KiB
Plaintext
101 lines
3.8 KiB
Plaintext
import { Meta } from '@storybook/addon-docs/blocks';
|
|
import { useState, useLayoutEffect, useRef } from 'react';
|
|
|
|
<Meta title="Foundations/Design Tokens" />
|
|
|
|
# Design tokens
|
|
|
|
We do not hand-write colours or spacing. `src/styles.scss` defines a semantic `--rhc-*` token
|
|
vocabulary and redefines every one of those tokens onto the vendored **CIBG Huisstijl**
|
|
(Bootstrap 5.2) values — `--bs-*`/`--ro-*` custom properties where one exists, CIBG palette hex
|
|
otherwise (that one file is exempt from `npm run check:tokens`, which fails the build on any
|
|
_other_ hardcoded hex colour in atoms/molecules/chrome). The `--rhc-*` names are an internal
|
|
alias set now; the values are CIBG's.
|
|
|
|
**Prefer a CIBG class over a token where one exists** — `.btn`, `.form-control`, `.card`,
|
|
`.stepper`, `.confirmation`, `.applications`, … are already themed by the vendored CSS (see
|
|
`public/cibg-huisstijl/`). Reach for a `--rhc-*` token only where CIBG has no ready-made class
|
|
(an `alert` surface, a skeleton loader, a status badge — see ADR-0003).
|
|
|
|
> Resolved values below are read live from the running theme via `getComputedStyle`, so they
|
|
> can't drift from what ships. `body.brand--cibg` (set in `index.html` and Storybook's
|
|
> `preview.ts`) activates CIBG's robijn/lintblauw palette; no extra wrapper class is needed.
|
|
|
|
export const Resolved = ({ token }) => {
|
|
const ref = useRef(null);
|
|
const [val, setVal] = useState('');
|
|
useLayoutEffect(() => {
|
|
if (ref.current) setVal(getComputedStyle(ref.current).getPropertyValue(token).trim());
|
|
}, [token]);
|
|
return (
|
|
<span ref={ref} style={{ fontFamily: 'monospace', fontSize: '0.75rem', color: '#666' }}>
|
|
{val || '…'}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
## When to use which token
|
|
|
|
- **CIBG class first** (see above) — a token is for the gaps a CIBG class doesn't cover.
|
|
- **Semantic first** — reach for a role token (`--rhc-color-foreground-default`,
|
|
`--rhc-color-border-default`, `--rhc-color-foreground-link`) before a raw palette step
|
|
(`--rhc-color-lintblauw-500`). Roles survive a theme swap; palette steps don't.
|
|
- **`--rhc-space-max-*`** for all spacing/gaps — never a raw `rem`.
|
|
- **`--app-*`** (in `src/styles.scss`) only for app measures CIBG has no token for
|
|
(`--app-content-max`, `--app-form-narrow`). If you're tempted to add one, check CIBG first.
|
|
|
|
## Spacing scale — `--rhc-space-max-*`
|
|
|
|
<div style={{ display: 'grid', gap: '0.4rem', margin: '1rem 0' }}>
|
|
{['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl'].map((step) => {
|
|
const token = `--rhc-space-max-${step}`;
|
|
return (
|
|
<div key={step} style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
<code style={{ width: '12rem', fontSize: '0.78rem' }}>{token}</code>
|
|
<div
|
|
style={{
|
|
height: '1rem',
|
|
width: `var(${token})`,
|
|
background: 'var(--rhc-color-lintblauw-500)',
|
|
borderRadius: '2px',
|
|
}}
|
|
/>
|
|
<Resolved token={token} />
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
## Semantic colours
|
|
|
|
<div
|
|
style={{
|
|
display: 'grid',
|
|
gridTemplateColumns: 'repeat(auto-fill, minmax(14rem, 1fr))',
|
|
gap: '0.75rem',
|
|
margin: '1rem 0',
|
|
}}
|
|
>
|
|
{[
|
|
'--rhc-color-foreground-default',
|
|
'--rhc-color-foreground-subtle',
|
|
'--rhc-color-foreground-link',
|
|
'--rhc-color-layout',
|
|
'--rhc-color-lintblauw-500',
|
|
'--rhc-color-lintblauw-700',
|
|
'--rhc-color-border-default',
|
|
'--rhc-color-border-strong',
|
|
'--rhc-color-cool-grey-100',
|
|
].map((token) => (
|
|
<div key={token} style={{ border: '1px solid #ddd', borderRadius: '6px', overflow: 'hidden' }}>
|
|
<div style={{ height: '3rem', background: `var(${token})` }} />
|
|
<div style={{ padding: '0.4rem 0.5rem' }}>
|
|
<div style={{ fontFamily: 'monospace', fontSize: '0.72rem', wordBreak: 'break-all' }}>
|
|
{token}
|
|
</div>
|
|
<Resolved token={token} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|