mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
Merge wave-rings: flatten the health-score rings to the chart style
This commit is contained in:
commit
0a4be95aba
3 files changed
+116
-222
No files matched your search
+70
-153
@@ -235,38 +235,38 @@
|
||||
--dose-accent: oklch(0.714 0.203 305.504);
|
||||
|
||||
/*
|
||||
* v1.14.0 — wellness-ring per-metric gradients (Dracula dark).
|
||||
* Five DISTINCT single-hue two-stop arcs (from = darker, to = lighter):
|
||||
* readiness green · recovery cyan · sleep purple · stress orange ·
|
||||
* strain pink. Every `to` stop IS the matching Dracula palette colour
|
||||
* and the `from` stop is a hand-darkened tone of the same hue, so the
|
||||
* arcs read as Dracula rather than generic chart colours (the v1.14.0
|
||||
* set leaned indigo/teal/violet, which sat next to the palette instead
|
||||
* of on it). Each `to` doubles as the ring's bloom colour. The Alucard
|
||||
* light set lives on `:root.light`.
|
||||
* v1.18.7 — wellness-ring per-metric arc colours (Dracula dark), CALM pass.
|
||||
* Five DISTINCT but MUTED single-hue arcs: readiness green · recovery cyan ·
|
||||
* sleep purple · stress orange · strain pink. The earlier set ran a
|
||||
* dark→neon two-stop sweep (`to` == the raw Dracula palette colour) plus a
|
||||
* bloom + sheen, which read as glowing/3-D against the flat Recharts charts.
|
||||
* The arc is now a near-flat single tone per hue: `from`/`to` sit a hair
|
||||
* apart for a whisper of depth, both pulled down from the neon palette and
|
||||
* desaturated toward the chart colours, so the ring reads as quiet as a
|
||||
* chart series. The Alucard light set lives on `:root.light`.
|
||||
*/
|
||||
--ring-readiness-from: #1fa854;
|
||||
--ring-readiness-to: #50fa7b;
|
||||
--ring-readiness-from: #3fb86b;
|
||||
--ring-readiness-to: #46c476;
|
||||
--tile-readiness: #50fa7b;
|
||||
--ring-recovery-from: #2fa8c4;
|
||||
--ring-recovery-to: #8be9fd;
|
||||
--ring-recovery-from: #4fb6cc;
|
||||
--ring-recovery-to: #58c0d6;
|
||||
--tile-recovery: #8be9fd;
|
||||
--ring-sleep-from: #8655d6;
|
||||
--ring-sleep-to: #bd93f9;
|
||||
--ring-sleep-from: #9a73da;
|
||||
--ring-sleep-to: #a37fe0;
|
||||
--tile-sleep: #bd93f9;
|
||||
--ring-stress-from: #d9842e;
|
||||
--ring-stress-to: #ffb86c;
|
||||
--ring-stress-from: #e09a52;
|
||||
--ring-stress-to: #e8a55e;
|
||||
--tile-stress: #ffb86c;
|
||||
--ring-strain-from: #d6429b;
|
||||
--ring-strain-to: #ff79c6;
|
||||
--ring-strain-from: #e06aa8;
|
||||
--ring-strain-to: #ea74b1;
|
||||
--tile-strain: #ff79c6;
|
||||
/* Band fallback (anatomy detail view, no per-metric hue). */
|
||||
--ring-green-from: #1f9d57;
|
||||
--ring-green-to: #5cf08f;
|
||||
--ring-yellow-from: #e0922f;
|
||||
--ring-yellow-to: #ffce6b;
|
||||
--ring-red-from: #c93a2a;
|
||||
--ring-red-to: #ff7a6b;
|
||||
--ring-green-from: #3fb868;
|
||||
--ring-green-to: #48c473;
|
||||
--ring-yellow-from: #e0a050;
|
||||
--ring-yellow-to: #e8ab5c;
|
||||
--ring-red-from: #e0594a;
|
||||
--ring-red-to: #e96456;
|
||||
|
||||
/*
|
||||
* v1.15.0 — cycle-phase ring hues (Dracula dark). Four calm, distinct
|
||||
@@ -332,33 +332,35 @@
|
||||
--sidebar-ring: #644ac9;
|
||||
|
||||
/*
|
||||
* v1.14.0 — wellness-ring per-metric gradients (Alucard light). DEEPER +
|
||||
* more saturated than the dark set so each hue holds AA-grade presence on
|
||||
* the white `--card` (raw Dracula cyan/green wash out on white). Same five
|
||||
* Dracula hue families as the dark set: readiness green · recovery cyan ·
|
||||
* sleep purple · stress orange · strain pink.
|
||||
* v1.18.7 — wellness-ring per-metric arc colours (Alucard light), CALM pass.
|
||||
* Deep + saturated enough to hold AA presence on the white `--card` (raw
|
||||
* Dracula cyan/green wash out on white), but the dark→light two-stop SWEEP
|
||||
* is collapsed to a near-flat single tone (`from`/`to` a hair apart) so the
|
||||
* arc reads as quiet as a chart series rather than a glowing gradient. Same
|
||||
* five hue families as the dark set: readiness green · recovery cyan · sleep
|
||||
* purple · stress orange · strain pink.
|
||||
*/
|
||||
--ring-readiness-from: #0f7a3a;
|
||||
--ring-readiness-to: #18a34e;
|
||||
--ring-readiness-from: #138043;
|
||||
--ring-readiness-to: #168a48;
|
||||
--tile-readiness: #14720a;
|
||||
--ring-recovery-from: #067f96;
|
||||
--ring-recovery-to: #0d95b0;
|
||||
--ring-recovery-from: #07849c;
|
||||
--ring-recovery-to: #098ba3;
|
||||
--tile-recovery: #08869e;
|
||||
--ring-sleep-from: #5b2db8;
|
||||
--ring-sleep-to: #7a45d6;
|
||||
--ring-sleep-from: #6638c2;
|
||||
--ring-sleep-to: #6c3fc8;
|
||||
--tile-sleep: #6233c0;
|
||||
--ring-stress-from: #b06a16;
|
||||
--ring-stress-to: #c47a1e;
|
||||
--ring-stress-from: #b27018;
|
||||
--ring-stress-to: #b8771c;
|
||||
--tile-stress: #a34d14;
|
||||
--ring-strain-from: #ad1e6f;
|
||||
--ring-strain-to: #cc2e88;
|
||||
--ring-strain-from: #b62478;
|
||||
--ring-strain-to: #bd2a7e;
|
||||
--tile-strain: #b0277d;
|
||||
--ring-green-from: #0f7a3a;
|
||||
--ring-green-to: #18a34e;
|
||||
--ring-yellow-from: #b06a16;
|
||||
--ring-yellow-to: #d68a2a;
|
||||
--ring-red-from: #a3271a;
|
||||
--ring-red-to: #cb3a2a;
|
||||
--ring-green-from: #138043;
|
||||
--ring-green-to: #168a48;
|
||||
--ring-yellow-from: #b27018;
|
||||
--ring-yellow-to: #bd7a1e;
|
||||
--ring-red-from: #b22e20;
|
||||
--ring-red-to: #ba3526;
|
||||
|
||||
/*
|
||||
* v1.15.0 — cycle-phase ring hues (Alucard light). Deeper + more
|
||||
@@ -606,22 +608,13 @@
|
||||
}
|
||||
|
||||
/*
|
||||
* v1.14.0 — the wellness-strip "signature reveal" motion system.
|
||||
*
|
||||
* The whole moment plays ONCE per session (the strip toggles
|
||||
* `data-revealed="true"` once, gated on a sessionStorage flag) so a
|
||||
* background Apple-Health-sync refetch never re-triggers it. Three layers:
|
||||
* 1. tile rise+fade (staggered left-to-right by an inline animation-delay),
|
||||
* 2. the ring's spring-fill arc sweep (in score-ring.tsx, --ring-spring),
|
||||
* 3. a conic SHEEN that sweeps the arc once (the "expensive" specular touch).
|
||||
* A single prefers-reduced-motion block at the bottom zeroes all of it.
|
||||
* v1.18.7 — the wellness-strip reveal, calmed. What remains is a quiet
|
||||
* left-to-right tile rise+fade (gated once per session via `data-revealed`)
|
||||
* and the arc's spring-fill sweep (in score-ring.tsx, `--ring-spring`). The
|
||||
* conic specular sheen + the bloom + the breathing pulse were removed so the
|
||||
* strip settles as flat as the surrounding charts. A single
|
||||
* prefers-reduced-motion block at the bottom zeroes the tile rise.
|
||||
*/
|
||||
@property --shimmer-angle {
|
||||
syntax: "<angle>";
|
||||
inherits: false;
|
||||
initial-value: 0deg;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* Sampled spring (stiffness ~120, damping ~14): overshoots ~6% then settles
|
||||
— the Oura/WHOOP fill feel. Falls back to the browser default on very old
|
||||
@@ -658,93 +651,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* The conic sheen overlay sits over the ring; opacity animates from 0 so a
|
||||
browser without @property support (Safari <16.4 / FF <128) shows nothing
|
||||
rather than a frozen highlight band. */
|
||||
/* v1.18.7 — the conic specular SHEEN is retired. It swept a white highlight
|
||||
across the arc once on reveal, which was the most overtly "premium / 3-D"
|
||||
touch and clashed hardest with the flat charts. The class is kept as a
|
||||
no-op so the cycle-ring + score-ring call sites that still render the
|
||||
overlay div simply paint nothing. */
|
||||
.wellness-ring-sheen {
|
||||
position: absolute;
|
||||
inset: 6%;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
/* A specular highlight must always LIGHTEN. Under mix-blend overlay a
|
||||
near-black light-mode `--card-foreground` would darken the tile into a
|
||||
grey band, so the sheen rides a fixed white in both themes. */
|
||||
background: radial-gradient(
|
||||
circle at 50% 50%,
|
||||
rgba(255, 255, 255, 0.72) 0%,
|
||||
transparent 70%
|
||||
);
|
||||
mix-blend-mode: overlay;
|
||||
pointer-events: none;
|
||||
-webkit-mask: conic-gradient(
|
||||
from var(--shimmer-angle),
|
||||
transparent 0deg,
|
||||
transparent 38deg,
|
||||
#000 58deg,
|
||||
transparent 80deg,
|
||||
transparent 360deg
|
||||
);
|
||||
mask: conic-gradient(
|
||||
from var(--shimmer-angle),
|
||||
transparent 0deg,
|
||||
transparent 38deg,
|
||||
#000 58deg,
|
||||
transparent 80deg,
|
||||
transparent 360deg
|
||||
);
|
||||
}
|
||||
[data-revealed="true"] .wellness-ring-sheen {
|
||||
animation: ringSheen 1500ms var(--ring-ease) forwards;
|
||||
animation-delay: calc(var(--reveal-delay, 0ms) + 550ms);
|
||||
}
|
||||
@keyframes ringSheen {
|
||||
0% {
|
||||
--shimmer-angle: 0deg;
|
||||
opacity: 0;
|
||||
}
|
||||
15% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
85% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
--shimmer-angle: 360deg;
|
||||
opacity: 0;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Token-tinted bloom behind the progress arc. The breathing pulse runs only
|
||||
on the strongest (green-band) ring so the strip celebrates a good score
|
||||
rather than jittering all five. `--ring-glow` is set inline per ring. */
|
||||
.wellness-ring-arc {
|
||||
filter: drop-shadow(
|
||||
0 0 3px color-mix(in srgb, var(--ring-glow) 45%, transparent)
|
||||
);
|
||||
}
|
||||
/* Flat 2-D arc — no bloom, no pulse. The dashboard hero ring uses this so it
|
||||
reads as calmly as the chart + tile surfaces around it. */
|
||||
.wellness-ring-arc--flat {
|
||||
filter: none;
|
||||
}
|
||||
/* v1.18.7 — the arc is FLAT by default. The earlier treatment painted a
|
||||
token-tinted drop-shadow bloom behind every arc plus a breathing pulse on
|
||||
the green-band ring; against the flat 2-D Recharts charts that read as a
|
||||
glowing 3-D dial. Both are gone — the arc is a plain stroke, the same
|
||||
weight a chart series carries. `.wellness-ring-arc--flat` is kept as an
|
||||
alias so the dashboard-hero call site (and any other) stays valid. */
|
||||
.wellness-ring-arc,
|
||||
.wellness-ring-arc--flat,
|
||||
.wellness-ring-arc--pulse {
|
||||
/* Breathe a few times to celebrate a strong score, then settle — an
|
||||
infinite loop would repaint the (non-compositable) drop-shadow filter
|
||||
forever. Motion happens, then the surface goes calm. */
|
||||
animation: ringGlow 3.4s ease-in-out 2s 3;
|
||||
}
|
||||
@keyframes ringGlow {
|
||||
0%,
|
||||
100% {
|
||||
filter: drop-shadow(
|
||||
0 0 2px color-mix(in srgb, var(--ring-glow) 40%, transparent)
|
||||
);
|
||||
}
|
||||
50% {
|
||||
filter: drop-shadow(
|
||||
0 0 8px color-mix(in srgb, var(--ring-glow) 65%, transparent)
|
||||
);
|
||||
}
|
||||
filter: none;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
@@ -762,15 +688,6 @@
|
||||
transform: none;
|
||||
animation: none;
|
||||
}
|
||||
[data-revealed="true"] .wellness-ring-sheen {
|
||||
animation: none;
|
||||
opacity: 0;
|
||||
}
|
||||
.wellness-ring-arc,
|
||||
.wellness-ring-arc--pulse {
|
||||
filter: none;
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
/**
|
||||
* v1.14.0 — per-metric ring hues for the wellness-score strip.
|
||||
*
|
||||
* The premium signature is a SINGLE-hue, TWO-stop gradient per ring
|
||||
* (dark → light tones of the *same* colour), never a multi-hue rainbow.
|
||||
* Each metric leans toward one intentional, distinct hue (Oura's per-metric
|
||||
* move): readiness green, recovery cyan, sleep purple, stress orange,
|
||||
* strain pink — five clearly different hues so the strip never reads as
|
||||
* "a wash of green/cyan". In the dark theme every `to` stop sits exactly
|
||||
* on the matching Dracula palette colour.
|
||||
* Each metric leans toward one intentional, distinct hue: readiness green,
|
||||
* recovery cyan, sleep purple, stress orange, strain pink — five clearly
|
||||
* different hues so the strip never reads as "a wash of green/cyan".
|
||||
*
|
||||
* The actual colours live as CSS custom properties in `globals.css`
|
||||
* v1.18.7 — CALM. The arc was a dark→neon two-stop gradient (the `to` stop
|
||||
* sat on the raw Dracula palette colour) plus a bloom + sheen, which glowed
|
||||
* against the flat charts. The two stops are now MUTED and sit a hair apart,
|
||||
* so each arc reads as a near-flat single tone — quiet as a chart series. The
|
||||
* actual colours live as CSS custom properties in `globals.css`
|
||||
* (`--ring-<key>-from` / `--ring-<key>-to` / `--tile-<key>`) with a Dracula
|
||||
* dark set on `:root` and an Alucard light set on `:root.light`, so each hue
|
||||
* is HAND-TUNED per theme — deep + saturated enough to hold contrast on the
|
||||
* white Alucard card, vivid on the dark Dracula card. (The v1.13.x version
|
||||
* mixed through ambiguous semantic tokens — `--info` == `--dracula-cyan` —
|
||||
* which collapsed three of the five rings to cyan in the dark theme and
|
||||
* washed recovery/strain out on white. Dedicated per-theme vars fix that.)
|
||||
* is HAND-TUNED per theme — deep enough to hold contrast on the white Alucard
|
||||
* card without going neon on the dark Dracula card.
|
||||
*
|
||||
* The band semantic is never carried by the hue: it still rides `data-band`
|
||||
* + the band word + the aria-label, so a red-band readiness still reads "low"
|
||||
@@ -29,11 +26,11 @@ import type { ScoreBand } from "./band-tokens";
|
||||
export type RingHue = "readiness" | "sleep" | "recovery" | "stress" | "strain";
|
||||
|
||||
/**
|
||||
* Single-hue two-stop gradient `[from, to]` (dark → light) per metric, plus a
|
||||
* band fallback for the anatomy detail view (which passes no `hue`, so the
|
||||
* ring keeps its green/yellow/red band semantics there). Values are CSS var
|
||||
* references resolved per theme — consumed straight by the SVG
|
||||
* `<linearGradient>` stops.
|
||||
* Near-flat single-hue arc `[from, to]` per metric, plus a band fallback for
|
||||
* the anatomy detail view (which passes no `hue`, so the ring keeps its
|
||||
* green/yellow/red band semantics there). The two stops are a hair apart for a
|
||||
* whisper of depth, not a neon sweep. Values are CSS var references resolved
|
||||
* per theme — consumed straight by the SVG `<linearGradient>` stops.
|
||||
*/
|
||||
export const RING_GRADIENT: Record<RingHue | ScoreBand, [string, string]> = {
|
||||
readiness: ["var(--ring-readiness-from)", "var(--ring-readiness-to)"],
|
||||
@@ -47,21 +44,6 @@ export const RING_GRADIENT: Record<RingHue | ScoreBand, [string, string]> = {
|
||||
red: ["var(--ring-red-from)", "var(--ring-red-to)"],
|
||||
};
|
||||
|
||||
/**
|
||||
* The `to` (light) stop per key — used as the ring's glow colour
|
||||
* (`--ring-glow`) so the bloom matches the brighter end of the arc.
|
||||
*/
|
||||
export const RING_GLOW: Record<RingHue | ScoreBand, string> = {
|
||||
readiness: "var(--ring-readiness-to)",
|
||||
recovery: "var(--ring-recovery-to)",
|
||||
sleep: "var(--ring-sleep-to)",
|
||||
stress: "var(--ring-stress-to)",
|
||||
strain: "var(--ring-strain-to)",
|
||||
green: "var(--ring-green-to)",
|
||||
yellow: "var(--ring-yellow-to)",
|
||||
red: "var(--ring-red-to)",
|
||||
};
|
||||
|
||||
/**
|
||||
* The surface tint per metric — the `--tile-hue` the `.wellness-tile` CSS
|
||||
* mixes (gently) over the theme `--card`. Set inline by each `RingTile`.
|
||||
|
||||
@@ -6,25 +6,31 @@ import { cn } from "@/lib/utils";
|
||||
import { useCountUp } from "@/hooks/use-count-up";
|
||||
import { prefersReducedMotion } from "@/lib/charts/reduced-motion";
|
||||
import { bandForScore, clampScore, type ScoreBand } from "./band-tokens";
|
||||
import { RING_GRADIENT, RING_GLOW, type RingHue } from "./ring-hues";
|
||||
import { RING_GRADIENT, type RingHue } from "./ring-hues";
|
||||
|
||||
/**
|
||||
* v1.14.0 — the composite-score dial: a hand-rolled SVG arc gauge with a
|
||||
* premium "signature reveal" (Oura/WHOOP-tier), 0 KB runtime, no animation
|
||||
* library. A score dial is a fixed-geometry gauge, not a data chart, so SVG
|
||||
* gives exact control over a thin round-cap arc, a segmented same-hue track,
|
||||
* a single-hue two-stop gradient, a faint "vs your baseline" ghost arc, and a
|
||||
* token-tinted bloom — all CSS-driven.
|
||||
* v1.14.0 — the composite-score dial: a hand-rolled SVG arc gauge, 0 KB
|
||||
* runtime, no animation library. A score dial is a fixed-geometry gauge, not a
|
||||
* data chart, so SVG gives exact control over a thin round-cap arc, a
|
||||
* segmented same-hue track, a near-flat single-hue arc, and a faint "vs your
|
||||
* baseline" ghost arc.
|
||||
*
|
||||
* Motion (all CSS-first, all gated on `prefers-reduced-motion`):
|
||||
* v1.18.7 — CALM by default. The earlier dial wore a token-tinted bloom, a
|
||||
* conic specular sheen, and a breathing pulse on the green ring; against the
|
||||
* flat 2-D Recharts charts that read as a glowing 3-D gauge. All three are
|
||||
* gone everywhere — the ring now paints a plain stroke in a muted single hue,
|
||||
* as quiet as a chart series. The only motion left is a subtle spring fill on
|
||||
* first reveal + a count-up, both gated on `prefers-reduced-motion`.
|
||||
*
|
||||
* Motion (CSS-first, gated on `prefers-reduced-motion`):
|
||||
* • the arc sweeps from empty on mount via a `linear()` SPRING that
|
||||
* overshoots ~6% then settles (`--ring-spring`); the spring is swapped for
|
||||
* a plain ease-out above score 94 so a high arc never wraps past full;
|
||||
* • `delayMs` staggers the sweep + the count-up so the strip reveals
|
||||
* left-to-right and each number trails its arc;
|
||||
* • a conic SHEEN + the tile rise + glow live in `globals.css`, gated on the
|
||||
* strip's `data-revealed` flag (set once per session) so a background
|
||||
* refetch never re-triggers the moment.
|
||||
* • the quiet tile rise lives in `globals.css`, gated on the strip's
|
||||
* `data-revealed` flag (set once per session) so a background refetch
|
||||
* never re-triggers it.
|
||||
*
|
||||
* The arc/track/ghost are real SVG JSX (`<linearGradient>` is NOT
|
||||
* `dangerouslySetInnerHTML`). The `<svg>` is rotated -90° so the arc starts at
|
||||
@@ -78,10 +84,10 @@ export interface ScoreRingProps {
|
||||
*/
|
||||
delayMs?: number;
|
||||
/**
|
||||
* Flat 2-D treatment: drops the drop-shadow bloom, the breathing pulse, the
|
||||
* conic sheen, and the sweep/count-up entrance. Used on the dashboard hero so
|
||||
* the ring sits as calmly as the surrounding chart + tile surfaces. The
|
||||
* /insights wellness strip + anatomy view keep the full premium reveal.
|
||||
* v1.18.7 — the bloom / sheen / pulse are gone for every ring, so the only
|
||||
* thing `flat` still does is drop the spring-fill sweep + the count-up: the
|
||||
* dashboard-hero ring paints its final value at once, with no entrance
|
||||
* motion. The /insights strip + anatomy view keep the subtle sweep.
|
||||
*/
|
||||
flat?: boolean;
|
||||
/**
|
||||
@@ -121,10 +127,10 @@ export function ScoreRing({
|
||||
const resolvedBand: ScoreBand = band ?? bandForScore(clamped);
|
||||
const hueKey = hue ?? resolvedBand;
|
||||
|
||||
// Single-hue two-stop gradient. The per-metric `hue` leans the colour
|
||||
// (Oura's move); with no `hue` the anatomy view falls back to the band token.
|
||||
// Near-flat single-hue arc. The two stops sit a hair apart for a whisper of
|
||||
// depth; the per-metric `hue` leans the colour, with no `hue` the anatomy
|
||||
// view falls back to the muted band token.
|
||||
const [from, to] = RING_GRADIENT[hueKey];
|
||||
const glow = RING_GLOW[hueKey];
|
||||
|
||||
const reduced = prefersReducedMotion();
|
||||
// `flat` forces the calm static treatment regardless of the `animate` prop:
|
||||
@@ -175,18 +181,15 @@ export function ScoreRing({
|
||||
{
|
||||
width: dims.px,
|
||||
height: dims.px,
|
||||
"--ring-glow": glow,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
{/* `overflow-visible`: the arc's drop-shadow bloom (`.wellness-ring-arc`)
|
||||
paints outside the viewBox — the arc fills the 0 0 100 100 box, so the
|
||||
default `overflow: hidden` on SVG clipped the glow flat at the circle's
|
||||
edge. The -90° rotation is unaffected (the bloom is radially symmetric)
|
||||
and the parent div never clips, so the glow now feathers out fully. */}
|
||||
{/* The -90° rotation starts the arc at 12 o'clock so it sweeps clockwise
|
||||
without per-point trig. The arc now carries no bloom, so the SVG needs
|
||||
no `overflow-visible`. */}
|
||||
<svg
|
||||
viewBox={`0 0 ${VIEW} ${VIEW}`}
|
||||
className="h-full w-full -rotate-90 overflow-visible"
|
||||
className="h-full w-full -rotate-90"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<defs>
|
||||
@@ -227,15 +230,10 @@ export function ScoreRing({
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{/* The progress arc — single-hue gradient, round cap, spring sweep, bloom. */}
|
||||
{/* The progress arc — muted single hue, round cap, subtle spring sweep.
|
||||
No bloom / pulse: `.wellness-ring-arc` is a plain flat stroke. */}
|
||||
<circle
|
||||
className={cn(
|
||||
flat ? "wellness-ring-arc--flat" : "wellness-ring-arc",
|
||||
!flat &&
|
||||
shouldAnimate &&
|
||||
resolvedBand === "green" &&
|
||||
"wellness-ring-arc--pulse",
|
||||
)}
|
||||
className="wellness-ring-arc"
|
||||
cx={CX}
|
||||
cy={CX}
|
||||
r={R}
|
||||
@@ -252,9 +250,6 @@ export function ScoreRing({
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
{/* Conic specular sheen — sweeps the arc once on the strip reveal.
|
||||
Omitted entirely in the flat treatment (dashboard hero). */}
|
||||
{flat ? null : <div className="wellness-ring-sheen" aria-hidden="true" />}
|
||||
{/* Centred number as real DOM text — design tokens + tabular-nums. */}
|
||||
<div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center">
|
||||
<span
|
||||
|
||||
Reference in new issue
Block a user