|
1 | | -"use client"; |
| 1 | +import { MathStudio } from "@/components/math-studio"; |
| 2 | +import { getStaticPosts } from "@/lib/posts"; |
2 | 3 |
|
3 | | -import React, { useState, useEffect } from "react"; |
4 | | -import { MarkdownEditor } from "@/components/editor"; |
5 | | -import { MarkdownPreview } from "@/components/preview"; |
6 | | -import { Sidebar } from "@/components/sidebar"; |
7 | | -import { Navbar } from "@/components/navbar"; |
8 | | -import { useFileSystem } from "@/hooks/use-file-system"; |
9 | | -import { cn } from "@/lib/utils"; |
10 | | -import { Columns, Eye, Code2 } from "lucide-react"; |
11 | | - |
12 | | -export default function Home() { |
13 | | - const fileSystem = useFileSystem(); |
14 | | - const { files, activeFileId, updateFileContent } = fileSystem; |
15 | | - |
16 | | - const [mounted, setMounted] = useState(false); |
17 | | - const [viewMode, setViewMode] = useState<"split" | "editor" | "preview">("split"); |
18 | | - const [isSidebarOpen, setIsSidebarOpen] = useState(true); |
19 | | - |
20 | | - // Sidebar resizing & Mobile state |
21 | | - const [sidebarWidth, setSidebarWidth] = useState(256); |
22 | | - const [isResizing, setIsResizing] = useState(false); |
23 | | - const [isMobile, setIsMobile] = useState(false); |
24 | | - |
25 | | - useEffect(() => { |
26 | | - setMounted(true); |
27 | | - const checkMobile = () => { |
28 | | - const mobile = window.innerWidth < 768; |
29 | | - setIsMobile(mobile); |
30 | | - if (mobile) { |
31 | | - setIsSidebarOpen(false); |
32 | | - if (viewMode === "split") setViewMode("editor"); |
33 | | - } else { |
34 | | - setIsSidebarOpen(true); |
35 | | - } |
36 | | - }; |
37 | | - |
38 | | - checkMobile(); |
39 | | - window.addEventListener("resize", checkMobile); |
40 | | - return () => window.removeEventListener("resize", checkMobile); |
41 | | - }, []); |
42 | | - |
43 | | - const startResizing = React.useCallback((e: React.MouseEvent) => { |
44 | | - e.preventDefault(); |
45 | | - setIsResizing(true); |
46 | | - }, []); |
47 | | - |
48 | | - const stopResizing = React.useCallback(() => { |
49 | | - setIsResizing(false); |
50 | | - }, []); |
51 | | - |
52 | | - const resize = React.useCallback( |
53 | | - (mouseMoveEvent: MouseEvent) => { |
54 | | - if (isResizing) { |
55 | | - const newWidth = mouseMoveEvent.clientX; |
56 | | - if (newWidth > 150 && newWidth < 600) { |
57 | | - setSidebarWidth(newWidth); |
58 | | - } |
59 | | - } |
60 | | - }, |
61 | | - [isResizing] |
62 | | - ); |
63 | | - |
64 | | - useEffect(() => { |
65 | | - window.addEventListener("mousemove", resize); |
66 | | - window.addEventListener("mouseup", stopResizing); |
67 | | - return () => { |
68 | | - window.removeEventListener("mousemove", resize); |
69 | | - window.removeEventListener("mouseup", stopResizing); |
70 | | - }; |
71 | | - }, [resize, stopResizing]); |
72 | | - |
73 | | - const activeFile = activeFileId ? files[activeFileId] : null; |
74 | | - |
75 | | - const handleContentChange = (newContent: string) => { |
76 | | - if (activeFileId) { |
77 | | - updateFileContent(activeFileId, newContent); |
78 | | - } |
79 | | - }; |
80 | | - |
81 | | - if (!mounted) return null; |
82 | | - |
83 | | - return ( |
84 | | - <div className="flex flex-col h-screen w-screen bg-background text-foreground overflow-hidden"> |
85 | | - <Navbar fileSystem={fileSystem} /> |
86 | | - |
87 | | - <div className="flex-1 flex overflow-hidden relative"> |
88 | | - {/* Mobile Backdrop */} |
89 | | - {isMobile && isSidebarOpen && ( |
90 | | - <div |
91 | | - className="absolute inset-0 bg-black/50 z-40" |
92 | | - onClick={() => setIsSidebarOpen(false)} |
93 | | - /> |
94 | | - )} |
95 | | - |
96 | | - {/* Sidebar */} |
97 | | - <div |
98 | | - className={cn( |
99 | | - "h-full bg-card border-r border-border flex-shrink-0 relative z-50", |
100 | | - isMobile ? "absolute left-0 top-0 bottom-0 shadow-2xl transition-transform duration-300" : "transition-[width] ease-linear duration-0", |
101 | | - !isSidebarOpen && isMobile && "-translate-x-full", |
102 | | - !isSidebarOpen && !isMobile && "w-0 border-none overflow-hidden" |
103 | | - )} |
104 | | - style={{ width: isMobile ? "80%" : (isSidebarOpen ? sidebarWidth : 0) }} |
105 | | - > |
106 | | - <Sidebar fileSystem={fileSystem} className="border-none" /> |
107 | | - |
108 | | - {/* Resizer Handle (Desktop only) */} |
109 | | - {!isMobile && isSidebarOpen && ( |
110 | | - <div |
111 | | - className="absolute right-0 top-0 w-1 h-full cursor-col-resize hover:bg-primary/50 transition-colors z-50 translate-x-1/2" |
112 | | - onMouseDown={startResizing} |
113 | | - /> |
114 | | - )} |
115 | | - </div> |
116 | | - |
117 | | - {/* Main Area */} |
118 | | - <main className="flex-1 flex flex-col overflow-hidden min-w-0 bg-background relative z-0"> |
119 | | - |
120 | | - {/* Toolbar */} |
121 | | - <div className="h-10 border-b border-border flex items-center justify-between px-4 bg-muted/20 shrink-0"> |
122 | | - <div className="flex items-center gap-2 overflow-hidden"> |
123 | | - <button |
124 | | - onClick={() => setIsSidebarOpen(!isSidebarOpen)} |
125 | | - className="p-1 hover:bg-accent rounded text-muted-foreground shrink-0" |
126 | | - title="Toggle Sidebar" |
127 | | - > |
128 | | - {isSidebarOpen ? ( |
129 | | - <svg width="16" height="16" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 3C1.22386 3 1 3.22386 1 3.5V11.5C1 11.7761 1.22386 12 1.5 12H13.5C13.7761 12 14 11.7761 14 11.5V3.5C14 3.22386 13.7761 3 13.5 3H1.5ZM1 3.5C1 2.67157 1.67157 2 2.5 2H12.5C13.3284 2 14 2.67157 14 3.5V11.5C14 12.3284 13.3284 13 12.5 13H2.5C1.67157 13 1 12.3284 1 11.5V3.5Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path><path d="M5 3V12H4V3H5Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path></svg> |
130 | | - ) : ( |
131 | | - <svg width="16" height="16" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 3C1.22386 3 1 3.22386 1 3.5V11.5C1 11.7761 1.22386 12 1.5 12H13.5C13.7761 12 14 11.7761 14 11.5V3.5C14 3.22386 13.7761 3 13.5 3H1.5ZM1 3.5C1 2.67157 1.67157 2 2.5 2H12.5C13.3284 2 14 2.67157 14 3.5V11.5C14 12.3284 13.3284 13 12.5 13H2.5C1.67157 13 1 12.3284 1 11.5V3.5Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path></svg> |
132 | | - )} |
133 | | - </button> |
134 | | - <span className="text-sm text-muted-foreground truncate"> |
135 | | - {activeFile ? activeFile.name : "No file selected"} |
136 | | - </span> |
137 | | - </div> |
138 | | - |
139 | | - <div className="flex items-center gap-1 border border-input rounded-md overflow-hidden bg-background shrink-0"> |
140 | | - <button |
141 | | - onClick={() => setViewMode("editor")} |
142 | | - className={cn( |
143 | | - "p-1.5 hover:bg-accent transition-colors", |
144 | | - viewMode === "editor" && "bg-accent text-accent-foreground" |
145 | | - )} |
146 | | - title="Editor Only" |
147 | | - > |
148 | | - <Code2 size={16} /> |
149 | | - </button> |
150 | | - <button |
151 | | - onClick={() => setViewMode("split")} |
152 | | - className={cn( |
153 | | - "p-1.5 hover:bg-accent transition-colors", |
154 | | - viewMode === "split" && "bg-accent text-accent-foreground" |
155 | | - )} |
156 | | - title="Split View" |
157 | | - > |
158 | | - <Columns size={16} /> |
159 | | - </button> |
160 | | - <button |
161 | | - onClick={() => setViewMode("preview")} |
162 | | - className={cn( |
163 | | - "p-1.5 hover:bg-accent transition-colors", |
164 | | - viewMode === "preview" && "bg-accent text-accent-foreground" |
165 | | - )} |
166 | | - title="Preview Only" |
167 | | - > |
168 | | - <Eye size={16} /> |
169 | | - </button> |
170 | | - </div> |
171 | | - </div> |
172 | | - |
173 | | - {/* Editor/Preview Area */} |
174 | | - <div className="flex-1 flex overflow-hidden relative"> |
175 | | - {activeFile && activeFile.type === 'file' ? ( |
176 | | - <> |
177 | | - {(viewMode === "split" || viewMode === "editor") && ( |
178 | | - <div className={cn( |
179 | | - "h-full border-r border-border transition-all", |
180 | | - viewMode === "split" ? "w-1/2" : "w-full" |
181 | | - )}> |
182 | | - <MarkdownEditor |
183 | | - value={activeFile.content} |
184 | | - onChange={handleContentChange} |
185 | | - /> |
186 | | - </div> |
187 | | - )} |
188 | | - |
189 | | - {(viewMode === "split" || viewMode === "preview") && ( |
190 | | - <div className={cn( |
191 | | - "h-full bg-background transition-all", |
192 | | - viewMode === "split" ? "w-1/2" : "w-full" |
193 | | - )}> |
194 | | - <MarkdownPreview content={activeFile.content} /> |
195 | | - </div> |
196 | | - )} |
197 | | - </> |
198 | | - ) : ( |
199 | | - <div className="flex-1 flex items-center justify-center text-muted-foreground"> |
200 | | - {activeFile && activeFile.type === 'folder' |
201 | | - ? "Select a file to edit" |
202 | | - : "Select or create a file to start editing"} |
203 | | - </div> |
204 | | - )} |
205 | | - </div> |
206 | | - </main> |
207 | | - </div> |
208 | | - </div> |
209 | | - ); |
| 4 | +export default function Page() { |
| 5 | + const posts = getStaticPosts(); |
| 6 | + return <MathStudio initialPosts={posts} />; |
210 | 7 | } |
0 commit comments