- 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.
202 lines
9.1 KiB
Markdown
202 lines
9.1 KiB
Markdown
# 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.
|