Put the pager back, and let any turn be played again
SP7 replaced the pager with chips, on the grounds that a chip could also offer "take this path" while a pager could only step. Driving it by hand said otherwise, and the reason is worth keeping: the chip meant two different things depending on where the reader was standing -- a real switch at the tip, a preview needing a second button above it further back. Two meanings in one control is what made the tree unusable. So: one control that does one thing. Stepping reads a take and nothing else, and it tells the server nothing, because reading is not a decision. The transcript below a take that is not live simply ends -- such a take is a leaf by construction, since whatever was played after the turn was played after the take that *is* live. The decision is made by writing, and `after_id` carries it. One step does reach the server and is still not a fork: a take with a story of its own lives on its own branch, so going there is a branch switch and only the server can say what is underneath. `branch_id` on the take is what tells the two apart without asking first. And a fork button on every turn but the opening. On the AI's it regenerates; on your own it opens the text so you can say something else. What the story made of the old take is kept, on the line it was written on. `selectVariant` and `forkFromAttempt` leave the client. Both endpoints stay -- tested, and `stand_on` is shared with the write path -- but the pager needs neither. 426 backend tests; lint and build clean. Not yet driven by hand: the frontend still has no test runner, so this needs the `--keep` fixture and eyes, exactly as SP7 did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Dvvqn9ZDR4ixeFPHNbww7
This commit is contained in:
committed by
Parth
co-authored by
Claude Opus 5
parent
ea7336e5d3
commit
f9b836fc0b
+32
-33
@@ -426,51 +426,50 @@ button:disabled { opacity: 0.45; cursor: default; transform: none; box-shadow: n
|
||||
}
|
||||
.story .action-tools button:hover { color: var(--text); }
|
||||
|
||||
/* The attempts at one AI beat. Stays quiet until hovered — it's a footnote on
|
||||
the message, not part of the prose. */
|
||||
.attempts {
|
||||
/* The takes of one turn: ‹ 2/4 ›. Stays quiet until hovered — it's a footnote
|
||||
on the message, not part of the prose.
|
||||
|
||||
Small and unemphatic on purpose. Stepping through takes reads them and does
|
||||
nothing else, so it should not carry the visual weight of a decision; the
|
||||
decision is made by writing, which happens in the composer below. */
|
||||
.take-pager {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
gap: 2px;
|
||||
margin-top: 6px;
|
||||
font-family: var(--font-ui);
|
||||
opacity: 0.45;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.story .action:hover .attempts,
|
||||
.attempts:focus-within { opacity: 1; }
|
||||
.attempt-chip {
|
||||
padding: 3px 10px;
|
||||
font-size: 0.73rem;
|
||||
line-height: 1.5;
|
||||
border-radius: 999px;
|
||||
.story .action:hover .take-pager,
|
||||
.take-pager:focus-within { opacity: 1; }
|
||||
.take-pager button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1;
|
||||
color: var(--text-dim);
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.attempt-chip:hover:not(:disabled) { color: var(--text); border-color: var(--border-bright); }
|
||||
.attempt-chip[aria-pressed="true"] {
|
||||
color: var(--bg);
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
font-weight: 600;
|
||||
.take-pager button:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: var(--border-bright);
|
||||
}
|
||||
.attempt-chip:disabled { opacity: 0.35; cursor: default; }
|
||||
/* Dashed until hovered: taking a path the story moved past creates a branch,
|
||||
so it should not look like the same weight of click as browsing one. */
|
||||
.take-path {
|
||||
padding: 3px 10px;
|
||||
font-size: 0.73rem;
|
||||
line-height: 1.5;
|
||||
color: var(--accent);
|
||||
background: transparent;
|
||||
border: 1px dashed var(--accent-dim);
|
||||
.take-pager button:disabled { opacity: 0.3; cursor: default; }
|
||||
.take-count {
|
||||
min-width: 30px;
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.take-path:hover:not(:disabled) { color: var(--accent-bright); border-style: solid; }
|
||||
.take-path:disabled { opacity: 0.35; cursor: default; }
|
||||
.attempt-note {
|
||||
margin-left: 2px;
|
||||
/* Only while a take that isn't the live one is on screen: it says what the
|
||||
next thing typed will do, because that is the click that forks. */
|
||||
.take-note {
|
||||
margin-left: 6px;
|
||||
font-size: 0.72rem;
|
||||
font-style: italic;
|
||||
color: var(--accent-dim);
|
||||
|
||||
Reference in New Issue
Block a user