diff --git a/services/frontend/src/app/(dashboard)/dashboard/view.tsx b/services/frontend/src/app/(dashboard)/dashboard/view.tsx index c6ab1f87..af4b4355 100644 --- a/services/frontend/src/app/(dashboard)/dashboard/view.tsx +++ b/services/frontend/src/app/(dashboard)/dashboard/view.tsx @@ -58,7 +58,7 @@ export function DashboardView({ error, mutate: mutateStats, } = useStats(initialStats); - const { data: activity } = useActivity(14, initialActivity as never); + const { data: activity } = useActivity(14, initialActivity); const { data: reactions } = useTopReactions(); const ambient = useAmbient(); diff --git a/services/frontend/src/components/ambient/ambient-canvas.tsx b/services/frontend/src/components/ambient/ambient-canvas.tsx index 5af9f2de..c251398d 100644 --- a/services/frontend/src/components/ambient/ambient-canvas.tsx +++ b/services/frontend/src/components/ambient/ambient-canvas.tsx @@ -35,15 +35,18 @@ export function AmbientCanvas({ let raf = 0; let last = performance.now(); - // Lerp state + // Lerp state (start values match the inline style defaults on the element). let r = 45, g = 212, b = 191; - let targetR = 45, - targetG = 212, - targetB = 191; let intensity = 0.35; - let targetIntensity = 0.35; + // Last values actually written to the DOM — lets us skip `setProperty` + // entirely once a channel settles, so the continuous loop stops invalidating + // style/layout every frame when the ambient is static. + let lastR = -1, + lastG = -1, + lastB = -1, + lastAlpha = "-1"; const lerp = (a: number, b: number, t: number) => a + (b - a) * t; @@ -53,21 +56,34 @@ export function AmbientCanvas({ const tgt = targetRef.current; const [tr, tg, tb] = TONE_css[tgt.tone].split(",").map(Number); - targetR = tr; - targetG = tg; - targetB = tb; - targetIntensity = 0.15 + tgt.intensity * 0.85; + const targetIntensity = 0.15 + tgt.intensity * 0.85; - r = lerp(r, targetR, 0.03); - g = lerp(g, targetG, 0.03); - b = lerp(b, targetB, 0.03); + r = lerp(r, tr, 0.03); + g = lerp(g, tg, 0.03); + b = lerp(b, tb, 0.03); intensity = lerp(intensity, targetIntensity, 0.03); const root = mount; - root.style.setProperty("--ab-r", String(Math.round(r))); - root.style.setProperty("--ab-g", String(Math.round(g))); - root.style.setProperty("--ab-b", String(Math.round(b))); - root.style.setProperty("--ab-alpha", intensity.toFixed(3)); + const R = Math.round(r); + const G = Math.round(g); + const B = Math.round(b); + const A = intensity.toFixed(3); + if (R !== lastR) { + root.style.setProperty("--ab-r", String(R)); + lastR = R; + } + if (G !== lastG) { + root.style.setProperty("--ab-g", String(G)); + lastG = G; + } + if (B !== lastB) { + root.style.setProperty("--ab-b", String(B)); + lastB = B; + } + if (A !== lastAlpha) { + root.style.setProperty("--ab-alpha", A); + lastAlpha = A; + } raf = requestAnimationFrame(frame); }; diff --git a/services/frontend/src/components/primitives/select.tsx b/services/frontend/src/components/primitives/select.tsx index 9cfe2313..29634896 100644 --- a/services/frontend/src/components/primitives/select.tsx +++ b/services/frontend/src/components/primitives/select.tsx @@ -101,6 +101,9 @@ export function Select({ ref={triggerRef} type="button" onClick={() => setOpen((o) => !o)} + aria-haspopup="listbox" + aria-expanded={open} + aria-label={selected?.label ?? placeholder} className={cn( "flex w-full items-center justify-between gap-2 rounded-[8px] border border-hairline bg-surface-2 text-left text-ink transition-colors hover:border-signal/40", "focus:outline-none focus:border-signal/60", @@ -123,6 +126,7 @@ export function Select({ createPortal(