@kitlangton/knobs 0.4.0-next.6 → 0.4.0-next.8
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 +6 -4
- package/dist/dev/{chunk-ya44t7z5.js → chunk-a9pwf5c0.js} +28 -22
- package/dist/dev/{chunk-nhz9en4k.js → chunk-tttj4xpd.js} +1 -1
- package/dist/dev/index.js +3 -3
- package/dist/panel.js +28 -22
- package/dist/types/ui/compare-css.d.ts +1 -1
- package/dist/types/ui/compare.d.ts +1 -1
- package/dist/types/ui/player-css.d.ts +1 -1
- package/dist/types/ui/player.d.ts +0 -9
- package/dist/types/ui/timeline.d.ts +2 -4
- package/dist/types/ui/walkthrough-blocks.d.ts +19 -14
- package/dist/types/ui/walkthrough-media.d.ts +3 -1
- package/dist/types/ui/walkthrough-model.d.ts +21 -2
- package/dist/ui-react.js +450 -205
- package/dist/ui-solid.js +450 -205
- package/dist/ui.js +450 -372
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -575,13 +575,14 @@ var compareCss = `
|
|
|
575
575
|
picked: the pill's bright copy is. */
|
|
576
576
|
.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}
|
|
577
577
|
.knobs-cmp-modes[hidden]{display:none}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
578
|
+
/* Hover is a quiet fill under the arrow cursor (no hand, no brightening), there at once. */
|
|
579
|
+
.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:default;white-space:nowrap;
|
|
580
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
581
|
+
.knobs-ui .knobs-cmp-mode:not([aria-checked="true"]):is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
581
582
|
/* Toggles: icon buttons, the accent's wash when on. */
|
|
582
|
-
.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-
|
|
583
|
-
transition:
|
|
584
|
-
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){
|
|
583
|
+
.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-2);cursor:default;
|
|
584
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
585
|
+
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
585
586
|
.knobs-ui .knobs-cmp-toggle[aria-pressed="true"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}
|
|
586
587
|
.knobs-cmp-toggle svg{display:block}
|
|
587
588
|
.knobs-cmp-fill{flex:1}
|
|
@@ -595,11 +596,10 @@ var compareCss = `
|
|
|
595
596
|
.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}
|
|
596
597
|
.knobs-compare[data-frame="flat"] .knobs-cmp-stage{border-radius:0}
|
|
597
598
|
.knobs-compare[data-mode="wipe"] .knobs-cmp-stage{cursor:ew-resize}
|
|
598
|
-
/* Videos: a click on the stage plays and pauses. */
|
|
599
|
-
.knobs-compare[data-video]:not([data-mode="wipe"],[data-zoomed]) .knobs-cmp-stage{cursor:pointer}
|
|
600
599
|
/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */
|
|
601
|
-
.
|
|
602
|
-
.knobs-compare[data-
|
|
600
|
+
/* Zoomed, it pans: a move cursor, never a hand. */
|
|
601
|
+
.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:move;touch-action:none}
|
|
602
|
+
.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:move!important}
|
|
603
603
|
/* Wiping, the grip stands in for the cursor. */
|
|
604
604
|
.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}
|
|
605
605
|
.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}
|
|
@@ -646,8 +646,8 @@ var compareCss = `
|
|
|
646
646
|
opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}
|
|
647
647
|
.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)}
|
|
648
648
|
: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;
|
|
649
|
-
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:
|
|
650
|
-
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){
|
|
649
|
+
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:default;transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
650
|
+
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
651
651
|
.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}
|
|
652
652
|
.knobs-cmp-note:empty{display:none}
|
|
653
653
|
.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}
|
|
@@ -665,23 +665,29 @@ var playerCss = `
|
|
|
665
665
|
.knobs-ui.knobs-player{--_kp-stage:var(--_k-compare-stage);display:flex;flex-direction:column;gap:6px;width:100%;outline:none;
|
|
666
666
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
667
667
|
: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)}
|
|
668
|
-
.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)
|
|
668
|
+
.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)}
|
|
669
669
|
.knobs-player[data-frame="flat"] .knobs-player-frame{border-radius:0}
|
|
670
670
|
.knobs-player-media{position:absolute;inset:0;display:block;width:100%;height:100%;margin:0;padding:0;border:0;object-fit:contain;
|
|
671
671
|
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)}
|
|
672
672
|
.knobs-player[data-ready] .knobs-player-media{opacity:1;filter:none}
|
|
673
|
-
.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;
|
|
674
|
-
opacity:0;filter:blur(4px);scale:.96;
|
|
675
|
-
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);
|
|
676
|
-
box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim);
|
|
677
|
-
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)}
|
|
678
|
-
.knobs-player-glyph svg{width:16px;height:16px}
|
|
679
|
-
.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}
|
|
680
673
|
.knobs-player-line{flex:none;min-height:0}
|
|
681
|
-
/*
|
|
682
|
-
|
|
674
|
+
/* The timeline's own stylesheet is look.ts's; what the player's row and every timeline share
|
|
675
|
+
about the hand is set here, after it. No hand cursor anywhere (the arrow, or a resize where it
|
|
676
|
+
resizes); hover is a quiet fill (fill-hover), in at once (hover-in, 0 ms), out easing. */
|
|
677
|
+
.knobs-ui .knobs-tl-play,.knobs-ui.knobs-timeline :is(.knobs-tl-pin,.knobs-tl-rlabel),
|
|
678
|
+
.knobs-ui.knobs-timeline[data-dragging] .knobs-tl-marker :is(.knobs-tl-pin,.knobs-tl-mlabel){cursor:default}
|
|
683
679
|
.knobs-ui .knobs-tl-play:hover,.knobs-tl-edge:hover::after,.knobs-tl-rlabel:hover,.knobs-tl-track:hover .knobs-tl-hover,
|
|
684
680
|
.knobs-timeline[data-variant="line"] .knobs-tl-track:hover .knobs-tl-segs{transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
681
|
+
/* The line's row: a minimal play/pause (the filled pair, a 28px target, no fill at rest), then
|
|
682
|
+
the line, centred on it. */
|
|
683
|
+
.knobs-ui.knobs-timeline[data-variant="line"]{gap:4px;align-items:center}
|
|
684
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-transport{display:flex}
|
|
685
|
+
.knobs-ui.knobs-timeline[data-variant="line"] .knobs-tl-play{width:28px;height:28px;min-width:28px;min-height:28px;border-radius:var(--_k-radius);background:transparent;color:var(--_k-fg-2);
|
|
686
|
+
transition:background calc(var(--_k-hover-out) * 1ms),transform .15s var(--_ku-ease)}
|
|
687
|
+
.knobs-ui.knobs-timeline[data-variant="line"][data-playing] .knobs-tl-play{background:transparent;color:var(--_k-fg-2)}
|
|
688
|
+
.knobs-ui.knobs-timeline[data-variant="line"] .knobs-tl-play:hover{background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
689
|
+
.knobs-ui.knobs-timeline[data-variant="line"] .knobs-tl-track{cursor:default;transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
690
|
+
.knobs-ui.knobs-timeline[data-variant="line"] .knobs-tl-track:hover{background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
685
691
|
`;
|
|
686
692
|
|
|
687
693
|
// src/ui/overlay-css.ts
|
|
@@ -8177,196 +8183,6 @@ var init_compare_strip = __esm(() => {
|
|
|
8177
8183
|
DIFF = { w: 32, h: 18 };
|
|
8178
8184
|
});
|
|
8179
8185
|
|
|
8180
|
-
// src/ui/player.ts
|
|
8181
|
-
function player(container, options) {
|
|
8182
|
-
const doc = container.ownerDocument;
|
|
8183
|
-
const el = (tag, cls) => {
|
|
8184
|
-
const n = doc.createElement(tag);
|
|
8185
|
-
n.className = cls;
|
|
8186
|
-
return n;
|
|
8187
|
-
};
|
|
8188
|
-
const look = {
|
|
8189
|
-
...options.preset ? { preset: options.preset } : {},
|
|
8190
|
-
...options.theme ? { theme: options.theme } : {},
|
|
8191
|
-
...options.appearance ? { appearance: options.appearance } : {}
|
|
8192
|
-
};
|
|
8193
|
-
const root = el("div", "knobs-player");
|
|
8194
|
-
root.setAttribute("role", "group");
|
|
8195
|
-
root.setAttribute("aria-label", options.label ?? "Video");
|
|
8196
|
-
applyLook2(root, options);
|
|
8197
|
-
const frame = el("div", "knobs-player-frame");
|
|
8198
|
-
frame.style.setProperty("--kp-aspect", String(options.aspect ?? 16 / 9));
|
|
8199
|
-
const v = el("video", "knobs-player-media");
|
|
8200
|
-
v.muted = options.muted ?? true;
|
|
8201
|
-
v.defaultMuted = v.muted;
|
|
8202
|
-
v.playsInline = true;
|
|
8203
|
-
v.preload = "metadata";
|
|
8204
|
-
v.setAttribute("playsinline", "");
|
|
8205
|
-
if (options.poster)
|
|
8206
|
-
v.poster = options.poster;
|
|
8207
|
-
if (options.captions) {
|
|
8208
|
-
const track = doc.createElement("track");
|
|
8209
|
-
track.kind = "captions";
|
|
8210
|
-
track.label = "Captions";
|
|
8211
|
-
track.srclang = doc.documentElement.lang || "en";
|
|
8212
|
-
track.default = true;
|
|
8213
|
-
track.src = options.captions;
|
|
8214
|
-
v.append(track);
|
|
8215
|
-
}
|
|
8216
|
-
const glyph = playGlyph(doc);
|
|
8217
|
-
frame.append(v, glyph.element);
|
|
8218
|
-
const host = el("div", "knobs-player-line");
|
|
8219
|
-
root.append(frame, host);
|
|
8220
|
-
container.append(root);
|
|
8221
|
-
const markers = (options.chapters ?? []).map((c, i) => ({
|
|
8222
|
-
id: c.id ?? `c${i}`,
|
|
8223
|
-
time: c.start,
|
|
8224
|
-
label: c.label
|
|
8225
|
-
}));
|
|
8226
|
-
const tl = timeline(host, {
|
|
8227
|
-
...look,
|
|
8228
|
-
variant: "line",
|
|
8229
|
-
duration: 1,
|
|
8230
|
-
fps: options.fps ?? 30,
|
|
8231
|
-
markers,
|
|
8232
|
-
repeat: options.loop ?? true,
|
|
8233
|
-
arrows: { step: 5, shift: 10 },
|
|
8234
|
-
label: options.label ? `${options.label} time` : "Video time",
|
|
8235
|
-
...options.hints === false ? { hints: false } : {}
|
|
8236
|
-
});
|
|
8237
|
-
const onFrame = () => root.setAttribute("data-ready", "");
|
|
8238
|
-
let pending = null;
|
|
8239
|
-
const seekVideo = (t) => {
|
|
8240
|
-
if (v.readyState < 1)
|
|
8241
|
-
return;
|
|
8242
|
-
if (v.seeking)
|
|
8243
|
-
pending = t;
|
|
8244
|
-
else
|
|
8245
|
-
v.currentTime = t;
|
|
8246
|
-
};
|
|
8247
|
-
let reported = 0;
|
|
8248
|
-
const onSeeked = () => {
|
|
8249
|
-
if (pending !== null) {
|
|
8250
|
-
const t = pending;
|
|
8251
|
-
pending = null;
|
|
8252
|
-
v.currentTime = t;
|
|
8253
|
-
return;
|
|
8254
|
-
}
|
|
8255
|
-
if (!v.paused || tl.playing || Math.abs(v.currentTime - reported) < 0.1)
|
|
8256
|
-
return;
|
|
8257
|
-
reported = v.currentTime;
|
|
8258
|
-
options.onSeek?.(reported);
|
|
8259
|
-
};
|
|
8260
|
-
const onMeta = () => {
|
|
8261
|
-
onFrame();
|
|
8262
|
-
if (v.videoWidth)
|
|
8263
|
-
frame.style.setProperty("--kp-aspect", String(v.videoWidth / v.videoHeight));
|
|
8264
|
-
if (Number.isFinite(v.duration))
|
|
8265
|
-
tl.update({ duration: v.duration });
|
|
8266
|
-
};
|
|
8267
|
-
v.addEventListener("loadedmetadata", onMeta);
|
|
8268
|
-
v.addEventListener("loadeddata", onFrame);
|
|
8269
|
-
v.addEventListener("seeked", onSeeked);
|
|
8270
|
-
const unlisten = tl.listen({
|
|
8271
|
-
onSeek(t, source) {
|
|
8272
|
-
if (source === "play") {
|
|
8273
|
-
if (Math.abs(v.currentTime - t) > 0.25)
|
|
8274
|
-
v.currentTime = t;
|
|
8275
|
-
return;
|
|
8276
|
-
}
|
|
8277
|
-
if (Math.abs(v.currentTime - t) < 1 / (options.fps ?? 30))
|
|
8278
|
-
return;
|
|
8279
|
-
seekVideo(t);
|
|
8280
|
-
},
|
|
8281
|
-
onPlay(on) {
|
|
8282
|
-
if (on)
|
|
8283
|
-
v.play().catch(() => tl.pause());
|
|
8284
|
-
else {
|
|
8285
|
-
v.pause();
|
|
8286
|
-
reported = tl.time;
|
|
8287
|
-
}
|
|
8288
|
-
root.toggleAttribute("data-playing", on);
|
|
8289
|
-
options.onPlay?.(on, tl.time);
|
|
8290
|
-
},
|
|
8291
|
-
onScrub(on) {
|
|
8292
|
-
if (on)
|
|
8293
|
-
v.pause();
|
|
8294
|
-
}
|
|
8295
|
-
});
|
|
8296
|
-
tl.drive(() => {
|
|
8297
|
-
if (v.readyState < 1)
|
|
8298
|
-
return Number.NaN;
|
|
8299
|
-
if (v.seeking)
|
|
8300
|
-
return tl.time;
|
|
8301
|
-
return v.ended ? Number.POSITIVE_INFINITY : v.currentTime;
|
|
8302
|
-
});
|
|
8303
|
-
const onClick = (e) => {
|
|
8304
|
-
if (e.button !== 0)
|
|
8305
|
-
return;
|
|
8306
|
-
tl.toggle();
|
|
8307
|
-
glyph.flash(tl.playing);
|
|
8308
|
-
tl.focus();
|
|
8309
|
-
};
|
|
8310
|
-
frame.addEventListener("click", onClick);
|
|
8311
|
-
v.src = options.src;
|
|
8312
|
-
const api = {
|
|
8313
|
-
element: root,
|
|
8314
|
-
video: v,
|
|
8315
|
-
timeline: tl,
|
|
8316
|
-
get time() {
|
|
8317
|
-
return tl.time;
|
|
8318
|
-
},
|
|
8319
|
-
get playing() {
|
|
8320
|
-
return tl.playing;
|
|
8321
|
-
},
|
|
8322
|
-
get duration() {
|
|
8323
|
-
return Number.isFinite(v.duration) ? v.duration : 0;
|
|
8324
|
-
},
|
|
8325
|
-
play: () => tl.play(),
|
|
8326
|
-
pause: () => tl.pause(),
|
|
8327
|
-
toggle: () => tl.toggle(),
|
|
8328
|
-
seek: (t, o) => tl.seek(t, o?.glide ? { glide: true } : undefined),
|
|
8329
|
-
seekBy: (d) => tl.seek(Math.min(tl.duration, Math.max(0, tl.time + d)), { glide: true }),
|
|
8330
|
-
focus: () => tl.focus(),
|
|
8331
|
-
dispose() {
|
|
8332
|
-
unlisten();
|
|
8333
|
-
glyph.dispose();
|
|
8334
|
-
tl.drive(null);
|
|
8335
|
-
tl.dispose();
|
|
8336
|
-
v.pause();
|
|
8337
|
-
v.removeEventListener("loadedmetadata", onMeta);
|
|
8338
|
-
v.removeEventListener("loadeddata", onFrame);
|
|
8339
|
-
v.removeEventListener("seeked", onSeeked);
|
|
8340
|
-
v.removeAttribute("src");
|
|
8341
|
-
v.load();
|
|
8342
|
-
root.remove();
|
|
8343
|
-
}
|
|
8344
|
-
};
|
|
8345
|
-
return api;
|
|
8346
|
-
}
|
|
8347
|
-
function playGlyph(doc) {
|
|
8348
|
-
const element = doc.createElement("span");
|
|
8349
|
-
element.className = "knobs-player-glyph";
|
|
8350
|
-
element.setAttribute("aria-hidden", "true");
|
|
8351
|
-
let timer = 0;
|
|
8352
|
-
const win = doc.defaultView;
|
|
8353
|
-
return {
|
|
8354
|
-
element,
|
|
8355
|
-
flash(playing) {
|
|
8356
|
-
element.innerHTML = playing ? PLAY : PAUSE;
|
|
8357
|
-
element.setAttribute("data-flash", "");
|
|
8358
|
-
win.clearTimeout(timer);
|
|
8359
|
-
timer = win.setTimeout(() => element.removeAttribute("data-flash"), FLASH_MS);
|
|
8360
|
-
},
|
|
8361
|
-
dispose: () => win.clearTimeout(timer)
|
|
8362
|
-
};
|
|
8363
|
-
}
|
|
8364
|
-
var FLASH_MS = 450;
|
|
8365
|
-
var init_player = __esm(() => {
|
|
8366
|
-
init_look();
|
|
8367
|
-
init_timeline();
|
|
8368
|
-
});
|
|
8369
|
-
|
|
8370
8186
|
// src/ui/compare.ts
|
|
8371
8187
|
function compare(container, options) {
|
|
8372
8188
|
const doc = container.ownerDocument;
|
|
@@ -8485,8 +8301,7 @@ function compare(container, options) {
|
|
|
8485
8301
|
grip.setAttribute("aria-hidden", "true");
|
|
8486
8302
|
handle.append(grip);
|
|
8487
8303
|
const note = el("div", "knobs-cmp-note");
|
|
8488
|
-
|
|
8489
|
-
stage.append(canvas, split, seam, labels[0], labels[1], handle, zoomPill, note, glyph.element);
|
|
8304
|
+
stage.append(canvas, split, seam, labels[0], labels[1], handle, zoomPill, note);
|
|
8490
8305
|
root.append(bar, stage);
|
|
8491
8306
|
const wantsStrip = options.strip === true;
|
|
8492
8307
|
let tl = bound;
|
|
@@ -8528,7 +8343,6 @@ function compare(container, options) {
|
|
|
8528
8343
|
let drag = null;
|
|
8529
8344
|
const touches = new Map;
|
|
8530
8345
|
let pinch = null;
|
|
8531
|
-
let press = null;
|
|
8532
8346
|
const zu = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
8533
8347
|
const zv = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
8534
8348
|
const zw = new Spring(1, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
@@ -9357,10 +9171,8 @@ function compare(container, options) {
|
|
|
9357
9171
|
root.focus({ preventScroll: true });
|
|
9358
9172
|
touches.set(e.pointerId, p);
|
|
9359
9173
|
stage.setPointerCapture(e.pointerId);
|
|
9360
|
-
press = touches.size === 1 && mode !== "wipe" && master() ? p : null;
|
|
9361
9174
|
if (touches.size >= 2) {
|
|
9362
9175
|
e.preventDefault();
|
|
9363
|
-
press = null;
|
|
9364
9176
|
return startPinch();
|
|
9365
9177
|
}
|
|
9366
9178
|
if (mode === "wipe") {
|
|
@@ -9388,8 +9200,6 @@ function compare(container, options) {
|
|
|
9388
9200
|
const onMove = (e) => {
|
|
9389
9201
|
const p = local(e);
|
|
9390
9202
|
pointer = p;
|
|
9391
|
-
if (press && Math.hypot(p.x - press.x, p.y - press.y) > 4)
|
|
9392
|
-
press = null;
|
|
9393
9203
|
if (touches.has(e.pointerId))
|
|
9394
9204
|
touches.set(e.pointerId, p);
|
|
9395
9205
|
if (pinch && touches.size >= 2) {
|
|
@@ -9419,11 +9229,6 @@ function compare(container, options) {
|
|
|
9419
9229
|
drawNow();
|
|
9420
9230
|
};
|
|
9421
9231
|
const endDrag = (e) => {
|
|
9422
|
-
if (press && e.type === "pointerup") {
|
|
9423
|
-
api.toggle();
|
|
9424
|
-
glyph.flash(isPlaying());
|
|
9425
|
-
}
|
|
9426
|
-
press = null;
|
|
9427
9232
|
touches.delete(e.pointerId);
|
|
9428
9233
|
if (touches.size < 2)
|
|
9429
9234
|
pinch = null;
|
|
@@ -9585,7 +9390,6 @@ function compare(container, options) {
|
|
|
9585
9390
|
old.el.replaceWith(s.el);
|
|
9586
9391
|
old.preview.replaceWith(s.preview);
|
|
9587
9392
|
sides[index] = s;
|
|
9588
|
-
root.toggleAttribute("data-video", sides.some((x) => x.kind === "video"));
|
|
9589
9393
|
note.textContent = "";
|
|
9590
9394
|
setLabel(index, labelOf(index));
|
|
9591
9395
|
if (near)
|
|
@@ -9600,7 +9404,6 @@ function compare(container, options) {
|
|
|
9600
9404
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
9601
9405
|
setLabel(0, labelOf(0));
|
|
9602
9406
|
setLabel(1, labelOf(1));
|
|
9603
|
-
root.toggleAttribute("data-video", sides.some((s) => s.kind === "video"));
|
|
9604
9407
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
9605
9408
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
9606
9409
|
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
@@ -9801,7 +9604,6 @@ function compare(container, options) {
|
|
|
9801
9604
|
disposed = true;
|
|
9802
9605
|
loop.stop();
|
|
9803
9606
|
modePill?.dispose();
|
|
9804
|
-
glyph.dispose();
|
|
9805
9607
|
win.clearTimeout(releaseTimer);
|
|
9806
9608
|
ro.disconnect();
|
|
9807
9609
|
nearIo?.disconnect();
|
|
@@ -9842,7 +9644,6 @@ var init_compare = __esm(() => {
|
|
|
9842
9644
|
init_icons();
|
|
9843
9645
|
init_look();
|
|
9844
9646
|
init_rgba();
|
|
9845
|
-
init_player();
|
|
9846
9647
|
init_selection_pill();
|
|
9847
9648
|
init_timeline();
|
|
9848
9649
|
init_timeline_model();
|
|
@@ -9861,6 +9662,171 @@ var init_compare = __esm(() => {
|
|
|
9861
9662
|
};
|
|
9862
9663
|
});
|
|
9863
9664
|
|
|
9665
|
+
// src/ui/player.ts
|
|
9666
|
+
function player(container, options) {
|
|
9667
|
+
const doc = container.ownerDocument;
|
|
9668
|
+
const el = (tag, cls) => {
|
|
9669
|
+
const n = doc.createElement(tag);
|
|
9670
|
+
n.className = cls;
|
|
9671
|
+
return n;
|
|
9672
|
+
};
|
|
9673
|
+
const look = {
|
|
9674
|
+
...options.preset ? { preset: options.preset } : {},
|
|
9675
|
+
...options.theme ? { theme: options.theme } : {},
|
|
9676
|
+
...options.appearance ? { appearance: options.appearance } : {}
|
|
9677
|
+
};
|
|
9678
|
+
const root = el("div", "knobs-player");
|
|
9679
|
+
root.setAttribute("role", "group");
|
|
9680
|
+
root.setAttribute("aria-label", options.label ?? "Video");
|
|
9681
|
+
applyLook2(root, options);
|
|
9682
|
+
const frame = el("div", "knobs-player-frame");
|
|
9683
|
+
frame.style.setProperty("--kp-aspect", String(options.aspect ?? 16 / 9));
|
|
9684
|
+
const v = el("video", "knobs-player-media");
|
|
9685
|
+
v.muted = options.muted ?? true;
|
|
9686
|
+
v.defaultMuted = v.muted;
|
|
9687
|
+
v.playsInline = true;
|
|
9688
|
+
v.preload = "metadata";
|
|
9689
|
+
v.setAttribute("playsinline", "");
|
|
9690
|
+
if (options.poster)
|
|
9691
|
+
v.poster = options.poster;
|
|
9692
|
+
if (options.captions) {
|
|
9693
|
+
const track = doc.createElement("track");
|
|
9694
|
+
track.kind = "captions";
|
|
9695
|
+
track.label = "Captions";
|
|
9696
|
+
track.srclang = doc.documentElement.lang || "en";
|
|
9697
|
+
track.default = true;
|
|
9698
|
+
track.src = options.captions;
|
|
9699
|
+
v.append(track);
|
|
9700
|
+
}
|
|
9701
|
+
frame.append(v);
|
|
9702
|
+
const host = el("div", "knobs-player-line");
|
|
9703
|
+
root.append(frame, host);
|
|
9704
|
+
container.append(root);
|
|
9705
|
+
const markers = (options.chapters ?? []).map((c, i) => ({
|
|
9706
|
+
id: c.id ?? `c${i}`,
|
|
9707
|
+
time: c.start,
|
|
9708
|
+
label: c.label
|
|
9709
|
+
}));
|
|
9710
|
+
const tl = timeline(host, {
|
|
9711
|
+
...look,
|
|
9712
|
+
variant: "line",
|
|
9713
|
+
duration: 1,
|
|
9714
|
+
fps: options.fps ?? 30,
|
|
9715
|
+
markers,
|
|
9716
|
+
repeat: options.loop ?? true,
|
|
9717
|
+
arrows: { step: 5, shift: 10 },
|
|
9718
|
+
label: options.label ? `${options.label} time` : "Video time",
|
|
9719
|
+
...options.hints === false ? { hints: false } : {}
|
|
9720
|
+
});
|
|
9721
|
+
const onFrame = () => root.setAttribute("data-ready", "");
|
|
9722
|
+
let pending = null;
|
|
9723
|
+
const seekVideo = (t) => {
|
|
9724
|
+
if (v.readyState < 1)
|
|
9725
|
+
return;
|
|
9726
|
+
if (v.seeking)
|
|
9727
|
+
pending = t;
|
|
9728
|
+
else
|
|
9729
|
+
v.currentTime = t;
|
|
9730
|
+
};
|
|
9731
|
+
let reported = 0;
|
|
9732
|
+
const onSeeked = () => {
|
|
9733
|
+
if (pending !== null) {
|
|
9734
|
+
const t = pending;
|
|
9735
|
+
pending = null;
|
|
9736
|
+
v.currentTime = t;
|
|
9737
|
+
return;
|
|
9738
|
+
}
|
|
9739
|
+
if (!v.paused || tl.playing || Math.abs(v.currentTime - reported) < 0.1)
|
|
9740
|
+
return;
|
|
9741
|
+
reported = v.currentTime;
|
|
9742
|
+
options.onSeek?.(reported);
|
|
9743
|
+
};
|
|
9744
|
+
const onMeta = () => {
|
|
9745
|
+
onFrame();
|
|
9746
|
+
if (v.videoWidth)
|
|
9747
|
+
frame.style.setProperty("--kp-aspect", String(v.videoWidth / v.videoHeight));
|
|
9748
|
+
if (Number.isFinite(v.duration))
|
|
9749
|
+
tl.update({ duration: v.duration });
|
|
9750
|
+
};
|
|
9751
|
+
v.addEventListener("loadedmetadata", onMeta);
|
|
9752
|
+
v.addEventListener("loadeddata", onFrame);
|
|
9753
|
+
v.addEventListener("seeked", onSeeked);
|
|
9754
|
+
const unlisten = tl.listen({
|
|
9755
|
+
onSeek(t, source) {
|
|
9756
|
+
if (source === "play") {
|
|
9757
|
+
if (Math.abs(v.currentTime - t) > 0.25)
|
|
9758
|
+
v.currentTime = t;
|
|
9759
|
+
return;
|
|
9760
|
+
}
|
|
9761
|
+
if (Math.abs(v.currentTime - t) < 1 / (options.fps ?? 30))
|
|
9762
|
+
return;
|
|
9763
|
+
seekVideo(t);
|
|
9764
|
+
},
|
|
9765
|
+
onPlay(on) {
|
|
9766
|
+
if (on)
|
|
9767
|
+
v.play().catch(() => tl.pause());
|
|
9768
|
+
else {
|
|
9769
|
+
v.pause();
|
|
9770
|
+
reported = tl.time;
|
|
9771
|
+
}
|
|
9772
|
+
root.toggleAttribute("data-playing", on);
|
|
9773
|
+
options.onPlay?.(on, tl.time);
|
|
9774
|
+
},
|
|
9775
|
+
onScrub(on) {
|
|
9776
|
+
if (on)
|
|
9777
|
+
v.pause();
|
|
9778
|
+
}
|
|
9779
|
+
});
|
|
9780
|
+
tl.drive(() => {
|
|
9781
|
+
if (v.readyState < 1)
|
|
9782
|
+
return Number.NaN;
|
|
9783
|
+
if (v.seeking)
|
|
9784
|
+
return tl.time;
|
|
9785
|
+
return v.ended ? Number.POSITIVE_INFINITY : v.currentTime;
|
|
9786
|
+
});
|
|
9787
|
+
const onClick = () => tl.focus();
|
|
9788
|
+
frame.addEventListener("click", onClick);
|
|
9789
|
+
v.src = options.src;
|
|
9790
|
+
const api = {
|
|
9791
|
+
element: root,
|
|
9792
|
+
video: v,
|
|
9793
|
+
timeline: tl,
|
|
9794
|
+
get time() {
|
|
9795
|
+
return tl.time;
|
|
9796
|
+
},
|
|
9797
|
+
get playing() {
|
|
9798
|
+
return tl.playing;
|
|
9799
|
+
},
|
|
9800
|
+
get duration() {
|
|
9801
|
+
return Number.isFinite(v.duration) ? v.duration : 0;
|
|
9802
|
+
},
|
|
9803
|
+
play: () => tl.play(),
|
|
9804
|
+
pause: () => tl.pause(),
|
|
9805
|
+
toggle: () => tl.toggle(),
|
|
9806
|
+
seek: (t, o) => tl.seek(t, o?.glide ? { glide: true } : undefined),
|
|
9807
|
+
seekBy: (d) => tl.seek(Math.min(tl.duration, Math.max(0, tl.time + d)), { glide: true }),
|
|
9808
|
+
focus: () => tl.focus(),
|
|
9809
|
+
dispose() {
|
|
9810
|
+
unlisten();
|
|
9811
|
+
tl.drive(null);
|
|
9812
|
+
tl.dispose();
|
|
9813
|
+
v.pause();
|
|
9814
|
+
frame.removeEventListener("click", onClick);
|
|
9815
|
+
v.removeEventListener("loadedmetadata", onMeta);
|
|
9816
|
+
v.removeEventListener("loadeddata", onFrame);
|
|
9817
|
+
v.removeEventListener("seeked", onSeeked);
|
|
9818
|
+
v.removeAttribute("src");
|
|
9819
|
+
v.load();
|
|
9820
|
+
root.remove();
|
|
9821
|
+
}
|
|
9822
|
+
};
|
|
9823
|
+
return api;
|
|
9824
|
+
}
|
|
9825
|
+
var init_player = __esm(() => {
|
|
9826
|
+
init_look();
|
|
9827
|
+
init_timeline();
|
|
9828
|
+
});
|
|
9829
|
+
|
|
9864
9830
|
// src/ui/scrollbar.ts
|
|
9865
9831
|
function overlayScrollbar(scroller, content) {
|
|
9866
9832
|
const doc = scroller.ownerDocument;
|
|
@@ -10935,16 +10901,17 @@ var init_diff_css = __esm(() => {
|
|
|
10935
10901
|
.knobs-diff-nav>span{min-width:3.6em;text-align:center}
|
|
10936
10902
|
:where(.knobs-ui) :is(.knobs-diff-btn,.knobs-diff-choice,.knobs-diff-viewed,.knobs-diff-filter>input,.knobs-diff-filter>button){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;border-radius:0;
|
|
10937
10903
|
margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
10938
|
-
.knobs-ui .knobs-diff-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:calc(var(--_k-radius) * 999);color:var(--_k-fg-
|
|
10939
|
-
transition:background
|
|
10940
|
-
|
|
10904
|
+
.knobs-ui .knobs-diff-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:calc(var(--_k-radius) * 999);color:var(--_k-fg-2);cursor:default;
|
|
10905
|
+
transition:background calc(var(--_k-hover-out) * 1ms),opacity .15s}
|
|
10906
|
+
/* Hover is a quiet fill under the arrow cursor (no hand, no brightening), there at once. */
|
|
10907
|
+
.knobs-ui .knobs-diff-btn:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
10941
10908
|
.knobs-ui .knobs-diff-btn[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
10942
10909
|
.knobs-ui .knobs-diff-btn:disabled{opacity:.35;cursor:default;background:transparent}
|
|
10943
10910
|
.knobs-diff-btn svg{width:16px;height:16px}
|
|
10944
10911
|
/* Viewed: a check with its word, as on GitHub; the path dims once it's ticked. */
|
|
10945
10912
|
.knobs-ui .knobs-diff-viewed{flex:none;display:inline-flex;align-items:center;gap:5px;height:var(--_k-control-h);padding:0 8px 0 6px;border-radius:var(--kd-ctl);color:var(--_k-fg-2);
|
|
10946
|
-
font-size:var(--_k-text-meta);font-weight:var(--_k-weight-label);white-space:nowrap;cursor:
|
|
10947
|
-
.knobs-ui .knobs-diff-viewed:is(:hover,:focus-visible){background:var(--
|
|
10913
|
+
font-size:var(--_k-text-meta);font-weight:var(--_k-weight-label);white-space:nowrap;cursor:default;transition:background calc(var(--_k-hover-out) * 1ms),color .15s}
|
|
10914
|
+
.knobs-ui .knobs-diff-viewed:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
10948
10915
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
10949
10916
|
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
10950
10917
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
@@ -10963,8 +10930,8 @@ var init_diff_css = __esm(() => {
|
|
|
10963
10930
|
choice isn't brighter for being picked. Choices are styled by class, as the copy holds them too. */
|
|
10964
10931
|
.knobs-diff-seg{position:relative;flex:none;display:grid;grid-template-columns:1fr 1fr;height:var(--_k-control-h);padding:2px;border-radius:var(--kd-ctl);background:var(--_k-fill)}
|
|
10965
10932
|
.knobs-ui .knobs-diff-choice{padding:0 9px;border-radius:max(0px,calc(var(--kd-ctl) - 2px));color:var(--_k-fg-2);font-size:var(--_k-text-meta);
|
|
10966
|
-
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:
|
|
10967
|
-
.knobs-ui .knobs-diff-choice:is(:hover,:focus-visible){
|
|
10933
|
+
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:default;transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
10934
|
+
.knobs-ui .knobs-diff-choice:not([aria-checked="true"]):is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
10968
10935
|
/* The diff: one layer per file or layout on show, the old fading under the new. */
|
|
10969
10936
|
.knobs-diff-body{position:relative;flex:1;min-height:0}
|
|
10970
10937
|
.knobs-diff-probe{position:absolute;left:0;top:0;width:0;height:var(--kd-line);visibility:hidden;pointer-events:none}
|
|
@@ -11060,8 +11027,8 @@ var init_diff_css = __esm(() => {
|
|
|
11060
11027
|
.knobs-diff-filter svg{width:12px;height:12px;flex:none}
|
|
11061
11028
|
.knobs-ui .knobs-diff-filter>input{flex:1;min-width:0;height:100%;font:var(--_k-weight) var(--_k-font-size)/1 var(--_k-font);color:var(--_k-fg);caret-color:var(--_k-accent);background:transparent}
|
|
11062
11029
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
11063
|
-
.knobs-ui .knobs-diff-filter>button{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;color:var(--_k-fg-3);cursor:
|
|
11064
|
-
.knobs-ui .knobs-diff-filter>button:hover{background:var(--
|
|
11030
|
+
.knobs-ui .knobs-diff-filter>button{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;color:var(--_k-fg-3);cursor:default;transition:background calc(var(--_k-hover-out) * 1ms),opacity .12s}
|
|
11031
|
+
.knobs-ui .knobs-diff-filter>button:hover{background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
11065
11032
|
.knobs-diff-filter>button svg{width:12px;height:12px}
|
|
11066
11033
|
.knobs-diff-list{position:relative;flex:1;min-height:0}
|
|
11067
11034
|
.knobs-diff-files .knobs-diff-counts{font-size:var(--_k-text-meta);align-items:center}
|
|
@@ -17451,25 +17418,63 @@ function normalizeWalkthrough(doc) {
|
|
|
17451
17418
|
})),
|
|
17452
17419
|
sections: withKickers(sections, doc.sections, doc.kickers),
|
|
17453
17420
|
steps,
|
|
17454
|
-
prs: knownPRs(doc, sections),
|
|
17421
|
+
prs: knownPRs(doc, sections, steps),
|
|
17455
17422
|
...repoOf(doc) ? { repo: repoOf(doc) } : {}
|
|
17456
17423
|
};
|
|
17457
17424
|
}
|
|
17458
17425
|
var prNumber = (href) => /\/(?:pull|merge_requests)\/(\d+)(?:[/?#]|$)/.exec(href)?.[1] ?? null;
|
|
17459
17426
|
var repoOf = (doc) => doc.repo?.trim().replace(/^https?:\/\/github\.com\//, "").replace(/\/+$/, "") || undefined;
|
|
17460
|
-
|
|
17427
|
+
var PR_STATES = ["merged", "open", "draft", "closed"];
|
|
17428
|
+
function prStatus(status) {
|
|
17429
|
+
const words = (status ?? "").trim().toLowerCase();
|
|
17430
|
+
const first = /^[a-z]+/.exec(words)?.[0] ?? "";
|
|
17431
|
+
const state = PR_STATES.includes(first) ? first : first === "shipped" || first === "done" ? "merged" : null;
|
|
17432
|
+
return { state, checks: /\b(green|passing|passed|ci|checks? pass)/.test(words) };
|
|
17433
|
+
}
|
|
17434
|
+
function knownPRs(doc, sections, steps = []) {
|
|
17461
17435
|
const out = {};
|
|
17462
17436
|
const repo = repoOf(doc);
|
|
17463
|
-
|
|
17464
|
-
const
|
|
17465
|
-
|
|
17466
|
-
|
|
17467
|
-
|
|
17437
|
+
const add = (n, pr) => {
|
|
17438
|
+
const known = out[n] ?? {};
|
|
17439
|
+
const next = { ...known };
|
|
17440
|
+
for (const [k, v] of Object.entries(pr))
|
|
17441
|
+
if (v !== undefined && next[k] === undefined)
|
|
17442
|
+
next[k] = v;
|
|
17443
|
+
out[n] = next;
|
|
17444
|
+
};
|
|
17468
17445
|
for (const [k, pr] of Object.entries(doc.prs ?? {})) {
|
|
17469
17446
|
const n = k.replace(/^#/, "");
|
|
17470
17447
|
if (!/^\d+$/.test(n))
|
|
17471
17448
|
continue;
|
|
17472
|
-
|
|
17449
|
+
add(n, pr);
|
|
17450
|
+
}
|
|
17451
|
+
for (const step of steps)
|
|
17452
|
+
for (const m of step.media) {
|
|
17453
|
+
if (m.kind !== "stack")
|
|
17454
|
+
continue;
|
|
17455
|
+
for (const it of m.items) {
|
|
17456
|
+
const n = it.pr.replace(/^#/, "");
|
|
17457
|
+
if (!/^\d+$/.test(n))
|
|
17458
|
+
continue;
|
|
17459
|
+
const said = prStatus(it.status);
|
|
17460
|
+
add(n, {
|
|
17461
|
+
...said.state ? { state: said.state } : {},
|
|
17462
|
+
...said.state && said.checks ? { checks: true } : {},
|
|
17463
|
+
...it.title ? { title: plainMarkdown(it.title) } : {},
|
|
17464
|
+
...it.href ? { href: it.href } : {}
|
|
17465
|
+
});
|
|
17466
|
+
}
|
|
17467
|
+
}
|
|
17468
|
+
for (const s of sections) {
|
|
17469
|
+
const n = s.link && prNumber(s.link.href);
|
|
17470
|
+
if (!n)
|
|
17471
|
+
continue;
|
|
17472
|
+
const said = prStatus(s.status);
|
|
17473
|
+
add(n, {
|
|
17474
|
+
href: s.link.href.replace(/(\/pull\/\d+).*$/, "$1"),
|
|
17475
|
+
...said.state ? { state: said.state } : {},
|
|
17476
|
+
title: plainMarkdown(s.title)
|
|
17477
|
+
});
|
|
17473
17478
|
}
|
|
17474
17479
|
if (repo) {
|
|
17475
17480
|
for (const n of Object.keys(out))
|
|
@@ -17478,12 +17483,17 @@ function knownPRs(doc, sections) {
|
|
|
17478
17483
|
}
|
|
17479
17484
|
return out;
|
|
17480
17485
|
}
|
|
17481
|
-
function findPR(prs, n, repo) {
|
|
17482
|
-
const
|
|
17486
|
+
function findPR(prs, n, repo, kind = "pr") {
|
|
17487
|
+
const entry = prs[n];
|
|
17488
|
+
const known = entry && (entry.kind ?? "pr") === kind ? entry : undefined;
|
|
17489
|
+
const path = kind === "issue" ? "issues" : "pull";
|
|
17490
|
+
const href = repo ? `https://github.com/${repo}/${path}/${n}` : undefined;
|
|
17491
|
+
const base = kind === "issue" ? { kind } : {};
|
|
17483
17492
|
if (known)
|
|
17484
|
-
return known;
|
|
17485
|
-
return
|
|
17493
|
+
return known.href || !href ? { ...base, ...known } : { ...base, ...known, href };
|
|
17494
|
+
return href ? { ...base, href } : kind === "issue" ? { kind } : null;
|
|
17486
17495
|
}
|
|
17496
|
+
var issueNumber = (href) => /^https?:\/\/[^/]+\/.+\/issues\/(\d+)\/?(?:[?#].*)?$/.exec(href)?.[1] ?? null;
|
|
17487
17497
|
var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
|
|
17488
17498
|
function withKickers(sections, source, kickers = "pr") {
|
|
17489
17499
|
if (kickers === false)
|
|
@@ -21979,7 +21989,7 @@ function mountHistory(host, m, steps) {
|
|
|
21979
21989
|
context: () => ({ kind: "history" })
|
|
21980
21990
|
};
|
|
21981
21991
|
}
|
|
21982
|
-
function mountStack(host, m, steps) {
|
|
21992
|
+
function mountStack(host, m, steps, findPR) {
|
|
21983
21993
|
const doc = host.ownerDocument;
|
|
21984
21994
|
const layout = stackLayout(m);
|
|
21985
21995
|
const root = el2(doc, "div", "knobs-wt-stack");
|
|
@@ -22021,7 +22031,10 @@ function mountStack(host, m, steps) {
|
|
|
22021
22031
|
const line = el2(doc, "div", "knobs-wt-sline");
|
|
22022
22032
|
if (it.order)
|
|
22023
22033
|
line.append(text2(doc, "span", "knobs-wt-sord", it.order));
|
|
22024
|
-
|
|
22034
|
+
const known = findPR?.(it.pr.replace(/^#/, "")) ?? null;
|
|
22035
|
+
const pr = link(doc, "knobs-wt-spr", it.pr, it.href ?? known?.href);
|
|
22036
|
+
pr.addEventListener("click", (e) => e.stopPropagation());
|
|
22037
|
+
line.append(pr);
|
|
22025
22038
|
const target = it.step ? steps?.find(it.step) : null;
|
|
22026
22039
|
if (target && steps) {
|
|
22027
22040
|
const title = text2(doc, "button", "knobs-wt-stitle", it.title);
|
|
@@ -22056,7 +22069,11 @@ function mountStack(host, m, steps) {
|
|
|
22056
22069
|
if (meta.childNodes.length)
|
|
22057
22070
|
main.append(meta);
|
|
22058
22071
|
row.append(main);
|
|
22059
|
-
|
|
22072
|
+
const said = prStatus(it.status);
|
|
22073
|
+
const state = known?.state ?? said.state;
|
|
22074
|
+
if (state)
|
|
22075
|
+
row.append(prStateLabel(doc, state, said.checks, it.status));
|
|
22076
|
+
else if (it.status) {
|
|
22060
22077
|
const chip = text2(doc, "span", "knobs-wt-chip knobs-wt-sstatus", it.status);
|
|
22061
22078
|
chip.dataset.tone = it.tone ?? "dim";
|
|
22062
22079
|
row.append(chip);
|
|
@@ -22363,8 +22380,29 @@ var PR_PATHS = {
|
|
|
22363
22380
|
pull: "M104,64A32,32,0,1,0,64,95v66a32,32,0,1,0,16,0V95A32.06,32.06,0,0,0,104,64ZM56,64A16,16,0,1,1,72,80,16,16,0,0,1,56,64ZM88,192a16,16,0,1,1-16-16A16,16,0,0,1,88,192Zm120-31V110.63a23.85,23.85,0,0,0-7-17L163.31,56H192a8,8,0,0,0,0-16H144a8,8,0,0,0-8,8V96a8,8,0,0,0,16,0V67.31L189.66,105a8,8,0,0,1,2.34,5.66V161a32,32,0,1,0,16,0Zm-8,47a16,16,0,1,1,16-16A16,16,0,0,1,200,208Z",
|
|
22364
22381
|
merge: "M208,112a32.05,32.05,0,0,0-30.69,23l-42.21-6a8,8,0,0,1-4.95-2.71L94.43,84.55A32,32,0,1,0,72,87v82a32,32,0,1,0,16,0V101.63l30,35a24,24,0,0,0,14.83,8.14l44,6.28A32,32,0,1,0,208,112ZM64,56A16,16,0,1,1,80,72,16,16,0,0,1,64,56ZM96,200a16,16,0,1,1-16-16A16,16,0,0,1,96,200Zm112-40a16,16,0,1,1,16-16A16,16,0,0,1,208,160Z"
|
|
22365
22382
|
};
|
|
22366
|
-
var
|
|
22383
|
+
var DRAFT = "M104,64A32,32,0,1,0,64,95v66a32,32,0,1,0,16,0V95A32.06,32.06,0,0,0,104,64ZM56,64A16,16,0,1,1,72,80,16,16,0,0,1,56,64ZM88,192a16,16,0,1,1-16-16A16,16,0,0,1,88,192ZM232,192a32,32,0,1,1-32-32A32,32,0,0,1,232,192ZM216,192a16,16,0,1,0-16,16A16,16,0,0,0,216,192ZM212,120a12,12,0,1,1-12-12A12,12,0,0,1,212,120ZM212,60a12,12,0,1,1-12-12A12,12,0,0,1,212,60Z";
|
|
22384
|
+
var X = "M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z";
|
|
22385
|
+
var CHECK3 = "M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z";
|
|
22386
|
+
var svg12 = (d, evenodd = false) => `<svg class="knobs-icon" viewBox="0 0 256 256" width="12" height="12" fill="currentColor"${evenodd ? ' fill-rule="evenodd"' : ""} aria-hidden="true" focusable="false"><path d="${d}"/></svg>`;
|
|
22387
|
+
var prGlyph = (state) => state === "merged" ? svg12(PR_PATHS.merge) : state === "draft" ? svg12(DRAFT, true) : state === "closed" ? svg12(X) : svg12(PR_PATHS.pull);
|
|
22367
22388
|
var PR_STATE = { merged: "Merged", open: "Open", draft: "Draft", closed: "Closed" };
|
|
22389
|
+
var ISSUE = "M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-88a16,16,0,1,1-16-16A16,16,0,0,1,144,128Z";
|
|
22390
|
+
function prStateLabel(doc, state, checks, title) {
|
|
22391
|
+
const s = el2(doc, "span", "knobs-wt-prstate");
|
|
22392
|
+
s.dataset.state = state;
|
|
22393
|
+
s.innerHTML = prGlyph(state);
|
|
22394
|
+
s.append(text2(doc, "span", "", PR_STATE[state]));
|
|
22395
|
+
if (checks) {
|
|
22396
|
+
const c = el2(doc, "span", "knobs-wt-prchecks");
|
|
22397
|
+
c.innerHTML = svg12(CHECK3);
|
|
22398
|
+
c.title = "Checks pass";
|
|
22399
|
+
c.setAttribute("aria-label", "checks pass");
|
|
22400
|
+
s.append(c);
|
|
22401
|
+
}
|
|
22402
|
+
if (title)
|
|
22403
|
+
s.title = title;
|
|
22404
|
+
return s;
|
|
22405
|
+
}
|
|
22368
22406
|
function prChip(doc, n, pr) {
|
|
22369
22407
|
const chip = el2(doc, pr.href ? "a" : "span", "knobs-wt-pr");
|
|
22370
22408
|
if (pr.href) {
|
|
@@ -22372,27 +22410,55 @@ function prChip(doc, n, pr) {
|
|
|
22372
22410
|
chip.setAttribute("target", "_blank");
|
|
22373
22411
|
chip.setAttribute("rel", "noreferrer");
|
|
22374
22412
|
}
|
|
22413
|
+
const issue = pr.kind === "issue";
|
|
22414
|
+
if (issue)
|
|
22415
|
+
chip.dataset.kind = "issue";
|
|
22375
22416
|
if (pr.state)
|
|
22376
22417
|
chip.dataset.state = pr.state;
|
|
22377
|
-
chip.innerHTML = prGlyph(pr.state
|
|
22418
|
+
chip.innerHTML = issue ? svg12(ISSUE) : prGlyph(pr.state);
|
|
22378
22419
|
chip.append(text2(doc, "span", "", `#${n}`));
|
|
22379
|
-
|
|
22380
|
-
|
|
22381
|
-
|
|
22420
|
+
if (pr.checks) {
|
|
22421
|
+
const c = el2(doc, "span", "knobs-wt-prchecks");
|
|
22422
|
+
c.innerHTML = svg12(CHECK3);
|
|
22423
|
+
chip.append(c);
|
|
22424
|
+
}
|
|
22425
|
+
const words = [
|
|
22426
|
+
`${issue ? "Issue" : "Pull request"} #${n}`,
|
|
22427
|
+
pr.title,
|
|
22428
|
+
pr.state ? PR_STATE[pr.state] : "",
|
|
22429
|
+
pr.checks ? "checks pass" : ""
|
|
22430
|
+
].filter(Boolean);
|
|
22431
|
+
chip.title = words.slice(1).length ? `#${n} · ${words.slice(1).join(" · ")}` : `#${n}`;
|
|
22432
|
+
chip.setAttribute("aria-label", words.join(" · "));
|
|
22382
22433
|
return chip;
|
|
22383
22434
|
}
|
|
22384
22435
|
var PR_URL = /^https?:\/\/[^/]+\/.+\/(?:pull|merge_requests)\/(\d+)\/?(?:[?#].*)?$/;
|
|
22385
|
-
var
|
|
22436
|
+
var ISSUE_URL = /^https?:\/\/[^/]+\/.+\/issues\/(\d+)\/?(?:[?#].*)?$/;
|
|
22437
|
+
var REF = /(^|[^\w&/#:])(issue:)?#(\d{3,7})\b/gi;
|
|
22438
|
+
var WHOLE_REF = /^(issue:)?#(\d{1,7})$/i;
|
|
22439
|
+
var KEEP = 'a,pre,button,.knobs-wt-pr,.knobs-wt-slot:not([data-kind="table"]),.knobs-wt-stack';
|
|
22386
22440
|
function linkPRs(root, find) {
|
|
22387
22441
|
const doc = root.ownerDocument;
|
|
22442
|
+
const chip = (n, kind, href) => prChip(doc, n, { ...kind === "issue" ? { kind } : {}, ...find(n, kind), ...href ? { href } : {} });
|
|
22388
22443
|
for (const a of Array.from(root.querySelectorAll("a[href]"))) {
|
|
22389
|
-
if (a.classList.contains("knobs-wt-pr") || a.closest(
|
|
22444
|
+
if (a.classList.contains("knobs-wt-pr") || a.parentElement?.closest(KEEP))
|
|
22445
|
+
continue;
|
|
22446
|
+
const url = a.getAttribute("href") ?? "";
|
|
22447
|
+
const pr = PR_URL.exec(url)?.[1];
|
|
22448
|
+
const n = pr ?? ISSUE_URL.exec(url)?.[1];
|
|
22449
|
+
if (!n)
|
|
22390
22450
|
continue;
|
|
22391
|
-
const
|
|
22392
|
-
|
|
22393
|
-
if (!n || !(words === `#${n}` || words === n || words === a.getAttribute("href")))
|
|
22451
|
+
const words = (a.textContent ?? "").trim().replace(/^issue:/i, "");
|
|
22452
|
+
if (!(words === `#${n}` || words === n || words === url))
|
|
22394
22453
|
continue;
|
|
22395
|
-
a.replaceWith(
|
|
22454
|
+
a.replaceWith(chip(n, pr ? "pr" : "issue", a.href));
|
|
22455
|
+
}
|
|
22456
|
+
for (const c of Array.from(root.querySelectorAll("code"))) {
|
|
22457
|
+
if (c.closest("pre") || c.parentElement?.closest(KEEP))
|
|
22458
|
+
continue;
|
|
22459
|
+
const m = WHOLE_REF.exec((c.textContent ?? "").trim());
|
|
22460
|
+
if (m)
|
|
22461
|
+
c.replaceWith(chip(m[2], m[1] ? "issue" : "pr"));
|
|
22396
22462
|
}
|
|
22397
22463
|
const walker = doc.createTreeWalker(root, 5);
|
|
22398
22464
|
const hits = [];
|
|
@@ -22400,29 +22466,22 @@ function linkPRs(root, find) {
|
|
|
22400
22466
|
if (t.nodeType !== 3)
|
|
22401
22467
|
continue;
|
|
22402
22468
|
const p = t.parentElement;
|
|
22403
|
-
if (!p || p.closest(
|
|
22469
|
+
if (!p || p.closest(`${KEEP},code`))
|
|
22404
22470
|
continue;
|
|
22405
|
-
|
|
22406
|
-
if (
|
|
22471
|
+
REF.lastIndex = 0;
|
|
22472
|
+
if (REF.test(t.nodeValue ?? ""))
|
|
22407
22473
|
hits.push(t);
|
|
22408
22474
|
}
|
|
22409
22475
|
for (const t of hits) {
|
|
22410
22476
|
const value = t.nodeValue ?? "";
|
|
22411
22477
|
const frag = doc.createDocumentFragment();
|
|
22412
22478
|
let last = 0;
|
|
22413
|
-
|
|
22414
|
-
|
|
22415
|
-
for (let m = PR_REF.exec(value);m; m = PR_REF.exec(value)) {
|
|
22416
|
-
const pr = find(m[2]);
|
|
22417
|
-
if (!pr)
|
|
22418
|
-
continue;
|
|
22479
|
+
REF.lastIndex = 0;
|
|
22480
|
+
for (let m = REF.exec(value);m; m = REF.exec(value)) {
|
|
22419
22481
|
const at = m.index + m[1].length;
|
|
22420
|
-
frag.append(value.slice(last, at),
|
|
22421
|
-
last =
|
|
22422
|
-
changed = true;
|
|
22482
|
+
frag.append(value.slice(last, at), chip(m[3], m[2] ? "issue" : "pr"));
|
|
22483
|
+
last = m.index + m[0].length;
|
|
22423
22484
|
}
|
|
22424
|
-
if (!changed)
|
|
22425
|
-
continue;
|
|
22426
22485
|
frag.append(value.slice(last));
|
|
22427
22486
|
t.replaceWith(frag);
|
|
22428
22487
|
}
|
|
@@ -22441,7 +22500,7 @@ var snappy3 = springCss(SPRINGS.snappy);
|
|
|
22441
22500
|
var calm = springCss(SPRINGS.calm);
|
|
22442
22501
|
var state = springCss(SPRINGS.default);
|
|
22443
22502
|
var quick = springCss(FADE);
|
|
22444
|
-
var fade2 = "-webkit-mask-image:linear-gradient(to right,#000 calc(100% -
|
|
22503
|
+
var fade2 = "-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 16px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 16px),transparent)";
|
|
22445
22504
|
var walkthroughCss = `
|
|
22446
22505
|
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
22447
22506
|
.knobs-ui:is(.knobs-walkthrough,.knobs-wt-slot){--k-glass:0;--k-glow:0;--kw-quick:${quick.easing};--kw-quick-ms:${quick.duration}ms}
|
|
@@ -22453,7 +22512,7 @@ var walkthroughCss = `
|
|
|
22453
22512
|
.knobs-walkthrough [hidden]{display:none!important}
|
|
22454
22513
|
/* (0,0,1): a host's element rules stop here, and every class rule below wins over it. */
|
|
22455
22514
|
:where(.knobs-walkthrough) :is(h1,h2,h3,p,ol,ul,dl,dd){margin:0;font:inherit;letter-spacing:inherit}
|
|
22456
|
-
.knobs-walkthrough a{color:inherit;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);text-underline-offset:2px;transition:text-decoration-color
|
|
22515
|
+
.knobs-walkthrough a{cursor:default;color:inherit;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);text-underline-offset:2px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
|
|
22457
22516
|
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
22458
22517
|
.knobs-walkthrough code,.knobs-wt-slot code{font:var(--_k-type-label) var(--_k-mono);padding:1px 5px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
|
|
22459
22518
|
:where(.knobs-ui) :is(.knobs-wt-btn,.knobs-wt-pick,.knobs-wt-toc-row,button.knobs-wt-stitle,.knobs-wt-chapter,.knobs-wt-disc-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;
|
|
@@ -22481,14 +22540,17 @@ var walkthroughCss = `
|
|
|
22481
22540
|
.knobs-walkthrough .knobs-wt-metaline a:not(.knobs-wt-pr){display:inline-flex;align-items:baseline;color:inherit;text-decoration:none;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
22482
22541
|
.knobs-walkthrough .knobs-wt-metaline a:not(.knobs-wt-pr):hover{color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22483
22542
|
.knobs-wt-metaline svg{align-self:center;width:12px;height:12px;margin-left:2px}
|
|
22484
|
-
/* A pull request: a
|
|
22485
|
-
the success hue, merged the violet series, draft and closed
|
|
22486
|
-
|
|
22543
|
+
/* A pull request or issue: a capsule, its state's icon and number in a quiet tint of the state
|
|
22544
|
+
(open the success hue, merged the violet series, draft and closed faint, unknown neutral; a
|
|
22545
|
+
closed issue is done, so violet), a faint check where its checks pass, its title on hover. */
|
|
22546
|
+
.knobs-ui .knobs-wt-pr{--kw-pr:var(--_k-fg-2);display:inline-flex;align-items:center;gap:3px;height:18px;padding:0 6px 0 5px;margin:0 1px;border-radius:9px;vertical-align:1px;
|
|
22487
22547
|
background:color-mix(in oklch,var(--kw-pr) 12%,transparent);color:var(--kw-pr);font:var(--_k-weight-label) var(--_k-type-small)/1 var(--_k-font);font-variant-numeric:tabular-nums;white-space:nowrap;text-decoration:none;
|
|
22488
22548
|
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
22489
22549
|
.knobs-ui .knobs-wt-pr[data-state="open"]{--kw-pr:color-mix(in oklch,var(--_k-ok) 60%,var(--_k-fg-2))}
|
|
22490
22550
|
.knobs-ui .knobs-wt-pr[data-state="merged"]{--kw-pr:color-mix(in oklch,var(--_k-series-5) 60%,var(--_k-fg-2))}
|
|
22491
22551
|
.knobs-ui .knobs-wt-pr:is([data-state="draft"],[data-state="closed"]){--kw-pr:var(--_k-fg-3)}
|
|
22552
|
+
.knobs-ui .knobs-wt-pr[data-kind="issue"][data-state="closed"]{--kw-pr:color-mix(in oklch,var(--_k-series-5) 60%,var(--_k-fg-2))}
|
|
22553
|
+
.knobs-ui .knobs-wt-pr .knobs-wt-prchecks{margin-left:0}
|
|
22492
22554
|
.knobs-ui a.knobs-wt-pr:is(:hover,:focus-visible){background:color-mix(in oklch,var(--kw-pr) 22%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22493
22555
|
.knobs-wt-pr svg{flex:none}
|
|
22494
22556
|
.knobs-wt-metaline .knobs-wt-pr{align-self:center;margin:0}
|
|
@@ -22547,14 +22609,14 @@ var walkthroughCss = `
|
|
|
22547
22609
|
.knobs-wt-fi-ask{max-width:var(--kw-measure);color:var(--_k-fg);font-weight:var(--kw-strong);text-wrap:pretty}
|
|
22548
22610
|
.knobs-wt-fi-text{max-width:var(--kw-measure);color:var(--_k-fg);text-wrap:pretty}
|
|
22549
22611
|
.knobs-wt-fi-answer{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
22550
|
-
:where(.knobs-ui) .knobs-wt-fi-step{all:revert;box-sizing:border-box;font:inherit;color:inherit;background:transparent;border:0;margin:0;padding:0;cursor:
|
|
22612
|
+
:where(.knobs-ui) .knobs-wt-fi-step{all:revert;box-sizing:border-box;font:inherit;color:inherit;background:transparent;border:0;margin:0;padding:0;cursor:default;outline:none;
|
|
22551
22613
|
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
22552
22614
|
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22553
22615
|
|
|
22554
22616
|
/* ——— a disclosure: a small faint toggle with a caret, no fill. The body's height springs (in
|
|
22555
22617
|
script) and its content fades in place, top-anchored, under a soft bottom mask ——— */
|
|
22556
22618
|
.knobs-wt-disc{display:flex;flex-direction:column;min-width:0}
|
|
22557
|
-
.knobs-ui .knobs-wt-disc-toggle{display:inline-flex;align-items:center;gap:var(--_k-space-inside);width:max-content;height:20px;color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);cursor:
|
|
22619
|
+
.knobs-ui .knobs-wt-disc-toggle{display:inline-flex;align-items:center;gap:var(--_k-space-inside);width:max-content;height:20px;color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);cursor:default;
|
|
22558
22620
|
border-radius:calc(var(--_k-radius) / 2);transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
22559
22621
|
.knobs-ui .knobs-wt-disc-toggle:is(:hover,:focus-visible),.knobs-wt-disc[data-open]>.knobs-wt-disc-toggle{color:var(--_k-fg-2);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22560
22622
|
.knobs-ui .knobs-wt-disc-toggle:focus-visible{box-shadow:0 0 0 2px var(--_k-focus)}
|
|
@@ -22581,7 +22643,7 @@ var walkthroughCss = `
|
|
|
22581
22643
|
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
22582
22644
|
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
22583
22645
|
.knobs-wt-n-meta{flex:none;min-width:44px;color:var(--_k-fg-3);font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-body) var(--_k-mono)}
|
|
22584
|
-
.knobs-wt-n-meta[data-seek]{cursor:
|
|
22646
|
+
.knobs-wt-n-meta[data-seek]{cursor:default}
|
|
22585
22647
|
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
22586
22648
|
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
22587
22649
|
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
@@ -22598,7 +22660,7 @@ var walkthroughCss = `
|
|
|
22598
22660
|
/* Collapsed: the launcher and the bar swap in place, a quick fade with a little scale and blur
|
|
22599
22661
|
from the launcher's corner; the exit is the shorter. */
|
|
22600
22662
|
:where(.knobs-ui) .knobs-wt-launch{all:revert;box-sizing:border-box;justify-self:end;align-self:end;display:inline-flex;align-items:center;gap:6px;height:32px;margin:0;padding:0 10px 0 9px;border:0;border-radius:var(--_k-round);
|
|
22601
|
-
background:var(--_k-bg);color:var(--_k-fg-2);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);cursor:
|
|
22663
|
+
background:var(--_k-bg);color:var(--_k-fg-2);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);cursor:default;outline:none;transform-origin:100% 100%;
|
|
22602
22664
|
transition:color calc(var(--_k-hover-out) * 1ms),opacity var(--kw-quick-ms) var(--kw-quick),scale var(--kw-quick-ms) var(--kw-quick),filter var(--kw-quick-ms) var(--kw-quick)}
|
|
22603
22665
|
.knobs-ui .knobs-wt-launch:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
22604
22666
|
.knobs-ui .knobs-wt-launch:focus-visible{box-shadow:var(--_k-focus-ring)}
|
|
@@ -22618,11 +22680,11 @@ var walkthroughCss = `
|
|
|
22618
22680
|
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
22619
22681
|
.knobs-wt-attach:empty{display:none}
|
|
22620
22682
|
.knobs-wt-chip-a{display:inline-flex;align-items:center;gap:2px;height:24px;padding:0 2px 0 9px;border-radius:var(--_k-round);background:var(--_k-fill-selected);font-size:var(--_k-type-small);white-space:nowrap}
|
|
22621
|
-
.knobs-ui .knobs-wt-x{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;color:var(--_k-fg-3);cursor:
|
|
22683
|
+
.knobs-ui .knobs-wt-x{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;color:var(--_k-fg-3);cursor:default;transition:background .15s,color .15s}
|
|
22622
22684
|
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
22623
22685
|
.knobs-wt-x svg{width:12px;height:12px}
|
|
22624
22686
|
.knobs-ui .knobs-wt-tool{flex:none;display:inline-flex;align-items:center;justify-content:center;gap:5px;min-width:32px;height:32px;padding:0 8px;border-radius:calc(var(--_k-radius) + 2px);
|
|
22625
|
-
color:var(--_k-fg-2);cursor:
|
|
22687
|
+
color:var(--_k-fg-2);cursor:default;transition:background .15s,color .15s}
|
|
22626
22688
|
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
22627
22689
|
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
22628
22690
|
.knobs-wt-tool svg{width:16px;height:16px}
|
|
@@ -22632,7 +22694,7 @@ var walkthroughCss = `
|
|
|
22632
22694
|
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
22633
22695
|
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
22634
22696
|
.knobs-ui .knobs-wt-back{position:absolute;left:8px;bottom:calc(100% + 8px);display:inline-flex;align-items:center;gap:var(--_k-space-inside);max-width:min(360px,calc(100% - 16px));height:28px;padding:0 12px 0 9px;
|
|
22635
|
-
border-radius:var(--_k-round);background:var(--_k-bg);color:var(--_k-fg);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font-size:var(--_k-type-small);font-weight:var(--kw-strong);cursor:
|
|
22697
|
+
border-radius:var(--_k-round);background:var(--_k-bg);color:var(--_k-fg);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font-size:var(--_k-type-small);font-weight:var(--kw-strong);cursor:default;
|
|
22636
22698
|
opacity:0;scale:.96;filter:blur(3px);pointer-events:none;transition:opacity .11s cubic-bezier(.4,0,1,1),scale .11s cubic-bezier(.4,0,1,1),filter .11s cubic-bezier(.4,0,1,1)}
|
|
22637
22699
|
.knobs-ui .knobs-wt-back[data-on]{opacity:1;scale:1;filter:none;pointer-events:auto;transition:opacity .15s cubic-bezier(.2,.8,.2,1),scale .15s cubic-bezier(.2,.8,.2,1),filter .15s cubic-bezier(.2,.8,.2,1)}
|
|
22638
22700
|
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
@@ -22659,6 +22721,9 @@ var walkthroughCss = `
|
|
|
22659
22721
|
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
22660
22722
|
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
22661
22723
|
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
22724
|
+
.knobs-wt-step[data-full] .knobs-wt-slot[data-kind="video"]>.knobs-wt-body{display:flex;flex-direction:column}
|
|
22725
|
+
.knobs-wt-step[data-full] .knobs-wt-slot[data-kind="video"] .knobs-player{flex:1;min-height:0}
|
|
22726
|
+
.knobs-wt-step[data-full] .knobs-wt-slot[data-kind="video"] .knobs-player-frame{flex:1;min-height:0;aspect-ratio:auto}
|
|
22662
22727
|
|
|
22663
22728
|
/* ——— a taste test: the options side by side, Kit's pick checked and the rest stepping back. On
|
|
22664
22729
|
the step's card, so no fill of their own ——— */
|
|
@@ -22667,7 +22732,7 @@ var walkthroughCss = `
|
|
|
22667
22732
|
.knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
22668
22733
|
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
22669
22734
|
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
22670
|
-
.knobs-ui .knobs-wt-pick{display:flex;align-items:center;gap:8px;width:100%;min-height:28px;margin:0 -6px;width:calc(100% + 12px);padding:0 6px;border-radius:var(--_k-radius);cursor:
|
|
22735
|
+
.knobs-ui .knobs-wt-pick{display:flex;align-items:center;gap:8px;width:100%;min-height:28px;margin:0 -6px;width:calc(100% + 12px);padding:0 6px;border-radius:var(--_k-radius);cursor:default;color:var(--_k-fg-2);text-align:left;
|
|
22671
22736
|
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
22672
22737
|
.knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_k-fill);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22673
22738
|
.knobs-wt-letter{flex:none;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
@@ -22690,17 +22755,18 @@ var walkthroughCss = `
|
|
|
22690
22755
|
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
22691
22756
|
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
22692
22757
|
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
22693
|
-
/* The contents: every row on one text edge and in one colour, title rows (
|
|
22694
|
-
radius) and the steps under them (20 high, half of it), bled out so their text sits on the
|
|
22695
|
-
rail's edge
|
|
22696
|
-
|
|
22758
|
+
/* The contents: every row on one text edge and in one colour, title rows (28 high, the control
|
|
22759
|
+
radius) and the steps under them (20 high, half of it), bled 6 px out so their text sits on the
|
|
22760
|
+
rail's edge and the first title's words on the column's top line; a narrow fade where a title
|
|
22761
|
+
runs out of room; the selection pill slides to the current step, and base rows never brighten. */
|
|
22762
|
+
.knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column;gap:var(--_k-space-sibling);margin:-4px -6px 0;padding:0 0 8px}
|
|
22697
22763
|
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
22698
22764
|
.knobs-wt-toc-group{display:flex;flex-direction:column;min-width:0}
|
|
22699
|
-
.knobs-ui .knobs-wt-toc-row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;flex:none;width:100%;height:
|
|
22700
|
-
padding:0
|
|
22701
|
-
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
22765
|
+
.knobs-ui .knobs-wt-toc-row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;flex:none;width:100%;height:28px;
|
|
22766
|
+
padding:0 6px;border-radius:var(--_k-radius);color:var(--_k-fg-2);font-size:var(--_k-type-body);line-height:var(--_k-leading-body);font-weight:var(--_k-weight);text-align:left;white-space:nowrap;cursor:default;
|
|
22767
|
+
transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
22702
22768
|
.knobs-ui .knobs-wt-toc-sub{height:20px;border-radius:calc(var(--_k-radius) / 2);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);font-weight:var(--_k-weight)}
|
|
22703
|
-
.knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22769
|
+
.knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22704
22770
|
.knobs-ui .knobs-wt-toc-row:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
22705
22771
|
.knobs-wt-toc-end{display:flex;align-items:center;font-size:var(--_k-type-small);line-height:var(--_k-leading-small);font-weight:var(--_k-weight);color:var(--_k-fg-3)}
|
|
22706
22772
|
.knobs-wt-toc-label{min-width:0;overflow:hidden;${fade2}}
|
|
@@ -22712,7 +22778,7 @@ var walkthroughCss = `
|
|
|
22712
22778
|
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
22713
22779
|
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
22714
22780
|
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
22715
|
-
.knobs-ui .knobs-wt-btn{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:
|
|
22781
|
+
.knobs-ui .knobs-wt-btn{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:default;white-space:nowrap;
|
|
22716
22782
|
transition:background .15s,color .15s}
|
|
22717
22783
|
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
22718
22784
|
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
@@ -22746,11 +22812,10 @@ var walkthroughCss = `
|
|
|
22746
22812
|
/* One frame for every slot that has one (a picture, a video, a code block, a compare's stage, a
|
|
22747
22813
|
slot still loading): the panel radius and a quiet fill, no ring; concentric on a card. */
|
|
22748
22814
|
.knobs-wt-slot .knobs-cmp-stage{border-radius:var(--kw-frame-r)}
|
|
22749
|
-
/* A compare is
|
|
22750
|
-
|
|
22815
|
+
/* A compare is as tall as its two pictures side by side at this width, in every mode (Wipe fuses
|
|
22816
|
+
them at one side's size, so nothing grows or re-measures), plus its mode bar, the line and gaps
|
|
22751
22817
|
(92 px), and the frame strip with its gap (158 px). */
|
|
22752
22818
|
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
22753
|
-
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
22754
22819
|
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
22755
22820
|
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
22756
22821
|
.knobs-wt-frame{position:relative;width:100%;overflow:hidden;border-radius:var(--kw-frame-r);background:var(--_k-fill);aspect-ratio:var(--kw-aspect,16/9)}
|
|
@@ -22759,8 +22824,12 @@ var walkthroughCss = `
|
|
|
22759
22824
|
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
22760
22825
|
/* Diff, code and terminal: one plain container (no glass): a flat inset fill, a hairline ring, the
|
|
22761
22826
|
control radius and room inside, so a diff's buttons and the code under them can breathe. */
|
|
22762
|
-
.knobs-wt-slot[data-kind="diff"]>.knobs-wt-body{padding:var(--_k-
|
|
22763
|
-
|
|
22827
|
+
.knobs-wt-slot[data-kind="diff"]>.knobs-wt-body{padding:var(--_k-pad-card);border-radius:var(--_k-radius-panel);background:var(--_k-bg-inset);box-shadow:inset 0 0 0 1px var(--_k-border-subtle)}
|
|
22828
|
+
/* The diff inside it: its header row 28 high on the container's padding, a hairline under it, and
|
|
22829
|
+
no line of its own under the code (the container's ring closes it). */
|
|
22830
|
+
.knobs-wt-slot[data-kind="diff"] .knobs-ui.knobs-diff:not([data-on="pane"]){--kd-head:28px;--kd-x:0px}
|
|
22831
|
+
.knobs-wt-slot[data-kind="diff"] .knobs-ui.knobs-diff:not([data-on="pane"])::after{display:none}
|
|
22832
|
+
.knobs-wt-code{margin:0;padding:var(--_k-pad-card);max-height:420px;overflow:auto;border-radius:var(--_k-radius-panel);background:var(--_k-bg-inset);box-shadow:inset 0 0 0 1px var(--_k-border-subtle);color:var(--_k-fg);
|
|
22764
22833
|
font:var(--_k-type-label)/var(--_k-leading-body) var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
22765
22834
|
.knobs-surface :is(.knobs-wt-code,.knobs-wt-slot[data-kind="diff"]>.knobs-wt-body){padding-inline:0;border-radius:0;background:transparent;box-shadow:inset 0 1px 0 var(--_k-border-subtle),inset 0 -1px 0 var(--_k-border-subtle)}
|
|
22766
22835
|
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
@@ -22806,7 +22875,7 @@ var walkthroughCss = `
|
|
|
22806
22875
|
.knobs-wt-mark:is([data-shape="dot"],[data-shape="arrow"]) .knobs-wt-mark-label{left:12px;bottom:auto;top:10px}
|
|
22807
22876
|
.knobs-wt-mark[data-shape="arrow"] .knobs-wt-mark-label{left:auto;right:30px;top:auto;bottom:30px}
|
|
22808
22877
|
.knobs-ui .knobs-wt-anno-toggle{all:revert;box-sizing:border-box;position:absolute;top:8px;right:8px;display:grid;place-items:center;width:28px;height:28px;padding:0;border:0;margin:0;
|
|
22809
|
-
border-radius:var(--_k-radius);background:color-mix(in srgb,var(--_k-bg) 72%,transparent);color:var(--_k-fg-2);cursor:
|
|
22878
|
+
border-radius:var(--_k-radius);background:color-mix(in srgb,var(--_k-bg) 72%,transparent);color:var(--_k-fg-2);cursor:default;opacity:.6;outline:none;
|
|
22810
22879
|
transition:opacity calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
22811
22880
|
.knobs-ui .knobs-wt-anno-toggle:is(:hover,:focus-visible){opacity:1;color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22812
22881
|
.knobs-ui .knobs-wt-anno-toggle:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
@@ -22827,7 +22896,7 @@ var walkthroughCss = `
|
|
|
22827
22896
|
.knobs-wt-srow{display:grid;grid-template-columns:auto minmax(0,1fr) auto;column-gap:10px;align-items:start;margin:0 -8px;padding:var(--kw-spt) 8px var(--kw-spb);
|
|
22828
22897
|
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
22829
22898
|
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
22830
|
-
.knobs-wt-srow[data-go]{cursor:
|
|
22899
|
+
.knobs-wt-srow[data-go]{cursor:default}
|
|
22831
22900
|
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22832
22901
|
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
22833
22902
|
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
@@ -22843,7 +22912,7 @@ var walkthroughCss = `
|
|
|
22843
22912
|
.knobs-ui .knobs-wt-spr{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2);text-decoration:none;white-space:nowrap}
|
|
22844
22913
|
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
22845
22914
|
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
22846
|
-
.knobs-ui button.knobs-wt-stitle{cursor:
|
|
22915
|
+
.knobs-ui button.knobs-wt-stitle{cursor:default;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
|
|
22847
22916
|
.knobs-ui :is(.knobs-wt-srow[data-go]:hover button.knobs-wt-stitle,button.knobs-wt-stitle:focus-visible){text-decoration-color:color-mix(in oklch,currentColor 45%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22848
22917
|
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
22849
22918
|
.knobs-wt-smeta{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 12px;font:var(--_k-weight) var(--_k-type-small)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
|
|
@@ -22851,12 +22920,21 @@ var walkthroughCss = `
|
|
|
22851
22920
|
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
22852
22921
|
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
22853
22922
|
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
22923
|
+
/* A PR's state the GitHub way: its glyph and word, open and merged quietly tinted (as PR chips),
|
|
22924
|
+
draft and closed faint; no fill, no dot. A check after it where the checks pass, faint too. One
|
|
22925
|
+
width for every row, so the glyphs and words line up. */
|
|
22926
|
+
.knobs-ui .knobs-wt-prstate{--kw-pr:var(--_k-fg-3);display:inline-flex;align-items:center;gap:4px;min-width:calc(7ch + 32px);height:var(--kw-line);color:var(--kw-pr);
|
|
22927
|
+
font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);white-space:nowrap}
|
|
22928
|
+
.knobs-ui .knobs-wt-prstate[data-state="open"]{--kw-pr:color-mix(in oklch,var(--_k-ok) 60%,var(--_k-fg-2))}
|
|
22929
|
+
.knobs-ui .knobs-wt-prstate[data-state="merged"]{--kw-pr:color-mix(in oklch,var(--_k-series-5) 60%,var(--_k-fg-2))}
|
|
22930
|
+
.knobs-wt-prstate svg{flex:none}
|
|
22931
|
+
.knobs-ui .knobs-wt-prchecks{display:inline-flex;margin-left:2px;color:var(--_k-fg-3)}
|
|
22854
22932
|
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
22855
22933
|
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
22856
22934
|
@container knobs-wt-slot (max-width:520px){
|
|
22857
22935
|
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
22858
22936
|
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
22859
|
-
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
22937
|
+
:is(.knobs-wt-sstatus,.knobs-wt-prstate){grid-column:-2;justify-self:start;margin-top:4px}
|
|
22860
22938
|
}
|
|
22861
22939
|
|
|
22862
22940
|
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
@@ -22866,7 +22944,7 @@ var walkthroughCss = `
|
|
|
22866
22944
|
.knobs-wt-tablebox{min-width:0}
|
|
22867
22945
|
/* A row with a step goes there: the whole row, a wash under the pointer, no arrow, so rows with and
|
|
22868
22946
|
without one line up. */
|
|
22869
|
-
.knobs-wt-tablebox [data-go]{cursor:
|
|
22947
|
+
.knobs-wt-tablebox [data-go]{cursor:default;outline:none}
|
|
22870
22948
|
.knobs-wt-tablebox tr[data-go]>td,.knobs-wt-trow[data-go]{transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
22871
22949
|
.knobs-wt-tablebox tr[data-go]:is(:hover,:focus-visible)>td,.knobs-wt-trow[data-go]:is(:hover,:focus-visible){background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22872
22950
|
.knobs-wt-tablebox [data-go]:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
@@ -22922,13 +23000,18 @@ var walkthroughCss = `
|
|
|
22922
23000
|
.knobs-wt-body:has(>.knobs-wt-chapters){display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
22923
23001
|
.knobs-wt-chapters{position:relative;display:flex;flex-direction:column;margin:0 calc(var(--_k-space-sibling) * -1)}
|
|
22924
23002
|
.knobs-ui .knobs-wt-chapter{position:relative;display:grid;grid-template-columns:2ch minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;height:32px;padding:0 var(--_k-space-sibling);
|
|
22925
|
-
border-radius:var(--_k-radius);color:var(--_k-fg-2);text-align:left;white-space:nowrap;cursor:
|
|
22926
|
-
.knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
23003
|
+
border-radius:var(--_k-radius);color:var(--_k-fg-2);text-align:left;white-space:nowrap;cursor:default;transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
23004
|
+
.knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22927
23005
|
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
22928
23006
|
.knobs-wt-chapter-n{font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
22929
23007
|
.knobs-wt-chapter-label{min-width:0;overflow:hidden;${fade2}}
|
|
22930
23008
|
.knobs-wt-chapter-time{font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);color:var(--_k-fg-3)}
|
|
22931
23009
|
.knobs-pick-copy :is(.knobs-wt-chapter-n,.knobs-wt-chapter-time){color:var(--_k-fg-2)}
|
|
23010
|
+
/* Every hover in the walkthrough lands at once (hover-in, 0 ms) and eases out (hover-out): links,
|
|
23011
|
+
buttons, chips, rail, chapter, table and stack rows (its own; the pieces inside keep theirs). */
|
|
23012
|
+
:is(.knobs-walkthrough,.knobs-wt-slot) :is(a,button,[data-go])[class*="knobs-wt-"]:is(:hover,:focus-visible),
|
|
23013
|
+
.knobs-walkthrough a:not([class]):hover,
|
|
23014
|
+
:is(.knobs-walkthrough,.knobs-wt-slot) :is(.knobs-wt-srow,tr)[data-go]:is(:hover,:focus-visible) :is(td,.knobs-wt-stitle){transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
22932
23015
|
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
22933
23016
|
@media(prefers-reduced-motion:reduce){.knobs-wt-disc-content{transition:opacity .15s}}
|
|
22934
23017
|
`;
|
|
@@ -23029,7 +23112,6 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
23029
23112
|
fit.style.setProperty("--kw-aspect", String(known ?? DEFAULT_ASPECT));
|
|
23030
23113
|
const width = host.getBoundingClientRect().width;
|
|
23031
23114
|
const mode = m.mode ?? (width && width < 560 ? "wipe" : "side");
|
|
23032
|
-
fit.toggleAttribute("data-overlay", mode !== "side");
|
|
23033
23115
|
host.append(fit);
|
|
23034
23116
|
const [aspect, lib] = await Promise.all([
|
|
23035
23117
|
known ? Promise.resolve(known) : probeAspect(doc, after.src),
|
|
@@ -23053,7 +23135,6 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
23053
23135
|
...aspect ? { aspect } : {},
|
|
23054
23136
|
...m.strip ? { strip: true } : {},
|
|
23055
23137
|
onMode: (next) => {
|
|
23056
|
-
fit.toggleAttribute("data-overlay", next !== "side");
|
|
23057
23138
|
onEvent?.({ what: "mode", detail: next });
|
|
23058
23139
|
const layer = marks?.element;
|
|
23059
23140
|
if (layer) {
|
|
@@ -23077,6 +23158,12 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
23077
23158
|
}
|
|
23078
23159
|
});
|
|
23079
23160
|
const stage = fit.querySelector(".knobs-cmp-stage");
|
|
23161
|
+
if (stage)
|
|
23162
|
+
doc.defaultView?.requestAnimationFrame(() => {
|
|
23163
|
+
const chrome = fit.clientHeight - stage.clientHeight;
|
|
23164
|
+
if (alive() && stage.clientHeight > 0 && chrome > 0)
|
|
23165
|
+
fit.style.setProperty("--kw-chrome", `${Math.round(chrome)}px`);
|
|
23166
|
+
});
|
|
23080
23167
|
if (m.annotations?.length && stage) {
|
|
23081
23168
|
const shape = { w: aspect ?? DEFAULT_ASPECT, h: 1 };
|
|
23082
23169
|
marks = annotationLayer(stage, m.annotations, () => {
|
|
@@ -23152,45 +23239,38 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
23152
23239
|
var round2 = (v) => Math.round(v * 100) / 100;
|
|
23153
23240
|
var MARK_GLIDE = 450;
|
|
23154
23241
|
var zoomedIn = (z) => z.w < 0.999 || z.h < 0.999;
|
|
23155
|
-
function mountVideo(host, m, onEvent) {
|
|
23242
|
+
async function mountVideo(host, m, look, alive, onEvent) {
|
|
23156
23243
|
const doc = host.ownerDocument;
|
|
23157
|
-
|
|
23244
|
+
await Promise.resolve().then(() => init_player());
|
|
23245
|
+
if (!alive())
|
|
23246
|
+
return { dispose() {} };
|
|
23158
23247
|
const aspect = parseAspect(m.aspect);
|
|
23159
|
-
|
|
23160
|
-
|
|
23161
|
-
const
|
|
23162
|
-
|
|
23163
|
-
|
|
23164
|
-
|
|
23165
|
-
|
|
23166
|
-
|
|
23167
|
-
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23177
|
-
|
|
23178
|
-
v.append(track);
|
|
23179
|
-
}
|
|
23180
|
-
v.src = m.src;
|
|
23181
|
-
v.addEventListener("play", () => onEvent?.({ what: "play", time: round2(v.currentTime) }));
|
|
23182
|
-
v.addEventListener("pause", () => onEvent?.({ what: "pause", time: round2(v.currentTime) }));
|
|
23183
|
-
v.addEventListener("seeked", () => {
|
|
23184
|
-
if (v.paused)
|
|
23185
|
-
onEvent?.({ what: "seek", time: round2(v.currentTime) });
|
|
23248
|
+
let pills = null;
|
|
23249
|
+
let marking = null;
|
|
23250
|
+
const p = player(host, {
|
|
23251
|
+
...look,
|
|
23252
|
+
src: m.src,
|
|
23253
|
+
...m.poster ? { poster: m.poster } : {},
|
|
23254
|
+
...m.captions ? { captions: m.captions } : {},
|
|
23255
|
+
...aspect ? { aspect } : {},
|
|
23256
|
+
...m.label ? { label: m.label } : {},
|
|
23257
|
+
...m.chapters?.length ? { chapters: m.chapters.map((c) => ({ label: c.label, start: c.start, ...c.id ? { id: c.id } : {} })) } : {},
|
|
23258
|
+
onPlay: (on, time) => {
|
|
23259
|
+
marking?.kick();
|
|
23260
|
+
onEvent?.({ what: on ? "play" : "pause", time: round2(time) });
|
|
23261
|
+
},
|
|
23262
|
+
onSeek: (time) => {
|
|
23263
|
+
pills?.sync();
|
|
23264
|
+
marking?.kick();
|
|
23265
|
+
onEvent?.({ what: "seek", time: round2(time) });
|
|
23266
|
+
}
|
|
23186
23267
|
});
|
|
23187
|
-
|
|
23188
|
-
host.
|
|
23189
|
-
|
|
23190
|
-
now: () => v.currentTime,
|
|
23268
|
+
const v = p.video;
|
|
23269
|
+
pills = m.chapters?.length ? chapterPills(host, m.chapters, {
|
|
23270
|
+
now: () => p.time,
|
|
23191
23271
|
seek: (t) => {
|
|
23192
|
-
|
|
23193
|
-
|
|
23272
|
+
p.seek(t, { glide: true });
|
|
23273
|
+
p.play();
|
|
23194
23274
|
},
|
|
23195
23275
|
onEvent
|
|
23196
23276
|
}) : null;
|
|
@@ -23198,36 +23278,33 @@ function mountVideo(host, m, onEvent) {
|
|
|
23198
23278
|
if (pills)
|
|
23199
23279
|
for (const type of ["timeupdate", "seeking", "seeked"])
|
|
23200
23280
|
v.addEventListener(type, sync);
|
|
23281
|
+
const frame = p.element.querySelector(".knobs-player-frame") ?? p.element;
|
|
23201
23282
|
const marks = m.annotations?.length ? annotationLayer(frame, m.annotations, () => ({
|
|
23202
23283
|
rects: [
|
|
23203
23284
|
contain({ w: frame.clientWidth, h: frame.clientHeight }, { w: v.videoWidth, h: v.videoHeight })
|
|
23204
23285
|
],
|
|
23205
|
-
time:
|
|
23286
|
+
time: p.time
|
|
23206
23287
|
})) : null;
|
|
23207
|
-
|
|
23208
|
-
|
|
23209
|
-
for (const type of ["
|
|
23210
|
-
v.addEventListener(type, () => marking
|
|
23288
|
+
if (marks) {
|
|
23289
|
+
marking = follow(doc.defaultView, () => p.playing, () => marks.update());
|
|
23290
|
+
for (const type of ["seeked", "loadedmetadata", "timeupdate"])
|
|
23291
|
+
v.addEventListener(type, () => marking?.kick());
|
|
23292
|
+
}
|
|
23211
23293
|
return {
|
|
23212
|
-
pause: () =>
|
|
23213
|
-
seekBy: (d) =>
|
|
23214
|
-
v.currentTime = Math.max(0, Math.min(v.duration || Infinity, v.currentTime + d));
|
|
23215
|
-
},
|
|
23294
|
+
pause: () => p.pause(),
|
|
23295
|
+
seekBy: (d) => p.seekBy(d),
|
|
23216
23296
|
context: () => ({
|
|
23217
23297
|
kind: "video",
|
|
23218
|
-
time: round2(
|
|
23219
|
-
...
|
|
23220
|
-
playing:
|
|
23298
|
+
time: round2(p.time),
|
|
23299
|
+
...p.duration ? { duration: round2(p.duration) } : {},
|
|
23300
|
+
playing: p.playing,
|
|
23221
23301
|
...pills?.current ? { chapter: pills.current.label } : {}
|
|
23222
23302
|
}),
|
|
23223
23303
|
dispose: () => {
|
|
23224
23304
|
marking?.stop();
|
|
23225
23305
|
marks?.dispose();
|
|
23226
23306
|
pills?.dispose();
|
|
23227
|
-
|
|
23228
|
-
v.removeAttribute("src");
|
|
23229
|
-
v.load();
|
|
23230
|
-
frame.remove();
|
|
23307
|
+
p.dispose();
|
|
23231
23308
|
}
|
|
23232
23309
|
};
|
|
23233
23310
|
}
|
|
@@ -23488,7 +23565,7 @@ function mediaSlot(container, options) {
|
|
|
23488
23565
|
case "diff":
|
|
23489
23566
|
return void mountDiff(host, m, look, alive, options.onEvent).then(done, fail("diff"));
|
|
23490
23567
|
case "video":
|
|
23491
|
-
return
|
|
23568
|
+
return void mountVideo(host, m, look, alive, options.onEvent).then(done, fail("video"));
|
|
23492
23569
|
case "image":
|
|
23493
23570
|
return done(mountImage(host, m));
|
|
23494
23571
|
case "code":
|
|
@@ -23502,7 +23579,7 @@ function mediaSlot(container, options) {
|
|
|
23502
23579
|
case "history":
|
|
23503
23580
|
return done(mountHistory(host, m, options.steps));
|
|
23504
23581
|
case "stack":
|
|
23505
|
-
return done(mountStack(host, m, options.steps));
|
|
23582
|
+
return done(mountStack(host, m, options.steps, options.findPR));
|
|
23506
23583
|
case "table":
|
|
23507
23584
|
return done(mountTable(host, m, options.steps));
|
|
23508
23585
|
case "mount": {
|
|
@@ -23556,7 +23633,7 @@ function mediaSlot(container, options) {
|
|
|
23556
23633
|
}
|
|
23557
23634
|
};
|
|
23558
23635
|
}
|
|
23559
|
-
var
|
|
23636
|
+
var CHECK4 = icon("check", { small: true });
|
|
23560
23637
|
|
|
23561
23638
|
// src/ui/walkthrough.ts
|
|
23562
23639
|
var el3 = (doc, tag, cls) => {
|
|
@@ -23643,7 +23720,7 @@ function tasteTest(container, options) {
|
|
|
23643
23720
|
pick.append(key);
|
|
23644
23721
|
}
|
|
23645
23722
|
const check = el3(doc, "span", "knobs-wt-check");
|
|
23646
|
-
check.innerHTML =
|
|
23723
|
+
check.innerHTML = CHECK4;
|
|
23647
23724
|
pick.append(check);
|
|
23648
23725
|
pick.addEventListener("click", () => {
|
|
23649
23726
|
const next = picked === o.id ? null : o.id;
|
|
@@ -24471,11 +24548,12 @@ function walkthrough(container, options) {
|
|
|
24471
24548
|
line.append(s);
|
|
24472
24549
|
return s;
|
|
24473
24550
|
};
|
|
24474
|
-
const findPRIn = (n) => findPR(page.prs, n, page.repo);
|
|
24551
|
+
const findPRIn = (n, kind = "pr") => findPR(page.prs, n, page.repo, kind);
|
|
24475
24552
|
const metaLink = (line, text, href) => {
|
|
24476
24553
|
const n = prNumber(href);
|
|
24477
|
-
|
|
24478
|
-
|
|
24554
|
+
const issue = n ? null : issueNumber(href);
|
|
24555
|
+
if (n || issue) {
|
|
24556
|
+
const chip = n ? prChip(doc, n, { ...findPRIn(n), href }) : prChip(doc, issue, { ...findPRIn(issue, "issue"), href });
|
|
24479
24557
|
line.append(chip);
|
|
24480
24558
|
return chip;
|
|
24481
24559
|
}
|
|
@@ -24804,7 +24882,7 @@ function walkthrough(container, options) {
|
|
|
24804
24882
|
media = el3(doc, "div", "knobs-wt-media");
|
|
24805
24883
|
media.style.setProperty("--kw-n", String(Math.min(step.media.length, step.columns)));
|
|
24806
24884
|
for (const m of step.media)
|
|
24807
|
-
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
24885
|
+
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks, findPR: findPRIn }));
|
|
24808
24886
|
card.append(media);
|
|
24809
24887
|
}
|
|
24810
24888
|
let taste = null;
|