From 79651bc41d443a23396bfb3b49db3d847e36ed0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Sun, 15 Mar 2026 01:22:35 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20dashboard=20widget=20animations=20?= =?UTF-8?q?=E2=80=94=20staggered=20entrance,=20hover=20glow,=20progress=20?= =?UTF-8?q?bars?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Widgets scale in with staggered delays (60ms per widget, up to 12) - Widget hover: lift 3px + accent border glow (dark mode: accent shadow) - Inner numbers animate up with count-up effect - Progress bars grow from left with spring curve (800ms delay for content-first feel) - All wrapped in prefers-reduced-motion guard Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/index.css | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/frontend/src/index.css b/frontend/src/index.css index 03a603d..2afd0c6 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -669,6 +669,68 @@ html { scroll-behavior: smooth; } +/* ── Dashboard widget animations ───────────────────────────── */ + +/* Dashboard widgets: staggered scale-in entrance */ +.grid > div > .card { + animation: widgetEnter 450ms cubic-bezier(0.16, 1, 0.3, 1) both; +} + +@keyframes widgetEnter { + from { + opacity: 0; + transform: scale(0.94) translateY(8px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +/* Staggered delays for dashboard widgets */ +.grid > div:nth-child(1) > .card { animation-delay: 0ms; } +.grid > div:nth-child(2) > .card { animation-delay: 60ms; } +.grid > div:nth-child(3) > .card { animation-delay: 120ms; } +.grid > div:nth-child(4) > .card { animation-delay: 180ms; } +.grid > div:nth-child(5) > .card { animation-delay: 240ms; } +.grid > div:nth-child(6) > .card { animation-delay: 300ms; } +.grid > div:nth-child(7) > .card { animation-delay: 360ms; } +.grid > div:nth-child(8) > .card { animation-delay: 420ms; } +.grid > div:nth-child(9) > .card { animation-delay: 480ms; } +.grid > div:nth-child(10) > .card { animation-delay: 540ms; } +.grid > div:nth-child(11) > .card { animation-delay: 600ms; } +.grid > div:nth-child(12) > .card { animation-delay: 660ms; } +.grid > div:nth-child(n+13) > .card { animation-delay: 700ms; } + +/* Dashboard widget hover: subtle glow + lift */ +.grid > div > .card:hover { + transform: translateY(-3px); + box-shadow: 0 12px 32px -6px rgba(0, 0, 0, 0.15), 0 4px 12px -2px rgba(0, 0, 0, 0.08); + border-color: var(--color-accent); + transition: all 250ms cubic-bezier(0.16, 1, 0.3, 1); +} +:root.dark .grid > div > .card:hover { + box-shadow: 0 12px 32px -6px rgba(0, 0, 0, 0.5), 0 0 0 1px var(--color-accent), 0 0 20px -4px rgba(var(--accent-rgb, 0, 137, 61), 0.15); +} + +/* Widget inner content numbers — count-up effect */ +.card .text-2xl, +.card .text-3xl, +.card .text-4xl { + animation: countUp 600ms cubic-bezier(0.16, 1, 0.3, 1) both; + animation-delay: inherit; +} + +/* Widget progress bars — animated grow from left */ +.card [class*="bg-green"], +.card [class*="bg-red"], +.card [class*="bg-amber"], +.card [class*="bg-blue"], +.card [class*="bg-status"] { + animation: progressGrow 800ms cubic-bezier(0.16, 1, 0.3, 1) both; + animation-delay: 400ms; +} + /* ── Reduced motion: respect user preference ───────────────── */ @media (prefers-reduced-motion: reduce) {