|
| 1 | +# Central Control Bar & Design Mode — Tests TODO |
| 2 | + |
| 3 | +Planned as `mainview`-category integration tests (spawns full Phoenix iframe so |
| 4 | +sidebar, CCB, live-preview panel, and main-toolbar are all real). Single suite: |
| 5 | + |
| 6 | +```js |
| 7 | +describe("mainview: central control bar + design mode", function () { … }); |
| 8 | +``` |
| 9 | + |
| 10 | +Keep this file updated as we add coverage; remove lines as suites land. |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## 1. Layout / DOM structure |
| 15 | + |
| 16 | +- [ ] `#centralControlBar` exists at boot, positioned between sidebar and |
| 17 | + `.content`, 30px wide. |
| 18 | +- [ ] CCB groups render in order: collapse-editor, sidebar-toggle, undo/redo, |
| 19 | + save, nav (search / back / forward), vertical filename label. |
| 20 | +- [ ] Sidebar's `data-minsize` is `30` (so drag can't auto-collapse below CCB). |
| 21 | +- [ ] Sidebar's resizer handle is shifted right of the CCB via CSS |
| 22 | + `transform: translateX(30px)` — clicking at `sidebar.right + 30` lands |
| 23 | + on the resizer element. |
| 24 | +- [ ] When the sidebar is hidden, the Resizer moves the handle to be a sibling |
| 25 | + of `#sidebar` inside `.main-view`; the same shift still applies. |
| 26 | + |
| 27 | +## 2. CCB buttons |
| 28 | + |
| 29 | +- [ ] Undo / Redo / Save buttons fire `Commands.EDIT_UNDO`, `EDIT_REDO`, |
| 30 | + `FILE_SAVE` respectively. |
| 31 | +- [ ] Search / Back / Forward / Show-in-Tree buttons still trigger the |
| 32 | + `NavigationProvider` behaviors after being moved out of `#mainNavBarRight`. |
| 33 | +- [ ] `#ccbSidebarToggleBtn` executes `VIEW_HIDE_SIDEBAR` and the icon flips |
| 34 | + `fa-angles-left` ↔ `fa-angles-right` on panelCollapsed/panelExpanded. |
| 35 | +- [ ] The old `#sidebar-toggle-btn` in the menubar is NOT in the DOM. |
| 36 | +- [ ] Clicking `#ccbFileLabel` executes `NAVIGATE_SHOW_IN_FILE_TREE` and (if |
| 37 | + sidebar was hidden) re-opens the sidebar as part of that command. |
| 38 | +- [ ] File label shows the current doc's `file.name` and uses |
| 39 | + `Phoenix.app.getDisplayPath` for its tooltip. |
| 40 | +- [ ] Dirty indicator dot toggles with `DocumentManager`'s `dirtyFlagChange`. |
| 41 | + |
| 42 | +## 3. Toggle Design Mode command |
| 43 | + |
| 44 | +- [ ] `Commands.VIEW_TOGGLE_DESIGN_MODE === "view.toggleDesignMode"` is |
| 45 | + registered at module load, visible via `CommandManager.get`. |
| 46 | +- [ ] Default keybinding: `Ctrl-F11` (from `base-config/keyboard.json`). |
| 47 | +- [ ] File menu has "Toggle Design Mode" directly below "Live Preview" and |
| 48 | + above "Reload Live Preview". |
| 49 | +- [ ] Command's checked state mirrors `WorkspaceManager.isInDesignMode()` on |
| 50 | + both entry and exit. |
| 51 | +- [ ] Clicking `#ccbCollapseEditorBtn` routes through the command |
| 52 | + (verify via a spy on `CommandManager.execute`). |
| 53 | +- [ ] Icon swap: `fa-feather` (expanded) ↔ `fa-code` (design mode). Title |
| 54 | + swap: "Switch to Visual Edit" ↔ "Switch to Code Editor". |
| 55 | + |
| 56 | +## 4. Enter design mode |
| 57 | + |
| 58 | +- [ ] With live preview closed: executing the toggle first opens LP (verify a |
| 59 | + single execution of `FILE_LIVE_FILE_PREVIEW`), then applies collapsed |
| 60 | + layout on its `.always()`. |
| 61 | +- [ ] With live preview open: sidebar width is preserved, `.content` goes to |
| 62 | + `width: 0`, `#main-toolbar` gets `left: sidebarW + 30`, `width: |
| 63 | + innerWidth - sidebarW - 30` with `!important`, `right: auto`. |
| 64 | +- [ ] `savedToolbarWidth` captures pre-collapse `#main-toolbar.outerWidth` for |
| 65 | + later restore (only when LP was already open). |
| 66 | +- [ ] `$sidebar.data("maxsize")` is stored and replaced with `"1000%"` so |
| 67 | + `Resizer.updateResizeLimits` doesn't shrink the sidebar on subsequent |
| 68 | + window resizes. |
| 69 | +- [ ] `#main-toolbar > .horz-resizer` gets `display: none` via CSS. |
| 70 | +- [ ] `document.body` gets class `ccb-editor-collapsed`. |
| 71 | +- [ ] `WorkspaceManager.isInDesignMode()` returns `true` and |
| 72 | + `EVENT_WORKSPACE_DESIGN_MODE_CHANGE` fires with `true`. |
| 73 | + |
| 74 | +## 5. Exit design mode |
| 75 | + |
| 76 | +- [ ] Before flipping the body class, `sidebar.style.width` is pinned to the |
| 77 | + currently rendered (max-width-capped) value so removing the cap |
| 78 | + doesn't cause the sidebar to snap back to the stale uncapped width. |
| 79 | +- [ ] `Resizer.resyncSizer` runs after the pin so the handle follows. |
| 80 | +- [ ] Normal exit restores `#main-toolbar` to `savedToolbarWidth` (LP had |
| 81 | + been open pre-collapse) or `innerWidth / 2.5` default (LP was opened by |
| 82 | + the toggle itself). Never closes LP. |
| 83 | +- [ ] Exit clamps: sidebar + CCB + toolbar + 200 (min editor) ≤ window; if |
| 84 | + the pre-collapse toolbar width would overflow, trim the sidebar first |
| 85 | + and `data("resyncSizer")()` afterwards. |
| 86 | +- [ ] `livePanel.minWidth + iconsBar` lower bound is honored when picking |
| 87 | + the restored toolbar width. |
| 88 | +- [ ] `$sidebar.data("maxsize")` is restored to its saved percentage. |
| 89 | +- [ ] `WorkspaceManager.isInDesignMode()` returns `false`, event fires with |
| 90 | + `false`. |
| 91 | + |
| 92 | +## 6. Exit triggered by hiding live preview |
| 93 | + |
| 94 | +- [ ] Clicking `#toolbar-go-live` while in design mode: |
| 95 | + - LP panel hides. |
| 96 | + - `_restoreExpandedLayout` is called with `skipToolbarRestore: true`. |
| 97 | + - `#main-toolbar` ends at the icon-bar-only width (WSM's |
| 98 | + `_hidePluginSidePanel` width), not the pre-collapse LP size. |
| 99 | + - `body.ccb-editor-collapsed` is removed. |
| 100 | + |
| 101 | +## 7. Sidebar drag in design mode |
| 102 | + |
| 103 | +- [ ] Dragging the sidebar resizer rightward grows the sidebar linearly |
| 104 | + (1:1 with mouse delta) up to the CSS max-width cap. |
| 105 | +- [ ] CSS cap is `calc(100vw - 230px)`: on a 1500px viewport the rendered |
| 106 | + sidebar never exceeds ~1270px even if style.width is much larger. |
| 107 | +- [ ] During a capped drag, `style.width` may exceed the render width (this |
| 108 | + is expected); no ResizeObserver warnings land in `console.error`. |
| 109 | +- [ ] Dragging back left respects `data-minsize: 30` (no auto-collapse via |
| 110 | + drag — only via the sidebar-toggle button). |
| 111 | +- [ ] During the drag, `panelResizeStart` / `panelResizeUpdate` / |
| 112 | + `panelResizeEnd` are re-fired on `#main-toolbar` so |
| 113 | + `lpedit-helper/resize-ruler-edit` activates the media-query ruler. |
| 114 | + |
| 115 | +## 8. Window resize while in design mode |
| 116 | + |
| 117 | +- [ ] After 20 synthetic `window.dispatchEvent(new Event("resize"))` bursts, |
| 118 | + sidebar width is unchanged (`"1000%"` short-circuits the Resizer |
| 119 | + shrink loop). |
| 120 | +- [ ] `#main-toolbar` stays flush with the window's right edge; the |
| 121 | + `applyingCollapsedLayout` guard keeps our reassertion from recursing |
| 122 | + through `EVENT_WORKSPACE_UPDATE_LAYOUT`. |
| 123 | +- [ ] With sidebar hidden, `main-toolbar` width tracks the full available |
| 124 | + width (no ~70–300px gap from WSM clamping). |
| 125 | + |
| 126 | +## 9. Plugin toolbar resizer in design mode |
| 127 | + |
| 128 | +- [ ] `#main-toolbar > .horz-resizer` has `display: none` while collapsed — |
| 129 | + user never sees / grabs it; sidebar resizer is the only splitter. |
| 130 | +- [ ] Normal mode: main-toolbar resizer is visible and draggable as usual. |
| 131 | + |
| 132 | +## 10. `WorkspaceManager.setPluginPanelWidth` in design mode |
| 133 | + |
| 134 | +- [ ] Setting width W while collapsed resizes the sidebar to |
| 135 | + `window - W - pluginIcons - 30 (CCB)` (clamped to ≥ 0) and derives |
| 136 | + main-toolbar width accordingly. |
| 137 | +- [ ] Setting width W in normal mode falls through to the original |
| 138 | + implementation (which clamps against 75% window / `window - sidebar |
| 139 | + - 100`). |
| 140 | + |
| 141 | +## 11. Cycle stability |
| 142 | + |
| 143 | +- [ ] Enter design → drag sidebar past cap → exit → re-enter: CCB, |
| 144 | + main-toolbar, sidebar all end up aligned (`ccb.left === sidebar.right`, |
| 145 | + `mainToolbar.left === sidebar.right + 30`). |
| 146 | +- [ ] After the cycle, `sidebar.style.width === sidebar.offsetWidth + "px"` |
| 147 | + (pinned at the capped value, not the uncapped Resizer value). |
| 148 | +- [ ] Toggle back to normal mode preserves live preview (panel stays open |
| 149 | + at `savedToolbarWidth` or the default). |
| 150 | + |
| 151 | +## 12. Integration with NoDistractions |
| 152 | + |
| 153 | +- [ ] Design mode + toggling `noDistractions` preference to `true`: |
| 154 | + - sidebar hides, |
| 155 | + - main-toolbar and bottom panels stay visible, |
| 156 | + - `_hidePanelsIfRequired` is NOT invoked (spy). |
| 157 | +- [ ] Design mode + toggling `noDistractions` to `false`: |
| 158 | + - sidebar shows, |
| 159 | + - `_showPanelsIfRequired` is NOT invoked. |
| 160 | +- [ ] Normal mode + toggling `noDistractions`: original behavior — |
| 161 | + `ViewUtils.hideMainToolBar()`, sidebar hide, panels hidden. |
| 162 | + |
| 163 | +## 13. Command / event surface |
| 164 | + |
| 165 | +- [ ] `WorkspaceManager.isInDesignMode` exists and returns the current state. |
| 166 | +- [ ] `WorkspaceManager.setDesignMode(true/false)` triggers |
| 167 | + `EVENT_WORKSPACE_DESIGN_MODE_CHANGE` with the new boolean. |
| 168 | +- [ ] Repeat calls to `setDesignMode` with the same value do NOT fire the |
| 169 | + event. |
| 170 | +- [ ] `exports.isEditorCollapsed()` / `setEditorCollapsed()` on CCB still |
| 171 | + work (back-compat surface). |
| 172 | + |
| 173 | +## 14. Theming / colors |
| 174 | + |
| 175 | +- [ ] CCB background is `#222` regardless of theme (sanity check with a |
| 176 | + forced light-theme and dark-theme load). |
| 177 | +- [ ] Icon color is `@project-panel-text-2`; hover transitions to |
| 178 | + `@project-panel-text-1` + `rgba(255,255,255,0.08)` overlay. |
| 179 | +- [ ] File label has `cursor: pointer` and hover adds underline. |
| 180 | + |
| 181 | +## 15. Accessibility / titles |
| 182 | + |
| 183 | +- [ ] Each CCB button has a `title` attribute (collapse, sidebar toggle, |
| 184 | + undo, redo, save, search, back, forward). |
| 185 | +- [ ] `ccbCollapseEditorBtn` title changes with state. |
| 186 | +- [ ] `ccbSidebarToggleBtn` title changes with sidebar visibility. |
| 187 | + |
| 188 | +--- |
| 189 | + |
| 190 | +## Test harness notes |
| 191 | + |
| 192 | +- The suite is expected to run under the `mainview` category (embedded |
| 193 | + Phoenix iframe). Use `SpecRunnerUtils.createWindowAndRun` or the existing |
| 194 | + mainview bootstrap. |
| 195 | +- Never use `awaits(number)` — every "wait for X" must be `awaitsFor` on a |
| 196 | + boolean condition. |
| 197 | +- Clean up between tests: |
| 198 | + - `_setEditorCollapsed(false)` (if currently collapsed), |
| 199 | + - close live preview via `FILE_LIVE_FILE_PREVIEW`, |
| 200 | + - reset sidebar width via `$("#sidebar").width("")`. |
| 201 | +- Prefer `editor.*` / `WorkspaceManager.*` APIs over reading inline styles |
| 202 | + directly; fall back to `offsetWidth` only where CSS `max-width` can make |
| 203 | + `style.width` misleading. |
0 commit comments