Draw each dashboard on a round panel's track in its own look
The canvas states the look of the dashboard shown, so a neighbour beside it and the one a turn leaves wore that look too. Each page now restates its own look, theme and palette. The ring's paint moves from rules under [data-look] to variables each look sets on its root, which stop at the nearer root where a descendant rule reached into both.
This commit is contained in:
@@ -330,7 +330,7 @@ dashboard's look's.
|
||||
| What | Moves | From → to | Timing | Input during it |
|
||||
|---|---|---|---|---|
|
||||
| Face paging (round) | the faces, side by side on a track | the track slides one face width S, the new face coming in from the side it lies on (the next from the right). A dot that skips faces brings its face in beside the one shown, so a turn is always one width | spring, from where the track is (a swipe's release speed carried on) | a new turn while one runs: the running one lands at once and the next starts |
|
||||
| Dashboard paging (round panel) | the dashboard, and beside it the next one | slides S up (the next, from below) or down (the previous, from above), the next one drawn on the face it opens on; once landed, it is the dashboard shown, and its name pill shows for a moment. One opened by its address replaces the last at once | spring | further paging waits for the turn to land |
|
||||
| Dashboard paging (round panel) | the dashboard, and beside it the next one | slides S up (the next, from below) or down (the previous, from above), the next one drawn on the face it opens on; once landed, it is the dashboard shown, and its name pill shows for a moment. Each one on the track wears its own look, theme and palette. The ground is the dashboard shown's and changes over as the turn begins, without a fade. One opened by its address replaces the last at once | spring | further paging waits for the turn to land |
|
||||
| Page dot | the current dot and the last | muted at 0.5 opacity ↔ text colour at 1 | 200 ms, cubic-bezier(0.4, 0, 0.2, 1) | retargets |
|
||||
| Dashboard name | the pill, on landing on another dashboard | opacity 0 → 1, held 1000 ms, 1 → 0 | in 200 ms, out 150 ms, cubic-bezier(0.4, 0, 0.2, 1) | — |
|
||||
| Ring value set by a notch, a key or the engine | the value arc's end, the handle (slider, selector, colour) | from where it is drawn to the new fraction of the sweep | spring | each notch retargets from where it is, at the speed it has |
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { WidgetDef } from "@/client"
|
||||
import { slotsFor } from "@/components/Common/UplotChart"
|
||||
import { fadeIn } from "@/lib/motion"
|
||||
import { useShortcuts } from "@/lib/shortcuts"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useClock } from "./ClockWidget"
|
||||
import type { Dashboard } from "./DashboardView"
|
||||
import { useBoundValue, useBoundValues } from "./dataContext"
|
||||
@@ -40,7 +41,7 @@ import {
|
||||
text,
|
||||
} from "./ui/core/config"
|
||||
import { TESTID } from "./ui/core/contract"
|
||||
import { useLook } from "./ui/core/look"
|
||||
import { LookProvider, useCanvasRoot, useLook } from "./ui/core/look"
|
||||
import { LOOK } from "./ui/core/motion"
|
||||
import {
|
||||
ANNOUNCE_MS,
|
||||
@@ -334,12 +335,7 @@ export function RoundPanel({
|
||||
return (
|
||||
// Keyed by name, so a neighbour becomes the one shown, and back,
|
||||
// without being drawn afresh: its own face memory and all.
|
||||
<div
|
||||
key={page.name}
|
||||
className="absolute inset-0"
|
||||
style={{ translate: `0 ${at * size}px` }}
|
||||
inert={at !== 0}
|
||||
>
|
||||
<TrackPage key={page.name} dashboard={page} at={at} size={size}>
|
||||
<PaletteProvider dashboard={page}>
|
||||
{editing ? (
|
||||
view
|
||||
@@ -347,13 +343,52 @@ export function RoundPanel({
|
||||
<LockedProvider dashboard={page}>{view}</LockedProvider>
|
||||
)}
|
||||
</PaletteProvider>
|
||||
</div>
|
||||
</TrackPage>
|
||||
)
|
||||
})}
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* One dashboard on a round panel's track, in its own look.
|
||||
*
|
||||
* The canvas states the look, theme and palette of the dashboard shown, so a
|
||||
* neighbour beside it, or the one a turn is leaving, would wear those too.
|
||||
* Each page restates its own instead. The ground stays the canvas's, which
|
||||
* changes over as soon as the turn begins.
|
||||
*/
|
||||
function TrackPage({
|
||||
dashboard,
|
||||
at,
|
||||
size,
|
||||
children,
|
||||
}: {
|
||||
dashboard: Dashboard
|
||||
/** Its place on the track, in screens from the one shown. */
|
||||
at: number
|
||||
size: number
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
// Touch belongs to the screen, so it is the canvas's whichever page this is.
|
||||
const { touch } = useLook()
|
||||
const root = useCanvasRoot(dashboard, touch)
|
||||
return (
|
||||
<LookProvider dashboard={dashboard} touch={touch}>
|
||||
<div
|
||||
data-look={root["data-look"]}
|
||||
data-touch={root["data-touch"]}
|
||||
data-palette={root["data-palette"]}
|
||||
className={cn("absolute inset-0 text-foreground", root.className)}
|
||||
style={{ ...root.style, translate: `0 ${at * size}px` }}
|
||||
inert={at !== 0}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</LookProvider>
|
||||
)
|
||||
}
|
||||
|
||||
/** A dashboard's icon and title: what a panel shows for a moment of a
|
||||
* dashboard it has just landed on. Opaque, so the face under it does not
|
||||
* read through the name. */
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
);
|
||||
--dui-reading: var(--foreground);
|
||||
--dui-reading-reached: var(--primary-foreground);
|
||||
--dui-reading-on-handle: var(--foreground);
|
||||
--dui-reading-on-handle: var(--dui-on-handle, var(--foreground));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -785,6 +785,47 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ring's paint. Each look states it on its root as these variables rather
|
||||
* than in rules under `[data-look]`: a round panel draws a dashboard beside
|
||||
* one in another look, and a descendant rule would reach into both, where an
|
||||
* inherited value stops at the nearer root. Reset on every root, so a look
|
||||
* that leaves one out takes the fallback rather than the outer root's.
|
||||
*/
|
||||
:where([data-look]) {
|
||||
--dui-ring-track: initial;
|
||||
--dui-ring-glow: initial;
|
||||
--dui-ring-handle: initial;
|
||||
--dui-ring-handle-edge: initial;
|
||||
--dui-ring-handle-edge-width: initial;
|
||||
--dui-ring-handle-shadow: initial;
|
||||
--dui-ring-swatch: initial;
|
||||
--dui-ring-swatch-width: initial;
|
||||
--dui-on-handle: initial;
|
||||
}
|
||||
|
||||
.dui-ring-track {
|
||||
stroke: var(--dui-ring-track, var(--muted));
|
||||
}
|
||||
|
||||
.dui-ring-fill {
|
||||
stroke: var(--primary);
|
||||
filter: var(--dui-ring-glow, none);
|
||||
}
|
||||
|
||||
.dui-ring-handle {
|
||||
fill: var(--dui-ring-handle, var(--primary));
|
||||
stroke: var(--dui-ring-handle-edge, none);
|
||||
stroke-width: var(--dui-ring-handle-edge-width, 0);
|
||||
filter: var(--dui-ring-handle-shadow, none);
|
||||
}
|
||||
|
||||
/* A colour's handle is filled with the colour, so only its edge is the look's. */
|
||||
.dui-ring-swatch {
|
||||
stroke: var(--dui-ring-swatch, var(--card));
|
||||
stroke-width: var(--dui-ring-swatch-width, 3px);
|
||||
}
|
||||
|
||||
.dui-ring-hit {
|
||||
pointer-events: stroke;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
[data-look="fluksio"] {
|
||||
--fx-radius: var(--radius-lg);
|
||||
--fx-field: var(--radius-md);
|
||||
/* A round face's ring (`core.css`): the slider's handle, a ring of primary
|
||||
around the page colour. */
|
||||
--dui-ring-handle: var(--background);
|
||||
--dui-ring-handle-edge: var(--primary);
|
||||
--dui-ring-handle-edge-width: 2px;
|
||||
--dui-ring-handle-shadow: drop-shadow(0 1px 2px rgb(0 0 0 / 0.2));
|
||||
}
|
||||
|
||||
/* --- surfaces ------------------------------------------------------------ */
|
||||
@@ -315,26 +321,3 @@
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 50%, transparent);
|
||||
}
|
||||
|
||||
/* --- a round dashboard's ring -------------------------------------------- */
|
||||
|
||||
[data-look="fluksio"] .dui-ring-track {
|
||||
stroke: var(--muted);
|
||||
}
|
||||
|
||||
[data-look="fluksio"] .dui-ring-fill {
|
||||
stroke: var(--primary);
|
||||
}
|
||||
|
||||
/* The slider's handle: a ring of primary around the page colour. */
|
||||
[data-look="fluksio"] .dui-ring-handle {
|
||||
fill: var(--background);
|
||||
stroke: var(--primary);
|
||||
stroke-width: 2px;
|
||||
filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.2));
|
||||
}
|
||||
|
||||
[data-look="fluksio"] .dui-ring-swatch {
|
||||
stroke: var(--card);
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,17 @@
|
||||
/* A round face's press, which has no card behind it. See below. */
|
||||
--gl-press: var(--gl-bg);
|
||||
--gl-press-shadow: var(--gl-inset);
|
||||
/* A round face's ring (`core.css`): lit, as the gauge's arc is, under a
|
||||
white handle, which a reading's dot on it shows dark against. */
|
||||
--dui-ring-track: var(--gl-track);
|
||||
--dui-ring-glow: drop-shadow(0 0 4px var(--primary));
|
||||
--dui-ring-handle: #fff;
|
||||
--dui-ring-handle-edge: var(--gl-border);
|
||||
--dui-ring-handle-edge-width: 1px;
|
||||
--dui-ring-handle-shadow: drop-shadow(0 2px 8px rgb(0 0 0 / 0.35));
|
||||
--dui-ring-swatch: rgb(255 255 255 / 0.85);
|
||||
--dui-ring-swatch-width: 2px;
|
||||
--dui-on-handle: rgb(0 0 0 / 0.75);
|
||||
}
|
||||
|
||||
[data-look="glass"].light {
|
||||
@@ -433,32 +444,3 @@
|
||||
outline: 2px solid var(--ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* --- a round dashboard's ring -------------------------------------------- */
|
||||
|
||||
[data-look="glass"] .dui-ring-track {
|
||||
stroke: var(--gl-track);
|
||||
}
|
||||
|
||||
/* Lit, as the gauge's arc is. */
|
||||
[data-look="glass"] .dui-ring-fill {
|
||||
stroke: var(--primary);
|
||||
filter: drop-shadow(0 0 4px var(--primary));
|
||||
}
|
||||
|
||||
[data-look="glass"] .dui-ring-handle {
|
||||
fill: #fff;
|
||||
stroke: var(--gl-border);
|
||||
stroke-width: 1px;
|
||||
filter: drop-shadow(0 2px 8px rgb(0 0 0 / 0.35));
|
||||
}
|
||||
|
||||
/* A reading's dot on the handle, which is white here in either theme. */
|
||||
[data-look="glass"] :is(.dui-ring, .dui-slider) {
|
||||
--dui-reading-on-handle: rgb(0 0 0 / 0.75);
|
||||
}
|
||||
|
||||
[data-look="glass"] .dui-ring-swatch {
|
||||
stroke: rgb(255 255 255 / 0.85);
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
--m3-sc: color-mix(in oklab, var(--primary) 22%, var(--card));
|
||||
--m3-outline: var(--border);
|
||||
--m3-radius: 1rem;
|
||||
/* A round face's ring (`core.css`): a tonal track under a primary handle,
|
||||
which a reading's dot on it shows light against. */
|
||||
--dui-ring-track: var(--m3-sc);
|
||||
--dui-on-handle: var(--primary-foreground);
|
||||
}
|
||||
|
||||
/* --- surfaces ----------------------------------------------------------- */
|
||||
@@ -319,27 +323,3 @@
|
||||
outline: 2px solid var(--primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* --- a round dashboard's ring -------------------------------------------- */
|
||||
|
||||
[data-look="material"] .dui-ring-track {
|
||||
stroke: var(--m3-sc);
|
||||
}
|
||||
|
||||
[data-look="material"] .dui-ring-fill {
|
||||
stroke: var(--primary);
|
||||
}
|
||||
|
||||
[data-look="material"] .dui-ring-handle {
|
||||
fill: var(--primary);
|
||||
}
|
||||
|
||||
/* A reading's dot on the handle, which is primary here. */
|
||||
[data-look="material"] :is(.dui-ring, .dui-slider) {
|
||||
--dui-reading-on-handle: var(--primary-foreground);
|
||||
}
|
||||
|
||||
[data-look="material"] .dui-ring-swatch {
|
||||
stroke: var(--card);
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user