Files
app/DESIGN-GUIDELINES.md
T
stroblme 4c2df681d3 Flow canvas: label and edge popovers follow pan and zoom, the editors' dock is a full-width bar on a phone
- InputInspector hangs off the label's element and EdgeInspector off a point in flow coordinates (ViewportPortal), both re-measured every frame while open and hidden once the anchor leaves the view. A label that leaves the canvas closes its popover.
- Dock: below md a bar across the width, flush with the bottom edge (bg-card, top border, safe-area inset, no shadow); from md the floating pill as before. The flow dock drops the Run caption and the dashboard editor clears the bar with its own padding, so the editing state fits one row from 360px.
- Tests: the search spec checks the popover rides along with a pan; the mobile spec checks both docks are a full-width bar flush with the bottom.
2026-10-28 07:38:04 +01:00

202 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fluksio design guidelines
UI reference for the app, its dashboard editor and documentation site.
Paths below are relative to this repository.
## Design language
Use neutral white and near-black surfaces with a slate-blue primary accent.
Reserve terracotta for one secondary action per view. `--card` is the main
surface. Separate surfaces with borders and elevation. Controls are pills;
cards and panels use a 16px radius.
## Colour tokens
| Token | Light | Dark | Use |
|---|---|---|---|
| `--background` | `#ffffff` | `#0a0a0a` | page |
| `--foreground` | `#333232` | `#f5f5f5` | body text |
| `--card` / `--popover` | `#ffffff` | `#1a1a1a` | dominant surface; dark lifts above the page |
| `--card-foreground` / `--popover-foreground` | `#333232` | `#f5f5f5` | text on those surfaces |
| `--primary` | `#4a7189` | `#7ba3b8` | primary fills, active state, focus ring |
| `--primary-foreground` | `#ffffff` | `#0a0a0a` | text on `--primary` |
| `--primary-nested` | `#152128` | `#345160` | a reading drawn inside a `--primary` fill |
| `--brand-secondary` | `#de8f6e` | `#e5a184` | the one secondary call-to-action per view |
| `--brand-secondary-foreground` | `#333232` | `#0a0a0a` | text on `--brand-secondary` |
| `--secondary` / `--muted` | `#f2f2f2` | `#232323` | recessed surfaces |
| `--secondary-foreground` | `#333232` | `#f5f5f5` | text on those |
| `--muted-foreground` | `#6b6b6b` | `#a3a3a3` | secondary text, section headers |
| `--accent` | `#f5f5f5` | `#262626` | hover / selected surface |
| `--accent-foreground` | `#333232` | `#f5f5f5` | text on `--accent` |
| `--destructive` | `#b94d4d` | `#cf6666` | destructive actions, failing nodes |
| `--status-success` | `#5e8b6d` | `#87b596` | a node's last run succeeded |
| `--status-warning` | `#b45309` | `#e8a33d` | a node that works, but degraded, such as a device that is offline |
| `--chart-1` … `--chart-8` | see [Chart palette](#chart-palette) | | chart series, in slot order |
| `--border` / `--input` | `#e4e4e4` | `#2a2a2a` | hairlines, field borders |
| `--ring` | `#4a7189` | `#7ba3b8` | focus ring; always equals `--primary` |
| `--sidebar*` | mirrors card / accent / primary | | sidebar surface set |
The identity blue `#59849b` stays in the wordmark. Use `--primary` for controls
so text on primary fills meets contrast requirements. `--primary-nested` is
for stacked readings inside a primary fill, separated by a gutter.
- Use tokens in UI components. Custom SVG glyphs may use `currentColor`.
- Keep `--sidebar-accent` equal to `--accent`.
- Use one `--brand-secondary` action per view.
- Name every status in text. Running uses `--primary`, success
`--status-success`, failure `--destructive`, and degraded
`--status-warning`. Idle has no indicator.
- Home's brain graph uses primary discs as its identity. Its outer ring uses
`--foreground` for runnable nodes and terracotta for flow faults. Failed
nodes keep a terracotta disc until acknowledged. Persistent faults keep
their labels visible.
### Chart palette
| Slot | Hue | Light | Dark |
|---|---|---|---|
| 1 | `--primary` | `#4a7189` | `#7ba3b8` |
| 2 | orange | `#e26f00` | `#d26600` |
| 3 | violet | `#6f49ca` | `#8d71e6` |
| 4 | green | `#00721b` | `#55c15e` |
| 5 | orchid | `#c66ae1` | `#dd8bf6` |
| 6 | ochre | `#966a00` | `#ae7c00` |
| 7 | teal | `#00a093` | `#00c0b1` |
| 8 | magenta | `#b32474` | `#bf4483` |
Take colours in slot order. Line charts stop at five series and show a legend
when there is more than one. Reserve red, sage green and amber for status.
The terminal UI uses the terminal's named ANSI colours instead.
## The dashboard is exempt
User-defined dashboards can choose `fluksio`, `material` or `glass` under
`frontend/src/components/Dashboard/ui/`. The default `fluksio` look follows
these guidelines. Other looks may change surfaces and motion.
Behavior, keyboard handling and accessibility stay in `ui/core/`.
A dashboard palette overrides tokens on its own canvas, with colours assigned
by position. It must preserve contrast, named status, 44px touch targets and
reduced-motion behavior. Fault and success colours keep their meanings.
Widgets use container queries to follow their tile size.
Dashboard motion presets live in `ui/core/motion.ts`; the app shell uses
`frontend/src/lib/motion.ts`.
## Typography
Use the self-hosted Inter variable font at
`frontend/public/fonts/inter-latin-variable.woff2` for body text, headings and
wordmarks. `.font-display` selects it for display text. Use the system
monospace stack through `font-mono` for code, message names and payloads.
Use Tailwind's size scale. Arbitrary `text-[…]` sizes are banned and checked
by the `no-arbitrary-font-size` hook.
Section headers use:
```text
text-xs font-medium uppercase tracking-[0.5px] text-muted-foreground
```
## Radius
| Utility | Value | Use |
|---|---|---|
| `rounded-full` | pill | buttons, inputs, toggles, chips, badges |
| `rounded-sm` | 8px | checkboxes, small chips, nested items |
| `rounded-md` | 12px | menus, popovers, tooltips, textareas |
| `rounded-lg` | 16px | cards, panels, dialogs, alerts, sidebar |
| `rounded-xl` | 28px | large containers |
## Elevation
Use `shadow-e1` for resting cards, `shadow-e2` for floating surfaces, and
`shadow-e3` for modals. Avoid arbitrary or stock shadow utilities on surfaces.
Borders use `border border-border`, or `border-input` on fields.
## Motion
Use the `motion` package with presets from `frontend/src/lib/motion.ts`.
Keep JavaScript timings aligned with the CSS easing and duration tokens.
- Easing is `emphasized` for entering or expressive movement, `standard` for
neutral transitions.
- Durations are 150, 200 and 300 ms. One-shot activity feedback uses 500 ms.
- Variants are `fadeIn`, `scaleIn`, `slideUp`, `overlayFade` and `listStagger`.
- Wrap the app in `<MotionConfig reducedMotion="user">`.
## Microcopy
Keep captions short. Put explanations in `InfoTip`, `PanelSection.help` or
`FieldLabel.help`. A tooltip holds one or two sentences; longer instructions
belong in the docs. Help must work by tap as well as hover.
Visible supporting text describes state, such as an empty list, a stopped
flow or an error. A page may have one descriptive line below its heading.
Say what a control does. Keep design rationale in repository documentation.
Avoid em dashes in UI strings. Empty-value placeholders and structural
separators are allowed. The `no-em-dash` hook checks these rules, with
separators listed in `frontend/scripts/no-em-dash.allow.json`.
## Iconography
Use Lucide. Custom glyphs belong in `frontend/src/components/icons/` as 24×24
SVGs with no fill, `currentColor` strokes, weight 2 and round caps.
## Shells
The authenticated app uses a `bg-card` region with a floating translucent
sidebar. The flow editor floats its controls over the node canvas. Both use
`bg-card/80 backdrop-blur-md`, a token border and `shadow-e2`.
## Responsive
Use `md` at 768px as the mobile boundary. Keep `useIsMobile()` and Tailwind's
`md:` usage aligned, with stock breakpoints.
1. Keep the page within the viewport. Give wide tables and charts their own
`overflow-x-auto` region. Use `min-w-0` on flex and grid children when
content could stretch the page. `frontend/tests/mobile.spec.ts` checks this.
2. Cap floating controls with `max-w-[calc(100vw-2rem)]` and allow wrapping.
The editors' dock is the exception below `md`: a bar across the full width,
flush with the bottom edge (`bg-card`, top border, no shadow, safe-area
inset), whose brand button drops its caption so the usual row fits at 44px.
3. Use 44px touch targets below `md`, 32px above. Use `icon-touch`, `sm-touch`
or matching responsive utilities.
4. Turn floating panels into full-screen sheets on phones with the shared
`Flow/SidePanel`. Gate canvas side insets behind `md:`.
5. Provide tap or visible alternatives to hover actions.
6. Keep dragging, placing and resizing on desktop. Flow layout is automatic,
left-to-right on desktop and top-to-bottom on phones. Rectangular dashboard
grids stack to one column on phones.
Use `grid gap-* sm:grid-cols-2 lg:grid-cols-N` for card grids and
`p-4 sm:p-6 md:p-8` for page gutters.
## Overlay surfaces & content chips
Floating surfaces use `bg-card/80 backdrop-blur-md`, a token border and
`shadow-e2`. Use token alpha for translucency; panel opacity also fades text.
Content chips are transparent at rest and fill on hover or selection.
Use `hover:bg-accent/50` where hover and selection need distinct states.
Segmented controls use one bordered pill with no dividers, transparent
segments and `bg-accent` for the selected segment.
## UI configuration
`frontend/components.json` uses shadcn style `new-york`, CSS variables and
Lucide icons. Components under `frontend/src/components/ui/` are owned by
this repository. Update token definitions, component usage and this reference
together when changing the design.
## UX
- Keep common actions easy to reach without context menus.
- Apply theme through the `.dark` class on `<html>` and the pre-paint theme
script so the first frame uses the chosen theme.
- A dashboard subtree can use `.theme-light` or `.theme-dark` independently.
Menus and tooltips rendered outside it must carry that theme class too.