feat(ui): Aurora design system — glassmorphic dark mode, warm light mode, snappy animations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 22:10:52 +02:00
parent 97cfd0ed90
commit 1383169352
2 changed files with 118 additions and 39 deletions
+16 -16
View File
@@ -334,17 +334,17 @@ const NavItemLink = memo(function NavItemLink({
href={href as Route}
{...linkProps}
className={clsx(
"group relative flex items-center rounded-2xl text-sm font-medium transition-colors",
"group relative flex items-center rounded-2xl text-sm transition-colors",
collapsed ? "justify-center px-2 py-2" : "gap-3 px-3 py-2",
isActive
? "text-brand-800 dark:text-brand-200"
: "text-gray-700 hover:bg-gray-100/90 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-slate-900 dark:hover:text-white",
? "font-medium text-brand-700 dark:border-l-2 dark:border-brand-400/70 dark:text-brand-300"
: "font-medium text-gray-700 hover:bg-gray-100/90 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-white/[0.05] dark:hover:text-white",
)}
>
{isActive && (
<motion.div
layoutId="nav-indicator"
className="absolute inset-0 rounded-2xl bg-gradient-to-r from-brand-100 to-brand-50/80 shadow-sm ring-1 ring-brand-200/80 dark:from-brand-900/30 dark:to-brand-800/20 dark:ring-brand-900/40"
className="absolute inset-0 rounded-2xl bg-gradient-to-r from-brand-50 to-brand-100/60 shadow-sm ring-1 ring-brand-200/80 dark:from-brand-500/15 dark:to-brand-400/[0.08] dark:ring-brand-900/40"
transition={{ type: "spring", stiffness: 350, damping: 30 }}
/>
)}
@@ -426,7 +426,7 @@ function SidebarContent({
sidebarCollapsed ? "px-3 py-4" : "px-6 py-6",
)}>
<div className={clsx(
"inline-flex items-center rounded-2xl border border-brand-200/70 bg-gradient-to-br from-white to-brand-50 shadow-sm dark:border-brand-900/50 dark:from-slate-950 dark:to-slate-900",
"inline-flex items-center rounded-2xl border border-brand-200/70 bg-gradient-to-br from-white to-brand-50 shadow-sm dark:border-brand-900/40 dark:from-[#0d0e22] dark:to-[#13162a]",
sidebarCollapsed ? "p-2" : "gap-3 px-4 py-3",
)}>
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-brand-600 text-white shadow-lg shadow-brand-600/25">
@@ -551,7 +551,7 @@ function SidebarContent({
<button
type="button"
onClick={() => toggleSection(entry.label)}
className="flex w-full items-center gap-3 rounded-2xl px-3 py-2 text-sm font-medium text-gray-500 transition-all hover:bg-gray-100/90 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-slate-900 dark:hover:text-gray-200"
className="flex w-full items-center gap-3 rounded-2xl px-3 py-2 text-sm font-medium text-gray-500 transition-all hover:bg-gray-100/90 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/[0.05] dark:hover:text-gray-200"
>
<IconFrame><AdminIcon /></IconFrame>
<span className="flex-1 text-left">{entry.label}</span>
@@ -587,14 +587,14 @@ function SidebarContent({
className={clsx(
"group relative flex items-center gap-3 rounded-2xl px-3 py-1.5 text-sm font-medium transition-colors",
isActive
? "text-brand-800 dark:text-brand-200"
: "text-gray-700 hover:bg-gray-100/90 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-slate-900 dark:hover:text-white",
? "text-brand-700 dark:border-l-2 dark:border-brand-400/70 dark:text-brand-300"
: "text-gray-700 hover:bg-gray-100/90 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-white/[0.05] dark:hover:text-white",
)}
>
{isActive && (
<motion.div
layoutId="nav-indicator"
className="absolute inset-0 rounded-2xl bg-gradient-to-r from-brand-100 to-brand-50/80 shadow-sm ring-1 ring-brand-200/80 dark:from-brand-900/30 dark:to-brand-800/20 dark:ring-brand-900/40"
className="absolute inset-0 rounded-2xl bg-gradient-to-r from-brand-50 to-brand-100/60 shadow-sm ring-1 ring-brand-200/80 dark:from-brand-500/15 dark:to-brand-400/[0.08] dark:ring-brand-900/40"
transition={{ type: "spring", stiffness: 350, damping: 30 }}
/>
)}
@@ -649,7 +649,7 @@ function SidebarContent({
type="button"
onClick={onChatOpen}
className={clsx(
"flex w-full items-center rounded-2xl text-sm text-gray-700 transition-colors hover:bg-gray-100/90 dark:text-gray-300 dark:hover:bg-slate-900",
"flex w-full items-center rounded-2xl text-sm text-gray-700 transition-colors hover:bg-gray-100/90 dark:text-gray-300 dark:hover:bg-white/[0.05]",
sidebarCollapsed ? "justify-center px-2 py-2.5" : "gap-3 px-3 py-2.5",
)}
>
@@ -667,7 +667,7 @@ function SidebarContent({
type="button"
onClick={onPrefsOpen}
className={clsx(
"flex w-full items-center rounded-2xl text-sm text-gray-700 transition-colors hover:bg-gray-100/90 dark:text-gray-300 dark:hover:bg-slate-900",
"flex w-full items-center rounded-2xl text-sm text-gray-700 transition-colors hover:bg-gray-100/90 dark:text-gray-300 dark:hover:bg-white/[0.05]",
sidebarCollapsed ? "justify-center px-2 py-2.5" : "gap-3 px-3 py-2.5",
)}
>
@@ -686,7 +686,7 @@ function SidebarContent({
type="button"
onClick={() => void signOut({ callbackUrl: "/auth/signin" })}
className={clsx(
"flex w-full items-center rounded-2xl text-sm text-gray-700 transition-colors hover:bg-gray-100/90 dark:text-gray-300 dark:hover:bg-slate-900",
"flex w-full items-center rounded-2xl text-sm text-gray-700 transition-colors hover:bg-gray-100/90 dark:text-gray-300 dark:hover:bg-white/[0.05]",
sidebarCollapsed ? "justify-center px-2 py-2.5" : "gap-3 px-3 py-2.5",
)}
>
@@ -705,7 +705,7 @@ function SidebarContent({
type="button"
onClick={onToggleCollapse}
className={clsx(
"flex w-full items-center rounded-2xl text-sm text-gray-400 transition-colors hover:bg-gray-100/90 hover:text-gray-600 dark:text-gray-500 dark:hover:bg-slate-900 dark:hover:text-gray-300",
"flex w-full items-center rounded-2xl text-sm text-gray-400 transition-colors hover:bg-gray-100/90 hover:text-gray-600 dark:text-gray-500 dark:hover:bg-white/[0.05] dark:hover:text-gray-300",
sidebarCollapsed ? "justify-center px-2 py-2.5" : "gap-3 px-3 py-2.5",
)}
>
@@ -741,7 +741,7 @@ function DesktopSidebar({
return (
<nav
className={clsx(
"hidden shrink-0 border-r border-gray-200/60 bg-white/60 shadow-[1px_0_12px_rgba(0,0,0,0.03)] backdrop-blur-2xl backdrop-saturate-150 dark:border-slate-800 dark:bg-slate-950/75 dark:shadow-none lg:flex lg:flex-col",
"hidden shrink-0 border-r border-gray-200/60 bg-white/95 shadow-[1px_0_12px_rgba(0,0,0,0.03)] backdrop-blur-xl backdrop-saturate-150 dark:border-white/[0.06] dark:bg-[#0d0e22]/90 dark:shadow-none lg:flex lg:flex-col",
"transition-[width] duration-200 ease-out overflow-hidden",
sidebarCollapsed ? "w-[72px]" : "w-72",
)}
@@ -793,7 +793,7 @@ function MobileSidebar({
animate={{ x: 0 }}
exit={{ x: -288 }}
transition={{ type: "spring", stiffness: 400, damping: 35 }}
className="fixed inset-y-0 left-0 z-50 flex w-72 flex-col border-r border-gray-200/60 bg-white/95 shadow-2xl backdrop-blur-2xl backdrop-saturate-150 dark:border-slate-800 dark:bg-slate-950/95 lg:hidden"
className="fixed inset-y-0 left-0 z-50 flex w-72 flex-col border-r border-gray-200/60 bg-white/95 shadow-2xl backdrop-blur-2xl backdrop-saturate-150 dark:border-white/[0.06] dark:bg-[#0d0e22]/95 lg:hidden"
>
{/* Close button */}
<button
@@ -897,7 +897,7 @@ export function AppShell({ children, userRole = "USER" }: { children: React.Reac
{/* Main content area */}
<main ref={contentRef} className="flex-1 overflow-auto bg-transparent">
{/* Mobile hamburger */}
<div className="sticky top-0 z-20 flex items-center border-b border-gray-200/60 bg-white/80 px-4 py-2 backdrop-blur-lg dark:border-slate-800 dark:bg-slate-950/80 lg:hidden">
<div className="sticky top-0 z-20 flex items-center border-b border-gray-200/60 bg-white/85 px-4 py-2 backdrop-blur-xl dark:border-white/[0.06] dark:bg-[#0d0e22]/82 lg:hidden">
<button
type="button"
onClick={() => setMobileOpen(true)}