diff --git a/services/frontend/src/app/(dashboard)/analysis/page.tsx b/services/frontend/src/app/(dashboard)/analysis/page.tsx index dd76297..00eaeed 100644 --- a/services/frontend/src/app/(dashboard)/analysis/page.tsx +++ b/services/frontend/src/app/(dashboard)/analysis/page.tsx @@ -1,7 +1,12 @@ +import { PageTransition } from "@/components/shared"; import { AnalysisView } from "./view"; export const dynamic = "force-dynamic"; export default function AnalysisPage() { - return ; + return ( + + + + ); } diff --git a/services/frontend/src/app/(dashboard)/dashboard/page.tsx b/services/frontend/src/app/(dashboard)/dashboard/page.tsx index 7052caa..ee1b5c4 100644 --- a/services/frontend/src/app/(dashboard)/dashboard/page.tsx +++ b/services/frontend/src/app/(dashboard)/dashboard/page.tsx @@ -1,3 +1,4 @@ +import { PageTransition } from "@/components/shared"; import { getActivity, getDashboardStats } from "@/lib/api/server"; import { DashboardView } from "./view"; @@ -14,5 +15,9 @@ export default async function DashboardPage() { } catch { // Backend unavailable — client hooks will surface the error state. } - return ; + return ( + + + + ); } diff --git a/services/frontend/src/app/(dashboard)/media/page.tsx b/services/frontend/src/app/(dashboard)/media/page.tsx index f4b01b5..587fc7e 100644 --- a/services/frontend/src/app/(dashboard)/media/page.tsx +++ b/services/frontend/src/app/(dashboard)/media/page.tsx @@ -1,3 +1,4 @@ +import { PageTransition } from "@/components/shared"; import { getMediaStatus } from "@/lib/api/server"; import { MediaView } from "./view"; @@ -10,5 +11,9 @@ export default async function MediaPage() { } catch { /* client hooks surface errors */ } - return ; + return ( + + + + ); } diff --git a/services/frontend/src/app/(dashboard)/messages/page.tsx b/services/frontend/src/app/(dashboard)/messages/page.tsx index de6ce74..cb4c8a0 100644 --- a/services/frontend/src/app/(dashboard)/messages/page.tsx +++ b/services/frontend/src/app/(dashboard)/messages/page.tsx @@ -1,3 +1,4 @@ +import { PageTransition } from "@/components/shared"; import { getConfig, getGuilds } from "@/lib/api/server"; import { MessagesView } from "./view"; @@ -12,9 +13,11 @@ export default async function MessagesPage() { /* client hooks surface errors */ } return ( - + + + ); } diff --git a/services/frontend/src/app/(dashboard)/moderation/page.tsx b/services/frontend/src/app/(dashboard)/moderation/page.tsx index 9863712..1bfc694 100644 --- a/services/frontend/src/app/(dashboard)/moderation/page.tsx +++ b/services/frontend/src/app/(dashboard)/moderation/page.tsx @@ -1,3 +1,4 @@ +import { PageTransition } from "@/components/shared"; import { getModerationActions, getModerationStats } from "@/lib/api/server"; import { ModerationView } from "./view"; @@ -14,5 +15,9 @@ export default async function ModerationPage() { } catch { /* client hooks surface errors */ } - return ; + return ( + + + + ); } diff --git a/services/frontend/src/app/(dashboard)/recordings/page.tsx b/services/frontend/src/app/(dashboard)/recordings/page.tsx index 95b2da6..672a088 100644 --- a/services/frontend/src/app/(dashboard)/recordings/page.tsx +++ b/services/frontend/src/app/(dashboard)/recordings/page.tsx @@ -1,3 +1,4 @@ +import { PageTransition } from "@/components/shared"; import { getRecordings } from "@/lib/api/server"; import { RecordingsView } from "./view"; @@ -12,5 +13,9 @@ export default async function RecordingsPage() { } catch { /* client hooks surface errors */ } - return ; + return ( + + + + ); } diff --git a/services/frontend/src/app/(dashboard)/voice/page.tsx b/services/frontend/src/app/(dashboard)/voice/page.tsx index 7a9bfd6..d6eba00 100644 --- a/services/frontend/src/app/(dashboard)/voice/page.tsx +++ b/services/frontend/src/app/(dashboard)/voice/page.tsx @@ -1,3 +1,4 @@ +import { PageTransition } from "@/components/shared"; import { getGuilds, getVoiceStatus } from "@/lib/api/server"; import { VoiceView } from "./view"; @@ -11,5 +12,9 @@ export default async function VoicePage() { } catch { /* client hooks surface errors */ } - return ; + return ( + + + + ); } diff --git a/services/frontend/src/app/globals.css b/services/frontend/src/app/globals.css index 6960f4f..86aab0e 100644 --- a/services/frontend/src/app/globals.css +++ b/services/frontend/src/app/globals.css @@ -276,6 +276,11 @@ } .animate-breathe { animation: breathe 3.5s ease-in-out infinite; } +/* Page-enter: subtle rise+settle. Respect reduced-motion (handled globally). */ +.animate-fade-up { + animation: fade-up 0.4s cubic-bezier(0.22, 1, 0.36, 1) both; +} + @media (prefers-reduced-motion: reduce) { .scan-line::after, .scan-line, @@ -283,7 +288,8 @@ .animate-spin-disc, .animate-pulse-ring, .animate-shimmer, - .animate-breathe { + .animate-breathe, + .animate-fade-up { animation: none !important; } .scan-line { diff --git a/services/frontend/src/components/shared/index.ts b/services/frontend/src/components/shared/index.ts index cdac96c..3d5c499 100644 --- a/services/frontend/src/components/shared/index.ts +++ b/services/frontend/src/components/shared/index.ts @@ -1,5 +1,6 @@ export { GuildChannelPicker } from "./guild-picker"; export { MarkdownLite } from "./markdown"; +export { PageTransition } from "./page-transition"; export { MetricTile, SectionHeader } from "./section"; export { EmptyState, diff --git a/services/frontend/src/components/shared/page-transition.tsx b/services/frontend/src/components/shared/page-transition.tsx new file mode 100644 index 0000000..216ca41 --- /dev/null +++ b/services/frontend/src/components/shared/page-transition.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/lib/utils"; + +/** + * Wraps a view's root so the whole panel stack rises + settles on mount. + * The animation is disabled under prefers-reduced-motion via globals.css. + */ +export function PageTransition({ + children, + className, +}: { + children: React.ReactNode; + className?: string; +}) { + return
{children}
; +} diff --git a/services/frontend/src/components/shared/section.tsx b/services/frontend/src/components/shared/section.tsx index 8c461b0..f5e7e74 100644 --- a/services/frontend/src/components/shared/section.tsx +++ b/services/frontend/src/components/shared/section.tsx @@ -55,7 +55,12 @@ export function MetricTile({ ? "var(--color-signal)" : "var(--color-ink)"; return ( -
+
{label}
{icon && {icon}}