Rework the dashboard into two looks over one behaviour
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.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useLiveValue } from "@/components/Flow/liveStore"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { ICON_COLORS, ICONS } from "./icons"
|
||||
import { config } from "./ui/core/config"
|
||||
import type { WidgetProps } from "./widgets"
|
||||
|
||||
/** One column of a forecast, as the `list` message declares it. */
|
||||
@@ -11,9 +12,6 @@ type ForecastItem = {
|
||||
color?: string
|
||||
}
|
||||
|
||||
const config = (widget: WidgetProps["widget"]) =>
|
||||
(widget.config ?? {}) as Record<string, unknown>
|
||||
|
||||
/**
|
||||
* What comes next, as a strip of columns over a `list` message.
|
||||
*
|
||||
@@ -28,7 +26,7 @@ export function ForecastWidget({ widget }: WidgetProps) {
|
||||
const message = cfg.message ? String(cfg.message) : ""
|
||||
const live = useLiveValue(message || undefined)
|
||||
if (!message) {
|
||||
return <p className="text-sm text-muted-foreground">Pick a message.</p>
|
||||
return <p className="text-muted-foreground">Pick a message.</p>
|
||||
}
|
||||
|
||||
const count = Number(cfg.count)
|
||||
@@ -37,7 +35,7 @@ export function ForecastWidget({ widget }: WidgetProps) {
|
||||
.slice(0, Number.isFinite(count) ? count : 5)
|
||||
|
||||
if (items.length === 0) {
|
||||
return <p className="text-sm text-muted-foreground">Nothing forecast.</p>
|
||||
return <p className="text-muted-foreground">Nothing forecast.</p>
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -56,18 +54,18 @@ export function ForecastWidget({ widget }: WidgetProps) {
|
||||
// ramp out of an arbitrary Tailwind class.
|
||||
style={{ opacity: Math.max(0.45, 1 - index * 0.14) }}
|
||||
>
|
||||
<span className="w-full truncate text-center text-xs text-muted-foreground">
|
||||
<span className="w-full truncate text-center text-[0.85em] text-muted-foreground">
|
||||
{item.label ?? ""}
|
||||
</span>
|
||||
{Glyph ? (
|
||||
<Glyph
|
||||
className={cn(
|
||||
"size-5 shrink-0",
|
||||
"dui-glyph-sm shrink-0",
|
||||
ICON_COLORS[item.color ?? ""] ?? ICON_COLORS.default,
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
<span className="w-full truncate text-center text-sm tabular-nums">
|
||||
<span className="w-full truncate text-center tabular-nums">
|
||||
{item.value === null || item.value === undefined
|
||||
? ""
|
||||
: String(item.value)}
|
||||
|
||||
Reference in New Issue
Block a user