@kitlangton/knobs 0.4.0-next.5 → 0.4.0-next.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/dev/{chunk-y2axkmz3.js → chunk-nhz9en4k.js} +1 -1
- package/dist/dev/{chunk-qc6szek7.js → chunk-ya44t7z5.js} +7 -3
- package/dist/dev/index.js +3 -3
- package/dist/panel.js +7 -3
- package/dist/types/ui/compare-css.d.ts +1 -1
- package/dist/types/ui/compare-gpu.d.ts +2 -0
- package/dist/types/ui/compare-model.d.ts +25 -6
- package/dist/types/ui/index.d.ts +2 -1
- package/dist/types/ui/player-css.d.ts +1 -1
- package/dist/types/ui/walkthrough-annotations.d.ts +42 -0
- package/dist/types/ui/walkthrough-blocks.d.ts +6 -4
- package/dist/types/ui/walkthrough-model.d.ts +46 -9
- package/dist/ui-react.js +1601 -320
- package/dist/ui-solid.js +1613 -332
- package/dist/ui.js +5547 -4264
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1359,11 +1359,11 @@ const w = walkthrough(container, { doc, onFeedback: (fb) => send(fb) })
|
|
|
1359
1359
|
|
|
1360
1360
|
A section's meta line leads with its **kicker** in text colour: `"PR 2 of 5"` by default where its `link` is a pull request (counted among the sections that link one). The doc's `kickers` counts with another noun, `{ noun: "Part" }` giving every section "Part 2 of 6", or none with `false`. A section's own `kicker: "Epilogue"` wins over its count and `kicker: false` hides it, without renumbering the rest. The contents rail isn't numbered. Its PR link follows in faint, joined by `·` (its `status` only with review on). One type scale: the page's title 20/28, a section's 16/24, a step's 13/20 at 500, prose 13/20 in the second ink, meta 11/16 in the third. Steps aren't numbered on screen, but a ref still names one by its key, id or number (`"1.2"`): `step` on an update, a history event, a stack item or a table cell, and clicking goes there as `j` / `k` do.
|
|
1361
1361
|
|
|
1362
|
-
By default the page only shows: no progress, notes or Copy feedback, no key hints, and a step's `options` sit side by side under their labels. `review: true` brings Kit's review tools back: the progress in the rail, Copy feedback, picking between options (`1`–`9`) and the note bar. With review on, notes come from a launcher in the column's corner (`noteBar: "collapsed"`, the default) that opens into the bar on a click, `n`, a recording or ink, and folds back when it's empty; `"docked"` keeps the bar there, `"hidden"` drops it (`w.send()` still works). Typed, spoken or inked, each note carries what was on show (a video's time and chapter, a compare's loop and zoom, a diff's file) and a short log of what led up to it; `onFeedback`, `w.feedback` and `w.markdown()` hand it back. The page keeps the bar's height clear at its end and as its scroller's `scroll-padding-bottom`, so `j` / `k`, `go()` and the last step never land under it, and full window stops above it. `j` / `k` move between steps (`Home` / `End` to the first and last), `←` / `→` seek, `f` goes full window, `n` writes a note, `1`–`9` pick.
|
|
1362
|
+
By default the page only shows: no progress, notes or Copy feedback, no key hints, no statuses (a section's or an update's) and no counts, and a step's `options` sit side by side under their labels. `review: true` brings Kit's review tools back: the progress in the rail and its state dots, statuses, Copy feedback, picking between options (`1`–`9`) and the note bar. With review on, notes come from a launcher in the column's corner (`noteBar: "collapsed"`, the default) that opens into the bar on a click, `n`, a recording or ink, and folds back when it's empty; `"docked"` keeps the bar there, `"hidden"` drops it (`w.send()` still works). Typed, spoken or inked, each note carries what was on show (a video's time and chapter, a compare's loop and zoom, a diff's file) and a short log of what led up to it; `onFeedback`, `w.feedback` and `w.markdown()` hand it back. The page keeps the bar's height clear at its end and as its scroller's `scroll-padding-bottom`, so `j` / `k`, `go()` and the last step never land under it, and full window stops above it. `j` / `k` move between steps (`Home` / `End` to the first and last), `←` / `→` seek, `f` goes full window, `n` writes a note, `1`–`9` pick.
|
|
1363
1363
|
|
|
1364
|
-
Media is a bare URL (a video or picture), or `compare`, `video`, `image`, `diff`, `code`, `terminal`, `metric`, `callout`, `text`, `history`, `stack`, `table`, or `mount` (your own, `(el) => cleanup`; the one that isn't JSON). A step's media sit one under another (a group's room apart); `columns: 2` sets them side by side where there's room. Every
|
|
1364
|
+
Media is a bare URL (a video or picture), or `compare`, `video`, `image`, `diff`, `code`, `terminal`, `metric`, `callout`, `text`, `history`, `stack`, `table`, or `mount` (your own, `(el) => cleanup`; the one that isn't JSON). A step's media sit one under another (a group's room apart); `columns: 2` sets them side by side where there's room. Every picture, video and compare stage (and a slot still loading) takes the same frame: the panel radius and a quiet fill, no ring. A diff, code and a terminal sit in one plain container: a flat inset fill, a hairline ring, the control radius and room inside. Nothing in a walkthrough is glass. A metric, a callout, a table, a stack and a history sit on the page. A slot's `label` reads as written (sentence case), small and faint above it.
|
|
1365
1365
|
|
|
1366
|
-
**Keep it scannable.** A step's title is its claim, in about ten words; its caption is one sentence; everything else goes in `more` (Markdown, blank lines between paragraphs), folded under the caption behind a small **More** toggle whose height springs open on the state spring while the words fade
|
|
1366
|
+
**Keep it scannable.** A step's title is its claim, in about ten words; its caption is one sentence; everything else goes in `more` (Markdown, blank lines between paragraphs), folded under the caption behind a small **More** toggle whose height springs open on the state spring while the words come into focus (a fade with a small blur, from the top). Sections take `more` under their summary, and the page under its own. Media that mounts after the first paint (near the view, or a picture still loading) comes in the same way; nothing moves on load.
|
|
1367
1367
|
|
|
1368
1368
|
```json
|
|
1369
1369
|
{ "title": "Retired models get a way out", "caption": "After: **Pick another model**, and the prompt back.",
|
|
@@ -1372,7 +1372,7 @@ Media is a bare URL (a video or picture), or `compare`, `video`, `image`, `diff`
|
|
|
1372
1372
|
|
|
1373
1373
|
**Pull requests** read as small chips: an icon for their state, the number, the title and state on hover, in a quiet tint (open green, merged violet, draft and closed neutral). A section's PR `link` shows as its chip on the meta line ("PR 3 of 9 · ⟨#57158⟩"), and in titles, captions, summaries and `more`, a link to a pull request whose words are its number, and a bare `#57148` the page can resolve, become chips too. The doc's `prs` gives their state and title by number (`{ "57148": { state: "merged", title: "…" } }`), and `repo: "owner/name"` links bare numbers it doesn't list. So a caption needn't spell out "#57158 (Draft · Green)".
|
|
1374
1374
|
|
|
1375
|
-
**The feed** (`updates` and `qa`, newest first) is a calm list a group's room apart, a hairline between items and no boxes: a meta line (when · the step's PR
|
|
1375
|
+
**The feed** (`updates` and `qa`, newest first) is a calm list a group's room apart, a hairline between items and no boxes: a meta line (when · the step's PR, and `status` with review on), the question in text colour (or the update), its answer in dim prose, and its `trail` (what Kit did before asking, `"0:04 · Played the compare"`) folded under a small faint **Context** toggle whose height springs open on the state spring (.3 s) while the lines fade in place under a soft bottom edge. `status: "shipped"` reads Shipped, `"changes"` reads Changes queued.
|
|
1376
1376
|
|
|
1377
1377
|
```json
|
|
1378
1378
|
{ "qa": [{ "at": "2026-10-19T12:10:00-07:00", "q": "Why is there no video for #57158?",
|
|
@@ -1382,7 +1382,7 @@ Media is a bare URL (a video or picture), or `compare`, `video`, `image`, `diff`
|
|
|
1382
1382
|
|
|
1383
1383
|
The demo is `examples/walkthrough.html`.
|
|
1384
1384
|
|
|
1385
|
-
**`history`**:
|
|
1385
|
+
**`history`**: drawn by **`history(container, { data })`** (also exported on its own): a shared date axis (month ticks, today's line) over lanes, one per channel or track, each carrying spans whose tone says their state, marks for releases and deletions, faint bands for phases; hovering shows a date line and a tooltip, and a click or `←` / `→` opens one detail area under the chart. Write the lanes shape (`lanes: [{ id, label, spans: [{ from, to?, state, label?, detail?, provenance?, evidence?, step? }] }]`, `events: [{ date, lane?, title, type?, tone?, provenance?, step? }]`, `bands`, `states`, `axis`), or the older groups of dated events below, which it lays on one code lane under a band per heading. `provenance: "inferred"` hatches a span and hollows a mark; a `step` gets "Go to step" in the detail; `label` names it, and `marks` picks which event types are marked from the start (releases and deletions, or `"all"`).
|
|
1386
1386
|
|
|
1387
1387
|
```json
|
|
1388
1388
|
{ "kind": "history", "groups": [{ "heading": "v2 dropped it", "summary": "Jun 26 – Jul 30", "events": [
|
|
@@ -1403,7 +1403,7 @@ The demo is `examples/walkthrough.html`.
|
|
|
1403
1403
|
"delta": { "add": 446, "del": 47 }, "status": "Stacked on #57146", "tone": "good", "summary": "Modal, notice and prompt recall." } ] }
|
|
1404
1404
|
```
|
|
1405
1405
|
|
|
1406
|
-
**`table`**: a real `<table>` for audits and matrices. Rows are cells by column key, bare or under `cells`; a cell is text, a number, or `{ text, href?, code?, badge?, tone?, step? }` (a `badge` is a tone chip). Columns take `mono` and `align` (number columns go right by themselves). Figures are tabular; a tall table keeps its head stuck, and its bars show thin on hover. `caption` goes under it. Where the step is narrower than the columns' natural width (long text keeping a measure, code on one line), each row becomes a block: its `primary` cell (the first column by default) as its title with its badges at the end of the line, the rest as term and value under it, the blocks parted by hairlines. `stack: "always"` always stacks; `stack: "never"` scrolls across instead, edges fading where there's more.
|
|
1406
|
+
**`table`**: a real `<table>` for audits and matrices. Rows are cells by column key, bare or under `cells`; a cell is text, a number, or `{ text, href?, code?, badge?, tone?, step? }` (a `badge` is a tone chip). A row with a `step` on any cell goes there: the whole row, a wash under the pointer, Enter when it has focus, and nothing trailing it, so every row lines up. Columns take `mono` and `align` (number columns go right by themselves). Figures are tabular; a tall table keeps its head stuck, and its bars show thin on hover. `caption` goes under it. Where the step is narrower than the columns' natural width (long text keeping a measure, code on one line), each row becomes a block: its `primary` cell (the first column by default) as its title with its badges at the end of the line, the rest as term and value under it, the blocks parted by hairlines. `stack: "always"` always stacks; `stack: "never"` scrolls across instead, edges fading where there's more.
|
|
1407
1407
|
|
|
1408
1408
|
```json
|
|
1409
1409
|
{ "kind": "table", "caption": "From a clean HOME, Oct 20", "columns": [
|
|
@@ -1414,6 +1414,8 @@ The demo is `examples/walkthrough.html`.
|
|
|
1414
1414
|
{ "channel": "brew install …/opencode-v2", "days": 31, "state": { "text": "Pending", "badge": "info", "step": "4.6" } } ] }
|
|
1415
1415
|
```
|
|
1416
1416
|
|
|
1417
|
+
**`annotations`** on an `image`, a `video` or a `compare` draw the eye to what matters: `[{ x, y, w?, h?, label?, at?: [start, end], shape?: "box" | "dot" | "arrow" }]`, in 0–1 of the picture (a box's top-left, or the point). A box takes a calm ring, a point a dot (or an arrow pointing at it), each with a small label; on a video or compare one shows only between its `at` seconds, fading in and out with a small blur. On a compare they're drawn on both sides and stay on their spot through a zoom. They're on by default; the eye button on the picture, or `a`, hides or shows every one on the page.
|
|
1418
|
+
|
|
1417
1419
|
**`chapters`** on a `video` (or a `compare`): a readout list under it, a row each (number · label · start). A click selects the chapter at once while the media seeks there and plays, and goes in the note's log; the selection pill slides to the chapter playing (the last that started at or before the playhead) and fades out in place outside them, and a note's `media` names it (`chapter`). A chapter ends at `end`, else `start + duration`, else the next one's start. On a compare they're also its timeline's markers. A video's `captions` (or `captionsSrc`) is a WebVTT URL, shown by default.
|
|
1418
1420
|
|
|
1419
1421
|
```json
|
|
@@ -85,7 +85,7 @@ function attach(controls, element, options = {}) {
|
|
|
85
85
|
return;
|
|
86
86
|
loading = !0;
|
|
87
87
|
try {
|
|
88
|
-
let { createPanel } = await (__preload("
|
|
88
|
+
let { createPanel } = await (__preload("ya44t7z5"), import("./chunk-ya44t7z5.js"));
|
|
89
89
|
if (disposed || !controls.enabled || panel)
|
|
90
90
|
return;
|
|
91
91
|
if (panel = createPanel(controls, element, close, { restored, chip }), remember)
|
|
@@ -11455,11 +11455,11 @@ var compareCss = `
|
|
|
11455
11455
|
.knobs-cmp-modes[hidden]{display:none}
|
|
11456
11456
|
.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
|
|
11457
11457
|
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
11458
|
-
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
11458
|
+
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
11459
11459
|
/* Toggles: icon buttons, the accent's wash when on. */
|
|
11460
11460
|
.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-3);cursor:pointer;
|
|
11461
11461
|
transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
11462
|
-
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}
|
|
11462
|
+
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
11463
11463
|
.knobs-ui .knobs-cmp-toggle[aria-pressed="true"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}
|
|
11464
11464
|
.knobs-cmp-toggle svg{display:block}
|
|
11465
11465
|
.knobs-cmp-fill{flex:1}
|
|
@@ -11525,7 +11525,7 @@ var compareCss = `
|
|
|
11525
11525
|
.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}
|
|
11526
11526
|
:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;
|
|
11527
11527
|
display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}
|
|
11528
|
-
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent)}
|
|
11528
|
+
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
11529
11529
|
.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);font-size:var(--_k-text-meta);pointer-events:none}
|
|
11530
11530
|
.knobs-cmp-note:empty{display:none}
|
|
11531
11531
|
.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}
|
|
@@ -11556,6 +11556,10 @@ var playerCss = `
|
|
|
11556
11556
|
.knobs-player-glyph svg{width:16px;height:16px}
|
|
11557
11557
|
.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}
|
|
11558
11558
|
.knobs-player-line{flex:none;min-height:0}
|
|
11559
|
+
/* Hover in is immediate (0 ms), out eases. The timeline's own stylesheet is look.ts's; its hover
|
|
11560
|
+
states are set here, after it, so the player's line and every timeline share them. */
|
|
11561
|
+
.knobs-ui .knobs-tl-play:hover,.knobs-tl-edge:hover::after,.knobs-tl-rlabel:hover,.knobs-tl-track:hover .knobs-tl-hover,
|
|
11562
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-track:hover .knobs-tl-segs{transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
11559
11563
|
`;
|
|
11560
11564
|
|
|
11561
11565
|
// src/ui/overlay-css.ts
|
package/dist/dev/index.js
CHANGED
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
urlFlag2,
|
|
77
77
|
storageKey
|
|
78
78
|
} from "./chunk-3ygqgy1x.js";
|
|
79
|
-
__chunks(import.meta.url,["
|
|
79
|
+
__chunks(import.meta.url,["535tjwkq","ya44t7z5","nhz9en4k","3ygqgy1x","dyq4m24m"],[["./index.js",3],["./chunk-ya44t7z5.js",3,4],["./chunk-nhz9en4k.js",3,4],["./chunk-3ygqgy1x.js"],["./chunk-dyq4m24m.js",3]],0);
|
|
80
80
|
// src/core/random.ts
|
|
81
81
|
var lattice = (min, max, step, r) => min + Math.floor(r * (Math.floor((max - min) / step + 0.000000001) + 1)) * step, between = (min, max, r) => min + (max - min) * r;
|
|
82
82
|
function pick(field, random) {
|
|
@@ -1378,11 +1378,11 @@ function defineControls(id, input, options = {}) {
|
|
|
1378
1378
|
code: (format, values) => formatCode(values ?? get(), format),
|
|
1379
1379
|
variants,
|
|
1380
1380
|
attach(element, chip) {
|
|
1381
|
-
let load = options.ship ? () => options.ship().then((m) => m.attach) : () => (__preload("
|
|
1381
|
+
let load = options.ship ? () => options.ship().then((m) => m.attach) : () => (__preload("nhz9en4k"), import("./chunk-nhz9en4k.js")).then((m) => m.attach);
|
|
1382
1382
|
return live(load, (attach) => attach(controls, element, chip), (detach) => detach());
|
|
1383
1383
|
},
|
|
1384
1384
|
mount(container, mountOptions) {
|
|
1385
|
-
let load = options.ship ? () => options.ship().then((m) => m.mountPanel) : () => (__preload("
|
|
1385
|
+
let load = options.ship ? () => options.ship().then((m) => m.mountPanel) : () => (__preload("ya44t7z5"), import("./chunk-ya44t7z5.js")).then((m) => m.mountPanel);
|
|
1386
1386
|
return live(load, (mountPanel) => {
|
|
1387
1387
|
let panel = mountPanel(controls, container, mountOptions);
|
|
1388
1388
|
return mountOptions?.onReady?.(panel), panel;
|
package/dist/panel.js
CHANGED
|
@@ -21078,11 +21078,11 @@ var compareCss = `
|
|
|
21078
21078
|
.knobs-cmp-modes[hidden]{display:none}
|
|
21079
21079
|
.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
|
|
21080
21080
|
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21081
|
-
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
21081
|
+
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21082
21082
|
/* Toggles: icon buttons, the accent's wash when on. */
|
|
21083
21083
|
.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-3);cursor:pointer;
|
|
21084
21084
|
transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
21085
|
-
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}
|
|
21085
|
+
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21086
21086
|
.knobs-ui .knobs-cmp-toggle[aria-pressed="true"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}
|
|
21087
21087
|
.knobs-cmp-toggle svg{display:block}
|
|
21088
21088
|
.knobs-cmp-fill{flex:1}
|
|
@@ -21148,7 +21148,7 @@ var compareCss = `
|
|
|
21148
21148
|
.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}
|
|
21149
21149
|
:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;
|
|
21150
21150
|
display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}
|
|
21151
|
-
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent)}
|
|
21151
|
+
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21152
21152
|
.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);font-size:var(--_k-text-meta);pointer-events:none}
|
|
21153
21153
|
.knobs-cmp-note:empty{display:none}
|
|
21154
21154
|
.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}
|
|
@@ -21179,6 +21179,10 @@ var playerCss = `
|
|
|
21179
21179
|
.knobs-player-glyph svg{width:16px;height:16px}
|
|
21180
21180
|
.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}
|
|
21181
21181
|
.knobs-player-line{flex:none;min-height:0}
|
|
21182
|
+
/* Hover in is immediate (0 ms), out eases. The timeline's own stylesheet is look.ts's; its hover
|
|
21183
|
+
states are set here, after it, so the player's line and every timeline share them. */
|
|
21184
|
+
.knobs-ui .knobs-tl-play:hover,.knobs-tl-edge:hover::after,.knobs-tl-rlabel:hover,.knobs-tl-track:hover .knobs-tl-hover,
|
|
21185
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-track:hover .knobs-tl-segs{transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21182
21186
|
`;
|
|
21183
21187
|
|
|
21184
21188
|
// src/ui/overlay-css.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const compareCss = "\n:where(.knobs-compare,.knobs-compare *,.knobs-cmp-strip,.knobs-cmp-strip *){box-sizing:border-box}\n.knobs-ui.knobs-compare{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));--_ku-cmp-line:var(--_k-compare-divider);\n --_ku-cmp-stage:var(--_k-compare-stage);\n display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-ui) :is(.knobs-cmp-mode,.knobs-cmp-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}\n.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:var(--_k-gap);height:var(--_k-control-h)}\n/* The modes: one fill, the selection pill on the one picked; a mode isn't brighter for being\n picked: the pill's bright copy is. */\n.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}\n.knobs-cmp-modes[hidden]{display:none}\n.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;\n transition:color calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg)}\n/* Toggles: icon buttons, the accent's wash when on. */\n.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-3);cursor:pointer;\n transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}\n.knobs-ui .knobs-cmp-toggle[aria-pressed=\"true\"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}\n.knobs-cmp-toggle svg{display:block}\n.knobs-cmp-fill{flex:1}\n.knobs-cmp-toggle[hidden]{display:none}\n/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked\n data-nested, the stage drops its fill and the sides sit on that card. */\n:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-compare,.knobs-ui.knobs-compare[data-nested]{--_ku-cmp-stage:var(--k-compare-stage,transparent)}\n/* In a page's flow (a container with no height), it takes the height its sides need. */\n.knobs-ui.knobs-compare[data-auto]{height:auto}\n.knobs-compare[data-auto] .knobs-cmp-stage{flex:none;min-height:0}\n.knobs-cmp-stage{position:relative;flex:1;min-height:96px;overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_ku-cmp-stage);touch-action:pan-y;outline:none}\n.knobs-compare[data-frame=\"flat\"] .knobs-cmp-stage{border-radius:0}\n.knobs-compare[data-mode=\"wipe\"] .knobs-cmp-stage{cursor:ew-resize}\n/* Videos: a click on the stage plays and pauses. */\n.knobs-compare[data-video]:not([data-mode=\"wipe\"],[data-zoomed]) .knobs-cmp-stage{cursor:pointer}\n/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */\n.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}\n.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}\n/* Wiping, the grip stands in for the cursor. */\n.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}\n.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}\n.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n.knobs-cmp-media{position:absolute;left:0;top:0;display:block;max-width:none;margin:0;padding:0;border:0;object-fit:fill;transform-origin:0 0;pointer-events:none;will-change:transform}\n.knobs-compare[data-renderer=\"gpu\"] .knobs-cmp-media{opacity:0}\n/* The media comes in with its first frames: a fade and a 4px blur on the default spring. */\n.knobs-cmp-canvas,.knobs-compare[data-renderer=\"dom\"] .knobs-cmp-media{transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}\n.knobs-compare:not([data-ready]) :is(.knobs-cmp-canvas,.knobs-cmp-media){opacity:0;filter:blur(4px)}\n/* Glass: what's behind shows through, blurred, on the knobs tokens. */\n.knobs-cmp-label,.knobs-cmp-zoom{background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);\n box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim),0 2px 10px rgba(0,0,0,calc(.18 * var(--_k-shadow-k,1)))}\n/* \u2717 Before \u00B7 \u2713 After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */\n.knobs-cmp-label{position:absolute;left:0;top:0;display:flex;align-items:center;gap:4px;padding:1px 7px 1px 5px;border-radius:999px;font-size:var(--_k-text-meta);line-height:16px;font-weight:var(--_k-weight-label);\n white-space:nowrap;pointer-events:none;will-change:transform}\n.knobs-cmp-label[data-side=\"before\"]{color:var(--_k-fg-3)}\n.knobs-cmp-label[data-side=\"after\"]{color:var(--_k-fg)}\n/* Fusing, the mark folds away and the label is its name. */\n.knobs-cmp-mark{flex:none;display:flex;justify-content:flex-end;overflow:hidden}\n.knobs-cmp-mark svg{display:block;flex:none;width:12px;height:12px}\n/* The fuse's seam: a blurred strip over where the sides meet, soft at both sides. */\n.knobs-cmp-seam{position:absolute;left:0;top:0;width:8px;height:0;opacity:0;pointer-events:none;will-change:transform,opacity;\n -webkit-mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent);mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent)}\n/* The wipe: a hairline down the line with a raised grip in its middle (at the pointer's height\n while dragged); a wider strip takes the hand and the keys (a slider). It fades in with the\n fuse; wiping, line and grip brighten. */\n.knobs-cmp-handle{cursor:ew-resize;position:absolute;left:-12px;top:0;width:24px;height:0;opacity:0;pointer-events:none;outline:none;will-change:transform,opacity}\n.knobs-cmp-handle[data-on]{pointer-events:auto}\n.knobs-cmp-handle::before{content:\"\";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:color-mix(in srgb,var(--_ku-cmp-line) 72%,transparent);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}\n.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}\n.knobs-cmp-grip{position:absolute;top:0;left:4px;width:16px;height:28px;border-radius:min(8px,calc(var(--_k-radius) * 999));background:var(--_k-bg-overlay);\n box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border),inset 0 1px 0 var(--_k-rim);will-change:transform;transition:box-shadow calc(var(--_k-hover-out) * 1ms)}\n.knobs-cmp-grip::before,.knobs-cmp-grip::after{content:\"\";position:absolute;top:10px;width:1px;height:8px;background:var(--_k-fg-3);transition:background calc(var(--_k-hover-out) * 1ms)}\n.knobs-cmp-grip::before{left:6px}\n.knobs-cmp-grip::after{left:9px}\n.knobs-compare[data-dragging] .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border-strong),inset 0 1px 0 var(--_k-rim)}\n.knobs-compare[data-dragging] .knobs-cmp-grip::before,.knobs-compare[data-dragging] .knobs-cmp-grip::after{background:var(--_k-fg)}\n.knobs-cmp-handle:focus-visible .knobs-cmp-grip,.knobs-compare[data-keyboard] .knobs-cmp-handle:focus .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),0 0 0 2px var(--_k-accent)}\n/* The split's hairline, down the middle side by side. */\n.knobs-cmp-split{position:absolute;left:0;top:0;width:1px;height:0;margin-left:-.5px;background:color-mix(in srgb,var(--_k-bg) 72%,transparent);pointer-events:none;will-change:transform,opacity}\n/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */\n.knobs-cmp-zoom{position:absolute;right:8px;bottom:8px;display:flex;align-items:center;gap:4px;height:26px;padding:0 3px 0 10px;border-radius:999px;\n color:var(--_k-fg);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;\n opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}\n.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}\n:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;\n display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}\n:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent)}\n.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);font-size:var(--_k-text-meta);pointer-events:none}\n.knobs-cmp-note:empty{display:none}\n.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}\n.knobs-cmp-timeline-host{flex:none;min-height:0}\n/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */\n.knobs-ui.knobs-cmp-strip{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));position:relative;width:100%;height:100%;min-height:40px;overflow:hidden;cursor:col-resize;touch-action:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg)}\n.knobs-cmp-strip>canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n@media(prefers-reduced-motion:reduce){:is(.knobs-compare,.knobs-cmp-strip) :where(*,::before,::after){transition-duration:.12s!important}}\n";
|
|
1
|
+
export declare const compareCss = "\n:where(.knobs-compare,.knobs-compare *,.knobs-cmp-strip,.knobs-cmp-strip *){box-sizing:border-box}\n.knobs-ui.knobs-compare{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));--_ku-cmp-line:var(--_k-compare-divider);\n --_ku-cmp-stage:var(--_k-compare-stage);\n display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-ui) :is(.knobs-cmp-mode,.knobs-cmp-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}\n.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:var(--_k-gap);height:var(--_k-control-h)}\n/* The modes: one fill, the selection pill on the one picked; a mode isn't brighter for being\n picked: the pill's bright copy is. */\n.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}\n.knobs-cmp-modes[hidden]{display:none}\n.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;\n transition:color calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n/* Toggles: icon buttons, the accent's wash when on. */\n.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-3);cursor:pointer;\n transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}\n.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-ui .knobs-cmp-toggle[aria-pressed=\"true\"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}\n.knobs-cmp-toggle svg{display:block}\n.knobs-cmp-fill{flex:1}\n.knobs-cmp-toggle[hidden]{display:none}\n/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked\n data-nested, the stage drops its fill and the sides sit on that card. */\n:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-compare,.knobs-ui.knobs-compare[data-nested]{--_ku-cmp-stage:var(--k-compare-stage,transparent)}\n/* In a page's flow (a container with no height), it takes the height its sides need. */\n.knobs-ui.knobs-compare[data-auto]{height:auto}\n.knobs-compare[data-auto] .knobs-cmp-stage{flex:none;min-height:0}\n.knobs-cmp-stage{position:relative;flex:1;min-height:96px;overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_ku-cmp-stage);touch-action:pan-y;outline:none}\n.knobs-compare[data-frame=\"flat\"] .knobs-cmp-stage{border-radius:0}\n.knobs-compare[data-mode=\"wipe\"] .knobs-cmp-stage{cursor:ew-resize}\n/* Videos: a click on the stage plays and pauses. */\n.knobs-compare[data-video]:not([data-mode=\"wipe\"],[data-zoomed]) .knobs-cmp-stage{cursor:pointer}\n/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */\n.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}\n.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}\n/* Wiping, the grip stands in for the cursor. */\n.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}\n.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}\n.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n.knobs-cmp-media{position:absolute;left:0;top:0;display:block;max-width:none;margin:0;padding:0;border:0;object-fit:fill;transform-origin:0 0;pointer-events:none;will-change:transform}\n.knobs-compare[data-renderer=\"gpu\"] .knobs-cmp-media{opacity:0}\n/* The media comes in with its first frames: a fade and a 4px blur on the default spring. */\n.knobs-cmp-canvas,.knobs-compare[data-renderer=\"dom\"] .knobs-cmp-media{transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}\n.knobs-compare:not([data-ready]) :is(.knobs-cmp-canvas,.knobs-cmp-media){opacity:0;filter:blur(4px)}\n/* Glass: what's behind shows through, blurred, on the knobs tokens. */\n.knobs-cmp-label,.knobs-cmp-zoom{background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);\n box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim),0 2px 10px rgba(0,0,0,calc(.18 * var(--_k-shadow-k,1)))}\n/* \u2717 Before \u00B7 \u2713 After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */\n.knobs-cmp-label{position:absolute;left:0;top:0;display:flex;align-items:center;gap:4px;padding:1px 7px 1px 5px;border-radius:999px;font-size:var(--_k-text-meta);line-height:16px;font-weight:var(--_k-weight-label);\n white-space:nowrap;pointer-events:none;will-change:transform}\n.knobs-cmp-label[data-side=\"before\"]{color:var(--_k-fg-3)}\n.knobs-cmp-label[data-side=\"after\"]{color:var(--_k-fg)}\n/* Fusing, the mark folds away and the label is its name. */\n.knobs-cmp-mark{flex:none;display:flex;justify-content:flex-end;overflow:hidden}\n.knobs-cmp-mark svg{display:block;flex:none;width:12px;height:12px}\n/* The fuse's seam: a blurred strip over where the sides meet, soft at both sides. */\n.knobs-cmp-seam{position:absolute;left:0;top:0;width:8px;height:0;opacity:0;pointer-events:none;will-change:transform,opacity;\n -webkit-mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent);mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent)}\n/* The wipe: a hairline down the line with a raised grip in its middle (at the pointer's height\n while dragged); a wider strip takes the hand and the keys (a slider). It fades in with the\n fuse; wiping, line and grip brighten. */\n.knobs-cmp-handle{cursor:ew-resize;position:absolute;left:-12px;top:0;width:24px;height:0;opacity:0;pointer-events:none;outline:none;will-change:transform,opacity}\n.knobs-cmp-handle[data-on]{pointer-events:auto}\n.knobs-cmp-handle::before{content:\"\";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:color-mix(in srgb,var(--_ku-cmp-line) 72%,transparent);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}\n.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}\n.knobs-cmp-grip{position:absolute;top:0;left:4px;width:16px;height:28px;border-radius:min(8px,calc(var(--_k-radius) * 999));background:var(--_k-bg-overlay);\n box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border),inset 0 1px 0 var(--_k-rim);will-change:transform;transition:box-shadow calc(var(--_k-hover-out) * 1ms)}\n.knobs-cmp-grip::before,.knobs-cmp-grip::after{content:\"\";position:absolute;top:10px;width:1px;height:8px;background:var(--_k-fg-3);transition:background calc(var(--_k-hover-out) * 1ms)}\n.knobs-cmp-grip::before{left:6px}\n.knobs-cmp-grip::after{left:9px}\n.knobs-compare[data-dragging] .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border-strong),inset 0 1px 0 var(--_k-rim)}\n.knobs-compare[data-dragging] .knobs-cmp-grip::before,.knobs-compare[data-dragging] .knobs-cmp-grip::after{background:var(--_k-fg)}\n.knobs-cmp-handle:focus-visible .knobs-cmp-grip,.knobs-compare[data-keyboard] .knobs-cmp-handle:focus .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),0 0 0 2px var(--_k-accent)}\n/* The split's hairline, down the middle side by side. */\n.knobs-cmp-split{position:absolute;left:0;top:0;width:1px;height:0;margin-left:-.5px;background:color-mix(in srgb,var(--_k-bg) 72%,transparent);pointer-events:none;will-change:transform,opacity}\n/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */\n.knobs-cmp-zoom{position:absolute;right:8px;bottom:8px;display:flex;align-items:center;gap:4px;height:26px;padding:0 3px 0 10px;border-radius:999px;\n color:var(--_k-fg);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;\n opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}\n.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}\n:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;\n display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}\n:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}\n.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);font-size:var(--_k-text-meta);pointer-events:none}\n.knobs-cmp-note:empty{display:none}\n.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}\n.knobs-cmp-timeline-host{flex:none;min-height:0}\n/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */\n.knobs-ui.knobs-cmp-strip{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));position:relative;width:100%;height:100%;min-height:40px;overflow:hidden;cursor:col-resize;touch-action:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg)}\n.knobs-cmp-strip>canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}\n@media(prefers-reduced-motion:reduce){:is(.knobs-compare,.knobs-cmp-strip) :where(*,::before,::after){transition-duration:.12s!important}}\n";
|
|
@@ -11,6 +11,8 @@ export interface CompareDraw {
|
|
|
11
11
|
/** Device px: the part of the stage each side may draw in. */
|
|
12
12
|
readonly beforeClip: Rect;
|
|
13
13
|
readonly afterClip: Rect;
|
|
14
|
+
/** Device px: the clips' corner radii, Before's left and right, then After's. */
|
|
15
|
+
readonly radii: readonly [number, number, number, number];
|
|
14
16
|
readonly width: number;
|
|
15
17
|
readonly height: number;
|
|
16
18
|
readonly dpr: number;
|
|
@@ -100,10 +100,13 @@ export interface CompareLayout {
|
|
|
100
100
|
}
|
|
101
101
|
/** Where the two sides sit inside `box`, side by side and overlaid. */
|
|
102
102
|
export declare function compareLayout(box: Rect, before: Size, after: Size): CompareLayout;
|
|
103
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Kit Motion's blend blur, in px: the feather Before's cut swells to mid-fuse, the blur of the
|
|
105
|
+
* strip over the seam at its peak (mid-fuse too), and the overlap the seam fades in over.
|
|
106
|
+
*/
|
|
104
107
|
export declare const FUSE: {
|
|
105
|
-
readonly feather:
|
|
106
|
-
readonly blur:
|
|
108
|
+
readonly feather: 32;
|
|
109
|
+
readonly blur: 8;
|
|
107
110
|
readonly seamFade: 48;
|
|
108
111
|
};
|
|
109
112
|
export interface FuseFrame {
|
|
@@ -113,20 +116,36 @@ export interface FuseFrame {
|
|
|
113
116
|
readonly feather: number;
|
|
114
117
|
/** The seam's (and the wipe handle's) opacity, 0–1. */
|
|
115
118
|
readonly seam: number;
|
|
116
|
-
/** The seam's blur (px)
|
|
119
|
+
/** The seam's blur (px): none apart or fused, `FUSE.blur` mid-fuse. */
|
|
117
120
|
readonly blur: number;
|
|
118
121
|
}
|
|
119
122
|
/**
|
|
120
123
|
* Kit Motion's Comparison fuse, one frame of it: side by side (`k` 0) the panes glide together
|
|
121
124
|
* into one (`k` 1). Before is cut only where the inner edges overlap, with a feather that swells
|
|
122
|
-
* mid-transition
|
|
123
|
-
* `after` are where the sides are
|
|
125
|
+
* mid-transition, and a blurred strip over the seam blends the two, strongest mid-transition
|
|
126
|
+
* (the blend blur); it fades in as they overlap. `before` and `after` are where the sides are
|
|
127
|
+
* drawn this frame.
|
|
124
128
|
*/
|
|
125
129
|
export declare function fuseFrame(L: CompareLayout, before: Rect, after: Rect, k: number, wipe: number): FuseFrame;
|
|
126
130
|
/**
|
|
127
131
|
* A label folded `fold` (0 open, 1 folded to its name): its mark's width, opacity and blur (px,
|
|
128
132
|
* up to `blur` as it goes, kit-motion's in-place exit).
|
|
129
133
|
*/
|
|
134
|
+
/**
|
|
135
|
+
* Each side's corner radii, `left` and `right` (px), so the frame is rounded at every frame of the
|
|
136
|
+
* fuse: a side's outer corners always take the frame's radius `r`; its inner ones (at the split)
|
|
137
|
+
* are square apart and grow to `r` as the sides fuse into one picture.
|
|
138
|
+
*/
|
|
139
|
+
export declare const fuseCorners: (r: number, k: number) => {
|
|
140
|
+
before: {
|
|
141
|
+
left: number;
|
|
142
|
+
right: number;
|
|
143
|
+
};
|
|
144
|
+
after: {
|
|
145
|
+
left: number;
|
|
146
|
+
right: number;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
130
149
|
export declare const labelFold: (fold: number, mark: number, blur?: number) => {
|
|
131
150
|
width: number;
|
|
132
151
|
opacity: number;
|
package/dist/types/ui/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export { adjacentMarker, advance, CATCH_UP, clampView, currentMarker, followView
|
|
|
19
19
|
export { compare, COMPARE_FFMPEG, type Compare, type CompareLoop, type CompareMode, type CompareOptions, type CompareSource, type CompareView, type MediaKind, type ZoomRegion, } from "./compare.js";
|
|
20
20
|
export { compareStrip, type CompareStrip, type CompareStripOptions } from "./compare-strip.js";
|
|
21
21
|
export { player, type Player, type PlayerChapter, type PlayerOptions } from "./player.js";
|
|
22
|
+
export { history, type History, type HistoryBand, type HistoryData, type HistoryEvent, type HistoryEvidence, type HistoryGroup, type HistoryLane, type HistoryOptions, type HistoryProvenance, type HistorySpan, type HistoryState, type HistoryTone, } from "./history.js";
|
|
22
23
|
export { compareLayout, compareModes, frameMidpoint, frameOf, gripTop, letterbox, mediaKind, meanAbsDiff, modeForKey, requestSeek, seamLabels, seeked, seekTime, stripColumns, stripPeaks, syncAction, wipeAt, wipeGrab, wipeKey, wipeX, zoomAbout, type CompareLayout, type SeekState, type StripColumn, type SyncAction, } from "./compare-model.js";
|
|
23
24
|
export { tree, type Tree, type TreeOptions, type TreeRowContext, type TreeToggle } from "./tree.js";
|
|
24
25
|
export { applyMove, plainAccess, dropTarget, flatten, indexTree, matchLabel, navigate, select, stepMove, topmost, typeahead, validMove, virtualWindow, type DropTarget, type FlatRow, type Selection, type TreeAccess, type TreeFilter, type TreeMove, } from "./tree-model.js";
|
|
@@ -32,4 +33,4 @@ export { optionPicker, type OptionPicker, type OptionPickerOptions, type PickerO
|
|
|
32
33
|
export { claimsDigit, digitPick, keepPick, stepPick } from "./picker-model.js";
|
|
33
34
|
export { tasteTest, walkthrough, type TasteTest, type TasteTestOptions, type Walkthrough, type WalkthroughOptions, } from "./walkthrough.js";
|
|
34
35
|
export { mediaSlot, type MediaSlot, type MediaSlotOptions, type StepLinks, } from "./walkthrough-media.js";
|
|
35
|
-
export { collectFeedback, feedbackMarkdown, inlineMarkdown, normalizeWalkthrough, readState as readWalkthroughState, stackLayout, walkthroughProgress, type ContextEvent, type FeedbackItem, type FeedbackNote, type FeedItem, type MediaContext, type NoteContext, type StackLayout, type StackRow, type WalkInk, type WalkNote, type WalkVoice, type WalkthroughQA, type WalkthroughUpdate, type WalkPage, type WalkStep, type WalkthroughChapter, type WalkthroughDoc, type WalkthroughEvidence, type WalkthroughFeedback, type WalkthroughHistoryEvent, type WalkthroughHistoryGroup, type WalkthroughMedia, type WalkthroughMeta, type WalkthroughOption, type WalkthroughSection, type WalkthroughSource, type WalkthroughStackItem, type WalkthroughState, type WalkthroughStatus, type WalkthroughStep, type WalkthroughTableCell, type WalkthroughTableColumn, type WalkthroughTableRow, type WalkthroughTone, } from "./walkthrough-model.js";
|
|
36
|
+
export { collectFeedback, feedbackMarkdown, inlineMarkdown, plainMarkdown, normalizeWalkthrough, readState as readWalkthroughState, stackLayout, walkthroughProgress, type ContextEvent, type FeedbackItem, type FeedbackNote, type FeedItem, type MediaContext, type NoteContext, type StackLayout, type StackRow, type WalkInk, type WalkNote, type WalkVoice, type WalkthroughQA, type WalkthroughUpdate, type WalkPage, type WalkStep, type WalkthroughChapter, type WalkthroughDoc, type WalkthroughEvidence, type WalkthroughFeedback, type WalkthroughHistoryEvent, type WalkthroughHistoryGroup, type WalkthroughMedia, type WalkthroughMeta, type WalkthroughOption, type WalkthroughSection, type WalkthroughSource, type WalkthroughStackItem, type WalkthroughState, type WalkthroughStatus, type WalkthroughStep, type WalkthroughTableCell, type WalkthroughTableColumn, type WalkthroughTableRow, type WalkthroughTone, type WalkthroughPR, type WalkthroughAnnotation, } from "./walkthrough-model.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const playerCss = "\n:where(.knobs-player,.knobs-player *){box-sizing:border-box}\n.knobs-ui.knobs-player{--_kp-stage:var(--_k-compare-stage);display:flex;flex-direction:column;gap:6px;width:100%;outline:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-player,.knobs-ui.knobs-player[data-nested]{--_kp-stage:var(--k-compare-stage,transparent)}\n.knobs-player-frame{position:relative;width:100%;aspect-ratio:var(--kp-aspect,16/9);overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_kp-stage);cursor:pointer}\n.knobs-player[data-frame=\"flat\"] .knobs-player-frame{border-radius:0}\n.knobs-player-media{position:absolute;inset:0;display:block;width:100%;height:100%;margin:0;padding:0;border:0;object-fit:contain;\n opacity:0;filter:blur(4px);transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}\n.knobs-player[data-ready] .knobs-player-media{opacity:1;filter:none}\n.knobs-player-glyph{position:absolute;left:50%;top:50%;display:grid;place-items:center;width:44px;height:44px;margin:-22px 0 0 -22px;border-radius:50%;color:var(--_k-fg);pointer-events:none;\n opacity:0;filter:blur(4px);scale:.96;\n background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);\n box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim);\n transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy),filter calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy),scale calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy)}\n.knobs-player-glyph svg{width:16px;height:16px}\n.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}\n.knobs-player-line{flex:none;min-height:0}\n";
|
|
1
|
+
export declare const playerCss = "\n:where(.knobs-player,.knobs-player *){box-sizing:border-box}\n.knobs-ui.knobs-player{--_kp-stage:var(--_k-compare-stage);display:flex;flex-direction:column;gap:6px;width:100%;outline:none;\n font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}\n:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-player,.knobs-ui.knobs-player[data-nested]{--_kp-stage:var(--k-compare-stage,transparent)}\n.knobs-player-frame{position:relative;width:100%;aspect-ratio:var(--kp-aspect,16/9);overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_kp-stage);cursor:pointer}\n.knobs-player[data-frame=\"flat\"] .knobs-player-frame{border-radius:0}\n.knobs-player-media{position:absolute;inset:0;display:block;width:100%;height:100%;margin:0;padding:0;border:0;object-fit:contain;\n opacity:0;filter:blur(4px);transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}\n.knobs-player[data-ready] .knobs-player-media{opacity:1;filter:none}\n.knobs-player-glyph{position:absolute;left:50%;top:50%;display:grid;place-items:center;width:44px;height:44px;margin:-22px 0 0 -22px;border-radius:50%;color:var(--_k-fg);pointer-events:none;\n opacity:0;filter:blur(4px);scale:.96;\n background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);\n box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim);\n transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy),filter calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy),scale calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy)}\n.knobs-player-glyph svg{width:16px;height:16px}\n.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}\n.knobs-player-line{flex:none;min-height:0}\n/* Hover in is immediate (0 ms), out eases. The timeline's own stylesheet is look.ts's; its hover\n states are set here, after it, so the player's line and every timeline share them. */\n.knobs-ui .knobs-tl-play:hover,.knobs-tl-edge:hover::after,.knobs-tl-rlabel:hover,.knobs-tl-track:hover .knobs-tl-hover,\n.knobs-timeline[data-variant=\"line\"] .knobs-tl-track:hover .knobs-tl-segs{transition-duration:calc(var(--_k-hover-in) * 1ms)}\n";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { WalkthroughAnnotation } from "./walkthrough-model.js";
|
|
2
|
+
export interface Rect {
|
|
3
|
+
readonly x: number;
|
|
4
|
+
readonly y: number;
|
|
5
|
+
readonly w: number;
|
|
6
|
+
readonly h: number;
|
|
7
|
+
}
|
|
8
|
+
/** The part of the picture in view, 0–1 (`{ u: 0, v: 0, w: 1, h: 1 }` is all of it). */
|
|
9
|
+
export interface View {
|
|
10
|
+
readonly u: number;
|
|
11
|
+
readonly v: number;
|
|
12
|
+
readonly w: number;
|
|
13
|
+
readonly h: number;
|
|
14
|
+
}
|
|
15
|
+
/** Where the picture sits now: its rects in the layer (one, or a compare's two), view and time. */
|
|
16
|
+
export interface Placement {
|
|
17
|
+
readonly rects: readonly Rect[];
|
|
18
|
+
readonly view?: View;
|
|
19
|
+
readonly time?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface AnnotationLayer {
|
|
22
|
+
readonly element: HTMLElement;
|
|
23
|
+
/** Places the marks again: after a resize, a zoom, a seek, a mode change. */
|
|
24
|
+
update(): void;
|
|
25
|
+
dispose(): void;
|
|
26
|
+
}
|
|
27
|
+
/** Whether a mark shows at `time` (always without `at`, or without a time). */
|
|
28
|
+
export declare const showsAt: (a: WalkthroughAnnotation, time: number | undefined) => boolean;
|
|
29
|
+
/**
|
|
30
|
+
* A mark's box in the layer, in px, for a picture at `rect` showing `view` of itself; null when
|
|
31
|
+
* it's out of view.
|
|
32
|
+
*/
|
|
33
|
+
export declare function placeMark(a: WalkthroughAnnotation, rect: Rect, view?: View): Rect | null;
|
|
34
|
+
/** Whether a page's annotations show. */
|
|
35
|
+
export declare const annotationsOn: (scope: HTMLElement) => boolean;
|
|
36
|
+
/** Shows or hides every annotation on a page (or a lone slot); its eye buttons follow. */
|
|
37
|
+
export declare function setAnnotations(scope: HTMLElement, on: boolean): void;
|
|
38
|
+
/**
|
|
39
|
+
* Draws `list` over `host` (positioned, the picture's box or a compare's stage), placing it with
|
|
40
|
+
* `place()`; the eye button goes in `corner` (the host by default).
|
|
41
|
+
*/
|
|
42
|
+
export declare function annotationLayer(host: HTMLElement, list: readonly WalkthroughAnnotation[], place: () => Placement, corner?: HTMLElement): AnnotationLayer;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type ContextEvent, type WalkChapter, type WalkMedia } from "./walkthrough-model.js";
|
|
2
2
|
/** The glyphs the blocks draw. */
|
|
3
3
|
export declare const GLYPH: {
|
|
4
|
-
go: string;
|
|
5
4
|
caret: string;
|
|
6
5
|
};
|
|
7
6
|
/** How media reach the page's steps: `step` on a history event, a stack item or a table cell. */
|
|
@@ -22,8 +21,12 @@ export interface Block {
|
|
|
22
21
|
kind: string;
|
|
23
22
|
};
|
|
24
23
|
}
|
|
25
|
-
/**
|
|
26
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Makes a whole row go to the step a ref names (a click away from its links, Enter or Space when
|
|
26
|
+
* it has focus); nothing trails it, so rows with and without a step line up.
|
|
27
|
+
*/
|
|
28
|
+
export declare function rowLink(row: HTMLElement, ref: string | undefined, steps: StepLinks | undefined): void;
|
|
29
|
+
/** A history through `history()`: lanes of spans over a date axis, or the older groups of events. */
|
|
27
30
|
export declare function mountHistory(host: HTMLElement, m: Extract<WalkMedia, {
|
|
28
31
|
kind: "history";
|
|
29
32
|
}>, steps: StepLinks | undefined): Block;
|
|
@@ -55,7 +58,6 @@ export interface Disclosure {
|
|
|
55
58
|
}
|
|
56
59
|
export declare function disclosure(host: HTMLElement, options: {
|
|
57
60
|
label: string;
|
|
58
|
-
count?: number;
|
|
59
61
|
open?: boolean;
|
|
60
62
|
content: HTMLElement;
|
|
61
63
|
}): Disclosure;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CompareMode } from "./compare-model.js";
|
|
2
2
|
import type { DiffSource } from "./diff-model.js";
|
|
3
|
+
import type { HistoryData, HistoryEvent } from "./history-model.js";
|
|
3
4
|
/** Where a PR or topic stands, as the agent sees it: a chip beside its title. */
|
|
4
5
|
export type WalkthroughStatus = "ready" | "needs-taste" | "draft" | "blocked" | "merged" | (string & {});
|
|
5
6
|
/** A picture or video, by URL. */
|
|
@@ -89,6 +90,22 @@ export interface WalkthroughTableColumn {
|
|
|
89
90
|
export type WalkthroughTableRow = Readonly<Record<string, WalkthroughTableCell>> | {
|
|
90
91
|
readonly cells: Readonly<Record<string, WalkthroughTableCell>>;
|
|
91
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* A mark on a picture drawing the eye to what matters: a ring round a box, a dot or an arrow at a
|
|
95
|
+
* point, with a small label. In 0–1 of the picture (`x`, `y` the box's top-left or the point).
|
|
96
|
+
*/
|
|
97
|
+
export interface WalkthroughAnnotation {
|
|
98
|
+
readonly x: number;
|
|
99
|
+
readonly y: number;
|
|
100
|
+
/** A box's size; left out, it's a point. */
|
|
101
|
+
readonly w?: number;
|
|
102
|
+
readonly h?: number;
|
|
103
|
+
readonly label?: string;
|
|
104
|
+
/** Seconds it shows between, on a video or compare; always, left out. */
|
|
105
|
+
readonly at?: readonly [number, number];
|
|
106
|
+
/** `"box"` where it has a size, else `"dot"`. */
|
|
107
|
+
readonly shape?: "box" | "dot" | "arrow";
|
|
108
|
+
}
|
|
92
109
|
/** A stretch of a video: a pill under it, and a marker on its timeline. */
|
|
93
110
|
export interface WalkthroughChapter {
|
|
94
111
|
readonly id?: string;
|
|
@@ -115,6 +132,8 @@ export type WalkthroughMedia = string | {
|
|
|
115
132
|
readonly strip?: boolean;
|
|
116
133
|
/** Pills under it that seek, and markers on its timeline. */
|
|
117
134
|
readonly chapters?: readonly WalkthroughChapter[];
|
|
135
|
+
/** Marks on the pictures, on both sides (and under a zoom). */
|
|
136
|
+
readonly annotations?: readonly WalkthroughAnnotation[];
|
|
118
137
|
} | {
|
|
119
138
|
readonly kind: "video";
|
|
120
139
|
readonly src: string;
|
|
@@ -127,12 +146,23 @@ export type WalkthroughMedia = string | {
|
|
|
127
146
|
readonly captions?: string;
|
|
128
147
|
/** Another name for `captions`. */
|
|
129
148
|
readonly captionsSrc?: string;
|
|
149
|
+
/** Marks on the picture. */
|
|
150
|
+
readonly annotations?: readonly WalkthroughAnnotation[];
|
|
130
151
|
} | {
|
|
131
152
|
readonly kind: "history";
|
|
132
|
-
/**
|
|
153
|
+
/** Lanes of dated spans over one axis (`history()`'s shape)… */
|
|
154
|
+
readonly lanes?: HistoryData["lanes"];
|
|
155
|
+
readonly bands?: HistoryData["bands"];
|
|
156
|
+
readonly states?: HistoryData["states"];
|
|
157
|
+
readonly axis?: HistoryData["axis"];
|
|
158
|
+
/** …dated events (on the lanes, or one run of them in the older shape)… */
|
|
159
|
+
readonly events?: readonly (WalkthroughHistoryEvent | HistoryEvent)[];
|
|
160
|
+
/** …or the older groups of events under quiet headings. */
|
|
133
161
|
readonly groups?: readonly WalkthroughHistoryGroup[];
|
|
134
|
-
/**
|
|
135
|
-
readonly
|
|
162
|
+
/** Its accessible name. */
|
|
163
|
+
readonly label?: string;
|
|
164
|
+
/** The event types marked from the start (releases and deletions), or `"all"`. */
|
|
165
|
+
readonly marks?: readonly string[] | "all";
|
|
136
166
|
} | {
|
|
137
167
|
readonly kind: "stack";
|
|
138
168
|
/** The branch the stack lands on ("dev"); else the one most items merge into. */
|
|
@@ -157,6 +187,8 @@ export type WalkthroughMedia = string | {
|
|
|
157
187
|
readonly src: string;
|
|
158
188
|
readonly label?: string;
|
|
159
189
|
readonly alt?: string;
|
|
190
|
+
/** Marks on the picture. */
|
|
191
|
+
readonly annotations?: readonly WalkthroughAnnotation[];
|
|
160
192
|
} | {
|
|
161
193
|
readonly kind: "diff";
|
|
162
194
|
/** `git diff` / `git show` output. */
|
|
@@ -245,6 +277,7 @@ export interface WalkthroughSection {
|
|
|
245
277
|
* `link` is a pull request, or the doc's `kickers` noun), your own words, or `false` for none.
|
|
246
278
|
*/
|
|
247
279
|
readonly kicker?: string | false;
|
|
280
|
+
/** A chip on its meta line ("needs-taste" → Needs taste), with `review: true` only. */
|
|
248
281
|
readonly status?: WalkthroughStatus;
|
|
249
282
|
readonly summary?: string;
|
|
250
283
|
/** The rest, folded away under the summary behind "More" (Markdown). */
|
|
@@ -336,11 +369,6 @@ export interface WalkChapter {
|
|
|
336
369
|
readonly start: number;
|
|
337
370
|
readonly end?: number;
|
|
338
371
|
}
|
|
339
|
-
export interface WalkHistoryGroup {
|
|
340
|
-
readonly heading?: string;
|
|
341
|
-
readonly summary?: string;
|
|
342
|
-
readonly events: readonly WalkthroughHistoryEvent[];
|
|
343
|
-
}
|
|
344
372
|
/** A stack's item filled in: its PR as `#123`, its branch split, `step` for `stepId`. */
|
|
345
373
|
export interface WalkStackItem {
|
|
346
374
|
readonly pr: string;
|
|
@@ -387,7 +415,9 @@ export type WalkMedia = Exclude<WalkthroughMedia, string | {
|
|
|
387
415
|
readonly chapters?: readonly WalkChapter[];
|
|
388
416
|
}) | {
|
|
389
417
|
readonly kind: "history";
|
|
390
|
-
readonly
|
|
418
|
+
readonly data: HistoryData;
|
|
419
|
+
readonly label?: string;
|
|
420
|
+
readonly marks?: readonly string[] | "all";
|
|
391
421
|
} | {
|
|
392
422
|
readonly kind: "stack";
|
|
393
423
|
readonly base?: string;
|
|
@@ -486,6 +516,13 @@ export declare const mediaOf: (src: string) => WalkMedia;
|
|
|
486
516
|
export declare function parseAspect(aspect: number | string | undefined): number | undefined;
|
|
487
517
|
/** Media filled in: a bare URL as a video or image, sources resolved against `base`. */
|
|
488
518
|
export declare function fillMedia(m: WalkthroughMedia, base?: string): WalkMedia;
|
|
519
|
+
/**
|
|
520
|
+
* What `history()` draws: the lanes shape as written, or the older groups (`rows` read as
|
|
521
|
+
* `events`, bare `events` as one group first) for it to lay on the code lane.
|
|
522
|
+
*/
|
|
523
|
+
export declare function historyData(m: Extract<WalkthroughMedia, {
|
|
524
|
+
kind: "history";
|
|
525
|
+
}>): HistoryData;
|
|
489
526
|
/** `"head → base"` (or `->`, `=>`, `⇒`) as its two branches; one name is the head alone. */
|
|
490
527
|
export declare function parseBranch(branch: string | undefined): {
|
|
491
528
|
head?: string;
|