@@ -157,6 +157,8 @@ export function WordArtWorkbench() {
157157 const [ lightEl , setLightEl ] = useState ( ( ) => qn ( "lel" , 45 ) ) ;
158158 const [ activePreset , setActivePreset ] = useState < string | null > ( null ) ;
159159 const [ exporting , setExporting ] = useState ( false ) ;
160+ // Mobile: only one floating panel is open at a time, toggled by the bottom tabs.
161+ const [ mobilePanel , setMobilePanel ] = useState < "style" | "controls" | null > ( null ) ;
160162
161163 const handleCodePen = async ( ) => {
162164 const el = document . querySelector < HTMLElement > ( ".wa-stage .polycss-camera" )
@@ -173,6 +175,13 @@ export function WordArtWorkbench() {
173175 }
174176 } ;
175177
178+ useEffect ( ( ) => {
179+ if ( ! mobilePanel ) return ;
180+ const onKey = ( e : KeyboardEvent ) => { if ( e . key === "Escape" ) setMobilePanel ( null ) ; } ;
181+ window . addEventListener ( "keydown" , onKey ) ;
182+ return ( ) => window . removeEventListener ( "keydown" , onKey ) ;
183+ } , [ mobilePanel ] ) ;
184+
176185 // Default bundled font + Google catalog. If the URL named a font, select it
177186 // once the catalog is in.
178187 useEffect ( ( ) => {
@@ -366,7 +375,11 @@ export function WordArtWorkbench() {
366375 status = { status }
367376 />
368377
369- < aside className = "wa-card wa-left" aria-label = "Text and presets" >
378+ < aside
379+ id = "wa-style-panel"
380+ className = { `wa-card wa-left ${ mobilePanel === "style" ? "is-mobile-open" : "" } ` }
381+ aria-label = "Text and presets"
382+ >
370383 < div className = "wa-card__body" >
371384 < label className = "wa-field" >
372385 < span > Text</ span >
@@ -398,11 +411,37 @@ export function WordArtWorkbench() {
398411 </ div >
399412 </ aside >
400413
401- < GuiPanel values = { guiValues } set = { guiSet } />
414+ < GuiPanel
415+ id = "wa-controls-panel"
416+ className = { mobilePanel === "controls" ? "is-mobile-open" : "" }
417+ values = { guiValues }
418+ set = { guiSet }
419+ />
402420
403421 < button type = "button" className = "wa-codepen" onClick = { handleCodePen } disabled = { exporting } >
404422 { exporting ? "Exporting…" : "Open in CodePen" }
405423 </ button >
424+
425+ < nav className = "wa-mobile-tabs" aria-label = "WordArt panels" >
426+ < button
427+ type = "button"
428+ className = { `wa-mobile-tabs__button ${ mobilePanel === "style" ? "is-active" : "" } ` }
429+ aria-controls = "wa-style-panel"
430+ aria-expanded = { mobilePanel === "style" }
431+ onClick = { ( ) => setMobilePanel ( ( cur ) => ( cur === "style" ? null : "style" ) ) }
432+ >
433+ Style
434+ </ button >
435+ < button
436+ type = "button"
437+ className = { `wa-mobile-tabs__button ${ mobilePanel === "controls" ? "is-active" : "" } ` }
438+ aria-controls = "wa-controls-panel"
439+ aria-expanded = { mobilePanel === "controls" }
440+ onClick = { ( ) => setMobilePanel ( ( cur ) => ( cur === "controls" ? null : "controls" ) ) }
441+ >
442+ Controls
443+ </ button >
444+ </ nav >
406445 </ div >
407446 ) ;
408447}
@@ -540,7 +579,7 @@ interface GuiValues {
540579 * are identical, not a CSS approximation. lil-gui is imperative, so we mount it
541580 * once and bridge its onChange → React, and React state → updateDisplay().
542581 */
543- function GuiPanel ( { values, set } : { values : GuiValues ; set : ( k : keyof GuiValues , v : number | string | boolean ) => void } ) {
582+ function GuiPanel ( { id , className = "" , values, set } : { id ?: string ; className ?: string ; values : GuiValues ; set : ( k : keyof GuiValues , v : number | string | boolean ) => void } ) {
544583 const hostRef = useRef < HTMLDivElement > ( null ) ;
545584 const cfgRef = useRef < GuiValues > ( { ...values } ) ;
546585 const ctrlRef = useRef < Record < string , ReturnType < GUI [ "add" ] > > > ( { } ) ;
@@ -592,7 +631,7 @@ function GuiPanel({ values, set }: { values: GuiValues; set: (k: keyof GuiValues
592631 ctrlRef . current . profileSegments ?. [ values . profile === "round" ? "show" : "hide" ] ( ) ;
593632 } ) ;
594633
595- return < div className = " wa-gui" ref = { hostRef } /> ;
634+ return < div id = { id } className = { ` wa-gui ${ className } ` } ref = { hostRef } /> ;
596635}
597636
598637interface LeftValues {
0 commit comments