Skip to content

Commit 9dfae4d

Browse files
committed
UI: Refine tab indicators and add smooth page transitions for fluidity
1 parent 304c97e commit 9dfae4d

5 files changed

Lines changed: 37 additions & 16 deletions

File tree

web/src/app/globals.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ html {
2424
overflow-x: hidden;
2525
overscroll-behavior-y: none;
2626
background-color: var(--ochre);
27+
scroll-behavior: smooth;
2728
}
2829

2930
body {
@@ -56,4 +57,20 @@ body {
5657
.pt-safe {
5758
padding-top: env(safe-area-inset-top);
5859
}
60+
61+
.page-fade-in {
62+
animation: pageFadeIn 0.4s cubic-bezier(0.4, 0, 0.2, 1);
63+
}
64+
65+
@keyframes pageFadeIn {
66+
from {
67+
opacity: 0;
68+
transform: translateY(4px);
69+
}
70+
71+
to {
72+
opacity: 1;
73+
transform: translateY(0);
74+
}
75+
}
5976
}

web/src/components/admin/AdminBottomNav.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,22 @@ export default function AdminBottomNav() {
4848
key={item.href}
4949
href={item.href}
5050
prefetch={false}
51-
className={`flex flex-col items-center justify-center w-full h-full space-y-1 relative transition-colors select-none ${isActive ? 'text-ochre' : 'text-gray-500'
51+
className={`flex flex-col items-center justify-center w-full h-full space-y-1 relative transition-all select-none active:bg-white/10 ${isActive ? 'text-ochre' : 'text-gray-500'
5252
}`}
5353
style={{ touchAction: 'manipulation' }}
5454
>
55-
<div className="relative pointer-events-none">
56-
<Icon className={`w-5 h-5 transition-transform ${isActive ? 'scale-110' : 'scale-100'}`} />
55+
{isActive && (
56+
<div className="absolute inset-x-2 inset-y-1 bg-white/5 rounded-xl animate-in fade-in zoom-in duration-300" />
57+
)}
58+
<div className="relative pointer-events-none z-10">
59+
<Icon className={`w-5 h-5 transition-transform ${isActive ? 'scale-110 drop-shadow-sm' : 'scale-100'}`} />
5760
{item.isTickets && openCount > 0 && (
5861
<span className="absolute -top-1.5 -right-1.5 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-red-600 text-[7px] font-black text-white shadow-lg ring-1 ring-gray-900 animate-in zoom-in duration-300">
5962
{openCount}
6063
</span>
6164
)}
6265
</div>
63-
<span className="text-[9px] font-black uppercase tracking-tighter pointer-events-none">{item.label}</span>
64-
{isActive && (
65-
<span className="absolute bottom-1 w-1 h-1 bg-ochre rounded-full" />
66-
)}
66+
<span className="text-[9px] font-black uppercase tracking-tighter pointer-events-none z-10">{item.label}</span>
6767
</Link>
6868
);
6969
})}

web/src/components/admin/AdminClientWrapper.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
21
'use client';
32

43
import { useState } from 'react';
4+
import { usePathname } from 'next/navigation';
55
import AdminSidebar from './AdminSidebar';
66
import { Menu, ShieldCheck, Home, ArrowRight } from 'lucide-react';
77
import Link from 'next/link';
@@ -13,6 +13,7 @@ export default function AdminClientWrapper({
1313
children: React.ReactNode;
1414
}) {
1515
const [sidebarOpen, setSidebarOpen] = useState(false);
16+
const pathname = usePathname();
1617

1718
return (
1819
<div className="flex min-h-screen bg-gray-50">
@@ -51,7 +52,7 @@ export default function AdminClientWrapper({
5152
</header>
5253

5354
<main className="flex-1 p-6 md:py-10 lg:py-16 px-6 md:px-12 min-w-0 overflow-x-hidden">
54-
<div className="max-w-5xl mx-auto w-full">
55+
<div className="max-w-5xl mx-auto w-full page-fade-in" key={pathname}>
5556
{children}
5657
</div>
5758
</main>

web/src/components/layout/BottomNav.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,22 @@ export default function BottomNav() {
3030
key={item.href}
3131
href={item.href}
3232
prefetch={false}
33-
className={`flex flex-col items-center justify-center w-full h-full space-y-1 relative transition-colors select-none ${isActive ? 'text-ochre' : 'text-gray-400'
33+
className={`flex flex-col items-center justify-center w-full h-full space-y-1 relative transition-all select-none active:bg-gray-100/50 ${isActive ? 'text-ochre' : 'text-gray-400'
3434
}`}
3535
style={{ touchAction: 'manipulation' }}
3636
>
37-
<div className="relative pointer-events-none">
37+
{isActive && (
38+
<div className="absolute inset-x-2 inset-y-1 bg-ochre/5 rounded-xl animate-in fade-in zoom-in duration-300" />
39+
)}
40+
<div className="relative pointer-events-none z-10">
3841
<Icon className={`w-5 h-5 transition-transform ${isActive ? 'scale-110 drop-shadow-sm' : 'scale-100'}`} />
3942
{isAsk && unreadCount > 0 && (
4043
<span className="absolute -top-1.5 -right-1.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-blue-600 px-1 text-[8px] font-bold text-white shadow-md shadow-blue-500/30 animate-in zoom-in duration-300">
4144
{unreadCount}
4245
</span>
4346
)}
4447
</div>
45-
<span className="text-[10px] font-black uppercase tracking-tighter pointer-events-none">{item.label}</span>
46-
{isActive && (
47-
<span className="absolute bottom-1 w-1 h-1 bg-ochre rounded-full" />
48-
)}
48+
<span className="text-[10px] font-black uppercase tracking-tighter pointer-events-none z-10">{item.label}</span>
4949
</Link>
5050
);
5151
})}

web/src/components/layout/Layout.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
'use client';
12
import Header from './Header';
23
import BottomNav from './BottomNav';
34
import Sidebar from './Sidebar';
5+
import { usePathname } from 'next/navigation';
46
import { AudioProvider } from '@/context/AudioContext';
57
import { InquiryProvider } from '@/context/InquiryContext';
68
import MiniPlayer from '@/components/audio/MiniPlayer';
79
import audioTracks from '@/data/audio_tracks.json';
810

911

1012
export default function Layout({ children }: { children: React.ReactNode }) {
13+
const pathname = usePathname();
1114
return (
1215
<InquiryProvider>
1316
<AudioProvider allTracks={audioTracks}>
@@ -16,7 +19,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
1619
<div className="flex-1 flex flex-col md:ml-64 transition-all duration-300">
1720
<Header />
1821
<main className="flex-1 pt-16 md:pt-0 pb-32 md:pb-4 max-w-7xl mx-auto w-full relative">
19-
<div className="md:px-4">
22+
<div className="md:px-4 page-fade-in" key={pathname}>
2023
{children}
2124
</div>
2225
</main>

0 commit comments

Comments
 (0)