contributing
The nalet design system. Read the principles,
the foundations and brand/brand.md before you touch
anything. The rules below are not style preferences — they are the brand.
the test
If a screen would look at home in a tmux pane, it is on. If it looks like a SaaS landing page, start over.
non-negotiables (do not break these)
- Dark canvas only. Use the canvas / foreground tokens, never raw hex.
- The
>chevron is the brand glyph and is always--cloud-blue(#58A6FF). 'JetBrains Mono'for display / headings / system / code / brand,'Inter'for body / prose / UI labels.- Space is 4-base only: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64.
- Square frames.
border-radius: 0on every card, panel, tile, button, input, and dialog. Icons are the only rounded shape and that radius is baked into the PNGs — never add radius in CSS. - Two voices, one per typeface. Monospace is the system's voice and it is lowercase: titles and headings, buttons, tabs and navigation, statuses and badges, table headers, menu items, toolbar and filter labels, numbers and codes. The body face is the reader's language, in sentence case: descriptions, messages, field labels, hints and errors, checkbox and switch labels, and the prose of the docs. Both are short, with no emoji and no exclamation marks. This applies to copy, component labels, stories and docs; commit messages stay lowercase.
token-first
Tokens are the single source of truth. You do not hand-write a color, a font stack, a type metric, or a spacing value in a component.
- Edit
tokens/tokens.json(DTCG format). - Run
npm run build-tokens. This regeneratessrc/styles/tokens.css(CSS-vars + base + the type utilities),src/tokens.ts(typed tokens), andtailwind-preset.cjs. - Reference the CSS custom properties (
var(--bg),var(--cloud-blue),var(--s-4),var(--ff-mono)) in component CSS — never raw values.
the two documentation sites
The docs come in two parts, and each says a thing once:
- The guidelines site (
site/, built with Astro) — the design guidance: principles, foundations, styles, a page per component (when to use it, anatomy, states, behaviour, content, do and don't) and patterns. It is served at/design-system/. - The React subsite (
stories/, built with Storybook) — the implementation: each component's playground, examples, implementation notes and props. It is served at/design-system/react/.
Examples are written once, as stories in stories/**/*.stories.tsx. The React
subsite shows them with their code; the guidelines site renders the same stories
through Storybook's portable stories (site/src/examples/).
writing the guidelines
The guidelines are read by people who aren't designers, and by agents. Write for the people; give the agents their own compact version.
- Explain before you advise. Start with what something is for and why it matters, in a sentence or two, then say how to use it. Write like a colleague who knows the system and is happy to help: "Use tabs when…", "This helps people…", "Try to keep…". Save words like must and never for the accessibility baseline, where they are true.
- Keep the sentences flowing. Leave component names, prop names and token
names out of the prose. Say "the emphasized button" rather than
variant="primary"; the React pages carry the technical names. - Mark the words a reader may not know with
<Term id="…">, defined once insite/src/data/glossary/(core, patterns and general; an id is defined once). Mark a word the first time it appears on a page, not every time. The explanation shows in a popup and is not part of the text. - Draw the idea, not the component. Principles and patterns use storyboard
sketches (
site/src/sketches/, built fromkit.tsx): frames, placeholder lines, one blue accent, state colours only where they mean something, and a word only where it carries the point. Pair a "do" with a "don't" when the contrast is the lesson. Every sketch has a label that describes it. Component pages keep their live examples, because there the real component is the point. - Examples say true things. The text in stories, sketches and examples
follows
foundations/meaningful-text: real states and numbers, the reader's words, no promises. - For agents,
/llms.txtlists the rules in compact plain text, and/glossary.jsonholds the glossary. Both are built from the same data as the site.
how to add a component
- Create
src/components/<Name>/<Name>.tsxandsrc/components/<Name>/<Name>.css. The CSS uses the token CSS-vars only. No Tailwind inside the library. - Keep it square (
border-radius: 0) and dark. Settext-transform: lowercaseon monospace chrome only, never on text in the body face. - Re-export it from
src/index.tsso it ships from@nalet/design-system. - Write its tests next to it (
<Name>.test.tsx): behaviour, and axe for each state. - Write its stories in
stories/components/<Name>.stories.tsx, titledComponents/<role>/<name>, with aPlaygroundand one story per variant or state worth showing. - Write its React page,
stories/components/<Name>.mdx: a link to its guidance, the playground, the examples, the implementation notes and the props. - Write its guidance page,
site/src/pages/components/<slug>.mdx, and add it tosite/src/data/components.ts. Use the stories as its live examples. - Run
npm run build-tokens && npm run lint && npm test && npm run build && npm run site:build && npm run site:checkbefore opening a PR. CI runs the same steps on push and PR.
previewing the docs
npm run site:dev # the guidelines site on :4321/design-system/
npm run storybook # the react subsite on :6006
npm run site:build # the guidelines site, static, into site/dist/
npm run site:check # every internal link in the built site resolves
Previews render on the dark canvas with the brand fonts. Do not add a light background.
commits
Lowercase, short, imperative. No emoji, no exclamation marks, no co-author trailers.
This page is the repository's own contributing guide, shown as it is. Questions, issues and pull requests are welcome in the repository.