A dashboard is a wall panel somebody hangs in their own hallway, so it now wears what they choose: a look, and a palette of their own colours. Two complete component sets live under `Dashboard/ui/` — `glass` (translucent panes over a slowly moving ground) and `material` (Material 3 tonal cards) — behind one prop contract. Every control's state, keyboard and `aria-` live in `ui/core` and are shared, so the two sets are the same dashboard drawn twice rather than two products: a set only decides what a control looks like while doing it. Four settings join the channel, each drivable by a flow like any other: `look`, `palette`, `background` and `touch`. A palette is an ordered list of hex colours — background, surface, primary, accent, text, then more chart colours — pasted from a coolors.co link or typed, written onto the canvas as the token variables everything already reads. Trailing roles are derived, so three colours are a whole dashboard, and derived text is held to AA rather than trusted (`theme.check.ts` measures it). A palette also decides light or dark, since its first colour is the ground. Widgets are measured against their own tile with container queries rather than against the viewport, animate through `motion`, and can be drawn without their title. The three reworks: - a bar draws a row per reading, up to eight, each in the dashboard's own data colours and each able to carry its own scale — replacing readings nested in one fill, which could only ever share one colour and stop at three. Documents written the old way are read as rows. - a chart's range picker moved to a column down its right-hand edge, which gives the plot back a whole row of a short tile. - the colour wheel became a disc: hue is the angle and saturation the distance from the middle, so a colour is one gesture rather than three, with brightness on a slider beside it. `index.css` and `lib/motion.ts` are untouched — the dashboard overrides token *values* on its canvas, never the blocks the two repos share.
104 lines
3.8 KiB
CSS
104 lines
3.8 KiB
CSS
/*
|
|
* Dashboard surface, routed through the design tokens.
|
|
*
|
|
* Scoped like `Flow/flow.css`: the grid maths and the react-grid-layout
|
|
* overrides live beside the components that use them rather than in index.css,
|
|
* so nothing here touches the byte-identical token blocks.
|
|
*/
|
|
|
|
/* The placement grid, as plain CSS. One dot per cell corner: the surface hands
|
|
in the pitch its widgets actually snap to (`--dot-x` / `--dot-y`), and the
|
|
negative offset puts a dot centre on the grid's own origin. */
|
|
.dot-canvas {
|
|
background-image: radial-gradient(
|
|
circle at 1px 1px,
|
|
color-mix(in srgb, var(--muted-foreground) 30%, transparent) 1.5px,
|
|
transparent 0
|
|
);
|
|
background-size: var(--dot-x, 24px) var(--dot-y, 24px);
|
|
background-position: -1px -1px;
|
|
}
|
|
|
|
/*
|
|
* View mode's grid. Column count is per dashboard (`--widget-cols`), so a wall
|
|
* panel can be matched to its own width. It does not reflow: the grid lives on
|
|
* a canvas of the panel's own pixel size, which is scaled to the viewport.
|
|
* A phone gets `.widget-stacked` below instead, which is a different surface
|
|
* rather than a narrower version of this one.
|
|
*/
|
|
.widget-grid {
|
|
display: grid;
|
|
gap: 0.75rem;
|
|
/* The row height follows the canvas, handed in beside the column count;
|
|
5rem is what a 1920x1080 panel at 12 columns derives. */
|
|
grid-auto-rows: var(--row-height, 5rem);
|
|
grid-template-columns: repeat(var(--widget-cols), minmax(0, 1fr));
|
|
/* Stacked, this is a flex item in an `auto` track, and its automatic minimum
|
|
size is the widest thing any widget holds — one long message name would
|
|
size the column and take the page sideways with it. The fixed-pixel canvas
|
|
the non-stacked path sits on already uses `minmax(0, 1fr)`, so this only
|
|
ever matters on a phone. See DESIGN-GUIDELINES.md -> Responsive. */
|
|
min-width: 0;
|
|
}
|
|
|
|
.widget-cell {
|
|
grid-column: span var(--w);
|
|
grid-row: span var(--h);
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Only once something has actually been placed; an untouched dashboard has
|
|
every widget at 0,0 and would pile up on one cell. */
|
|
.widget-grid[data-placed] .widget-cell {
|
|
grid-column: var(--x) / span var(--w);
|
|
grid-row: var(--y) / span var(--h);
|
|
}
|
|
|
|
/*
|
|
* One column, in reading order, at the viewport's own width — what a phone
|
|
* gets instead of a wall panel shrunk to 18%. Arranging is not a phone
|
|
* feature, so the stored x/w are dropped and only the height a widget asked
|
|
* for survives: a chart still needs its room, a stat still does not.
|
|
* See DESIGN-GUIDELINES.md → Responsive.
|
|
*/
|
|
.widget-grid.widget-stacked,
|
|
.widget-grid.widget-stacked[data-placed] {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.widget-grid.widget-stacked .widget-cell {
|
|
grid-column: auto;
|
|
grid-row: auto;
|
|
height: calc(var(--h) * var(--row-height, 5rem) + (var(--h) - 1) * 0.75rem);
|
|
}
|
|
|
|
/*
|
|
* Motion. A selection indicator moving is emphasized (Material).
|
|
* `<MotionConfig reducedMotion="user">` only covers `motion/react`, so CSS
|
|
* asks for itself. The dashboard's own widgets are drawn by the component
|
|
* sets and animate through `motion`; what is left here is the app-side
|
|
* segmented shape, which the flow screens and the dashboard editor share.
|
|
*/
|
|
@media (prefers-reduced-motion: no-preference) {
|
|
/* One indicator that slides between segments, rather than a fill that jumps
|
|
from cell to cell. */
|
|
.widget-segment-thumb {
|
|
transition:
|
|
left var(--duration-base) var(--ease-emphasized),
|
|
width var(--duration-base) var(--ease-emphasized);
|
|
}
|
|
}
|
|
|
|
/* react-grid-layout ships a red placeholder and a black handle glyph. */
|
|
.react-grid-item.react-grid-placeholder {
|
|
background: var(--primary);
|
|
border-radius: var(--radius-lg);
|
|
opacity: 0.12;
|
|
}
|
|
|
|
.react-grid-item > .react-resizable-handle::after {
|
|
border-right-color: var(--muted-foreground);
|
|
border-bottom-color: var(--muted-foreground);
|
|
}
|