@@ -35,7 +35,7 @@ async function initWasm() {
3535 const runButtonMob = document . querySelector ( "#run-mobile" )
3636 runButton . onclick = handleRun
3737 runButton . classList . remove ( "loading" )
38- runButtonMob . onclick = handleMobRun
38+ runButtonMob . onclick = handlePrimaryClick
3939 runButtonMob . classList . remove ( "loading" )
4040}
4141
@@ -232,28 +232,52 @@ async function handleRun() {
232232 stopped ? start ( ) : stop ( )
233233}
234234
235- // handleMobRun handles three states for mobile devices:
236- // run -> stop -> code
237- async function handleMobRun ( ) {
235+ // handlePrimaryClick handles view states ( mobile, code, output) on mobile.
236+ async function handlePrimaryClick ( ) {
237+ // single column layout: run <-> stop
238238 if ( editorHidden && notesHidden ) {
239239 handleRun ( )
240240 return
241241 }
242- if ( onCodeScreen ( ) ) {
242+ const view = getView ( )
243+ const showNotesBtn = document . querySelector ( "#show-notes" )
244+ if ( view == "view-notes" && ! editorHidden ) {
245+ await slide ( "view-code" )
246+ if ( showNotesBtn ) showNotesBtn . disabled = false
247+ return
248+ }
249+ if ( view === "view-notes" || view === "view-code" ) {
243250 // we need to wait for the slide transition to finish otherwise
244251 // el.focus() in jsRead() messes up the layout
245- await slide ( )
252+ await slide ( "view-output" )
253+ if ( showNotesBtn ) showNotesBtn . disabled = false
246254 start ( )
247255 return
248256 }
249- // on output screen
250- if ( stopped ) {
251- const runButtonMob = document . querySelector ( "#run-mobile" )
252- runButtonMob . innerText = "Run"
253- slide ( )
257+ // on output view, running
258+ if ( ! stopped ) {
259+ stop ( )
254260 return
255261 }
256- stop ( )
262+ // on output view, stopped
263+ document . querySelector ( "#run-mobile" ) . innerText = "Run"
264+ const nextScreen = editorHidden ? "view-notes" : "view-code"
265+ slide ( nextScreen )
266+ }
267+
268+ function getView ( ) {
269+ const cl = document . querySelector ( "main.main" ) . classList
270+ if ( cl . contains ( "view-output" ) ) return "view-output"
271+ if ( cl . contains ( "view-code" ) ) return "view-code"
272+ if ( cl . contains ( "view-notes" ) ) return "view-notes"
273+ }
274+
275+ function showNotes ( ) {
276+ if ( notesHidden ) return
277+ if ( ! stopped ) stop ( )
278+ slide ( "view-notes" )
279+ const showNotesBtn = document . querySelector ( "#show-notes" )
280+ if ( showNotesBtn ) showNotesBtn . disabled = true
257281}
258282
259283// start calls evy wasm/go main(). It parses, formats and evaluates evy
@@ -301,36 +325,48 @@ function afterStop() {
301325 wasmInst = undefined
302326
303327 const runButton = document . querySelector ( "#run" )
304- const runButtonMob = document . querySelector ( "#run-mobile" )
305328 runButton . classList . remove ( "running" )
306329 runButton . innerText = "Run"
307- runButtonMob . classList . remove ( "running" )
308- runButtonMob . innerText = onCodeScreen ( ) ? "Run" : "Code"
330+ updateMobilePrimaryButton ( )
309331
310332 const readEl = document . querySelector ( "#read" )
311333 document . activeElement === readEl && readEl . blur ( )
312334}
313335
314- function onCodeScreen ( ) {
315- return ! document . querySelector ( "main" ) . classList . contains ( "view-output" )
336+ function updateMobilePrimaryButton ( ) {
337+ const classList = document . querySelector ( "#run-mobile" )
338+ classList . classList . remove ( "running" )
339+ classList . innerText = mobilePrimaryButtonText ( )
340+ }
341+
342+ function mobilePrimaryButtonText ( ) {
343+ if ( editorHidden && notesHidden ) return "Run"
344+ const view = getView ( )
345+ if ( view === "view-notes" && ! editorHidden ) return "Code"
346+ if ( view === "view-notes" && editorHidden ) return "Run"
347+ if ( view === "view-code" ) return "Run"
348+ // output screen
349+ if ( editorHidden ) return "Notes"
350+ return "Code"
316351}
317352
318- async function slide ( ) {
319- const el = document . querySelector ( "main" )
353+ async function slide ( view ) {
354+ const el = document . querySelector ( "main.main " )
320355 const cl = el . classList
321356 return new Promise ( ( resolve ) => {
322357 el . ontransitionend = ( ) => setTimeout ( resolve , 100 )
323358 el . onanimationend = ( ) => cl . remove ( "animate" )
324359 cl . add ( "animate" )
325- onCodeScreen ( ) ? cl . add ( " view-output" ) : cl . remove ( "view-output" )
360+ setView ( view )
326361 } )
327362}
328363
329- async function stopAndSlide ( ) {
330- if ( ! onCodeScreen ( ) ) {
331- await slide ( )
332- }
333- stop ( )
364+ function setView ( view ) {
365+ const cl = document . querySelector ( "main.main" ) . classList
366+ const viewClasses = [ "view-code" , "view-notes" , "view-output" ]
367+ viewClasses . map ( ( c ) => cl . remove ( c ) )
368+ cl . add ( view )
369+ updateMobilePrimaryButton ( )
334370}
335371
336372function clearOutput ( ) {
@@ -346,10 +382,13 @@ async function initUI() {
346382 document . addEventListener ( "keydown" , ctrlEnterListener )
347383 window . addEventListener ( "hashchange" , handleHashChange )
348384 document . querySelector ( "#modal-close" ) . onclick = hideModal
349- document . querySelector ( "#share" ) . onclick = share
350385 document . querySelector ( "#sidebar-about" ) . onclick = showAbout
351386 document . querySelector ( "#sidebar-share" ) . onclick = share
352387 document . querySelector ( "#sidebar-icon-share" ) . onclick = share
388+ const shareBtn = document . querySelector ( "#share" )
389+ if ( shareBtn ) shareBtn . onclick = share
390+ const showNotesBtn = document . querySelector ( "#show-notes" )
391+ if ( showNotesBtn ) showNotesBtn . onclick = showNotes
353392 await fetchSamples ( )
354393 await handleHashChangeNoFormat ( ) // Evy wasm for formatting might not be ready yet
355394 initModal ( )
@@ -409,15 +448,11 @@ async function handleHashChange() {
409448
410449async function handleHashChangeNoFormat ( ) {
411450 hideModal ( )
412- await stopAndSlide ( ) // go to code screen for new code
451+ await stop ( ) // go to code screen for new code
413452 let opts = parseHash ( )
414453 if ( ! opts . source && ! opts . sample && ! opts . content ) {
415- if ( hasEditorSession ( ) ) {
416- currentSample = "<UNSET>"
417- ! editor && initEditor ( )
418- editor . loadSession ( )
419- loadNotes ( )
420- toggleEditorVisibility ( true )
454+ if ( sessionStorage . getItem ( "evy-editor" ) !== null ) {
455+ loadSession ( )
421456 return
422457 }
423458 const sample = "welcome"
@@ -428,9 +463,35 @@ async function handleHashChangeNoFormat() {
428463 updateNotes ( notes )
429464 updateEditor ( source , opts )
430465 updateSampleTitle ( )
466+ resetView ( )
431467 clearOutput ( )
432468}
433469
470+ function loadSession ( ) {
471+ currentSample = "<UNSET>"
472+ ! editor && initEditor ( )
473+ editor . loadSession ( )
474+ loadNotes ( )
475+ toggleEditorVisibility ( true )
476+ resetView ( ) // on mobile go to Notes view or Code view if no notes available.
477+ }
478+
479+ // resetView resets the view based on content availability, on mobile only.
480+ // If notes are available, navigates to the notes view.
481+ // If no notes but the editor is present, switches to the code view.
482+ // Otherwise, defaults to the output view
483+ function resetView ( ) {
484+ const showNotesBtn = document . querySelector ( "#show-notes" )
485+ if ( showNotesBtn ) showNotesBtn . disabled = true
486+ if ( ! notesHidden ) {
487+ setView ( "view-notes" )
488+ } else if ( ! editorHidden ) {
489+ setView ( "view-code" )
490+ } else {
491+ setView ( "view-output" )
492+ }
493+ }
494+
434495function updateNotes ( notes ) {
435496 hasNotes ( notes ) ? addNotes ( notes ) : removeNotes ( )
436497}
@@ -918,10 +979,6 @@ function initEditor() {
918979 document . querySelector ( ".editor-wrap" ) . classList . remove ( "noscrollbar" )
919980}
920981
921- function hasEditorSession ( ) {
922- return ! ! sessionStorage . getItem ( "evy-editor" )
923- }
924-
925982// --- eventHandlers, evy `on` -----------------------------------------
926983
927984// registerEventHandler is exported to evy go/wasm
@@ -937,7 +994,7 @@ function registerEventHandler(ptr, len) {
937994 c . onpointermove = ( e ) => exp . onMove ( logicalX ( e ) , logicalY ( e ) )
938995 c . onmouseleave = ( e ) => exp . onMove ( ...leaveXY ( e ) ) // pointer can leave in middle of canvas
939996 } else if ( s === "key" ) {
940- unfocusRunBotton ( )
997+ unfocusRunButton ( )
941998 document . addEventListener ( "keydown" , keydownListener )
942999 } else if ( s === "input" ) {
9431000 addInputHandlers ( )
@@ -948,7 +1005,7 @@ function registerEventHandler(ptr, len) {
9481005 }
9491006}
9501007
951- function unfocusRunBotton ( ) {
1008+ function unfocusRunButton ( ) {
9521009 const runButton = document . querySelector ( "#run" )
9531010 const runButtonMob = document . querySelector ( "#run-mobile" )
9541011 document . activeElement === runButton && runButton . blur ( )
0 commit comments