redesign tasks
This commit is contained in:
54
tasks/yazi-remake/01-rearchitect-nav-model.md
Normal file
54
tasks/yazi-remake/01-rearchitect-nav-model.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# 01. Rearchitect nav model — remove the sidebar pane
|
||||
|
||||
meta:
|
||||
id: yazi-remake-01
|
||||
feature: yazi-remake
|
||||
priority: P1
|
||||
depends_on: []
|
||||
tags: [implementation, nav-model, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Remove the always-on `SIDEBAR_PANE` concept from the navigation context so `activeTab` is plain tab state (not a pane), establishing clean parent|current|preview semantics for the yazi remake.
|
||||
|
||||
deliverables:
|
||||
|
||||
- `src/context/NavigationContext.tsx` — delete `SIDEBAR_PANE` constant and all references; `activeTab` is no longer a pane
|
||||
- `src/utils/navigation.ts` — update `TabPaneCount` semantics; depth-tabs = 1 focusable pane (current), the 3 visible columns are a render concern not 3 panes
|
||||
- Updated header/comment block describing the parent|current|preview model
|
||||
- `swipe()` / `popDepth()` reworked: depth-tabs `l`=drill (`open`), `h`=pop (noop at depth 0); fixed-pane tabs `h/l` move between parent/current/preview
|
||||
- Tab-enter resets focus to `DEPTH_CENTER_PANE` (current pane), not a sidebar
|
||||
|
||||
steps:
|
||||
|
||||
- Audit every reference to `SIDEBAR_PANE` across the codebase (grep)
|
||||
- In `NavigationContext.tsx`: delete the `SIDEBAR_PANE = -1` export and the `focusedIndex`/`setFocusedIndex` SIDEBAR_PANE branch added previously
|
||||
- Set the initial `activePane` signal and the tab-switch createEffect to reset to `DEPTH_CENTER_PANE` (the current pane), not `SIDEBAR_PANE`
|
||||
- Rework `swipe()` to clamp to `[0, paneCount-1]` for fixed-pane tabs (the sidebar is no longer in the chain); depth-tabs don't use `swipe` for drill/pop (that lives in Shell dispatch)
|
||||
- In `utils/navigation.ts`: confirm `TabPaneCount` reflects focusable content panes only (depth-tabs = 1, Search = 3, Player = 1); update `PANE_RATIO` leave-behind note (ratio change happens in task 02)
|
||||
- Update the file header comment block to describe parent|current|preview
|
||||
- Run `lens_diagnostics` on the two files
|
||||
|
||||
tests:
|
||||
|
||||
- Unit: `focusedIndex(DEPTH_CENTER_PANE)` on a depth-tab returns the top frame's focus; `setFocusedIndex` writes to the top frame (Arrange a tab with a 2-frame stack, Act by calling setFocusedIndex, Assert topFrame.focus updated)
|
||||
- Integration: tab-switch effect sets `activePane` to `DEPTH_CENTER_PANE` (not -1); `swipe(-1, 3)` on a fixed tab clamps to 0 not -1
|
||||
- e2e (harness): app boots with `nav.state.pane === 0` (current), not -1
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- No symbol `SIDEBAR_PANE` exists anywhere in `src/`
|
||||
- Initial `activePane` === `DEPTH_CENTER_PANE` (0)
|
||||
- Tab-enter sets `activePane` to `DEPTH_CENTER_PANE`
|
||||
- `swipe()` lower bound is 0 (no `-1`)
|
||||
|
||||
validation:
|
||||
|
||||
- `grep -rn "SIDEBAR_PANE" src/` returns nothing
|
||||
- `bun run build` passes
|
||||
- `lens_diagnostics` paths=[`src/context/NavigationContext.tsx`,`src/utils/navigation.ts`] severity=error → 0 findings
|
||||
|
||||
notes:
|
||||
|
||||
- This task unblocks 03/04/05/06. It must not delete `DEPTH_CENTER_PANE` — that constant is generalised to "the current pane" and retained
|
||||
- `SIDEBAR_ACTIONS` (added in Shell in a prior turn) is removed in task 06 (the keybind rewrite), not here — but Shell will temporarily fail to compile after this task until 05/06 land; that's expected and the build command ignores type errors, so gate success on grep + targeted diagnostics, not the full build
|
||||
56
tasks/yazi-remake/02-build-three-pane-layout-primitive.md
Normal file
56
tasks/yazi-remake/02-build-three-pane-layout-primitive.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 02. Build the reusable 3-pane layout primitive (1:3:3 ratio, stable parent slot)
|
||||
|
||||
meta:
|
||||
id: yazi-remake-02
|
||||
feature: yazi-remake
|
||||
priority: P1
|
||||
depends_on: []
|
||||
tags: [implementation, layout, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Create one reusable `<YaziPaneRow>` primitive that renders three bordered columns (parent | current | preview) at a 1:3:3 grow ratio with a stable 1/7 parent slot even when blank, so every list tab shares an identical, layout-stable shell.
|
||||
|
||||
deliverables:
|
||||
|
||||
- `src/components/YaziPaneRow.tsx` — new component: props `parent`, `current`, `preview` (Solid JSX/accessors), `parentLabel`, `currentLabel`, `previewLabel`, `focused` (boolean, defaults to current)
|
||||
- `src/utils/navigation.ts` — `PANE_RATIO` updated to `{ parent: 1, current: 3, preview: 3 }` (was `{ parent: 1, current: 4, preview: 3 }`)
|
||||
- Each pane: bordered `scrollbox` + slim header label row (height=1)
|
||||
- Parent pane keeps its 1/7 `flexGrow` slot even when empty (renders a muted placeholder, never `width:0`)
|
||||
- Focus ring (border color = accent on current; muted `border` on parent & preview)
|
||||
|
||||
steps:
|
||||
|
||||
- Set `PANE_RATIO = { parent: 1, current: 3, preview: 3 }` in `utils/navigation.ts`
|
||||
- Create `YaziPaneRow.tsx` exporting a component that lays out three `<box flexGrow={PANE_RATIO.x}>` columns in a row
|
||||
- Each column: a height-1 header `<box>` with the label text, then a `<scrollbox height="100%" border borderColor=…>` rendering the passed children
|
||||
- Thread a `theme` via `useTheme()` inside the primitive (don't require callers to pass colors)
|
||||
- `focused` prop controls which column gets the accent border — default current; parent & preview always muted
|
||||
- Ensure the parent column renders a muted placeholder box (e.g. a single `<text fg={muted}>—</text>` or empty) when its children are null, but critically keeps `flexGrow={PANE_RATIO.parent}` so width never collapses
|
||||
- Add a JSDoc header describing the yazi 1:3:3 contract
|
||||
- Run diagnostics on the new file
|
||||
|
||||
tests:
|
||||
|
||||
- Unit: the primitive renders three boxes with flexGrow 1/3/3 regardless of null children (Arrange null parent, render, Assert three columns present with correct flexGrow)
|
||||
- Integration: toggling `focused` swaps the accent border onto the requested column
|
||||
- e2e (harness): a page using the primitive shows three equal-ratio columns with the parent column visibly non-zero width even when blank
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- `PANE_RATIO` is `{ parent: 1, current: 3, preview: 3 }`
|
||||
- `YaziPaneRow` accepts parent/current/preview children + labels + focused
|
||||
- Parent column width never collapses to 0 (stable 1/7 slot)
|
||||
- Only the focused column shows the accent border
|
||||
|
||||
validation:
|
||||
|
||||
- `grep -n "PANE_RATIO" src/utils/navigation.ts` shows the new 1:3:3 values
|
||||
- `lens_diagnostics` paths=[`src/components/YaziPaneRow.tsx`,`src/utils/navigation.ts`] severity=error → 0 findings
|
||||
- Harness: render a throwaway page using `<YaziPaneRow>`; confirm 3 columns at 1:3:3 via the frame
|
||||
|
||||
notes:
|
||||
|
||||
- Independent of task 01 (no nav-state dependency) — can be built in parallel
|
||||
- Callers (tasks 03/04) pass their own parent/current/preview JSX; the primitive is purely structural
|
||||
- opentui scrollbox: use `focused` only on the current pane so scroll focus follows the cursor
|
||||
58
tasks/yazi-remake/03-convert-list-tabs-to-primitive.md
Normal file
58
tasks/yazi-remake/03-convert-list-tabs-to-primitive.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 03. Convert Feed/MyShows/Discover/Settings to the shared parent|current|preview primitive
|
||||
|
||||
meta:
|
||||
id: yazi-remake-03
|
||||
feature: yazi-remake
|
||||
priority: P2
|
||||
depends_on: [yazi-remake-01, yazi-remake-02]
|
||||
tags: [implementation, pages, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Rewrite the four depth-stack list tabs to render through `<YaziPaneRow>`, with the previous-depth list now visible in the parent pane (blank at depth 0), the current-depth list in current, and the hovered item in preview — eliminating per-page bespoke 3-column JSX.
|
||||
|
||||
deliverables:
|
||||
|
||||
- `src/pages/Feed/FeedPage.tsx` — rewritten to use `<YaziPaneRow>`; parent = previous-depth list, current = current-depth list, preview = hovered item detail
|
||||
- `src/pages/MyShows/MyShowsPage.tsx` — same conversion
|
||||
- `src/pages/Discover/DiscoverPage.tsx` — same conversion
|
||||
- `src/pages/Settings/SettingsPage.tsx` — same conversion (sections → items → editor)
|
||||
- Each page's `nav.action` handler retained but only acts on the current pane
|
||||
- All per-page bespoke row/flexbox 3-column JSX removed
|
||||
|
||||
steps:
|
||||
|
||||
- For each of the four pages, read the current implementation to extract the parent/current/preview content builders
|
||||
- Wrap the page body in `<YaziPaneRow parent={…} current={…} preview={…} focused={isActive} />`
|
||||
- Parent pane: render the previous-depth frame's list (depth-1). At depth 0 the parent receives null/placeholder (the primitive keeps the slot)
|
||||
- Current pane: the current-depth list, focusable, with `onMouseDown` row handlers calling `nav.setActivePane(DEPTH_CENTER_PANE)` + `nav.setDepthFocus(i, depth)`
|
||||
- Preview pane: hovered-item detail derived from `focusedIndex(DEPTH_CENTER_PANE)` (unchanged logic, just relocated into the preview slot)
|
||||
- Keep `pushDepth`/`popDepth` calls in the `open` action (drill) — behaviour unchanged, only layout changes
|
||||
- Remove the old inline `<box flexGrow={PANE_RATIO.parent/current/preview}>` columns in favour of the primitive
|
||||
- Verify each page's `nav.action` handler guards on `data.pane === DEPTH_CENTER_PANE && nav.activePane() === DEPTH_CENTER_PANE`
|
||||
|
||||
tests:
|
||||
|
||||
- Unit: each page's `open` action pushes a frame and the parent pane switches from blank to the previous list (Arrange depth 0, Act open, Assert stack length 2 and parent renders the old list)
|
||||
- Integration: `h` (pop) returns parent to blank at depth 0; `l` (drill) populates parent with the previous list
|
||||
- e2e (harness): Feed depth 0→1→2 shows parent blank → previous feeds list → previous episodes list; Settings sections→items→editor shows the chain in the parent pane
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- All four pages render via `<YaziPaneRow>` (no bespoke 3-column JSX remains)
|
||||
- Parent pane is blank at depth 0, populated at depth ≥ 1
|
||||
- Drilling (l/Enter) populates the parent with the previous-depth list
|
||||
- Popping (h) empties the parent back to blank at depth 0
|
||||
- j/k move focus only within the current pane
|
||||
|
||||
validation:
|
||||
|
||||
- `grep -rn "YaziPaneRow" src/pages/` returns 4 files
|
||||
- `lens_diagnostics` paths over the four page files severity=error → 0 findings
|
||||
- Harness walk: `init` → navigate Feed → `l` (drill) → `l` (drill) → `h` (pop) → `h` (pop); confirm parent slot transitions blank→list→list→blank
|
||||
|
||||
notes:
|
||||
|
||||
- Depends on 01 (pane model) and 02 (the primitive) being merged
|
||||
- The already-working `<Show when={item}>{(item) => (… item() …)}</Show>` accessor pattern for opentui `<Show>` callbacks must be preserved in preview panes
|
||||
- Keep `LoadingIndicator` usages where they exist
|
||||
52
tasks/yazi-remake/04-fit-search-and-player-panes.md
Normal file
52
tasks/yazi-remake/04-fit-search-and-player-panes.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# 04. Fit Search and Player into the 3-pane (1:3:3) model
|
||||
|
||||
meta:
|
||||
id: yazi-remake-04
|
||||
feature: yazi-remake
|
||||
priority: P2
|
||||
depends_on: [yazi-remake-01, yazi-remake-02]
|
||||
tags: [implementation, pages, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Bring the two fixed-layout tabs (Search, Player) into the same 1:3:3 parent|current|preview shell, deciding per-page whether to adopt the depth-stack or stay fixed-3-pane, while applying the new ratios throughout.
|
||||
|
||||
deliverables:
|
||||
|
||||
- `src/pages/Search/SearchPage.tsx` — rendered through `<YaziPaneRow>`; parent = query input + recent-search history, current = results list, preview = focused-result detail
|
||||
- `src/pages/Player/PlayerPage.tsx` — rendered through `<YaziPaneRow>`; current = now-playing transport, preview = episode description/notes, parent = blank placeholder (or compact episode list if available)
|
||||
- Decision recorded in each file's header comment: depth-stack vs fixed-3-pane
|
||||
|
||||
steps:
|
||||
|
||||
- Read both pages to understand their current pane semantics
|
||||
- Search: map INPUT→parent, RESULTS→current, DETAIL→preview inside `<YaziPaneRow>`. If the 1/7 parent slot is too narrow for the input box, widen parent for Search only by passing an override ratio OR move the query into current and results into parent — pick the option that keeps the input usable and document it
|
||||
- Search: keep the `inputFocused` effect (Shell yields keys to `<input>` when current-pane focus is on the query) — adapt to whichever pane the input lives in
|
||||
- Player: single content pane; parent = blank/placeholder (1/7), current = transport + progress + controls (3/7), preview = episode art/description/notes (3/7). If no preview data, render a muted placeholder but keep the slot
|
||||
- Confirm fixed-pane tab swipe (h/l between parent/current/preview) still routes correctly for Search
|
||||
- Run diagnostics
|
||||
|
||||
tests:
|
||||
|
||||
- Unit: Search's `handleSubmit` swipes to the results pane and sets focus index 0 (Arrange empty results, Act submit, Assert activePane === results pane & focusedIndex 0)
|
||||
- Integration: Player renders with parent blank and the transport in current
|
||||
- e2e (harness): Search shows query | results | detail at 1:3:3; Player shows blank | transport | notes at 1:3:3
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- Both pages render via `<YaziPaneRow>` at 1:3:3
|
||||
- Search input remains typeable (Shell yields keys when the query pane is focused)
|
||||
- Player's transport is in the current pane with focus
|
||||
- No layout collapse: parent & preview keep their slots even if blank
|
||||
|
||||
validation:
|
||||
|
||||
- `grep -rn "YaziPaneRow" src/pages/Search src/pages/Player` returns 2 files
|
||||
- `lens_diagnostics` paths over both files severity=error → 0 findings
|
||||
- Harness: navigate to Search, type a query, press Enter, see results in current + detail in preview; navigate to Player, see transport + notes
|
||||
|
||||
notes:
|
||||
|
||||
- Depends on 01 (pane model — though Search is fixed-pane, the model cleanup affects `swipe` bounds) and 02 (the primitive)
|
||||
- If Search input at 1/7 is genuinely too tight (~14 cols at 100w), prefer moving the query into the current pane for Search only and the results into parent — but confirm width with the harness before committing
|
||||
- Player is single-content; the 1:3:3 with blanks is mostly cosmetic but keeps the layout globally consistent
|
||||
56
tasks/yazi-remake/05-rebuild-shell-chrome.md
Normal file
56
tasks/yazi-remake/05-rebuild-shell-chrome.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 05. Rebuild Shell chrome — drop sidebar, add yazi bottom status/tab bar
|
||||
|
||||
meta:
|
||||
id: yazi-remake-05
|
||||
feature: yazi-remake
|
||||
priority: P1
|
||||
depends_on: [yazi-remake-01]
|
||||
tags: [implementation, shell-chrome, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Remove the always-on left tab sidebar entirely and replace it with a full-width page area above a slim yazi-style bottom bar that surfaces the active tab, depth/counts, selection, now-playing, and a discoverable tab strip.
|
||||
|
||||
deliverables:
|
||||
|
||||
- `src/components/Shell.tsx` — sidebar JSX deleted; render `LayerGraph[tab]()` full-width + a rebuilt bottom status/command bar
|
||||
- Bottom bar (normal mode): mode label, `TAB_LABEL[tab] · depth N · i/len` (or `pane i/n` for fixed tabs), selection count `●N`, now-playing `♪ title`, pending-keybind hint, and a compact tab strip `[1]Feed [2]MyShows …` with the active tab marked
|
||||
- Bottom bar (command mode): `:` prompt + buffer + error (unchanged, just relocated if needed)
|
||||
- Help overlay kept; now-playing relocated from the old sidebar footer into the status bar
|
||||
|
||||
steps:
|
||||
|
||||
- Read `Shell.tsx` and delete the entire left tab sidebar `<box flexDirection="column" width={14}>…` block
|
||||
- Replace the middle row with a single full-width `<box flexGrow={1}>{LayerGraph[nav.activeTab()]()}</box>`
|
||||
- Rebuild the bottom bar: a height-1 `<box flexDirection="row">` with the fragments described above
|
||||
- Tab strip: render `Object.values(TABS)` filtered to numbers; for each tab show `[N] Label` with the active tab inverted/highlighted (accent bg or `≡` marker)
|
||||
- Status fragment: `nav.activePane() === DEPTH_CENTER_PANE ? (isDepthTab ? \`depth ${currentDepth()}\` : \`pane ${activePane()+1}/${count}\`) : 'tabs'` — but since the sidebar is gone, default to the depth/pane string (focus starts on current)
|
||||
- Relocate `nowPlaying()` text from the sidebar footer into the bottom bar
|
||||
- Keep `runCommand`, `handleCommandKey`, the help overlay, and `playEpisodeAndSwitch` untouched
|
||||
- Run diagnostics
|
||||
|
||||
tests:
|
||||
|
||||
- Unit: `nowPlaying()` formats `♪ <truncated title>` (Arrange a current episode, Assert the string)
|
||||
- Integration: switching tabs updates the tab strip's active marker and the status tab label
|
||||
- e2e (harness): `init` shows no left sidebar, a full-width page, and a bottom bar containing the tab strip + `Feed · depth 0`; cycling tabs moves the strip's active marker
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- No `width={14}` sidebar `<box>` remains in `Shell.tsx`
|
||||
- The active page fills the full content width
|
||||
- The bottom bar shows the active tab, depth, counts, selection, now-playing, and the tab strip
|
||||
- The active tab is visually marked in the strip
|
||||
|
||||
validation:
|
||||
|
||||
- `grep -n "width={14}" src/components/Shell.tsx` returns nothing
|
||||
- `grep -n "LayerGraph" src/components/Shell.tsx` shows the full-width render
|
||||
- `lens_diagnostics` paths=[`src/components/Shell.tsx`] severity=error → 0 findings
|
||||
- Harness: `init` frame has no sidebar column and shows the tab strip in the last row
|
||||
|
||||
notes:
|
||||
|
||||
- Depends on 01 (the pane model: focus starts on current, so the status fragment no longer needs the `SIDEBAR_PANE` branch)
|
||||
- Task 06 rewrites the dispatch keybinds in this same file; do the chrome here and leave the dispatch `SIDEBAR_ACTIONS` branch for 06 to remove (or remove it here if 01 already deleted the constant — coordinate with 01)
|
||||
- `playEpisodeAndSwitch` and the command bar must keep working
|
||||
56
tasks/yazi-remake/06-rewire-keybinds.md
Normal file
56
tasks/yazi-remake/06-rewire-keybinds.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 06. Rewire keybinds — h/l drill+pop, digits switch tabs, focus starts on current
|
||||
|
||||
meta:
|
||||
id: yazi-remake-06
|
||||
feature: yazi-remake
|
||||
priority: P1
|
||||
depends_on: [yazi-remake-01, yazi-remake-05]
|
||||
tags: [implementation, keybinds, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Rewire the Shell dispatch so the sidebar's special-cased j/k branch is gone, h/l drill/pop on depth-tabs and swipe on fixed tabs, digit keys + `[ ]` are the sole tab switcher, and app focus starts on the current pane.
|
||||
|
||||
deliverables:
|
||||
|
||||
- `src/components/Shell.tsx` (dispatch) — `SIDEBAR_ACTIONS` set + the `if (nav.activePane() === SIDEBAR_PANE)` branch deleted
|
||||
- `h`/`l` unified: depth-tabs `l`=current-drills (`open` emit), `h`=current-pops (noop at depth 0); fixed-pane tabs `h/l`=`swipe(∓1, count)`
|
||||
- `1`-`6` / `tab-goto-*`, `tab-next`/`tab-prev` (`[`/`]`) — the only tab switchers
|
||||
- Initial focus + tab-enter land on `DEPTH_CENTER_PANE`
|
||||
- `keybinds.jsonc` reviewed (update labels/help only if needed)
|
||||
|
||||
steps:
|
||||
|
||||
- Read the current `dispatch()` (post task 01 it references a deleted `SIDEBAR_PANE` — fix the compile here)
|
||||
- Remove the `SIDEBAR_ACTIONS` constant and its branch
|
||||
- In the `default` case, implement: digit/tab-goto → `setActiveTab`; `swipe-prev` → (depth-tab & current & depth>0) `popDepth` else (depth-tab & current & depth==0) noop else `swipe(-1, count)`; `swipe-next` → (depth-tab & current) emit `open` else `swipe(1, count)`
|
||||
- Move/list actions (`move-down/up`, `jump-*`, `page-*`, `goto-top/bottom`) flow to `PAGE_ACTIONS` → `emit("nav.action")` for the current pane only
|
||||
- Confirm `escape`/`command`/`visual-mode`/`toggle-select`/audio/global branches unchanged
|
||||
- Verify the app boot path sets focus to current (task 01 set the signal; confirm dispatch doesn't override)
|
||||
- Run diagnostics + harness key sequence
|
||||
|
||||
tests:
|
||||
|
||||
- Unit: `dispatch("move-down")` on a depth-tab current pane emits `nav.action {action:"move-down"}` (Arrange current pane, Act, Assert emit)
|
||||
- Integration: `dispatch("swipe-next")` on a depth-tab at depth 0 emits `open` (drill); `dispatch("swipe-prev")` at depth 1 pops to depth 0; at depth 0 `swipe-prev` is a noop
|
||||
- e2e (harness): `l` drills (depth 0→1, parent populates), `h` pops (1→0, parent blanks), `1`/`2`/`3` switch tabs, `j`/`k` move the current list cursor without changing depth
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- No `SIDEBAR_PANE` or `SIDEBAR_ACTIONS` references in `Shell.tsx`
|
||||
- `h` at depth 0 is a noop (does not error, does not change pane)
|
||||
- `l` at current on a depth-tab drills (depth+1)
|
||||
- Digit keys switch tabs; focus lands on current pane
|
||||
- `j`/`k` move within current only
|
||||
|
||||
validation:
|
||||
|
||||
- `grep -n "SIDEBAR" src/components/Shell.tsx` returns nothing
|
||||
- `lens_diagnostics` paths=[`src/components/Shell.tsx`] severity=error → 0 findings
|
||||
- Harness: `init` (focus on current) → `l` (depth 1, parent filled) → `l` (depth 2) → `h` (depth 1) → `h` (depth 0, parent blank) → `3` (Discover tab, focus on current) → `j`/`k` move
|
||||
|
||||
notes:
|
||||
|
||||
- Depends on 01 (pane model: `swipe` bounds, no SIDEBAR) and 05 (dispatch lives in the rebuilt Shell)
|
||||
- If `keybinds.jsonc` has a `tab-next`/`tab-prev` mapping conflict, resolve here
|
||||
- The noop `h` at depth 0 should feel inert (yazi: at root, `h` does nothing)
|
||||
60
tasks/yazi-remake/07-verify-remake.md
Normal file
60
tasks/yazi-remake/07-verify-remake.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# 07. Verify the remake — build + diagnostics + harness walk-through
|
||||
|
||||
meta:
|
||||
id: yazi-remake-07
|
||||
feature: yazi-remake
|
||||
priority: P1
|
||||
depends_on: [yazi-remake-03, yazi-remake-04, yazi-remake-05, yazi-remake-06]
|
||||
tags: [verification, tests-required]
|
||||
|
||||
objective:
|
||||
|
||||
- Confirm the yazi remake meets every exit criterion via a clean build, zero diagnostics, and a full harness walk-through of every tab and depth.
|
||||
|
||||
deliverables:
|
||||
|
||||
- A passing `bun run build`
|
||||
- `lens_diagnostics mode=all` with zero errors across edited files
|
||||
- Harness frames + state proving the parent|current|preview 1:3:3 layout, drill/pop behaviour, tab switching, and status bar across all six tabs
|
||||
|
||||
steps:
|
||||
|
||||
- Run `bun run build` — expect "Build complete"
|
||||
- Run `lens_diagnostics mode=all severity=error` — expect 0 findings across all session-edited files
|
||||
- Run the drive harness (`scripts/tui-harness.tsx`) walk-through:
|
||||
- `init` → confirm no sidebar, 3 columns at 1:3:3, focus on current, bottom tab strip visible
|
||||
- Feed: `l` (depth 0→1, parent fills) → `l` (1→2) → `h` (2→1) → `h` (1→0, parent blanks) ; `j`/`k` move current
|
||||
- `2` → MyShows: drill show→episodes, parent reflects
|
||||
- `3` → Discover: category→results, parent shows categories
|
||||
- `6` → Settings: sections→items→editor, parent shows the previous list at each depth
|
||||
- `4` → Search: query|results|detail at 1:3:3; type + Enter works
|
||||
- `5` → Player: blank|transport|notes at 1:3:3
|
||||
- Capture the status bar content (active tab + depth + counts + now-playing + tab strip) from a representative frame
|
||||
|
||||
tests:
|
||||
|
||||
- Build: `bun run build` exits 0 with "Build complete"
|
||||
- Diagnostics: `lens_diagnostics` mode=all → 0 errors
|
||||
- Harness (integration/e2e): the walk-through above produces the expected frames & state (parent blank at depth 0, populates on drill, blanks on pop; digits switch tabs; h noop at depth 0)
|
||||
|
||||
acceptance_criteria:
|
||||
|
||||
- `bun run build` passes
|
||||
- `lens_diagnostics` mode=all reports zero errors
|
||||
- All six tabs render 3 stable columns at 1:3:3
|
||||
- Parent pane is blank at depth 0; drill fills it with the previous-depth list; pop empties it
|
||||
- `h` is a noop at depth 0; `l` drills; `1-6`/`[`/`]` switch tabs; `j/k` move current only
|
||||
- No sidebar; focus starts on current; bottom bar shows active tab + depth + counts + tab strip
|
||||
|
||||
validation:
|
||||
|
||||
- `bun run build 2>&1 | tail -3` → "Build complete"
|
||||
- `lens_diagnostics` mode=all severity=error → "No error issues…"
|
||||
- Harness `state nav` after `init` shows `pane === 0` (current), not -1
|
||||
- Harness frames for Feed depth 0/1/2 show the parent slot transition blank→list→list
|
||||
|
||||
notes:
|
||||
|
||||
- This is the gate for the whole feature — do not mark done if any criterion fails; open a blocker task instead
|
||||
- If the harness reveals a visual regression (e.g. parent collapses, ratios off), file it against the responsible task (02 or 03) rather than patching here
|
||||
- Save a representative `.harness/last-frame.txt` snapshot if a visual reference is useful for future sessions
|
||||
40
tasks/yazi-remake/README.md
Normal file
40
tasks/yazi-remake/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Yazi UI Remake
|
||||
|
||||
Objective: Remake the PodTUI shell into a yazi-pure parent|current|preview 3-pane layout (1:3:3 ratio) with a bottom tab strip and no always-on sidebar.
|
||||
|
||||
Status legend: [ ] todo, [~] in-progress, [x] done
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] 01 — rearchitect-nav-model → `01-rearchitect-nav-model.md`
|
||||
- [ ] 02 — build-three-pane-layout-primitive → `02-build-three-pane-layout-primitive.md`
|
||||
- [ ] 03 — convert-list-tabs-to-primitive → `03-convert-list-tabs-to-primitive.md`
|
||||
- [ ] 04 — fit-search-and-player-panes → `04-fit-search-and-player-panes.md`
|
||||
- [ ] 05 — rebuild-shell-chrome → `05-rebuild-shell-chrome.md`
|
||||
- [ ] 06 — rewire-keybinds → `06-rewire-keybinds.md`
|
||||
- [ ] 07 — verify-remake → `07-verify-remake.md`
|
||||
|
||||
## Dependencies
|
||||
|
||||
- 03 depends on 01
|
||||
- 03 depends on 02
|
||||
- 04 depends on 01
|
||||
- 04 depends on 02
|
||||
- 05 depends on 01
|
||||
- 06 depends on 01
|
||||
- 06 depends on 05
|
||||
- 07 depends on 03
|
||||
- 07 depends on 04
|
||||
- 07 depends on 05
|
||||
- 07 depends on 06
|
||||
|
||||
## Exit criteria
|
||||
|
||||
- The feature is complete when the left tab sidebar is gone; tabs switch only via digit keys `1-6` / `[ ]` and a bottom tab strip
|
||||
- All tabs render three stable columns at 1/7 : 3/7 : 3/7 (parent | current | preview)
|
||||
- The parent pane renders the previous-depth list and is blank (but keeps its 1/7 slot) at depth 0
|
||||
- `h`/`l` drill (push) and pop depths on list tabs; `h` is a noop at depth 0
|
||||
- `j`/`k` move within the current pane only; focus starts on the current pane
|
||||
- Feed depth 0→1→2, MyShows, Discover, Settings (sections→items→editor), Search, and Player all render correctly via the drive harness
|
||||
- `bun run build` passes and `lens_diagnostics` (mode=all) reports zero errors
|
||||
- The bottom status bar shows active tab + depth + counts, selection count, now-playing, and the tab strip
|
||||
Reference in New Issue
Block a user