8.8 KiB
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 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-accentequal to--accent. - Use one
--brand-secondaryaction 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
--foregroundfor 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-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
emphasizedfor entering or expressive movement,standardfor neutral transitions. - Durations are 150, 200 and 300 ms. One-shot activity feedback uses 500 ms.
- Variants are
fadeIn,scaleIn,slideUp,overlayFadeandlistStagger. - 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.
- Keep the page within the viewport. Give wide tables and charts their own
overflow-x-autoregion. Usemin-w-0on flex and grid children when content could stretch the page.frontend/tests/mobile.spec.tschecks this. - Cap floating controls with
max-w-[calc(100vw-2rem)]and allow wrapping. - Use 44px touch targets below
md, 32px above. Useicon-touch,sm-touchor matching responsive utilities. - Turn floating panels into full-screen sheets on phones with the shared
Flow/SidePanel. Gate canvas side insets behindmd:. - Provide tap or visible alternatives to hover actions.
- 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
.darkclass on<html>and the pre-paint theme script so the first frame uses the chosen theme. - A dashboard subtree can use
.theme-lightor.theme-darkindependently. Menus and tooltips rendered outside it must carry that theme class too.