Skip to content

Commit f924e4b

Browse files
committed
fix: consistent demo
1 parent 873a392 commit f924e4b

File tree

1 file changed

+82
-72
lines changed

1 file changed

+82
-72
lines changed

apps/dashboard/app/demo/layout.tsx

Lines changed: 82 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
TargetIcon,
1313
UsersIcon,
1414
XIcon,
15+
type Icon as PhosphorIcon
1516
} from '@phosphor-icons/react';
1617
import Link from 'next/link';
1718
import { usePathname } from 'next/navigation';
@@ -24,32 +25,47 @@ import { Button } from '@/components/ui/button';
2425
import { ScrollArea } from '@/components/ui/scroll-area';
2526
import { cn } from '@/lib/utils';
2627

27-
const demoNavigation = [
28+
interface DemoNavigationItem {
29+
title: string;
30+
items: DemoNavigationItemItem[];
31+
}
32+
33+
interface DemoNavigationItemItem {
34+
name: string;
35+
icon: PhosphorIcon;
36+
href: string;
37+
highlight: boolean;
38+
}
39+
40+
const DEMO_WEBSITE_ID = 'OXmNQsViBT-FOS_wZCTHc';
41+
const DEMO_WEBSITE_URL = 'https://www.databuddy.cc';
42+
43+
const demoNavigation: DemoNavigationItem[] = [
2844
{
2945
title: 'Web Analytics',
3046
items: [
3147
{
3248
name: 'Overview',
3349
icon: HouseIcon,
34-
href: '/demo/OXmNQsViBT-FOS_wZCTHc',
50+
href: `/demo/${DEMO_WEBSITE_ID}`,
3551
highlight: true,
3652
},
3753
{
3854
name: 'Sessions',
3955
icon: ClockIcon,
40-
href: '/demo/OXmNQsViBT-FOS_wZCTHc/sessions',
56+
href: `/demo/${DEMO_WEBSITE_ID}/sessions`,
4157
highlight: true,
4258
},
4359
{
4460
name: 'Errors',
4561
icon: BugIcon,
46-
href: '/demo/OXmNQsViBT-FOS_wZCTHc/errors',
62+
href: `/demo/${DEMO_WEBSITE_ID}/errors`,
4763
highlight: true,
4864
},
4965
{
5066
name: 'Map',
5167
icon: MapPinIcon,
52-
href: '/demo/OXmNQsViBT-FOS_wZCTHc/map',
68+
href: `/demo/${DEMO_WEBSITE_ID}/map`,
5369
highlight: true,
5470
},
5571
],
@@ -60,198 +76,192 @@ const demoNavigation = [
6076
{
6177
name: 'Profiles',
6278
icon: UsersIcon,
63-
href: '/demo/OXmNQsViBT-FOS_wZCTHc/profiles',
79+
href: `/demo/${DEMO_WEBSITE_ID}/profiles`,
6480
highlight: true,
6581
},
6682
{
6783
name: 'Funnels',
6884
icon: FunnelIcon,
69-
href: '/demo/OXmNQsViBT-FOS_wZCTHc/funnels',
85+
href: `/demo/${DEMO_WEBSITE_ID}/funnels`,
7086
highlight: true,
7187
},
7288
{
7389
name: 'Goals',
7490
icon: TargetIcon,
75-
href: '/demo/OXmNQsViBT-FOS_wZCTHc/goals',
91+
href: `/demo/${DEMO_WEBSITE_ID}/goals`,
7692
highlight: true,
7793
},
7894
],
7995
},
8096
];
8197

82-
export function Sidebar() {
98+
function Sidebar() {
8399
const pathname = usePathname();
84100
const [isMobileOpen, setIsMobileOpen] = useState(false);
85101

86102
const closeSidebar = useCallback(() => {
87103
setIsMobileOpen(false);
88104
}, []);
89105

90-
// Handle keyboard navigation
91-
useEffect(() => {
92-
const handleKeyDown = (e: KeyboardEvent) => {
93-
if (e.key === 'Escape' && isMobileOpen) {
94-
closeSidebar();
95-
}
96-
};
106+
const handleKeyDown = useCallback((e: KeyboardEvent) => {
107+
if (e.key === 'Escape' && isMobileOpen) {
108+
closeSidebar();
109+
}
110+
}, [isMobileOpen, closeSidebar]);
97111

112+
useEffect(() => {
98113
document.addEventListener('keydown', handleKeyDown);
99114
return () => document.removeEventListener('keydown', handleKeyDown);
100-
}, [isMobileOpen, closeSidebar]);
115+
}, [handleKeyDown]);
101116

102117
return (
103118
<>
104-
{/* Top Header */}
105119
<header className="fixed top-0 right-0 left-0 z-50 h-16 w-full border-b bg-background/95 backdrop-blur-md">
106120
<div className="flex h-full items-center px-4 md:px-6">
107-
{/* Left side: Logo + Mobile menu */}
108121
<div className="flex items-center gap-4">
109122
<Button
123+
aria-label="Toggle menu"
110124
className="md:hidden"
111125
onClick={() => setIsMobileOpen(true)}
112126
size="icon"
113127
variant="ghost"
114128
>
115-
<ListIcon className="h-5 w-5" size={32} weight="duotone" />
116-
<span className="sr-only">Toggle menu</span>
129+
<ListIcon className="h-5 w-5" weight="duotone" />
117130
</Button>
118131

119132
<div className="flex items-center gap-3">
120-
<div className="flex flex-row items-center gap-3">
121-
<Logo />
122-
</div>
133+
<Logo />
123134
</div>
124135
</div>
125136

126-
{/* Right Side - User Controls */}
127137
<div className="ml-auto flex items-center gap-2">
128138
<ThemeToggle />
129139

130-
{/* Help */}
131140
<Button
141+
aria-label="Help"
132142
className="hidden h-8 w-8 md:flex"
133143
size="icon"
134144
variant="ghost"
135145
>
136-
<InfoIcon className="h-6 w-6" size={32} weight="duotone" />
137-
<span className="sr-only">Help</span>
146+
<InfoIcon className="h-6 w-6" weight="duotone" />
138147
</Button>
139148

140-
{/* Notifications */}
141149
<NotificationsPopover />
142-
143-
{/* User Menu */}
144150
<UserMenu />
145151
</div>
146152
</div>
147153
</header>
148154

149-
{/* Mobile backdrop */}
150155
{isMobileOpen && (
151156
<div
152157
aria-hidden="true"
153158
className="fixed inset-0 z-30 bg-black/20 md:hidden"
154159
onClick={closeSidebar}
155-
onKeyDown={closeSidebar}
156-
onKeyPress={closeSidebar}
157-
onKeyUp={closeSidebar}
158160
/>
159161
)}
160162

161-
{/* Sidebar */}
162-
<div
163+
<aside
164+
aria-label="Demo navigation"
163165
className={cn(
164166
'fixed inset-y-0 left-0 z-40 w-64 bg-background',
165167
'border-r pt-16 transition-transform duration-200 ease-out md:translate-x-0',
166168
isMobileOpen ? 'translate-x-0' : '-translate-x-full'
167169
)}
168170
>
169-
{/* Mobile close button */}
170171
<Button
172+
aria-label="Close sidebar"
171173
className="absolute top-3 right-3 z-50 h-8 w-8 p-0 md:hidden"
172174
onClick={closeSidebar}
173175
size="sm"
174176
variant="ghost"
175177
>
176-
<XIcon className="h-4 w-4" size={32} weight="duotone" />
177-
<span className="sr-only">Close sidebar</span>
178+
<XIcon className="h-4 w-4" weight="duotone" />
178179
</Button>
179180

180181
<ScrollArea className="h-[calc(100vh-4rem)]">
181-
<div className="space-y-4 p-3">
182-
{/* Demo Website Header */}
182+
<nav className="space-y-4 p-3">
183183
<div className="flex items-center gap-3 rounded border bg-muted/50 p-3">
184184
<div className="rounded border border-primary/20 bg-primary/10 p-2">
185185
<GlobeIcon
186+
aria-hidden="true"
186187
className="h-5 w-5 text-primary"
187-
size={32}
188188
weight="duotone"
189189
/>
190190
</div>
191191
<div className="min-w-0 flex-1">
192192
<h2 className="truncate font-semibold text-sm">Landing Page</h2>
193193
<Link
194194
className="truncate text-muted-foreground text-xs"
195-
href="https://www.databuddy.cc"
195+
href={DEMO_WEBSITE_URL}
196+
rel="noopener"
196197
target="_blank"
197198
>
198199
www.databuddy.cc
199200
</Link>
200201
</div>
201202
</div>
202203

203-
{/* Demo Navigation */}
204204
{demoNavigation.map((section) => (
205205
<div key={section.title}>
206206
<h3 className="mb-2 px-2 font-semibold text-muted-foreground text-xs uppercase tracking-wider">
207207
{section.title}
208208
</h3>
209-
<div className="ml-1 space-y-1">
209+
<ul className="ml-1 space-y-1">
210210
{section.items.map((item) => {
211211
const isActive = pathname === item.href;
212212
const Icon = item.icon;
213213

214214
return (
215-
<Link
216-
className={cn(
217-
'flex cursor-pointer items-center gap-3 rounded px-3 py-2 text-sm transition-all',
218-
isActive
219-
? 'bg-primary/15 font-medium text-primary'
220-
: 'text-foreground hover:bg-accent/70'
221-
)}
222-
href={item.href}
223-
key={item.name}
224-
>
225-
<Icon
226-
className={cn('h-4 w-4', isActive && 'text-primary')}
227-
size={32}
228-
weight="duotone"
229-
/>
230-
<span className="truncate">{item.name}</span>
231-
</Link>
215+
<li key={item.name}>
216+
<Link
217+
className={cn(
218+
'group flex items-center gap-x-3 rounded px-3 py-2 text-sm transition-all duration-200',
219+
'focus:outline-none focus:ring-2 focus:ring-primary/20 focus:ring-offset-1',
220+
isActive
221+
? 'bg-accent font-medium text-foreground shadow-sm'
222+
: 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'
223+
)}
224+
href={item.href}
225+
>
226+
<span className="flex-shrink-0">
227+
<Icon
228+
aria-hidden="true"
229+
className={cn(
230+
'h-5 w-5 transition-colors duration-200',
231+
isActive
232+
? 'text-primary'
233+
: 'not-dark:text-primary group-hover:text-primary'
234+
)}
235+
size={32}
236+
weight="duotone"
237+
/>
238+
</span>
239+
<span className="flex-grow truncate">{item.name}</span>
240+
</Link>
241+
</li>
232242
);
233243
})}
234-
</div>
244+
</ul>
235245
</div>
236246
))}
237-
</div>
247+
</nav>
238248
</ScrollArea>
239-
</div>
249+
</aside>
240250
</>
241251
);
242252
}
243253

244-
export default function MainLayout({
245-
children,
246-
}: {
254+
interface MainLayoutProps {
247255
children: React.ReactNode;
248-
}) {
256+
}
257+
258+
export default function MainLayout({ children }: MainLayoutProps) {
249259
return (
250260
<div className="h-screen overflow-hidden bg-gradient-to-br from-background to-muted/20 text-foreground">
251261
<Sidebar />
252-
<div className="relative h-screen pt-16 md:pl-64">
262+
<main className="relative h-screen pt-16 md:pl-64">
253263
<div className="h-[calc(100vh-4rem)] overflow-y-scroll">{children}</div>
254-
</div>
264+
</main>
255265
</div>
256266
);
257267
}

0 commit comments

Comments
 (0)