@@ -2,40 +2,28 @@ import { useCallback, useEffect, useRef, useState } from "react";
22import { PROJECT , PROJECT_SETTINGS } from "../project/project" ;
33import { WithCurrentFrame } from "./lib/frame"
44import { TimelineUI } from "./ui/timeline" ;
5- import { LeftPanelTabs } from "./ui/left-panel-tabs" ;
6- import { CodeEditor } from "./ui/code-editor" ;
7- import { EditorProvider } from "./ui/editor-context" ;
5+ import { ClipVisibilityPanel } from "./ui/clip-visibility" ;
86import { Store } from "./util/state" ;
97import { StudioStateContext } from "./lib/studio-state"
108
119// Back-compat re-exports (avoid HMR issues if some modules still import these from StudioApp).
1210export { StudioStateContext , useIsPlaying , useIsPlayingStore , useIsRender , useSetIsPlaying } from "./lib/studio-state"
1311
1412export const StudioApp = ( ) => {
15- const rowRef = useRef < HTMLDivElement > ( null ) ;
1613 const containerRef = useRef < HTMLDivElement > ( null ) ;
1714 const topRef = useRef < HTMLDivElement > ( null ) ;
1815 const previewRef = useRef < HTMLDivElement > ( null ) ;
1916 const [ verticalRatio , setVerticalRatio ] = useState ( 0.6 ) ; // top area height ratio
2017 const [ horizontalRatio , setHorizontalRatio ] = useState ( 0.3 ) ; // clips width ratio within top area
21- const [ editorWidth , setEditorWidth ] = useState ( ( ) => {
22- if ( typeof window === "undefined" ) return 460 ;
23- return Math . round ( window . innerWidth / 2 ) ;
24- } ) ;
25- const [ isEditorVisible , setIsEditorVisible ] = useState ( true ) ;
2618 const projectWidth = PROJECT_SETTINGS . width || 1920
2719 const projectHeight = PROJECT_SETTINGS . height || 1080
2820 const previewAspect = `${ projectWidth } / ${ projectHeight } `
2921 const previewAspectValue = projectHeight / projectWidth
3022 const previewMinWidth = 320 ;
3123 const previewMinHeight = previewMinWidth * previewAspectValue ;
3224 const timelineMinHeight = 200 ;
33- const leftPanelMinWidth = previewMinWidth + 220 + 6 + 20 ;
34- const editorMinWidth = 320 ;
35- const rowGap = 10 ;
3625 const [ previewViewport , setPreviewViewport ] = useState < { width : number ; height : number } > ( { width : 0 , height : 0 } ) ;
3726 const hasPreviewViewport = previewViewport . width > 0 && previewViewport . height > 0 ;
38- const editorWidthInitializedRef = useRef ( false ) ;
3927
4028 const clamp = ( value : number , min : number , max : number ) => Math . min ( max , Math . max ( min , value ) ) ;
4129
@@ -144,181 +132,108 @@ export const StudioApp = () => {
144132 [ isPlayingStore ]
145133 ) ;
146134
147- const clampEditorWidth = useCallback (
148- ( nextWidth : number ) => {
149- const row = rowRef . current ;
150- if ( ! row ) {
151- setEditorWidth ( Math . max ( editorMinWidth , nextWidth ) ) ;
152- return ;
153- }
154- const maxWidth = Math . max ( editorMinWidth , row . clientWidth - rowGap - leftPanelMinWidth ) ;
155- const clamped = Math . min ( Math . max ( nextWidth , editorMinWidth ) , maxWidth ) ;
156- setEditorWidth ( clamped ) ;
157- } ,
158- [ editorMinWidth , leftPanelMinWidth , rowGap ] ,
159- ) ;
160-
161- useEffect ( ( ) => {
162- const row = rowRef . current ;
163- if ( ! row ) return ;
164- const observer = new ResizeObserver ( ( ) => {
165- setEditorWidth ( ( prev ) => {
166- const maxWidth = Math . max ( editorMinWidth , row . clientWidth - rowGap - leftPanelMinWidth ) ;
167- return Math . min ( prev , maxWidth ) ;
168- } ) ;
169- } ) ;
170- observer . observe ( row ) ;
171- return ( ) => observer . disconnect ( ) ;
172- } , [ editorMinWidth , leftPanelMinWidth , rowGap ] ) ;
173-
174- useEffect ( ( ) => {
175- if ( editorWidthInitializedRef . current ) return ;
176- const row = rowRef . current ;
177- const baseWidth = row ?. clientWidth ?? window . innerWidth ;
178- editorWidthInitializedRef . current = true ;
179- clampEditorWidth ( Math . round ( baseWidth / 2 ) ) ;
180- } , [ clampEditorWidth ] ) ;
181-
182135 return (
183- < EditorProvider >
184- < StudioStateContext value = { { isPlaying, setIsPlaying, isPlayingStore, isRender : false } } >
185- < WithCurrentFrame >
186- < div style = { { padding : 16 , height : "100vh" , boxSizing : "border-box" , minHeight : 0 } } >
187- < div ref = { rowRef } style = { { display : "flex" , gap : 10 , height : "100%" , minHeight : 0 } } >
188- < div style = { { flex : 1 , minWidth : leftPanelMinWidth , display : "flex" , flexDirection : "column" , minHeight : 0 } } >
189- < div style = { { display : "flex" , justifyContent : "flex-end" , marginBottom : 8 } } >
190- < button
191- type = "button"
192- onClick = { ( ) => setIsEditorVisible ( ( prev ) => ! prev ) }
193- style = { {
194- padding : "6px 10px" ,
195- borderRadius : 6 ,
196- border : "1px solid #1f2937" ,
197- background : "#0f172a" ,
198- color : "#cbd5e1" ,
199- cursor : "pointer" ,
200- fontSize : 12 ,
201- fontWeight : 600 ,
202- } }
203- >
204- { isEditorVisible ? "Hide Editor" : "Show Editor" }
205- </ button >
206- </ div >
207-
136+ < StudioStateContext value = { { isPlaying, setIsPlaying, isPlayingStore, isRender : false } } >
137+ < WithCurrentFrame >
138+ < div style = { { padding : 16 , height : "100vh" , boxSizing : "border-box" , minHeight : 0 } } >
139+ < div
140+ ref = { containerRef }
141+ style = { {
142+ display : "flex" ,
143+ flexDirection : "column" ,
144+ gap : 10 ,
145+ width : "100%" ,
146+ height : "100%" ,
147+ boxSizing : "border-box" ,
148+ minHeight : 0 ,
149+ } }
150+ >
151+ < div
152+ ref = { topRef }
153+ style = { {
154+ display : "flex" ,
155+ gap : 10 ,
156+ alignItems : "stretch" ,
157+ width : "100%" ,
158+ flexBasis : `${ verticalRatio * 100 } %` ,
159+ minHeight : 240 ,
160+ maxHeight : "80%" ,
161+ minWidth : 0 ,
162+ } }
163+ >
164+ < div style = { { flexBasis : `${ horizontalRatio * 100 } %` , minWidth : 220 } } >
165+ < ClipVisibilityPanel />
166+ </ div >
167+ < div
168+ onPointerDown = { startHorizontalDrag }
169+ style = { {
170+ width : 6 ,
171+ cursor : "col-resize" ,
172+ background : "linear-gradient(180deg, #1f2937, #111827)" ,
173+ borderRadius : 4 ,
174+ flexShrink : 0 ,
175+ } }
176+ />
177+ < div style = { { flex : 1 , minWidth : 320 , display : "flex" , alignItems : "center" , justifyContent : "center" , minHeight : previewMinHeight , position : "relative" } } >
208178 < div
209- ref = { containerRef }
179+ ref = { previewRef }
210180 style = { {
211- display : "flex" ,
212- flexDirection : "column" ,
213- gap : 10 ,
214181 width : "100%" ,
215182 height : "100%" ,
183+ display : "flex" ,
184+ alignItems : "center" ,
185+ justifyContent : "center" ,
216186 boxSizing : "border-box" ,
217- minHeight : 0 ,
218- flex : 1 ,
219187 } }
220188 >
221189 < div
222- ref = { topRef }
223190 style = { {
224- display : "flex" ,
225- gap : 10 ,
226- alignItems : "stretch" ,
227- width : "100%" ,
228- flexBasis : `${ verticalRatio * 100 } %` ,
229- minHeight : 240 ,
230- maxHeight : "80%" ,
231- minWidth : 0 ,
191+ width : scaledWidth ,
192+ height : scaledHeight ,
193+ visibility : hasPreviewViewport ? "visible" : "hidden" ,
194+ aspectRatio : previewAspect ,
195+ border : "1px solid #444" ,
196+ borderRadius : 1 ,
197+ overflow : "hidden" ,
198+ backgroundColor : "#000" ,
199+ boxShadow : "0 10px 30px rgba(0,0,0,0.35)" ,
200+ position : "relative" ,
232201 } }
233202 >
234- < div style = { { flexBasis : `${ horizontalRatio * 100 } %` , minWidth : 220 } } >
235- < LeftPanelTabs />
236- </ div >
237203 < div
238- onPointerDown = { startHorizontalDrag }
239204 style = { {
240- width : 6 ,
241- cursor : "col-resize" ,
242- background : "linear-gradient(180deg, #1f2937, #111827)" ,
243- borderRadius : 4 ,
244- flexShrink : 0 ,
205+ width : projectWidth ,
206+ height : projectHeight ,
207+ transform : `scale(${ scale } )` ,
208+ transformOrigin : "top left" ,
245209 } }
246- />
247- < div style = { { flex : 1 , minWidth : 320 , display : "flex" , alignItems : "center" , justifyContent : "center" , minHeight : previewMinHeight , position : "relative" } } >
248- < div
249- ref = { previewRef }
250- style = { {
251- width : "100%" ,
252- height : "100%" ,
253- display : "flex" ,
254- alignItems : "center" ,
255- justifyContent : "center" ,
256- boxSizing : "border-box" ,
257- } }
258- >
259- < div
260- style = { {
261- width : scaledWidth ,
262- height : scaledHeight ,
263- visibility : hasPreviewViewport ? "visible" : "hidden" ,
264- aspectRatio : previewAspect ,
265- border : "1px solid #444" ,
266- borderRadius : 1 ,
267- overflow : "hidden" ,
268- backgroundColor : "#000" ,
269- boxShadow : "0 10px 30px rgba(0,0,0,0.35)" ,
270- position : "relative" ,
271- } }
272- >
273- < div
274- style = { {
275- width : projectWidth ,
276- height : projectHeight ,
277- transform : `scale(${ scale } )` ,
278- transformOrigin : "top left" ,
279- } }
280- >
281- < PROJECT />
282- </ div >
283- </ div >
284- </ div >
285- </ div >
286- </ div >
287-
288- < div
289- onPointerDown = { startVerticalDrag }
290- style = { {
291- height : 8 ,
292- cursor : "row-resize" ,
293- background : "linear-gradient(90deg, #1f2937, #111827)" ,
294- borderRadius : 4 ,
295- flexShrink : 0 ,
296- } }
297- />
298-
299- < div style = { { flex : 1 , minHeight : 160 , display : "flex" , minWidth : 0 } } >
300- < div style = { { flex : 1 , minHeight : 0 } } >
301- < TimelineUI />
210+ >
211+ < PROJECT />
302212 </ div >
303213 </ div >
304214 </ div >
305215 </ div >
216+ </ div >
306217
307- < div
308- style = { {
309- width : editorWidth ,
310- minWidth : editorMinWidth ,
311- height : "100%" ,
312- minHeight : 0 ,
313- display : isEditorVisible ? "flex" : "none" ,
314- } }
315- >
316- < CodeEditor width = { editorWidth } onWidthChange = { clampEditorWidth } />
218+ < div
219+ onPointerDown = { startVerticalDrag }
220+ style = { {
221+ height : 8 ,
222+ cursor : "row-resize" ,
223+ background : "linear-gradient(90deg, #1f2937, #111827)" ,
224+ borderRadius : 4 ,
225+ flexShrink : 0 ,
226+ } }
227+ />
228+
229+ < div style = { { flex : 1 , minHeight : 160 , display : "flex" , minWidth : 0 } } >
230+ < div style = { { flex : 1 , minHeight : 0 } } >
231+ < TimelineUI />
317232 </ div >
318233 </ div >
319234 </ div >
320- </ WithCurrentFrame >
321- </ StudioStateContext >
322- </ EditorProvider >
235+ </ div >
236+ </ WithCurrentFrame >
237+ </ StudioStateContext >
323238 ) ;
324239} ;
0 commit comments