Styling¶
DS folders, tokens, theming, Tailwind + cva for
@bricks-common/boandbricksoffice-*consumers. Keep in sync: changing tokens, theme vars, DS topical folders, the cva convention, ortokens.css/tokens.ts→ update this file in the same PR.
Hard rules¶
- No hardcoded hex / px. Missing token → add to
tokens.css+tokens.tsfirst, then use it. cvaonly, nevertailwind-variants. Seefeedback_cva_over_tailwind_variants.- Unified
radix-uipackage (import { Slot } from 'radix-ui'), not per-primitive@radix-ui/react-*. - Topical DS folders are mandatory — never dump everything in
components/. Seefeedback_ds_topical_folders. - No app-specific DS in consumers. If you'd add it in
bricksoffice-projects/src/..., add it to@bricks-common/boinstead.
Topical DS folders¶
Inside projects/common/back-office/src/design-system/:
| Folder | What goes here |
|---|---|
components/ |
Primitives the user doesn't enter a value into (button, tabs, dropdown, popover, sheet, tooltip, brand visuals) |
inputs/ |
Value-input controls (input, textarea, select, checkbox, toggle, calendar, command, date-picker, label) |
layouts/ |
Composed shells (sidebar + topical sub-folders like layouts/nav/) |
modals/ |
Dialogs, drawers, alert dialogs |
tables/ |
DataTable building blocks |
text-editor/ |
Rich text (Tiptap/Lexical when added) |
forms/ |
<Form /> wrapper + helpers |
styles/ |
Tokens, theme, global CSS entry |
Adding a new component¶
- Pick the right topical folder; if torn, prefer the most specific.
- Generate via shadcn from
projects/common/back-office:pnpm dlx shadcn@latest add <name>. Move into the right folder. - Use
cva+radix-uiunified. - Internal imports via
#-aliases (see./@bricks-common-bo.mdc). - Re-export from the topical barrel + the top-level
design-system/index.tsif public.
Disabled affordance¶
Two patterns, both token-driven:
- Text fields (
Input,Textarea,Select,Checkbox,DatePicker,RichTextEditor): disabled =cursor-not-allowed+bg-(--disabled-bg)+text-(--disabled-text). Dark--disabled-bgis lighter than card — a darker fill would vanish against near-black. - Buttons / toggles / tabs / command items / calendar days / sidebar buttons: disabled =
opacity-(--disabled-opacity). Don't opacity-fade text fields — they disappear on the dark card.
Tokens: --input-bg, --input-border-val, --disabled-bg, --disabled-opacity in tokens.css. bg-(--var) / text-(--var) / opacity-(--var) are Tailwind v4 arbitrary-property utilities.
Tokens (src/design-system/styles/)¶
- Colors: semantic shadcn (
--primary,--muted,--destructive,--ring,--sidebar-*) mapped to brand. Light/dark via:root+@custom-variant dark (&:is(.dark *)). - Radius: scaled off
--radius(sm0.6× →4xl2.6×). - Spacing:
none / 3xs / 2xs / … / 8xlintokens.ts. Usep-xl,gap-md, never raw px. - Containers:
sm480 /lg800 /xl1000 /2xl1200. - Status badges (
--badge-<tone>-bg/fg): saturated in light, pastel-on-tinted in dark. Tones instyles/badges.css→@utility status-badge-tone-<tone>.<Badge variant="status">lets the tone class own colors. - Cell highlights (
--cell-highlight-<tone>-fg): bg iscolor-mix(..., transparent), only fg flips per mode. Seetables.css.
Topical CSS files in design-system/styles/ are @import'd once from styles.css.
bg-backgroundvsbg-card: in BO themebg-backgroundis cream#f9f5f1, not white. Usebg-card/bg-popoverfor white surfaces (Dialog, popover, sheet).
Component stories (dev)¶
Dev-only DS gallery at @bricks-common/bo/modules/component-stories. One category per page. Author at stories/<category>/<name>.story.tsx, register in registry.ts. Categories: Tokens, Components, Forms, Modals, Layouts. Gate consumer routes on AppConfig.isDevEnv.
Theming¶
ThemeProvider, useTheme, ThemeToggle in design-system/styles/theme/. Token flow: tokens.css → styles.css (@theme inline) → Tailwind utilities + cva. Consumer pulls everything via one @import '@bricks-common/bo/styles.css'.
What NOT to do¶
- ❌ Modify a shared component spec to fix a local layout issue — fix the consumer. See
feedback_no_change_shared_component_specs. - ❌
bg-backgroundfor what should be a white surface — that's cream. Usebg-card/bg-popover. - ❌ Opacity-fade a disabled text field — it vanishes on dark.