docs: design — video notes view as a navigation-native, pane-scoped view mode (#335)#338
docs: design — video notes view as a navigation-native, pane-scoped view mode (#335)#338spolakh wants to merge 6 commits into
Conversation
…iew mode Design doc for Stvad#335: pane view modes as URL slot-grammar leaf annotations (b~video-notes) backed by panel-row props, a companion generic maximize-pane gesture (~max), and a two-stage playback-continuity plan. Adversarially reviewed against the current routing/projection/panelHistory code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n, string[] caveat Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex pls review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1976352675
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| <li>Enter/exit (<code>enterVideoNotesView</code>, the toggle action, the close button) write <code>panelViewModeProp</code> on the panel row instead of <code>videoPlayerViewProp</code>. <code>videoPlayerViewProp</code> is deleted; stale <code>video:playerView</code> values on blocks are simply ignored (it was UiState, nothing durable depends on it).</li> | ||
| <li><strong>Presentation: pane takeover, not viewport takeover.</strong> The notes layout drops <code>fixed inset-0 z-50</code> for <code>absolute inset-0</code> within the pane (the pane is <code>relative</code>). With a single pane this looks nearly identical (header stays visible); with splits, other panes stay usable — which is what "notes view in <em>this</em> pane" means. This is a deliberate behavior change and called out in the upstream issue.</li> | ||
| <li>Shortcut surface, <code>videoPlayerBlockId</code> context, timestamp/focus actions, and the pane-ratio pref are untouched: the same <code>VideoPlayerRenderer</code> wraps the block and the layout still mounts <code>Shell</code>.</li> | ||
| <li><strong>Per-pane player identity (fixes the §2 registry collision).</strong> Goal 3 ("two panes, same video, one in notes view") makes the shared-scope collision first-class, so PR 1 threads the panel id into the top-level render scope (<code>outlineRenderScopeId</code> gains a panel discriminator at the <code>PanelRenderer</code> call site) — registry handles, and therefore <code>video.insert_timestamp</code> / <code>video.toggle_focus</code>, resolve per pane. Without this, goal 3 only holds for <em>different</em> videos.</li> |
There was a problem hiding this comment.
Update every top-level render-scope producer
Threading the panel id only at the PanelRenderer call site leaves several non-rendering producers of top-level scope IDs on the old outline:<blockId> format: writePanelContent seeds focusedBlockLocationProp with outlineRenderScopeId(blockId) (src/utils/panelHistory.ts:226-229), new panel rows do the same (src/utils/panelLayoutProjection.ts:341-345), and global shortcuts target the active panel with outlineRenderScopeId(activeTopLevelBlockId) (src/shortcuts/defaultShortcuts.ts:188-191). If the rendered video registers under a panel-qualified scope but these callers keep writing/resolving the block-only scope, focus restoration and scoped video actions in duplicate-video panes will still miss the intended pane or fall back to an arbitrary player; the implementation plan should explicitly update these producers too.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — folded in. The doc now specifies the change as one shared derivation moved wholesale: a panel-qualified panelRenderScopeId(panelId, blockId) adopted by every top-level scope producer (PanelRenderer, writePanelContent/createPanelRowInTx focus seeding, defaultShortcuts.ts:190, the focusBlock default at properties.ts:384, and the selection.ts:447 fallback — your list plus the two you didn't hit), with embed scopes explicitly out of scope and a test for focus restoration + scoped actions with the same video in two panes. §4.3 + §6 updated.
Addresses codex review: panelRenderScopeId(panelId, blockId) as the single derivation adopted by every top-level scope producer (panelHistory, createPanelRowInTx, defaultShortcuts, focusBlock default, selection fallback); embed scopes untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
proposed url format feels arbitrary, and suggests that we potentially may want future extensions, what if we afford for that by allowing encoding arbitrary key-value context after block uid? |
|
|
also curious: any interactions with #332 ? |
|
kv context: agreed — the positional tokens forced a pile of disambiguation rules (reserved set, first-token-wins, drop-extras) that exist only because the tokens are anonymous. Proposed shape: Layout consumption: unchanged — the custom view stays a One shortcut: preserved — #332: no substrate overlap (threads are normal blocks; this is UiState panel-row props + the URL). Two real touchpoints: (1) terminology — I'll rename our "leaf annotations" to slot context so "annotations" stays #332's word; (2) if comments ever want per-pane state (comments panel visible, deep-link to a thread), this kv channel is exactly where it'd live — likely the "second consumer" that would justify graduating the opaque Updating the doc to the kv shape + rename + one-shortcut default now. |
uh no need is ~max shortcut for ~max=true in kv schema? |
|
what if value needs to contain ~ |
|
Value containing Rename — heard, no collision-driven need; I kept "slot context" anyway since it describes the kv shape better than "annotation" described the positional tokens (that name got weird once tokens stopped being anonymous). Zero-cost to flip back if you have a preference. Folding the |
…ut default Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
hmm, we're inventing this whole new grammar, do we have to, can we just use an existing well-known format? |
|
Fair challenge — and there is a well-known format for exactly this: matrix URI parameters ( So:
What still needs pinning regardless of syntax (any format needs these, so they're semantics, not grammar invention): duplicate keys first-wins, unknown keys preserved verbatim through parse→build, boolean normalization, canonical key order for idempotent rebuilds. One honest trade-off: |
|
ok, better. remind me why we're not using most starndard/boring query params format ?key=val&key2=val ? |
|
Two reasons, one conceptual, one mechanical-to-this-codebase:
So: query params = right format for URI-scoped state (and that's exactly what the existing Proceeding with |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Doc updated to matrix params: |
|
I see so we can't be like ws/a?k=v/b/c?k2=v ? |
|
Right — that shape isn't available, for one standard reason and one local one:
So: |
|
btw we don't care about backward compat on this for now - with that in mind, should we consider refactoring our url format to be better - come up with a few potential designs and lmk what you think overall |
|
Good frame. Current format's actual warts, judged with compat off the table: the bespoke stack syntax A. Status quo + matrix params (what the doc says today) B. Three separators, all standard — C. Layout as one structured query param D. Encoded-blob (base64 JSON tree) Overall take: B. It's the same refactor PR 1 already touches (
No version marker while compat stays free; if the format changes again post-adoption, a one-char version prefix can be introduced then. If B works for you I'll fold it into the doc (it shrinks §4.2 — the stack-parsing special cases go away). |
|
b if you look at original docs/git history I do think parens are there to enable depth/sub-splits. is there a version of this that preserves that option?
sure let's add this |
|
Yes — B generalizes to a recursive grammar where parens return as pure grouping, exactly preserving the depth option while never appearing at today's depth:
Folding B'+active into the doc now — §4.2 gets simpler (the |
|
make sense. should we fold mobile front/focused tab situation too, or is it just "max" ? |
|
It's
So: no new key, one sentence in the doc making the mobile equivalence explicit. |
…s, mobile front-tab) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Design doc for #335 — video notes view as a navigation-native, pane-scoped view mode.
Read it rendered: docs/video-notes-navigation-native.html (self-contained HTML, dark-mode aware, two SVG figures).
Summary of what it proposes (details, file:line grounding, alternatives, and test plan in the doc):
#ws/a/b~video-notes/c: a plugin-owned pane view mode projected from a newpanel:viewModepanel-row prop throughparseSlot/buildLayoutSlot/layoutSlotsFromRows/sameLayoutSlots/reconcilePanelRows(row reused on annotation-only diffs; LCS plan-matching needs no change — it's id-only). History entries, Back/Forward, session restore, and layout-serializing consumers then work via the existing projection machinery.absolute inset-0) instead of the viewport-fixed overlay;video:playerViewretired; mode cleared on in-pane navigation withVisitStatecapture (slot annotation authoritative on URL-driven reconcile); note auto-creation stays gesture-only (navigation never writes the document); a composednavigateInPanel(…, {viewMode})so nested-video enter is one tx/one history entry; per-pane player identity (panel discriminator in the top-level render scope — fixes the existing registry collision when two panes show the same video).~maxannotation +panel:maximized, rendered via a desktop analog of LayoutRenderer's mobile single-pane path, with the maximized row coerced to be the active panel.moveBefore/native-<video>limits documented).The doc went through an adversarial review pass against the current code — every cited mechanism (
pushHashon slot change, LCS row reuse,reconcileUrlNavigationblockId matching, mobile single-pane path, UiState sync semantics) was verified at the cited lines as of fad09f9.Happy to iterate on any of it — grammar char and the
maxreservation especially need your sign-off before I start on the implementation PR.Closes nothing on merge (design only); implementation will follow as PR 1 (annotations + video plugin) and PR 2 (maximize) per §6 of the doc.
🤖 Generated with Claude Code