feat(runner): DEV-2027 show window-maximize in play, full mode without the editor - #117
Merged
Merged
Conversation
…t the editor The button was gated on `savedId`, so it never appeared in `play` — no docs example, no starter, no anonymous visitor. The frames disagree: `72:15697`'s preview bar draws book + github + window-maximize and `repoUrl` is play-only, so that is a play-mode bar ending in maximize; `65:20432` "Mode Full" is drawn over `Drag to scroll - Standard example`, a docs example, which is always `play`. Full mode is now the view without the editor rather than a separate route, though its subject still differs by mode. `edit`/`share` are untouched: `fullModeId` routes to `FullMode`, which iframes the prebuilt `/d/:id/` in a new tab and stays the cheap path. `play` has no artifact, only the live preview already running, so `EditorShell` takes a `fullMode` flag — sidebar, editor column and splitter unmount, `FullBar` replaces `PreviewBar`, the top bar keeps theme toggle + Download (`65:20458`), and the example pill goes static per `65:21391`'s hidden chevron. Entering it in `play` is `replaceState` plus state, not a navigation. `window.open` there would boot a second runtime, and for Tier 2 a second container session per click against a pool that already exhausts; in place, the session, its container and every unsaved edit survive the toggle. The deep link works because play state lives in the URL (`?docs=` / `?example=` / `?v=`). `FullBar.onRefresh` becomes optional, mirroring `PreviewBar` — in `play` it re-runs the live preview instead of re-keying an iframe. Nothing in `e2e/` covered this button or the route, which is why a control missing from an entire mode shipped unnoticed; `e2e/full-mode.spec.ts` now does, including that the toggle does not re-mount the preview iframe. Recorded as ADR-0027 §13, with the one question it leaves for design: whether full mode over a saved demo should show the live workspace too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3ec67fa. Configure here.
… of unmounting it Bugbot on #117 reported the visible half: `EditorStatusBar` kept its pre-toggle `Ln, Col` after minimize, because the caret effect depends only on `active` and `openPaths` and so never re-ran. The cause is bigger than the readout — unmounting the panes discarded everything DEV-2169 keeps every tab mounted for. Per-tab undo history, scroll offset and caret all went with them, and coming back from full mode is meant to be a toggle. The editor side now sits under one `display: contents` wrapper that flips to `display: none`. `contents` because the sidebar, the editor column and the splitter are grid items of `s.body`, which a real box would collapse into a single track; `none` then takes the subtree out of layout, so the full-mode form of `s.body` can stay a single track. `display: none` does leave CodeMirror with no layout, so `props.fullMode` joins the caret effect's deps for its `requestMeasure()`. That call was there as a precaution against a `visibility: hidden` pane and is now load-bearing. The readout itself needs no reset: nothing re-mounts and nothing moves the caret. The two spec assertions that read `toHaveCount(0)` for the splitter and the editor pane were asserting the unmount, which would have forbidden this fix; they now assert invisibility. New test covers the cause rather than the symptom — a stale readout and a correct one are the same number, so it types, takes a trip through full mode and expects undo to still revert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
window-maximizewas gated onsavedId, so it never appeared inplay— no docs example, no starter, no anonymous visitor. It was not among ADR-0027's twelve recorded deviations, so it reads as a bug and has been re-filed as one more than once.The frames disagree with the gate.
72:15697's preview bar draws book + github + window-maximize, andrepoUrlisplay-only (App.tsx), so by the app's own mapping that is a play-mode bar ending in maximize.65:20432"Mode Full" is drawn overDrag to scroll - Standard example— a docs example, which is alwaysplay.Neither the frame names nor the URL text settle it, and both are easy to cite by mistake: "before login" is not "no id" (
savedIdis set insharetoo, so a signed-out visitor on/share/:idalready got the button), and the placeholder…/share/14z4151i1lappears identically in a starter frame and a docs frame. The play-only icons are the evidence.One question for design, non-blocking: both preview bars are auto-named
Frame 48112801, so "one bar component reused across frames" is a live alternative reading. The plain reading is taken here because the icon is drawn in two independentplayframes — but a line of confirmation would retire the question instead of leaving it for whoever reads the ADR next.What
The button now renders in every mode, and full mode means the view without the editor. Its subject still differs by mode, which is the part that does depart from the frames:
edit/share— unchanged.fullModeIdstill routes toFullMode, which iframes the prebuilt/d/:id/in a new tab. That is what the frames show and what the share dialog hands out, and it stays the cheap path: no bundler, no container, nothing to boot. It therefore shows the last build, not unsaved edits.play— new. There is no artifact there, only the live preview already running, soEditorShelltakes afullModeflag: the sidebar, editor column and splitter are hidden,FullBarreplacesPreviewBar, the top bar keeps theme toggle +Download(65:20458), and the example pill goes static per65:21391's hidden chevron.Hidden, not unmounted, and the distinction is the point of a toggle. The editor side sits under one
display: contentswrapper that flips todisplay: none—contentsbecause the sidebar, the editor column and the splitter are grid items ofs.body, which a real wrapper box would collapse into a single track. Unmounting was the first cut, and it discarded everything DEV-2169 keeps every tab mounted for: per-tab undo history, scroll offset and caret.display: nonedoes leave CodeMirror with no layout, soprops.fullModejoins the caret effect's deps for itsrequestMeasure()— a call that was already there as a precaution and is load-bearing now.Entering it in
playishistory.replaceStateplus state, not a navigation.window.openthere would boot a second runtime, and for Tier 2 that is a second container session per click against a pool that already exhausts; in place, the session, its container and every unsaved edit survive the toggle. The URL stays shareable, and the deep link works because play state lives in the URL (?docs=/?example=/?v=) — moving it anywhere else breaks?mode=full.FullBar.onRefreshbecomes optional, mirroringPreviewBar: inplayit re-runs the live preview rather than re-keying an iframe.Recorded as ADR-0027 §13, including the question it leaves for design — whether full mode over a saved demo should show the live workspace too. Answering "yes" collapses the two behaviours into one, at the cost of the share dialog's full-window link becoming a cold boot for the recipient.
Tests
e2e/full-mode.spec.tsis new. Nothing ine2e/touched this button or the route before, which is why a control missing from an entire mode shipped unnoticed. Five tests: the button is visible inplay; the toggle hides the editor side, showsFullBar, addsmode=fulland does not re-mount the preview iframe (asserted with a DOM stamp, which a navigation would also wipe); minimize restores the editor and drops the param; a pasted?mode=fulllink boots straight into full mode with a working way back; and the editor survives a trip through full mode, asserted by typing, toggling, returning and expectingCmd+Zto still revert.Watched every one fail first — the first four with
element(s) not foundon the maximize control, the undo one with the marker still present because the remounted view had an empty history.Full suite: 59 passed, 0 failed, 90 skipped (the
E2E_LIVE/ starter-matrix ones). Unit: 77 pass.pnpm -r run typecheckclean across all four projects.Two notes for whoever runs this locally:
authed-actions.spec.tsandsidebar-crud.spec.tsfail against any build that picks upapps/authoring/.env.local, which setsVITE_DEV_USER. Build withVITE_DEV_USER=or those two specs prove nothing. Not related to this change; it cost me one confused run.EditorShell.tsx:415contains a literalU+0000inside a React key template, sogit,grepandrtk grepall treat the file as binary — reading this PR's diff for that file needs--text, and a plaingrepfor a symbol in it silently returns nothing. Left alone here as unrelated, but it is worth its own one-line commit.Verified visually at 1728×900 against
65:20432: pill + theme toggle +Download,FullBarwith the italicLive previewplaceholder and minimize at the right edge, full-width preview, status bar intact. The preview was mid-boot both before and after the toggle — which is itself evidence the toggle changed no runtime state.🤖 Generated with Claude Code