@kitlangton/knobs 0.4.0-next.6 → 0.4.0-next.7
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 +3 -3
- 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 +14 -2
- package/dist/types/ui/walkthrough-media.d.ts +3 -1
- package/dist/ui-react.js +94 -82
- package/dist/ui-solid.js +94 -82
- package/dist/ui.js +256 -250
- 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();
|
|
@@ -10935,16 +10736,17 @@ var init_diff_css = __esm(() => {
|
|
|
10935
10736
|
.knobs-diff-nav>span{min-width:3.6em;text-align:center}
|
|
10936
10737
|
: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
10738
|
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
|
-
|
|
10739
|
+
.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;
|
|
10740
|
+
transition:background calc(var(--_k-hover-out) * 1ms),opacity .15s}
|
|
10741
|
+
/* Hover is a quiet fill under the arrow cursor (no hand, no brightening), there at once. */
|
|
10742
|
+
.knobs-ui .knobs-diff-btn:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
10941
10743
|
.knobs-ui .knobs-diff-btn[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
10942
10744
|
.knobs-ui .knobs-diff-btn:disabled{opacity:.35;cursor:default;background:transparent}
|
|
10943
10745
|
.knobs-diff-btn svg{width:16px;height:16px}
|
|
10944
10746
|
/* Viewed: a check with its word, as on GitHub; the path dims once it's ticked. */
|
|
10945
10747
|
.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(--
|
|
10748
|
+
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}
|
|
10749
|
+
.knobs-ui .knobs-diff-viewed:is(:hover,:focus-visible){background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
10948
10750
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
10949
10751
|
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
10950
10752
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
@@ -10963,8 +10765,8 @@ var init_diff_css = __esm(() => {
|
|
|
10963
10765
|
choice isn't brighter for being picked. Choices are styled by class, as the copy holds them too. */
|
|
10964
10766
|
.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
10767
|
.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){
|
|
10768
|
+
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:default;transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
10769
|
+
.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
10770
|
/* The diff: one layer per file or layout on show, the old fading under the new. */
|
|
10969
10771
|
.knobs-diff-body{position:relative;flex:1;min-height:0}
|
|
10970
10772
|
.knobs-diff-probe{position:absolute;left:0;top:0;width:0;height:var(--kd-line);visibility:hidden;pointer-events:none}
|
|
@@ -11060,8 +10862,8 @@ var init_diff_css = __esm(() => {
|
|
|
11060
10862
|
.knobs-diff-filter svg{width:12px;height:12px;flex:none}
|
|
11061
10863
|
.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
10864
|
.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(--
|
|
10865
|
+
.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}
|
|
10866
|
+
.knobs-ui .knobs-diff-filter>button:hover{background:var(--_k-fill-hover);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
11065
10867
|
.knobs-diff-filter>button svg{width:12px;height:12px}
|
|
11066
10868
|
.knobs-diff-list{position:relative;flex:1;min-height:0}
|
|
11067
10869
|
.knobs-diff-files .knobs-diff-counts{font-size:var(--_k-text-meta);align-items:center}
|
|
@@ -16577,8 +16379,169 @@ init_timeline();
|
|
|
16577
16379
|
init_timeline_model();
|
|
16578
16380
|
init_compare();
|
|
16579
16381
|
init_compare_strip();
|
|
16580
|
-
init_player();
|
|
16581
16382
|
|
|
16383
|
+
// src/ui/player.ts
|
|
16384
|
+
init_look();
|
|
16385
|
+
init_timeline();
|
|
16386
|
+
function player(container, options) {
|
|
16387
|
+
const doc = container.ownerDocument;
|
|
16388
|
+
const el = (tag, cls) => {
|
|
16389
|
+
const n = doc.createElement(tag);
|
|
16390
|
+
n.className = cls;
|
|
16391
|
+
return n;
|
|
16392
|
+
};
|
|
16393
|
+
const look = {
|
|
16394
|
+
...options.preset ? { preset: options.preset } : {},
|
|
16395
|
+
...options.theme ? { theme: options.theme } : {},
|
|
16396
|
+
...options.appearance ? { appearance: options.appearance } : {}
|
|
16397
|
+
};
|
|
16398
|
+
const root = el("div", "knobs-player");
|
|
16399
|
+
root.setAttribute("role", "group");
|
|
16400
|
+
root.setAttribute("aria-label", options.label ?? "Video");
|
|
16401
|
+
applyLook2(root, options);
|
|
16402
|
+
const frame = el("div", "knobs-player-frame");
|
|
16403
|
+
frame.style.setProperty("--kp-aspect", String(options.aspect ?? 16 / 9));
|
|
16404
|
+
const v = el("video", "knobs-player-media");
|
|
16405
|
+
v.muted = options.muted ?? true;
|
|
16406
|
+
v.defaultMuted = v.muted;
|
|
16407
|
+
v.playsInline = true;
|
|
16408
|
+
v.preload = "metadata";
|
|
16409
|
+
v.setAttribute("playsinline", "");
|
|
16410
|
+
if (options.poster)
|
|
16411
|
+
v.poster = options.poster;
|
|
16412
|
+
if (options.captions) {
|
|
16413
|
+
const track = doc.createElement("track");
|
|
16414
|
+
track.kind = "captions";
|
|
16415
|
+
track.label = "Captions";
|
|
16416
|
+
track.srclang = doc.documentElement.lang || "en";
|
|
16417
|
+
track.default = true;
|
|
16418
|
+
track.src = options.captions;
|
|
16419
|
+
v.append(track);
|
|
16420
|
+
}
|
|
16421
|
+
frame.append(v);
|
|
16422
|
+
const host = el("div", "knobs-player-line");
|
|
16423
|
+
root.append(frame, host);
|
|
16424
|
+
container.append(root);
|
|
16425
|
+
const markers = (options.chapters ?? []).map((c, i) => ({
|
|
16426
|
+
id: c.id ?? `c${i}`,
|
|
16427
|
+
time: c.start,
|
|
16428
|
+
label: c.label
|
|
16429
|
+
}));
|
|
16430
|
+
const tl = timeline(host, {
|
|
16431
|
+
...look,
|
|
16432
|
+
variant: "line",
|
|
16433
|
+
duration: 1,
|
|
16434
|
+
fps: options.fps ?? 30,
|
|
16435
|
+
markers,
|
|
16436
|
+
repeat: options.loop ?? true,
|
|
16437
|
+
arrows: { step: 5, shift: 10 },
|
|
16438
|
+
label: options.label ? `${options.label} time` : "Video time",
|
|
16439
|
+
...options.hints === false ? { hints: false } : {}
|
|
16440
|
+
});
|
|
16441
|
+
const onFrame = () => root.setAttribute("data-ready", "");
|
|
16442
|
+
let pending = null;
|
|
16443
|
+
const seekVideo = (t) => {
|
|
16444
|
+
if (v.readyState < 1)
|
|
16445
|
+
return;
|
|
16446
|
+
if (v.seeking)
|
|
16447
|
+
pending = t;
|
|
16448
|
+
else
|
|
16449
|
+
v.currentTime = t;
|
|
16450
|
+
};
|
|
16451
|
+
let reported = 0;
|
|
16452
|
+
const onSeeked = () => {
|
|
16453
|
+
if (pending !== null) {
|
|
16454
|
+
const t = pending;
|
|
16455
|
+
pending = null;
|
|
16456
|
+
v.currentTime = t;
|
|
16457
|
+
return;
|
|
16458
|
+
}
|
|
16459
|
+
if (!v.paused || tl.playing || Math.abs(v.currentTime - reported) < 0.1)
|
|
16460
|
+
return;
|
|
16461
|
+
reported = v.currentTime;
|
|
16462
|
+
options.onSeek?.(reported);
|
|
16463
|
+
};
|
|
16464
|
+
const onMeta = () => {
|
|
16465
|
+
onFrame();
|
|
16466
|
+
if (v.videoWidth)
|
|
16467
|
+
frame.style.setProperty("--kp-aspect", String(v.videoWidth / v.videoHeight));
|
|
16468
|
+
if (Number.isFinite(v.duration))
|
|
16469
|
+
tl.update({ duration: v.duration });
|
|
16470
|
+
};
|
|
16471
|
+
v.addEventListener("loadedmetadata", onMeta);
|
|
16472
|
+
v.addEventListener("loadeddata", onFrame);
|
|
16473
|
+
v.addEventListener("seeked", onSeeked);
|
|
16474
|
+
const unlisten = tl.listen({
|
|
16475
|
+
onSeek(t, source) {
|
|
16476
|
+
if (source === "play") {
|
|
16477
|
+
if (Math.abs(v.currentTime - t) > 0.25)
|
|
16478
|
+
v.currentTime = t;
|
|
16479
|
+
return;
|
|
16480
|
+
}
|
|
16481
|
+
if (Math.abs(v.currentTime - t) < 1 / (options.fps ?? 30))
|
|
16482
|
+
return;
|
|
16483
|
+
seekVideo(t);
|
|
16484
|
+
},
|
|
16485
|
+
onPlay(on) {
|
|
16486
|
+
if (on)
|
|
16487
|
+
v.play().catch(() => tl.pause());
|
|
16488
|
+
else {
|
|
16489
|
+
v.pause();
|
|
16490
|
+
reported = tl.time;
|
|
16491
|
+
}
|
|
16492
|
+
root.toggleAttribute("data-playing", on);
|
|
16493
|
+
options.onPlay?.(on, tl.time);
|
|
16494
|
+
},
|
|
16495
|
+
onScrub(on) {
|
|
16496
|
+
if (on)
|
|
16497
|
+
v.pause();
|
|
16498
|
+
}
|
|
16499
|
+
});
|
|
16500
|
+
tl.drive(() => {
|
|
16501
|
+
if (v.readyState < 1)
|
|
16502
|
+
return Number.NaN;
|
|
16503
|
+
if (v.seeking)
|
|
16504
|
+
return tl.time;
|
|
16505
|
+
return v.ended ? Number.POSITIVE_INFINITY : v.currentTime;
|
|
16506
|
+
});
|
|
16507
|
+
const onClick = () => tl.focus();
|
|
16508
|
+
frame.addEventListener("click", onClick);
|
|
16509
|
+
v.src = options.src;
|
|
16510
|
+
const api = {
|
|
16511
|
+
element: root,
|
|
16512
|
+
video: v,
|
|
16513
|
+
timeline: tl,
|
|
16514
|
+
get time() {
|
|
16515
|
+
return tl.time;
|
|
16516
|
+
},
|
|
16517
|
+
get playing() {
|
|
16518
|
+
return tl.playing;
|
|
16519
|
+
},
|
|
16520
|
+
get duration() {
|
|
16521
|
+
return Number.isFinite(v.duration) ? v.duration : 0;
|
|
16522
|
+
},
|
|
16523
|
+
play: () => tl.play(),
|
|
16524
|
+
pause: () => tl.pause(),
|
|
16525
|
+
toggle: () => tl.toggle(),
|
|
16526
|
+
seek: (t, o) => tl.seek(t, o?.glide ? { glide: true } : undefined),
|
|
16527
|
+
seekBy: (d) => tl.seek(Math.min(tl.duration, Math.max(0, tl.time + d)), { glide: true }),
|
|
16528
|
+
focus: () => tl.focus(),
|
|
16529
|
+
dispose() {
|
|
16530
|
+
unlisten();
|
|
16531
|
+
tl.drive(null);
|
|
16532
|
+
tl.dispose();
|
|
16533
|
+
v.pause();
|
|
16534
|
+
frame.removeEventListener("click", onClick);
|
|
16535
|
+
v.removeEventListener("loadedmetadata", onMeta);
|
|
16536
|
+
v.removeEventListener("loadeddata", onFrame);
|
|
16537
|
+
v.removeEventListener("seeked", onSeeked);
|
|
16538
|
+
v.removeAttribute("src");
|
|
16539
|
+
v.load();
|
|
16540
|
+
root.remove();
|
|
16541
|
+
}
|
|
16542
|
+
};
|
|
16543
|
+
return api;
|
|
16544
|
+
}
|
|
16582
16545
|
// src/ui/history.ts
|
|
16583
16546
|
init_motion();
|
|
16584
16547
|
init_glide();
|
|
@@ -17480,9 +17443,10 @@ function knownPRs(doc, sections) {
|
|
|
17480
17443
|
}
|
|
17481
17444
|
function findPR(prs, n, repo) {
|
|
17482
17445
|
const known = prs[n];
|
|
17446
|
+
const href = repo ? `https://github.com/${repo}/pull/${n}` : undefined;
|
|
17483
17447
|
if (known)
|
|
17484
|
-
return known;
|
|
17485
|
-
return
|
|
17448
|
+
return known.href || !href ? known : { ...known, href };
|
|
17449
|
+
return href ? { href } : null;
|
|
17486
17450
|
}
|
|
17487
17451
|
var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
|
|
17488
17452
|
function withKickers(sections, source, kickers = "pr") {
|
|
@@ -21979,7 +21943,7 @@ function mountHistory(host, m, steps) {
|
|
|
21979
21943
|
context: () => ({ kind: "history" })
|
|
21980
21944
|
};
|
|
21981
21945
|
}
|
|
21982
|
-
function mountStack(host, m, steps) {
|
|
21946
|
+
function mountStack(host, m, steps, findPR) {
|
|
21983
21947
|
const doc = host.ownerDocument;
|
|
21984
21948
|
const layout = stackLayout(m);
|
|
21985
21949
|
const root = el2(doc, "div", "knobs-wt-stack");
|
|
@@ -22021,7 +21985,10 @@ function mountStack(host, m, steps) {
|
|
|
22021
21985
|
const line = el2(doc, "div", "knobs-wt-sline");
|
|
22022
21986
|
if (it.order)
|
|
22023
21987
|
line.append(text2(doc, "span", "knobs-wt-sord", it.order));
|
|
22024
|
-
|
|
21988
|
+
const known = findPR?.(it.pr.replace(/^#/, "")) ?? null;
|
|
21989
|
+
const pr = link(doc, "knobs-wt-spr", it.pr, it.href ?? known?.href);
|
|
21990
|
+
pr.addEventListener("click", (e) => e.stopPropagation());
|
|
21991
|
+
line.append(pr);
|
|
22025
21992
|
const target = it.step ? steps?.find(it.step) : null;
|
|
22026
21993
|
if (target && steps) {
|
|
22027
21994
|
const title = text2(doc, "button", "knobs-wt-stitle", it.title);
|
|
@@ -22056,7 +22023,11 @@ function mountStack(host, m, steps) {
|
|
|
22056
22023
|
if (meta.childNodes.length)
|
|
22057
22024
|
main.append(meta);
|
|
22058
22025
|
row.append(main);
|
|
22059
|
-
|
|
22026
|
+
const said = prStatus(it.status);
|
|
22027
|
+
const state = known?.state ?? said.state;
|
|
22028
|
+
if (state)
|
|
22029
|
+
row.append(prStateLabel(doc, state, said.checks, it.status));
|
|
22030
|
+
else if (it.status) {
|
|
22060
22031
|
const chip = text2(doc, "span", "knobs-wt-chip knobs-wt-sstatus", it.status);
|
|
22061
22032
|
chip.dataset.tone = it.tone ?? "dim";
|
|
22062
22033
|
row.append(chip);
|
|
@@ -22363,8 +22334,34 @@ var PR_PATHS = {
|
|
|
22363
22334
|
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
22335
|
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
22336
|
};
|
|
22366
|
-
var
|
|
22337
|
+
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";
|
|
22338
|
+
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";
|
|
22339
|
+
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";
|
|
22340
|
+
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>`;
|
|
22341
|
+
var prGlyph = (state) => state === "merged" ? svg12(PR_PATHS.merge) : state === "draft" ? svg12(DRAFT, true) : state === "closed" ? svg12(X) : svg12(PR_PATHS.pull);
|
|
22367
22342
|
var PR_STATE = { merged: "Merged", open: "Open", draft: "Draft", closed: "Closed" };
|
|
22343
|
+
function prStatus(status) {
|
|
22344
|
+
const words = (status ?? "").trim().toLowerCase();
|
|
22345
|
+
const first = /^[a-z]+/.exec(words)?.[0] ?? "";
|
|
22346
|
+
const state = first in PR_STATE ? first : null;
|
|
22347
|
+
return { state, checks: /\b(green|passing|passed|ci|checks? pass)/.test(words) };
|
|
22348
|
+
}
|
|
22349
|
+
function prStateLabel(doc, state, checks, title) {
|
|
22350
|
+
const s = el2(doc, "span", "knobs-wt-prstate");
|
|
22351
|
+
s.dataset.state = state;
|
|
22352
|
+
s.innerHTML = prGlyph(state);
|
|
22353
|
+
s.append(text2(doc, "span", "", PR_STATE[state]));
|
|
22354
|
+
if (checks) {
|
|
22355
|
+
const c = el2(doc, "span", "knobs-wt-prchecks");
|
|
22356
|
+
c.innerHTML = svg12(CHECK3);
|
|
22357
|
+
c.title = "Checks pass";
|
|
22358
|
+
c.setAttribute("aria-label", "checks pass");
|
|
22359
|
+
s.append(c);
|
|
22360
|
+
}
|
|
22361
|
+
if (title)
|
|
22362
|
+
s.title = title;
|
|
22363
|
+
return s;
|
|
22364
|
+
}
|
|
22368
22365
|
function prChip(doc, n, pr) {
|
|
22369
22366
|
const chip = el2(doc, pr.href ? "a" : "span", "knobs-wt-pr");
|
|
22370
22367
|
if (pr.href) {
|
|
@@ -22374,7 +22371,7 @@ function prChip(doc, n, pr) {
|
|
|
22374
22371
|
}
|
|
22375
22372
|
if (pr.state)
|
|
22376
22373
|
chip.dataset.state = pr.state;
|
|
22377
|
-
chip.innerHTML = prGlyph(pr.state
|
|
22374
|
+
chip.innerHTML = prGlyph(pr.state);
|
|
22378
22375
|
chip.append(text2(doc, "span", "", `#${n}`));
|
|
22379
22376
|
const tip = [`#${n}`, pr.title, pr.state ? PR_STATE[pr.state] : ""].filter(Boolean).join(" · ");
|
|
22380
22377
|
chip.title = tip;
|
|
@@ -22851,12 +22848,21 @@ var walkthroughCss = `
|
|
|
22851
22848
|
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
22852
22849
|
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
22853
22850
|
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
22851
|
+
/* A PR's state the GitHub way: its glyph and word, open and merged quietly tinted (as PR chips),
|
|
22852
|
+
draft and closed faint; no fill, no dot. A check after it where the checks pass, faint too. One
|
|
22853
|
+
width for every row, so the glyphs and words line up. */
|
|
22854
|
+
.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);
|
|
22855
|
+
font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);white-space:nowrap}
|
|
22856
|
+
.knobs-ui .knobs-wt-prstate[data-state="open"]{--kw-pr:color-mix(in oklch,var(--_k-ok) 60%,var(--_k-fg-2))}
|
|
22857
|
+
.knobs-ui .knobs-wt-prstate[data-state="merged"]{--kw-pr:color-mix(in oklch,var(--_k-series-5) 60%,var(--_k-fg-2))}
|
|
22858
|
+
.knobs-wt-prstate svg{flex:none}
|
|
22859
|
+
.knobs-ui .knobs-wt-prchecks{display:inline-flex;margin-left:2px;color:var(--_k-fg-3)}
|
|
22854
22860
|
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
22855
22861
|
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
22856
22862
|
@container knobs-wt-slot (max-width:520px){
|
|
22857
22863
|
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
22858
22864
|
.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}
|
|
22865
|
+
:is(.knobs-wt-sstatus,.knobs-wt-prstate){grid-column:-2;justify-self:start;margin-top:4px}
|
|
22860
22866
|
}
|
|
22861
22867
|
|
|
22862
22868
|
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
@@ -23502,7 +23508,7 @@ function mediaSlot(container, options) {
|
|
|
23502
23508
|
case "history":
|
|
23503
23509
|
return done(mountHistory(host, m, options.steps));
|
|
23504
23510
|
case "stack":
|
|
23505
|
-
return done(mountStack(host, m, options.steps));
|
|
23511
|
+
return done(mountStack(host, m, options.steps, options.findPR));
|
|
23506
23512
|
case "table":
|
|
23507
23513
|
return done(mountTable(host, m, options.steps));
|
|
23508
23514
|
case "mount": {
|
|
@@ -23556,7 +23562,7 @@ function mediaSlot(container, options) {
|
|
|
23556
23562
|
}
|
|
23557
23563
|
};
|
|
23558
23564
|
}
|
|
23559
|
-
var
|
|
23565
|
+
var CHECK4 = icon("check", { small: true });
|
|
23560
23566
|
|
|
23561
23567
|
// src/ui/walkthrough.ts
|
|
23562
23568
|
var el3 = (doc, tag, cls) => {
|
|
@@ -23643,7 +23649,7 @@ function tasteTest(container, options) {
|
|
|
23643
23649
|
pick.append(key);
|
|
23644
23650
|
}
|
|
23645
23651
|
const check = el3(doc, "span", "knobs-wt-check");
|
|
23646
|
-
check.innerHTML =
|
|
23652
|
+
check.innerHTML = CHECK4;
|
|
23647
23653
|
pick.append(check);
|
|
23648
23654
|
pick.addEventListener("click", () => {
|
|
23649
23655
|
const next = picked === o.id ? null : o.id;
|
|
@@ -24804,7 +24810,7 @@ function walkthrough(container, options) {
|
|
|
24804
24810
|
media = el3(doc, "div", "knobs-wt-media");
|
|
24805
24811
|
media.style.setProperty("--kw-n", String(Math.min(step.media.length, step.columns)));
|
|
24806
24812
|
for (const m of step.media)
|
|
24807
|
-
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
24813
|
+
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks, findPR: findPRIn }));
|
|
24808
24814
|
card.append(media);
|
|
24809
24815
|
}
|
|
24810
24816
|
let taste = null;
|