diff --git a/src/components/layout/AppLayout.tsx b/src/components/layout/AppLayout.tsx
new file mode 100644
index 0000000..1937d21
--- /dev/null
+++ b/src/components/layout/AppLayout.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useState, type ReactNode } from 'react';
+import { Sidebar, SidebarToggle } from '@/components/layout/Sidebar';
+import { currentUser, chatHistories } from '@/data/mock';
+import { cn } from '@/lib/utils';
+
+interface AppLayoutProps {
+ children: ReactNode;
+ showHeader?: boolean;
+ headerContent?: ReactNode;
+}
+
+export function AppLayout({ children, showHeader = true, headerContent }: AppLayoutProps) {
+ const [sidebarOpen, setSidebarOpen] = useState(true);
+
+ return (
+
+ {/* 侧边栏 */}
+
setSidebarOpen(!sidebarOpen)}
+ />
+
+ {/* 主内容区 */}
+
+ {/* Header */}
+ {showHeader && (
+
+ setSidebarOpen(!sidebarOpen)} />
+ {headerContent}
+
+ )}
+
+ {/* Body */}
+
+ {children}
+
+
+
+ );
+}
diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx
new file mode 100644
index 0000000..4cc02f4
--- /dev/null
+++ b/src/components/layout/Sidebar.tsx
@@ -0,0 +1,107 @@
+'use client';
+
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { Plus, ChevronDown, PanelLeft } from 'lucide-react';
+import { Avatar } from '@/components/ui/Avatar';
+import { cn } from '@/lib/utils';
+import type { ChatHistory, User } from '@/types';
+
+interface SidebarProps {
+ user: User;
+ chatHistories: ChatHistory[];
+ isOpen?: boolean;
+ onToggle?: () => void;
+}
+
+export function Sidebar({ user, chatHistories, isOpen = true }: SidebarProps) {
+ const pathname = usePathname();
+
+ return (
+ <>
+ {/* 侧边栏 */}
+
+
+ {/* 移动端遮罩 */}
+ {isOpen && (
+
+ )}
+ >
+ );
+}
+
+// 侧边栏切换按钮
+export function SidebarToggle({ onClick }: { onClick?: () => void }) {
+ return (
+
+ );
+}