From 6f964f38f35a5355ca9aadff94b0a93b1bfeaab2 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Mon, 9 Mar 2026 23:41:34 +0100 Subject: [PATCH] feat: add sliding tab indicator and content crossfade animations Co-Authored-By: Claude Opus 4.6 --- app/sites/[id]/SiteLayoutShell.tsx | 16 +++++++++++++++- app/sites/[id]/page.tsx | 10 ++-------- app/sites/[id]/uptime/page.tsx | 9 ++------- components/dashboard/SiteNav.tsx | 14 +++++++++++--- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/app/sites/[id]/SiteLayoutShell.tsx b/app/sites/[id]/SiteLayoutShell.tsx index 1bc2a07..c4ec2c3 100644 --- a/app/sites/[id]/SiteLayoutShell.tsx +++ b/app/sites/[id]/SiteLayoutShell.tsx @@ -1,5 +1,7 @@ 'use client' +import { usePathname } from 'next/navigation' +import { AnimatePresence, motion } from 'framer-motion' import SiteNav from '@/components/dashboard/SiteNav' export default function SiteLayoutShell({ @@ -9,12 +11,24 @@ export default function SiteLayoutShell({ siteId: string children: React.ReactNode }) { + const pathname = usePathname() + return ( <>
- {children} + + + {children} + + ) } diff --git a/app/sites/[id]/page.tsx b/app/sites/[id]/page.tsx index fa2f4a1..7c4acac 100644 --- a/app/sites/[id]/page.tsx +++ b/app/sites/[id]/page.tsx @@ -4,7 +4,6 @@ import { logger } from '@/lib/utils/logger' import { useCallback, useEffect, useState, useMemo } from 'react' import { useParams, useRouter, useSearchParams } from 'next/navigation' -import { motion } from 'framer-motion' import { getPerformanceByPage, getTopPages, @@ -432,12 +431,7 @@ export default function SiteDashboardPage() { } return ( - +
@@ -649,6 +643,6 @@ export default function SiteDashboardPage() { topReferrers={referrers?.top_referrers} campaigns={campaigns} /> - +
) } diff --git a/app/sites/[id]/uptime/page.tsx b/app/sites/[id]/uptime/page.tsx index 7c435d9..a919409 100644 --- a/app/sites/[id]/uptime/page.tsx +++ b/app/sites/[id]/uptime/page.tsx @@ -688,12 +688,7 @@ export default function UptimePage() { const overallStatus = uptimeData?.status ?? 'operational' return ( - +
{/* Header */}
@@ -813,7 +808,7 @@ export default function UptimePage() { siteDomain={site.domain} /> - +
) } diff --git a/components/dashboard/SiteNav.tsx b/components/dashboard/SiteNav.tsx index 0c3bae6..c076939 100644 --- a/components/dashboard/SiteNav.tsx +++ b/components/dashboard/SiteNav.tsx @@ -2,6 +2,7 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' +import { motion } from 'framer-motion' import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard' import { useAuth } from '@/lib/auth/context' @@ -39,13 +40,20 @@ export default function SiteNav({ siteId }: SiteNavProps) { role="tab" aria-selected={isActive(tab.href)} tabIndex={isActive(tab.href) ? 0 : -1} - className={`px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange rounded-t cursor-pointer border-b-2 -mb-px ${ + className={`relative px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange rounded-t cursor-pointer -mb-px ${ isActive(tab.href) - ? 'border-brand-orange text-neutral-900 dark:text-white' - : 'border-transparent text-neutral-400 dark:text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300' + ? 'text-neutral-900 dark:text-white' + : 'text-neutral-400 dark:text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-300' }`} > {tab.label} + {isActive(tab.href) && ( + + )} ))}