diff --git a/app/(app)/AppLayoutClient.tsx b/app/(app)/AppLayoutClient.tsx
deleted file mode 100644
index 1d490fd..0000000
--- a/app/(app)/AppLayoutClient.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-'use client';
-
-import React from 'react';
-import { usePathname } from 'next/navigation';
-import Link from 'next/link';
-import { ProtectedRoute, useAuth } from '@/lib/auth';
-import { LayoutDashboard, BarChart3, UserCircle } from 'lucide-react';
-
-export default function AppLayoutClient({
- children,
-}: {
- children: React.ReactNode;
-}) {
- const { signOut, user } = useAuth();
- const pathname = usePathname();
-
- const navigationItems = [
- { name: 'Dashboard', href: '/dashboard', icon: },
- { name: 'Analytics', href: '/analytics', icon: },
- { name: 'Account', href: '/account', icon: },
- ];
-
- const handleSignOut = async () => {
- await signOut();
- };
-
- return (
-
-
- {/* 侧边栏导航 */}
-
-
-
- ShortURL Analytics
-
-
-
-
-
- {/* 主内容区域 */}
-
- {/* 顶部导航栏 */}
-
-
- {/* 页面内容 */}
-
- {children}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx
index 9f533c0..dc2a298 100644
--- a/app/(app)/layout.tsx
+++ b/app/(app)/layout.tsx
@@ -1,13 +1,10 @@
import '../globals.css';
import type { Metadata } from 'next';
-import { Inter } from 'next/font/google';
-import AppLayoutClient from './AppLayoutClient';
-
-const inter = Inter({ subsets: ['latin'] });
+import { Sidebar } from '@/app/components/Sidebar';
export const metadata: Metadata = {
title: 'ShortURL Analytics',
- description: 'Analytics dashboard for ShortURL service',
+ description: 'Analytics for your shortened URLs',
};
export default function AppLayout({
@@ -16,10 +13,16 @@ export default function AppLayout({
children: React.ReactNode;
}) {
return (
-
-
- {children}
-
+
+ {/* 侧边栏 */}
+
+
+ {/* 主内容区域 */}
+
+
+ {children}
+
+
);
}
\ No newline at end of file
diff --git a/app/components/Sidebar.tsx b/app/components/Sidebar.tsx
new file mode 100644
index 0000000..f7526b0
--- /dev/null
+++ b/app/components/Sidebar.tsx
@@ -0,0 +1,111 @@
+'use client';
+
+import { useState } from 'react';
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import {
+ BarChartIcon,
+ HomeIcon,
+ PersonIcon,
+ ChevronLeftIcon,
+ ChevronRightIcon
+} from '@radix-ui/react-icons';
+
+interface NavItemProps {
+ href: string;
+ label: string;
+ icon: React.ReactNode;
+ isCollapsed: boolean;
+ isActive?: boolean;
+}
+
+const NavItem = ({ href, label, icon, isCollapsed, isActive }: NavItemProps) => {
+ return (
+
+
{icon}
+ {!isCollapsed && (
+
+ {label}
+
+ )}
+ {isCollapsed && (
+
{label}
+ )}
+
+ );
+};
+
+export function Sidebar() {
+ const [isCollapsed, setIsCollapsed] = useState(false);
+ const pathname = usePathname();
+
+ const toggleSidebar = () => {
+ setIsCollapsed(!isCollapsed);
+ };
+
+ const navigation = [
+ { name: 'Dashboard', href: '/dashboard', icon:
},
+ { name: 'Analytics', href: '/analytics', icon:
},
+ { name: 'Account', href: '/account', icon:
},
+ ];
+
+ return (
+
+ {/* 顶部Logo和标题 */}
+
+
+ S
+
+ {!isCollapsed && (
+
+ ShortURL Analytics
+
+ )}
+
+
+ {/* 导航菜单 */}
+
+
+ {navigation.map((item) => (
+ -
+
+
+ ))}
+
+
+
+ {/* 底部折叠按钮 */}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 68d2cb9..7ec33e5 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
},
"dependencies": {
"@clickhouse/client": "^1.11.0",
+ "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/themes": "^3.2.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1bb6ae0..0cbcb7a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,6 +11,9 @@ importers:
'@clickhouse/client':
specifier: ^1.11.0
version: 1.11.0
+ '@radix-ui/react-icons':
+ specifier: ^1.3.2
+ version: 1.3.2(react@19.0.0)
'@radix-ui/react-popover':
specifier: ^1.1.6
version: 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -657,6 +660,11 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-icons@1.3.2':
+ resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==}
+ peerDependencies:
+ react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc
+
'@radix-ui/react-id@1.1.0':
resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==}
peerDependencies:
@@ -3531,6 +3539,10 @@ snapshots:
'@types/react': 19.0.12
'@types/react-dom': 19.0.4(@types/react@19.0.12)
+ '@radix-ui/react-icons@1.3.2(react@19.0.0)':
+ dependencies:
+ react: 19.0.0
+
'@radix-ui/react-id@1.1.0(@types/react@19.0.12)(react@19.0.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0)