@@ -16,11 +16,60 @@ export default function Home() {
1616 const [ mounted , setMounted ] = useState ( false ) ;
1717 const [ viewMode , setViewMode ] = useState < "split" | "editor" | "preview" > ( "split" ) ;
1818 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 ) ;
1924
2025 useEffect ( ( ) => {
2126 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 ) ;
2250 } , [ ] ) ;
2351
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+
2473 const activeFile = activeFileId ? files [ activeFileId ] : null ;
2574
2675 const handleContentChange = ( newContent : string ) => {
@@ -35,34 +84,59 @@ export default function Home() {
3584 < div className = "flex flex-col h-screen w-screen bg-background text-foreground overflow-hidden" >
3685 < Navbar fileSystem = { fileSystem } />
3786
38- < div className = "flex-1 flex overflow-hidden" >
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+
3996 { /* Sidebar */ }
40- < div className = { cn (
41- "h-full transition-all duration-300 ease-in-out border-r border-border bg-card" ,
42- isSidebarOpen ? "w-64" : "w-0 overflow-hidden border-r-0"
43- ) } >
44- < Sidebar fileSystem = { fileSystem } />
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+ ) }
45115 </ div >
46116
47117 { /* Main Area */ }
48- < main className = "flex-1 flex flex-col overflow-hidden min-w-0" >
118+ < main className = "flex-1 flex flex-col overflow-hidden min-w-0 bg-background relative z-0 " >
49119
50120 { /* Toolbar */ }
51- < div className = "h-10 border-b border-border flex items-center justify-between px-4 bg-muted/20" >
52- < div className = "flex items-center gap-2" >
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 " >
53123 < button
54124 onClick = { ( ) => setIsSidebarOpen ( ! isSidebarOpen ) }
55- className = "p-1 hover:bg-accent rounded text-muted-foreground"
125+ className = "p-1 hover:bg-accent rounded text-muted-foreground shrink-0 "
56126 title = "Toggle Sidebar"
57127 >
58- < 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 >
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+ ) }
59133 </ button >
60134 < span className = "text-sm text-muted-foreground truncate" >
61135 { activeFile ? activeFile . name : "No file selected" }
62136 </ span >
63137 </ div >
64138
65- < div className = "flex items-center gap-1 border border-input rounded-md overflow-hidden bg-background" >
139+ < div className = "flex items-center gap-1 border border-input rounded-md overflow-hidden bg-background shrink-0 " >
66140 < button
67141 onClick = { ( ) => setViewMode ( "editor" ) }
68142 className = { cn (
@@ -73,16 +147,18 @@ export default function Home() {
73147 >
74148 < Code2 size = { 16 } />
75149 </ button >
76- < button
77- onClick = { ( ) => setViewMode ( "split" ) }
78- className = { cn (
79- "p-1.5 hover:bg-accent transition-colors" ,
80- viewMode === "split" && "bg-accent text-accent-foreground"
81- ) }
82- title = "Split View"
83- >
84- < Columns size = { 16 } />
85- </ button >
150+ { ! isMobile && (
151+ < button
152+ onClick = { ( ) => setViewMode ( "split" ) }
153+ className = { cn (
154+ "p-1.5 hover:bg-accent transition-colors" ,
155+ viewMode === "split" && "bg-accent text-accent-foreground"
156+ ) }
157+ title = "Split View"
158+ >
159+ < Columns size = { 16 } />
160+ </ button >
161+ ) }
86162 < button
87163 onClick = { ( ) => setViewMode ( "preview" ) }
88164 className = { cn (
0 commit comments