@kitlangton/knobs 0.4.0-next.2 → 0.4.0-next.4
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 +62 -12
- package/dist/dev/{chunk-8mabjeyk.js → chunk-0w1xk9jc.js} +162 -1
- package/dist/dev/{chunk-1qzffbpa.js → chunk-76frnh2j.js} +78 -34
- package/dist/dev/{chunk-ayb292zj.js → chunk-rem3qrhz.js} +2 -2
- package/dist/dev/index.js +3 -3
- package/dist/panel.js +240 -34
- package/dist/themes.js +160 -0
- package/dist/types/tokens/schema.d.ts +180 -0
- package/dist/types/ui/compare-css.d.ts +1 -1
- package/dist/types/ui/compare-gpu.d.ts +0 -5
- package/dist/types/ui/compare-model.d.ts +31 -2
- package/dist/types/ui/compare.d.ts +17 -4
- package/dist/types/ui/history-css.d.ts +1 -0
- package/dist/types/ui/history-model.d.ts +236 -0
- package/dist/types/ui/history.d.ts +33 -0
- package/dist/types/ui/icons.d.ts +40 -0
- package/dist/types/ui/index.d.ts +4 -2
- package/dist/types/ui/selection-pill-css.d.ts +1 -0
- package/dist/types/ui/selection-pill.d.ts +103 -0
- package/dist/types/ui/timeline-model.d.ts +23 -0
- package/dist/types/ui/timeline.d.ts +11 -1
- package/dist/types/ui/tree.d.ts +3 -2
- package/dist/types/ui/walkthrough-blocks.d.ts +20 -1
- package/dist/types/ui/walkthrough-model.d.ts +59 -1
- package/dist/types/ui/walkthrough.d.ts +10 -2
- package/dist/ui-react.js +2027 -952
- package/dist/ui-solid.js +2027 -952
- package/dist/ui.js +2047 -952
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -570,12 +570,20 @@ var compareCss = `
|
|
|
570
570
|
display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;
|
|
571
571
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
572
572
|
:where(.knobs-ui) :is(.knobs-cmp-mode,.knobs-cmp-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}
|
|
573
|
-
.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
.knobs-
|
|
578
|
-
.knobs-ui .knobs-cmp-mode
|
|
573
|
+
.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:var(--_k-gap);height:var(--_k-control-h)}
|
|
574
|
+
/* The modes: one fill, the selection pill on the one picked; a mode isn't brighter for being
|
|
575
|
+
picked: the pill's bright copy is. */
|
|
576
|
+
.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}
|
|
577
|
+
.knobs-cmp-modes[hidden]{display:none}
|
|
578
|
+
.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
|
|
579
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
580
|
+
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
581
|
+
/* 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-3);cursor:pointer;
|
|
583
|
+
transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
584
|
+
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}
|
|
585
|
+
.knobs-ui .knobs-cmp-toggle[aria-pressed="true"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}
|
|
586
|
+
.knobs-cmp-toggle svg{display:block}
|
|
579
587
|
.knobs-cmp-fill{flex:1}
|
|
580
588
|
.knobs-cmp-toggle[hidden]{display:none}
|
|
581
589
|
/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked
|
|
@@ -590,7 +598,8 @@ var compareCss = `
|
|
|
590
598
|
/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */
|
|
591
599
|
.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}
|
|
592
600
|
.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}
|
|
593
|
-
.
|
|
601
|
+
/* Wiping, the grip stands in for the cursor. */
|
|
602
|
+
.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}
|
|
594
603
|
.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}
|
|
595
604
|
.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}
|
|
596
605
|
.knobs-cmp-media{position:absolute;left:0;top:0;display:block;max-width:none;margin:0;padding:0;border:0;object-fit:fill;transform-origin:0 0;pointer-events:none;will-change:transform}
|
|
@@ -598,18 +607,26 @@ var compareCss = `
|
|
|
598
607
|
/* Glass: what's behind shows through, blurred, on the knobs tokens. */
|
|
599
608
|
.knobs-cmp-label,.knobs-cmp-zoom{background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);
|
|
600
609
|
box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim),0 2px 10px rgba(0,0,0,calc(.18 * var(--_k-shadow-k,1)))}
|
|
601
|
-
|
|
602
|
-
.knobs-cmp-label
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
610
|
+
/* ✗ Before · ✓ After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */
|
|
611
|
+
.knobs-cmp-label{position:absolute;left:0;top:0;display:flex;align-items:center;gap:4px;padding:1px 7px 1px 5px;border-radius:999px;font-size:var(--_k-text-meta);line-height:16px;font-weight:var(--_k-weight-label);
|
|
612
|
+
white-space:nowrap;pointer-events:none;will-change:transform}
|
|
613
|
+
.knobs-cmp-label[data-side="before"]{color:var(--_k-fg-3)}
|
|
614
|
+
.knobs-cmp-label[data-side="after"]{color:var(--_k-fg)}
|
|
615
|
+
.knobs-cmp-mark svg{display:block;width:12px;height:12px}
|
|
616
|
+
/* The wipe: a hairline down the line with a raised grip at the pointer's height; a wider strip
|
|
617
|
+
takes the hand and the keys (a slider). It fades with the mode; wiping, line and grip brighten. */
|
|
606
618
|
.knobs-cmp-handle{cursor:ew-resize;position:absolute;left:-12px;top:0;width:24px;height:0;opacity:0;pointer-events:none;outline:none;will-change:transform;transition:opacity .18s cubic-bezier(.4,0,1,1)}
|
|
607
619
|
.knobs-cmp-handle[data-on]{opacity:1;pointer-events:auto;transition:opacity .22s cubic-bezier(.2,.8,.2,1)}
|
|
608
|
-
.knobs-cmp-handle::before{content:"";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:var(--_ku-cmp-line);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}
|
|
609
|
-
.knobs-cmp-handle::
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
.knobs-cmp-
|
|
620
|
+
.knobs-cmp-handle::before{content:"";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:color-mix(in srgb,var(--_ku-cmp-line) 72%,transparent);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}
|
|
621
|
+
.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}
|
|
622
|
+
.knobs-cmp-grip{position:absolute;top:0;left:4px;width:16px;height:28px;border-radius:min(8px,calc(var(--_k-radius) * 999));background:var(--_k-bg-overlay);
|
|
623
|
+
box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border),inset 0 1px 0 var(--_k-rim);will-change:transform;transition:box-shadow calc(var(--_k-hover-out) * 1ms)}
|
|
624
|
+
.knobs-cmp-grip::before,.knobs-cmp-grip::after{content:"";position:absolute;top:10px;width:1px;height:8px;background:var(--_k-fg-3);transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
625
|
+
.knobs-cmp-grip::before{left:6px}
|
|
626
|
+
.knobs-cmp-grip::after{left:9px}
|
|
627
|
+
.knobs-compare[data-dragging] .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border-strong),inset 0 1px 0 var(--_k-rim)}
|
|
628
|
+
.knobs-compare[data-dragging] .knobs-cmp-grip::before,.knobs-compare[data-dragging] .knobs-cmp-grip::after{background:var(--_k-fg)}
|
|
629
|
+
.knobs-cmp-handle:focus-visible .knobs-cmp-grip,.knobs-compare[data-keyboard] .knobs-cmp-handle:focus .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),0 0 0 2px var(--_k-accent)}
|
|
613
630
|
/* The split's hairline, down the middle side by side. */
|
|
614
631
|
.knobs-cmp-split{position:absolute;left:0;top:0;width:1px;height:0;margin-left:-.5px;background:color-mix(in srgb,var(--_k-bg) 72%,transparent);pointer-events:none;will-change:transform,opacity}
|
|
615
632
|
/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */
|
|
@@ -618,12 +635,12 @@ var compareCss = `
|
|
|
618
635
|
opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}
|
|
619
636
|
.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)}
|
|
620
637
|
: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;
|
|
621
|
-
height:20px;padding:0
|
|
638
|
+
display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}
|
|
622
639
|
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent)}
|
|
623
640
|
.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}
|
|
624
641
|
.knobs-cmp-note:empty{display:none}
|
|
625
642
|
.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}
|
|
626
|
-
.knobs-cmp-timeline-host{flex:none;
|
|
643
|
+
.knobs-cmp-timeline-host{flex:none;min-height:0}
|
|
627
644
|
/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */
|
|
628
645
|
.knobs-ui.knobs-cmp-strip{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));position:relative;width:100%;height:100%;min-height:40px;overflow:hidden;cursor:col-resize;touch-action:none;
|
|
629
646
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg)}
|
|
@@ -766,7 +783,7 @@ var init_picker_css = __esm(() => {
|
|
|
766
783
|
.knobs-picker-suggested{flex:none;color:var(--_k-fg-3);font-size:var(--_k-text-meta)}
|
|
767
784
|
.knobs-picker-check{flex:none;display:flex;width:14px;height:14px;color:var(--_k-accent);opacity:0;scale:.6;filter:blur(2px);
|
|
768
785
|
transition:opacity .11s ease-in,scale .11s ease-in,filter .11s ease-in}
|
|
769
|
-
.knobs-picker-check svg{display:block;width:
|
|
786
|
+
.knobs-picker-check svg{display:block;width:12px;height:12px}
|
|
770
787
|
.knobs-picker-option[data-chosen] .knobs-picker-check{opacity:1;scale:1;filter:none;transition:opacity .15s ease-out,scale var(--kp-snappy-ms) var(--kp-snappy),filter .15s ease-out}
|
|
771
788
|
.knobs-picker-body{position:relative;overflow:visible}
|
|
772
789
|
.knobs-picker-body[data-moving]{overflow:hidden}
|
|
@@ -870,6 +887,15 @@ var readoutCss = `
|
|
|
870
887
|
@media(prefers-reduced-motion:reduce){.knobs-rd :where(*){transition:none!important}}
|
|
871
888
|
`;
|
|
872
889
|
|
|
890
|
+
// src/ui/selection-pill-css.ts
|
|
891
|
+
var selectionPillCss = `
|
|
892
|
+
.knobs-pick-pill,.knobs-pick-copy{position:absolute;left:0;top:0;width:0;height:0;pointer-events:none;transition:opacity .1s linear}
|
|
893
|
+
.knobs-pick-pill{background:var(--_k-fill-selected);will-change:transform}
|
|
894
|
+
.knobs-pick-copy{overflow:hidden;will-change:transform}
|
|
895
|
+
.knobs-pick-copy-rows{position:absolute;left:0;top:0;width:0;height:0}
|
|
896
|
+
:is(.knobs-pick-pill,.knobs-pick-copy)[data-off]{opacity:0}
|
|
897
|
+
`;
|
|
898
|
+
|
|
873
899
|
// src/tokens/color.ts
|
|
874
900
|
function linearToOklch([r, g, b, a]) {
|
|
875
901
|
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
@@ -1310,6 +1336,22 @@ var init_schema = __esm(() => {
|
|
|
1310
1336
|
source: css("var(--k-warn)"),
|
|
1311
1337
|
doc: "Modified lines."
|
|
1312
1338
|
},
|
|
1339
|
+
{
|
|
1340
|
+
name: "before",
|
|
1341
|
+
tier: "semantic",
|
|
1342
|
+
type: "color",
|
|
1343
|
+
group: "Data",
|
|
1344
|
+
source: css("var(--k-fg-3)"),
|
|
1345
|
+
doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
name: "after",
|
|
1349
|
+
tier: "semantic",
|
|
1350
|
+
type: "color",
|
|
1351
|
+
group: "Data",
|
|
1352
|
+
source: css("var(--k-fg)"),
|
|
1353
|
+
doc: "After in a comparison, and only After."
|
|
1354
|
+
},
|
|
1313
1355
|
{
|
|
1314
1356
|
name: "series-1",
|
|
1315
1357
|
tier: "semantic",
|
|
@@ -1400,6 +1442,150 @@ var init_schema = __esm(() => {
|
|
|
1400
1442
|
source: value("288px"),
|
|
1401
1443
|
doc: "Panel width."
|
|
1402
1444
|
},
|
|
1445
|
+
{
|
|
1446
|
+
name: "space-inside",
|
|
1447
|
+
tier: "semantic",
|
|
1448
|
+
type: "length",
|
|
1449
|
+
group: "Space",
|
|
1450
|
+
source: css("var(--k-unit)"),
|
|
1451
|
+
doc: "Parts of one thing: an icon and its label, a meta line and its title."
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
name: "space-sibling",
|
|
1455
|
+
tier: "semantic",
|
|
1456
|
+
type: "length",
|
|
1457
|
+
group: "Space",
|
|
1458
|
+
source: css("calc(var(--k-unit) * 2)"),
|
|
1459
|
+
doc: "Siblings in a group: buttons in a row, a list item's lines."
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
name: "space-title",
|
|
1463
|
+
tier: "semantic",
|
|
1464
|
+
type: "length",
|
|
1465
|
+
group: "Space",
|
|
1466
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1467
|
+
doc: "A heading and what it heads."
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
name: "space-group",
|
|
1471
|
+
tier: "semantic",
|
|
1472
|
+
type: "length",
|
|
1473
|
+
group: "Space",
|
|
1474
|
+
source: css("calc(var(--k-unit) * 12)"),
|
|
1475
|
+
doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
name: "space-section",
|
|
1479
|
+
tier: "semantic",
|
|
1480
|
+
type: "length",
|
|
1481
|
+
group: "Space",
|
|
1482
|
+
source: css("calc(var(--k-unit) * 24)"),
|
|
1483
|
+
doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
name: "space-column",
|
|
1487
|
+
tier: "semantic",
|
|
1488
|
+
type: "length",
|
|
1489
|
+
group: "Space",
|
|
1490
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1491
|
+
doc: "Columns: a contents rail and the page, media side by side."
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
name: "pad-page",
|
|
1495
|
+
tier: "semantic",
|
|
1496
|
+
type: "length",
|
|
1497
|
+
group: "Space",
|
|
1498
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1499
|
+
doc: "A page's edge; 16px under 640px wide."
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
name: "pad-card",
|
|
1503
|
+
tier: "semantic",
|
|
1504
|
+
type: "length",
|
|
1505
|
+
group: "Space",
|
|
1506
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1507
|
+
doc: "Inside a card or popover."
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
name: "type-heading",
|
|
1511
|
+
tier: "semantic",
|
|
1512
|
+
type: "length",
|
|
1513
|
+
group: "Type",
|
|
1514
|
+
source: value("20px"),
|
|
1515
|
+
doc: "Section headings (a PR's title, under its kicker), weight 500."
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
name: "leading-heading",
|
|
1519
|
+
tier: "semantic",
|
|
1520
|
+
type: "length",
|
|
1521
|
+
group: "Type",
|
|
1522
|
+
source: value("28px"),
|
|
1523
|
+
doc: "Line height for type-heading."
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
name: "type-title",
|
|
1527
|
+
tier: "semantic",
|
|
1528
|
+
type: "length",
|
|
1529
|
+
group: "Type",
|
|
1530
|
+
source: value("16px"),
|
|
1531
|
+
doc: "A page's title, weight 500."
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
name: "leading-title",
|
|
1535
|
+
tier: "semantic",
|
|
1536
|
+
type: "length",
|
|
1537
|
+
group: "Type",
|
|
1538
|
+
source: value("24px"),
|
|
1539
|
+
doc: "Line height for type-title."
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
name: "type-body",
|
|
1543
|
+
tier: "semantic",
|
|
1544
|
+
type: "length",
|
|
1545
|
+
group: "Type",
|
|
1546
|
+
source: value("13px"),
|
|
1547
|
+
doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
name: "leading-body",
|
|
1551
|
+
tier: "semantic",
|
|
1552
|
+
type: "length",
|
|
1553
|
+
group: "Type",
|
|
1554
|
+
source: value("20px"),
|
|
1555
|
+
doc: "Line height for type-body."
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
name: "type-label",
|
|
1559
|
+
tier: "semantic",
|
|
1560
|
+
type: "length",
|
|
1561
|
+
group: "Type",
|
|
1562
|
+
source: value("12px"),
|
|
1563
|
+
doc: "Labels over media, weight 500; mono inside body text."
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
name: "leading-label",
|
|
1567
|
+
tier: "semantic",
|
|
1568
|
+
type: "length",
|
|
1569
|
+
group: "Type",
|
|
1570
|
+
source: value("16px"),
|
|
1571
|
+
doc: "Line height for type-label."
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
name: "type-small",
|
|
1575
|
+
tier: "semantic",
|
|
1576
|
+
type: "length",
|
|
1577
|
+
group: "Type",
|
|
1578
|
+
source: value("11px"),
|
|
1579
|
+
doc: "Meta, controls, keys, timestamps; mono inside labels."
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
name: "leading-small",
|
|
1583
|
+
tier: "semantic",
|
|
1584
|
+
type: "length",
|
|
1585
|
+
group: "Type",
|
|
1586
|
+
source: value("16px"),
|
|
1587
|
+
doc: "Line height for type-small."
|
|
1588
|
+
},
|
|
1403
1589
|
{
|
|
1404
1590
|
name: "font-size",
|
|
1405
1591
|
tier: "semantic",
|
|
@@ -2364,16 +2550,18 @@ function injectTokens(doc) {
|
|
|
2364
2550
|
style.textContent = rootCss;
|
|
2365
2551
|
doc.head.append(style);
|
|
2366
2552
|
}
|
|
2367
|
-
var ROOT_CLASS = "knobs-root", extras, spring, rootCss;
|
|
2553
|
+
var ROOT_CLASS = "knobs-root", extras, narrow, spring, rootCss;
|
|
2368
2554
|
var init_root = __esm(() => {
|
|
2369
2555
|
init_knobs();
|
|
2370
2556
|
init_css();
|
|
2371
2557
|
init_glide();
|
|
2372
2558
|
init_motion();
|
|
2373
2559
|
extras = `:where(.${ROOT_CLASS}){--_k-shadow-k:calc(var(--k-shadow-strength,calc(.48 - .32 * var(--_k-light,0))) / .48);--_k-glass-tone:var(--k-glass-tone,calc(.5 + .58 * var(--_k-light,0)));--_k-fill-base:var(--k-fill-base,var(--_k-fill-selected));--_k-fill-hover-mix:var(--k-fill-hover-mix,var(--k-fill-rest-mix,20%));--_k-reveal-ease:var(--k-ease,cubic-bezier(.2,.8,.2,1))}`;
|
|
2560
|
+
narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`;
|
|
2374
2561
|
spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`;
|
|
2375
2562
|
rootCss = `${tokensCss(knobs)}
|
|
2376
2563
|
${extras}
|
|
2564
|
+
${narrow}
|
|
2377
2565
|
${spring}
|
|
2378
2566
|
${DRIVERS}
|
|
2379
2567
|
${motionCss}`;
|
|
@@ -2663,6 +2851,12 @@ var css2 = `
|
|
|
2663
2851
|
--_ku-pane-bg and --_ku-pane-ring so this reaches them. */
|
|
2664
2852
|
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui:not(.knobs-surface),.knobs-ui[data-nested]{--_ku-gap:var(--k-ui-gap,0px);--_ku-pane-bg:transparent;--_ku-pane-ring:none;
|
|
2665
2853
|
--_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
|
|
2854
|
+
/* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
|
|
2855
|
+
ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
|
|
2856
|
+
card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
|
|
2857
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
|
|
2858
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-tl-track,.knobs-ui[data-nested] .knobs-tl-track{background:transparent;border-radius:0;box-shadow:inset 0 -1px 0 var(--_k-border-subtle)}
|
|
2859
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
|
|
2666
2860
|
/* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
|
|
2667
2861
|
.knobs-ui{box-sizing:border-box}
|
|
2668
2862
|
:where(.knobs-split>*,.knobs-pane-clip,.knobs-pane-inner,.knobs-pane-body,.knobs-pane-head,.knobs-pane-head *,.knobs-pane-rail,.knobs-pane-rail *,.knobs-tree,.knobs-tree *,.knobs-tree-ghost){box-sizing:border-box}
|
|
@@ -2797,11 +2991,9 @@ var css2 = `
|
|
|
2797
2991
|
.knobs-tree:focus .knobs-tree-row[data-active][aria-selected="true"]::before{background:var(--_ku-select-focus)}
|
|
2798
2992
|
.knobs-tree-row[data-drop="into"]::before{opacity:1;background:color-mix(in srgb,var(--_k-accent) 30%,transparent)}
|
|
2799
2993
|
.knobs-tree-row[data-dragged]{opacity:.38}
|
|
2800
|
-
/* glide:
|
|
2801
|
-
.knobs-tree-
|
|
2802
|
-
|
|
2803
|
-
.knobs-tree-cursor[data-on]{opacity:1}
|
|
2804
|
-
.knobs-tree:focus .knobs-tree-cursor{background:var(--_ku-select-focus)}
|
|
2994
|
+
/* glide: the selection pill on the selected row, in the selection's colour (the row's own stays off). */
|
|
2995
|
+
.knobs-tree>.knobs-pick-pill{background:var(--_ku-select)}
|
|
2996
|
+
.knobs-tree:focus>.knobs-pick-pill{background:var(--_ku-select-focus)}
|
|
2805
2997
|
.knobs-tree[data-glide] .knobs-tree-row[aria-selected="true"]::before{opacity:0!important}
|
|
2806
2998
|
.knobs-tree-row>*{position:relative}
|
|
2807
2999
|
.knobs-tree-caret{flex:none;display:flex;align-items:center;justify-content:center;width:16px;height:100%;color:var(--_k-fg-3);transition:transform var(--_ku-ease-ms) var(--_ku-ease)}
|
|
@@ -2833,22 +3025,20 @@ var css2 = `
|
|
|
2833
3025
|
box-shadow:0 0 0 1px var(--_k-border-strong),0 6px 18px rgba(0,0,0,calc(.35 * var(--_k-shadow-k,1)));pointer-events:none;white-space:nowrap;font:var(--_k-weight) var(--_k-font-size)/1.6 var(--_k-font)}
|
|
2834
3026
|
.knobs-tree-empty{padding:10px var(--_k-inset);color:var(--_k-fg-3)}
|
|
2835
3027
|
|
|
2836
|
-
/* Timeline:
|
|
2837
|
-
|
|
3028
|
+
/* Timeline: play beside a track: the ruler's canvas over a lane of markers, ranges as soft bands,
|
|
3029
|
+
and the playhead, a hairline in the accent with a cap. No clock: the time shows under the
|
|
3030
|
+
pointer on the track (the tag), in seconds, while hovering or scrubbing. */
|
|
2838
3031
|
:where(.knobs-timeline,.knobs-timeline *){box-sizing:border-box}
|
|
2839
3032
|
.knobs-ui.knobs-timeline{display:flex;align-items:stretch;gap:10px;width:100%;height:100%;min-height:52px;padding:6px var(--_k-inset) 8px 8px;outline:none;user-select:none;-webkit-user-select:none;
|
|
2840
3033
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
2841
3034
|
:where(.knobs-ui) :is(.knobs-tl-play,.knobs-tl-edit){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}
|
|
2842
|
-
.knobs-tl-transport{flex:none;display:flex;align-items:center
|
|
3035
|
+
.knobs-tl-transport{flex:none;display:flex;align-items:center}
|
|
2843
3036
|
.knobs-ui .knobs-tl-play{flex:none;display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);min-width:22px;min-height:22px;border-radius:calc(var(--_k-radius) * 999);
|
|
2844
3037
|
background:var(--_k-fill-selected);color:var(--_k-fg);cursor:pointer;transition:background .15s,transform .15s var(--_ku-ease)}
|
|
2845
3038
|
.knobs-ui .knobs-tl-play:hover{background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
2846
3039
|
.knobs-ui .knobs-tl-play:active{transform:scale(.94)}
|
|
2847
3040
|
.knobs-tl-play svg{width:12px;height:12px}
|
|
2848
3041
|
.knobs-timeline[data-playing] .knobs-tl-play{background:var(--_k-accent);color:var(--_k-bg)}
|
|
2849
|
-
.knobs-tl-time{display:flex;flex-direction:column;line-height:1.2;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
2850
|
-
.knobs-tl-now{font:var(--_k-weight) var(--_k-value-size)/1.2 var(--_k-value-font);font-variant-numeric:tabular-nums;font-feature-settings:"tnum";color:var(--_k-fg);white-space:nowrap}
|
|
2851
|
-
.knobs-tl-sub{font-size:var(--_k-text-meta);color:var(--_k-fg-3);white-space:nowrap}
|
|
2852
3042
|
.knobs-tl-track{position:relative;flex:1;min-width:0;overflow:hidden;border-radius:var(--_k-radius);background:var(--_k-fill);cursor:col-resize;touch-action:none;
|
|
2853
3043
|
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
2854
3044
|
.knobs-timeline:focus-visible .knobs-tl-track,.knobs-timeline[data-keyboard]:focus .knobs-tl-track{background:color-mix(in srgb,var(--_k-fill-selected) 80%,transparent)}
|
|
@@ -2872,7 +3062,8 @@ var css2 = `
|
|
|
2872
3062
|
.knobs-tl-pin{position:absolute;top:13px;left:-5px;width:10px;height:10px;pointer-events:auto;cursor:grab}
|
|
2873
3063
|
.knobs-tl-pin::after{content:"";position:absolute;inset:1.5px;border-radius:min(2px,var(--_k-radius));background:var(--knobs-tl-c);rotate:45deg;transition:background .15s,scale .2s var(--_ku-ease)}
|
|
2874
3064
|
.knobs-tl-mlabel{position:absolute;top:26px;left:3px;max-width:140px;padding:0 6px;border-radius:max(0px,calc(var(--_k-radius) - 3px));background:var(--_k-fill-selected);color:var(--_k-fg);
|
|
2875
|
-
font-size:var(--_k-text-meta);line-height:17px;white-space:nowrap;
|
|
3065
|
+
font-size:var(--_k-text-meta);line-height:17px;white-space:nowrap;pointer-events:auto;cursor:grab;transition:background .15s,color .15s}
|
|
3066
|
+
.knobs-tl-mtext{display:block;overflow:hidden;white-space:nowrap}
|
|
2876
3067
|
.knobs-tl-marker[data-selected]{--knobs-tl-c:var(--_k-accent)}
|
|
2877
3068
|
.knobs-tl-marker[data-selected] .knobs-tl-mlabel{background:color-mix(in srgb,var(--_k-accent) 24%,var(--_k-fill-selected))}
|
|
2878
3069
|
.knobs-tl-marker[data-selected] .knobs-tl-pin::after{scale:1.2}
|
|
@@ -2893,7 +3084,22 @@ var css2 = `
|
|
|
2893
3084
|
.knobs-timeline[data-scrubbing] .knobs-tl-hover{opacity:0}
|
|
2894
3085
|
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
2895
3086
|
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
2896
|
-
|
|
3087
|
+
.knobs-tl-tag{position:absolute;left:0;bottom:2px;font-size:var(--_k-text-meta);line-height:16px;color:var(--_k-fg);font-variant-numeric:tabular-nums;font-feature-settings:"tnum";white-space:nowrap;pointer-events:none;opacity:0}
|
|
3088
|
+
.knobs-tl-tag[data-on]{opacity:1}
|
|
3089
|
+
/* The lane (variant: "lane"): one slim track of ticks under a compare or a video; markers are
|
|
3090
|
+
faint chapter ticks, the current one in text colour; nothing to edit. */
|
|
3091
|
+
.knobs-ui.knobs-timeline[data-variant="lane"]{height:auto;min-height:0;padding:0;gap:var(--_k-gap)}
|
|
3092
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-track{height:var(--_k-control-h)}
|
|
3093
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-ruler{height:100%}
|
|
3094
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-lane{top:0}
|
|
3095
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker{top:0}
|
|
3096
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker::before{top:0;bottom:50%;left:-.75px;width:1.5px;background:var(--_k-fg-3)}
|
|
3097
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker[data-current]::before{background:var(--_k-fg)}
|
|
3098
|
+
.knobs-timeline[data-variant="lane"] :is(.knobs-tl-pin,.knobs-tl-mlabel,.knobs-tl-rlabel){display:none}
|
|
3099
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-head::before{top:0}
|
|
3100
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-head::after{content:none}
|
|
3101
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-tag{top:2px;bottom:auto}
|
|
3102
|
+
`, uiCss = () => aliased(css2 + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + compareCss + selectionPillCss) + rolling_css_default, RESTYLED = ".knobs-ui,.knobs-panel,.knobs-chip,.knobs-notice", lookDefaults, tune = (s, m) => {
|
|
2897
3103
|
s.omega = m.omega;
|
|
2898
3104
|
s.zeta = m.zeta;
|
|
2899
3105
|
return s;
|
|
@@ -4659,6 +4865,283 @@ var init_tree_model = __esm(() => {
|
|
|
4659
4865
|
};
|
|
4660
4866
|
});
|
|
4661
4867
|
|
|
4868
|
+
// src/ui/icons.ts
|
|
4869
|
+
function icon(name, options = {}) {
|
|
4870
|
+
const size = options.small ? 12 : 16;
|
|
4871
|
+
return `<svg class="knobs-icon" viewBox="0 0 256 256" width="${size}" height="${size}" fill="currentColor" aria-hidden="true" focusable="false"><path d="${PATHS[name]}"/></svg>`;
|
|
4872
|
+
}
|
|
4873
|
+
var PATHS, ICON_NAMES;
|
|
4874
|
+
var init_icons = __esm(() => {
|
|
4875
|
+
PATHS = {
|
|
4876
|
+
arrowLeft: "M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z",
|
|
4877
|
+
arrowUpRight: "M200,64V168a8,8,0,0,1-16,0V83.31L69.66,197.66a8,8,0,0,1-11.32-11.32L172.69,72H88a8,8,0,0,1,0-16H192A8,8,0,0,1,200,64Z",
|
|
4878
|
+
arrowSquareOut: "M224,104a8,8,0,0,1-16,0V59.32l-66.33,66.34a8,8,0,0,1-11.32-11.32L196.68,48H152a8,8,0,0,1,0-16h64a8,8,0,0,1,8,8Zm-40,24a8,8,0,0,0-8,8v72H48V80h72a8,8,0,0,0,0-16H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V136A8,8,0,0,0,184,128Z",
|
|
4879
|
+
arrowCounterClockwise: "M224,128a96,96,0,0,1-94.71,96H128A95.38,95.38,0,0,1,62.1,197.8a8,8,0,0,1,11-11.63A80,80,0,1,0,71.43,71.39a3.07,3.07,0,0,1-.26.25L44.59,96H72a8,8,0,0,1,0,16H24a8,8,0,0,1-8-8V56a8,8,0,0,1,16,0V85.8L60.25,60A96,96,0,0,1,224,128Z",
|
|
4880
|
+
arrowUDownLeft: "M232,112a64.07,64.07,0,0,1-64,64H51.31l34.35,34.34a8,8,0,0,1-11.32,11.32l-48-48a8,8,0,0,1,0-11.32l48-48a8,8,0,0,1,11.32,11.32L51.31,160H168a48,48,0,0,0,0-96H80a8,8,0,0,1,0-16h88A64.07,64.07,0,0,1,232,112Z",
|
|
4881
|
+
arrowsHorizontal: "M136,40V216a8,8,0,0,1-16,0V40a8,8,0,0,1,16,0ZM96,120H35.31l18.35-18.34A8,8,0,0,0,42.34,90.34l-32,32a8,8,0,0,0,0,11.32l32,32a8,8,0,0,0,11.32-11.32L35.31,136H96a8,8,0,0,0,0-16Zm149.66,2.34-32-32a8,8,0,0,0-11.32,11.32L220.69,120H160a8,8,0,0,0,0,16h60.69l-18.35,18.34a8,8,0,0,0,11.32,11.32l32-32A8,8,0,0,0,245.66,122.34Z",
|
|
4882
|
+
caretDown: "M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z",
|
|
4883
|
+
caretLeft: "M165.66,202.34a8,8,0,0,1-11.32,11.32l-80-80a8,8,0,0,1,0-11.32l80-80a8,8,0,0,1,11.32,11.32L91.31,128Z",
|
|
4884
|
+
caretRight: "M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z",
|
|
4885
|
+
caretUp: "M213.66,165.66a8,8,0,0,1-11.32,0L128,91.31,53.66,165.66a8,8,0,0,1-11.32-11.32l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,213.66,165.66Z",
|
|
4886
|
+
check: "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",
|
|
4887
|
+
checkCircle: "M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z",
|
|
4888
|
+
circle: "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,216Z",
|
|
4889
|
+
copy: "M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z",
|
|
4890
|
+
cornersIn: "M152,96V48a8,8,0,0,1,16,0V88h40a8,8,0,0,1,0,16H160A8,8,0,0,1,152,96ZM96,152H48a8,8,0,0,0,0,16H88v40a8,8,0,0,0,16,0V160A8,8,0,0,0,96,152Zm112,0H160a8,8,0,0,0-8,8v48a8,8,0,0,0,16,0V168h40a8,8,0,0,0,0-16ZM96,40a8,8,0,0,0-8,8V88H48a8,8,0,0,0,0,16H96a8,8,0,0,0,8-8V48A8,8,0,0,0,96,40Z",
|
|
4891
|
+
cornersOut: "M216,48V88a8,8,0,0,1-16,0V56H168a8,8,0,0,1,0-16h40A8,8,0,0,1,216,48ZM88,200H56V168a8,8,0,0,0-16,0v40a8,8,0,0,0,8,8H88a8,8,0,0,0,0-16Zm120-40a8,8,0,0,0-8,8v32H168a8,8,0,0,0,0,16h40a8,8,0,0,0,8-8V168A8,8,0,0,0,208,160ZM88,40H48a8,8,0,0,0-8,8V88a8,8,0,0,0,16,0V56H88a8,8,0,0,0,0-16Z",
|
|
4892
|
+
folder: "M216,72H130.67L102.93,51.2a16.12,16.12,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V200a16,16,0,0,0,16,16H216.89A15.13,15.13,0,0,0,232,200.89V88A16,16,0,0,0,216,72Zm0,128H40V64H93.33L123.2,86.4A8,8,0,0,0,128,88h88Z",
|
|
4893
|
+
keyboard: "M224,48H32A16,16,0,0,0,16,64V192a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V64A16,16,0,0,0,224,48Zm0,144H32V64H224V192Zm-16-64a8,8,0,0,1-8,8H56a8,8,0,0,1,0-16H200A8,8,0,0,1,208,128Zm0-32a8,8,0,0,1-8,8H56a8,8,0,0,1,0-16H200A8,8,0,0,1,208,96ZM72,160a8,8,0,0,1-8,8H56a8,8,0,0,1,0-16h8A8,8,0,0,1,72,160Zm96,0a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,160Zm40,0a8,8,0,0,1-8,8h-8a8,8,0,0,1,0-16h8A8,8,0,0,1,208,160Z",
|
|
4894
|
+
magnifyingGlass: "M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z",
|
|
4895
|
+
magnifyingGlassMinus: "M152,112a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h64A8,8,0,0,1,152,112Zm77.66,117.66a8,8,0,0,1-11.32,0l-50.06-50.07a88.11,88.11,0,1,1,11.31-11.31l50.07,50.06A8,8,0,0,1,229.66,229.66ZM112,184a72,72,0,1,0-72-72A72.08,72.08,0,0,0,112,184Z",
|
|
4896
|
+
magnifyingGlassPlus: "M152,112a8,8,0,0,1-8,8H120v24a8,8,0,0,1-16,0V120H80a8,8,0,0,1,0-16h24V80a8,8,0,0,1,16,0v24h24A8,8,0,0,1,152,112Zm77.66,117.66a8,8,0,0,1-11.32,0l-50.06-50.07a88.11,88.11,0,1,1,11.31-11.31l50.07,50.06A8,8,0,0,1,229.66,229.66ZM112,184a72,72,0,1,0-72-72A72.08,72.08,0,0,0,112,184Z",
|
|
4897
|
+
microphone: "M128,176a48.05,48.05,0,0,0,48-48V64a48,48,0,0,0-96,0v64A48.05,48.05,0,0,0,128,176ZM96,64a32,32,0,0,1,64,0v64a32,32,0,0,1-64,0Zm40,143.6V240a8,8,0,0,1-16,0V207.6A80.11,80.11,0,0,1,48,128a8,8,0,0,1,16,0,64,64,0,0,0,128,0,8,8,0,0,1,16,0A80.11,80.11,0,0,1,136,207.6Z",
|
|
4898
|
+
paperPlaneRight: "M231.87,114l-168-95.89A16,16,0,0,0,40.92,37.34L71.55,128,40.92,218.67A16,16,0,0,0,56,240a16.15,16.15,0,0,0,7.93-2.1l167.92-96.05a16,16,0,0,0,.05-27.89ZM56,224a.56.56,0,0,0,0-.12L85.74,136H144a8,8,0,0,0,0-16H85.74L56.06,32.16A.46.46,0,0,0,56,32l168,95.83Z",
|
|
4899
|
+
pencilSimple: "M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM92.69,208H48V163.31l88-88L180.69,120ZM192,108.68,147.31,64l24-24L216,84.68Z",
|
|
4900
|
+
repeat: "M24,128A72.08,72.08,0,0,1,96,56H204.69L194.34,45.66a8,8,0,0,1,11.32-11.32l24,24a8,8,0,0,1,0,11.32l-24,24a8,8,0,0,1-11.32-11.32L204.69,72H96a56.06,56.06,0,0,0-56,56,8,8,0,0,1-16,0Zm200-8a8,8,0,0,0-8,8,56.06,56.06,0,0,1-56,56H51.31l10.35-10.34a8,8,0,0,0-11.32-11.32l-24,24a8,8,0,0,0,0,11.32l24,24a8,8,0,0,0,11.32-11.32L51.31,200H160a72.08,72.08,0,0,0,72-72A8,8,0,0,0,224,120Z",
|
|
4901
|
+
sidebar: "M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM40,56H80V200H40ZM216,200H96V56H216V200Z",
|
|
4902
|
+
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"
|
|
4903
|
+
};
|
|
4904
|
+
ICON_NAMES = Object.keys(PATHS);
|
|
4905
|
+
});
|
|
4906
|
+
|
|
4907
|
+
// src/ui/selection-pill.ts
|
|
4908
|
+
function pillSpring(distance, base = SPRINGS.default) {
|
|
4909
|
+
return distance > 400 ? { duration: base.duration * 1.4, bounce: base.bounce } : base;
|
|
4910
|
+
}
|
|
4911
|
+
function pillBoxOf(row, container) {
|
|
4912
|
+
return {
|
|
4913
|
+
x: row.left - container.left - container.clientLeft + container.scrollLeft,
|
|
4914
|
+
y: row.top - container.top - container.clientTop + container.scrollTop,
|
|
4915
|
+
w: row.width,
|
|
4916
|
+
h: row.height
|
|
4917
|
+
};
|
|
4918
|
+
}
|
|
4919
|
+
function pillRadius(from, to, h, k) {
|
|
4920
|
+
const t = Math.abs(to.h - from.h) > 0.5 ? (h - from.h) / (to.h - from.h) : Number.isFinite(k) ? k : 1;
|
|
4921
|
+
return from.r + (to.r - from.r) * Math.min(1, Math.max(0, t));
|
|
4922
|
+
}
|
|
4923
|
+
function pillProgress(from, to, at) {
|
|
4924
|
+
const d = Math.hypot(to.x - from.x, to.y - from.y);
|
|
4925
|
+
if (d < 0.5)
|
|
4926
|
+
return 1;
|
|
4927
|
+
const p = ((at.x - from.x) * (to.x - from.x) + (at.y - from.y) * (to.y - from.y)) / (d * d);
|
|
4928
|
+
return Math.min(1, Math.max(0, p));
|
|
4929
|
+
}
|
|
4930
|
+
function planPill(state, next, flags = {}) {
|
|
4931
|
+
if (!next)
|
|
4932
|
+
return { kind: "hide" };
|
|
4933
|
+
if (!state.shown || !state.at || flags.first || flags.reduced || flags.snap)
|
|
4934
|
+
return { kind: "land", box: next };
|
|
4935
|
+
const t = state.target;
|
|
4936
|
+
if (t && t.x === next.x && t.y === next.y && t.w === next.w && t.h === next.h)
|
|
4937
|
+
return { kind: "stay" };
|
|
4938
|
+
const d = Math.hypot(next.x - state.at.x, next.y - state.at.y);
|
|
4939
|
+
return { kind: "travel", box: next, spring: pillSpring(d) };
|
|
4940
|
+
}
|
|
4941
|
+
function selectionPill(container, options) {
|
|
4942
|
+
const doc = container.ownerDocument;
|
|
4943
|
+
const win = doc.defaultView;
|
|
4944
|
+
injectUiStyles(doc);
|
|
4945
|
+
if (win.getComputedStyle(container).position === "static")
|
|
4946
|
+
container.style.position = "relative";
|
|
4947
|
+
const pill = doc.createElement("i");
|
|
4948
|
+
pill.className = "knobs-pick-pill";
|
|
4949
|
+
pill.setAttribute("aria-hidden", "true");
|
|
4950
|
+
pill.dataset.off = "";
|
|
4951
|
+
const copyOn = options.copy !== false;
|
|
4952
|
+
const copy = doc.createElement("div");
|
|
4953
|
+
copy.className = "knobs-pick-copy";
|
|
4954
|
+
copy.setAttribute("aria-hidden", "true");
|
|
4955
|
+
copy.inert = true;
|
|
4956
|
+
copy.dataset.off = "";
|
|
4957
|
+
const copyRows = doc.createElement("div");
|
|
4958
|
+
copyRows.className = "knobs-pick-copy-rows";
|
|
4959
|
+
copy.append(copyRows);
|
|
4960
|
+
container.prepend(pill);
|
|
4961
|
+
if (copyOn)
|
|
4962
|
+
container.append(copy);
|
|
4963
|
+
const { omega, zeta } = springMotion(SPRINGS.default);
|
|
4964
|
+
const springs = [0, 0, 0, 0].map(() => new Spring(0, omega, zeta, 0.01));
|
|
4965
|
+
const [sx, sy, sw, sh] = springs;
|
|
4966
|
+
let shown = false;
|
|
4967
|
+
let first = true;
|
|
4968
|
+
let target = null;
|
|
4969
|
+
let from = { x: 0, y: 0, w: 0, h: 0 };
|
|
4970
|
+
let fromR = 0;
|
|
4971
|
+
let toR = 0;
|
|
4972
|
+
let rowBoxes = [];
|
|
4973
|
+
const clones = new Map;
|
|
4974
|
+
let disposed = false;
|
|
4975
|
+
const radiusOf = (row) => options.radius?.(row) ?? (Number.parseFloat(win.getComputedStyle(row).borderTopLeftRadius) || 0);
|
|
4976
|
+
const rowsNow = () => options.rows ? [...options.rows()] : [...container.children].filter((n) => n !== pill && n !== copy);
|
|
4977
|
+
const measure = (row) => {
|
|
4978
|
+
const c = container.getBoundingClientRect();
|
|
4979
|
+
const r = row.getBoundingClientRect();
|
|
4980
|
+
return pillBoxOf(r, {
|
|
4981
|
+
left: c.left,
|
|
4982
|
+
top: c.top,
|
|
4983
|
+
scrollLeft: container.scrollLeft,
|
|
4984
|
+
scrollTop: container.scrollTop,
|
|
4985
|
+
clientLeft: container.clientLeft,
|
|
4986
|
+
clientTop: container.clientTop
|
|
4987
|
+
});
|
|
4988
|
+
};
|
|
4989
|
+
const at = () => ({ x: sx.x, y: sy.x, w: sw.x, h: sh.x });
|
|
4990
|
+
const syncCopy = (span) => {
|
|
4991
|
+
if (!copyOn)
|
|
4992
|
+
return;
|
|
4993
|
+
const keep = new Set;
|
|
4994
|
+
for (const { row, box } of rowBoxes) {
|
|
4995
|
+
if (!boxesMeet(box, span))
|
|
4996
|
+
continue;
|
|
4997
|
+
keep.add(row);
|
|
4998
|
+
let n = clones.get(row);
|
|
4999
|
+
if (!n) {
|
|
5000
|
+
n = row.cloneNode(true);
|
|
5001
|
+
n.removeAttribute("id");
|
|
5002
|
+
for (const d of n.querySelectorAll("[id]"))
|
|
5003
|
+
d.removeAttribute("id");
|
|
5004
|
+
clones.set(row, n);
|
|
5005
|
+
copyRows.append(n);
|
|
5006
|
+
}
|
|
5007
|
+
const s = n.style;
|
|
5008
|
+
s.position = "absolute";
|
|
5009
|
+
s.inset = "auto";
|
|
5010
|
+
s.left = `${box.x}px`;
|
|
5011
|
+
s.top = `${box.y}px`;
|
|
5012
|
+
s.width = `${box.w}px`;
|
|
5013
|
+
s.height = `${box.h}px`;
|
|
5014
|
+
s.margin = "0";
|
|
5015
|
+
s.transform = "none";
|
|
5016
|
+
s.clipPath = "";
|
|
5017
|
+
s.opacity = "";
|
|
5018
|
+
s.boxSizing = "border-box";
|
|
5019
|
+
s.color = options.color ?? "var(--_k-fg)";
|
|
5020
|
+
}
|
|
5021
|
+
for (const [row, n] of clones)
|
|
5022
|
+
if (!keep.has(row)) {
|
|
5023
|
+
n.remove();
|
|
5024
|
+
clones.delete(row);
|
|
5025
|
+
}
|
|
5026
|
+
};
|
|
5027
|
+
const paint = () => {
|
|
5028
|
+
const b = at();
|
|
5029
|
+
const x0 = grid(b.x);
|
|
5030
|
+
const y0 = grid(b.y);
|
|
5031
|
+
const w = grid(b.x + b.w) - x0;
|
|
5032
|
+
const h = grid(b.y + b.h) - y0;
|
|
5033
|
+
const r = target ? pillRadius({ h: from.h, r: fromR }, { h: target.h, r: toR }, b.h, pillProgress(from, target, b)) : toR;
|
|
5034
|
+
const radius = `${Math.max(0, Math.min(r, h / 2, w / 2)).toFixed(2)}px`;
|
|
5035
|
+
for (const n of copyOn ? [pill, copy] : [pill]) {
|
|
5036
|
+
n.style.transform = `translate3d(${x0}px,${y0}px,0)`;
|
|
5037
|
+
n.style.width = `${w}px`;
|
|
5038
|
+
n.style.height = `${h}px`;
|
|
5039
|
+
n.style.borderRadius = radius;
|
|
5040
|
+
}
|
|
5041
|
+
if (copyOn)
|
|
5042
|
+
copyRows.style.transform = `translate3d(${-x0}px,${-y0}px,0)`;
|
|
5043
|
+
};
|
|
5044
|
+
const loop = frameLoop(win, (dt) => {
|
|
5045
|
+
for (const s of springs)
|
|
5046
|
+
s.step(dt);
|
|
5047
|
+
paint();
|
|
5048
|
+
return springs.some((s) => !s.resting);
|
|
5049
|
+
});
|
|
5050
|
+
const show = (on) => {
|
|
5051
|
+
shown = on;
|
|
5052
|
+
pill.toggleAttribute("data-off", !on);
|
|
5053
|
+
copy.toggleAttribute("data-off", !on);
|
|
5054
|
+
container.toggleAttribute("data-pick-empty", !on);
|
|
5055
|
+
};
|
|
5056
|
+
const update = (o) => {
|
|
5057
|
+
if (disposed)
|
|
5058
|
+
return;
|
|
5059
|
+
const row = options.selected();
|
|
5060
|
+
const next = row?.isConnected ? measure(row) : null;
|
|
5061
|
+
const plan = planPill({ shown, at: shown ? at() : null, target }, next, {
|
|
5062
|
+
first,
|
|
5063
|
+
reduced: reducedMotion(win),
|
|
5064
|
+
...o?.snap ? { snap: true } : {}
|
|
5065
|
+
});
|
|
5066
|
+
first = false;
|
|
5067
|
+
for (const n of clones.values())
|
|
5068
|
+
n.remove();
|
|
5069
|
+
clones.clear();
|
|
5070
|
+
rowBoxes = copyOn ? rowsNow().filter((r) => r.isConnected).map((r) => ({ row: r, box: measure(r) })) : [];
|
|
5071
|
+
if (plan.kind === "hide") {
|
|
5072
|
+
if (shown)
|
|
5073
|
+
show(false);
|
|
5074
|
+
return;
|
|
5075
|
+
}
|
|
5076
|
+
if (plan.kind === "stay") {
|
|
5077
|
+
syncCopy(boxUnion(at(), target));
|
|
5078
|
+
return;
|
|
5079
|
+
}
|
|
5080
|
+
const r = radiusOf(row);
|
|
5081
|
+
if (plan.kind === "land") {
|
|
5082
|
+
sx.snap(plan.box.x);
|
|
5083
|
+
sy.snap(plan.box.y);
|
|
5084
|
+
sw.snap(plan.box.w);
|
|
5085
|
+
sh.snap(plan.box.h);
|
|
5086
|
+
from = plan.box;
|
|
5087
|
+
fromR = r;
|
|
5088
|
+
toR = r;
|
|
5089
|
+
target = plan.box;
|
|
5090
|
+
syncCopy(plan.box);
|
|
5091
|
+
paint();
|
|
5092
|
+
loop.stop();
|
|
5093
|
+
if (!shown)
|
|
5094
|
+
show(true);
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
5097
|
+
const m = springMotion(plan.spring);
|
|
5098
|
+
for (const s of springs) {
|
|
5099
|
+
s.omega = m.omega;
|
|
5100
|
+
s.zeta = m.zeta;
|
|
5101
|
+
}
|
|
5102
|
+
const now = at();
|
|
5103
|
+
fromR = target ? pillRadius({ h: from.h, r: fromR }, { h: target.h, r: toR }, now.h, pillProgress(from, target, now)) : r;
|
|
5104
|
+
from = now;
|
|
5105
|
+
toR = r;
|
|
5106
|
+
target = plan.box;
|
|
5107
|
+
sx.set(plan.box.x);
|
|
5108
|
+
sy.set(plan.box.y);
|
|
5109
|
+
sw.set(plan.box.w);
|
|
5110
|
+
sh.set(plan.box.h);
|
|
5111
|
+
syncCopy(boxUnion(now, plan.box));
|
|
5112
|
+
loop.wake();
|
|
5113
|
+
};
|
|
5114
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => update({ snap: true })) : null;
|
|
5115
|
+
ro?.observe(container);
|
|
5116
|
+
update();
|
|
5117
|
+
return {
|
|
5118
|
+
element: pill,
|
|
5119
|
+
update,
|
|
5120
|
+
dispose() {
|
|
5121
|
+
disposed = true;
|
|
5122
|
+
loop.stop();
|
|
5123
|
+
ro?.disconnect();
|
|
5124
|
+
pill.remove();
|
|
5125
|
+
copy.remove();
|
|
5126
|
+
container.removeAttribute("data-pick-empty");
|
|
5127
|
+
}
|
|
5128
|
+
};
|
|
5129
|
+
}
|
|
5130
|
+
var boxesMeet = (a, b) => a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h, boxUnion = (a, b) => {
|
|
5131
|
+
const x = Math.min(a.x, b.x);
|
|
5132
|
+
const y = Math.min(a.y, b.y);
|
|
5133
|
+
return {
|
|
5134
|
+
x,
|
|
5135
|
+
y,
|
|
5136
|
+
w: Math.max(a.x + a.w, b.x + b.w) - x,
|
|
5137
|
+
h: Math.max(a.y + a.h, b.y + b.h) - y
|
|
5138
|
+
};
|
|
5139
|
+
}, grid = (v) => Math.round(v * 64) / 64;
|
|
5140
|
+
var init_selection_pill = __esm(() => {
|
|
5141
|
+
init_motion();
|
|
5142
|
+
init_look();
|
|
5143
|
+
});
|
|
5144
|
+
|
|
4662
5145
|
// src/core/storage.ts
|
|
4663
5146
|
function browserStorage() {
|
|
4664
5147
|
return typeof window === "undefined" ? null : window.localStorage;
|
|
@@ -4981,10 +5464,25 @@ function advance(t, dt, o) {
|
|
|
4981
5464
|
}
|
|
4982
5465
|
return { t: hi, ended: true, wrapped: false };
|
|
4983
5466
|
}
|
|
4984
|
-
|
|
5467
|
+
function moveHead(head, t, motion, catching, minGap = 0) {
|
|
5468
|
+
if (motion === "jump" && Math.abs(t - head.x) > minGap)
|
|
5469
|
+
return { x: head.x, target: t, catching: true };
|
|
5470
|
+
if (catching)
|
|
5471
|
+
return { x: head.x + (t - head.target), target: t, catching: true };
|
|
5472
|
+
return { x: t, target: t, catching: false };
|
|
5473
|
+
}
|
|
5474
|
+
function currentMarker(markers, t, fps) {
|
|
5475
|
+
let best = null;
|
|
5476
|
+
for (const m of markers)
|
|
5477
|
+
if (m.time <= t + 0.5 / fps && (!best || m.time >= best.time))
|
|
5478
|
+
best = m;
|
|
5479
|
+
return best;
|
|
5480
|
+
}
|
|
5481
|
+
var SECOND_STEPS, FRAME_STEPS, toFrame = (t, fps) => Math.round(t * fps), frameTime = (t, fps) => Math.round(t * fps) / fps, round = (t) => Math.round(t * 1e6) / 1e6, CATCH_UP;
|
|
4985
5482
|
var init_timeline_model = __esm(() => {
|
|
4986
5483
|
SECOND_STEPS = [0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600];
|
|
4987
5484
|
FRAME_STEPS = [1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 9000, 18000];
|
|
5485
|
+
CATCH_UP = { duration: 0.15, bounce: 0 };
|
|
4988
5486
|
});
|
|
4989
5487
|
|
|
4990
5488
|
// src/ui/timeline.ts
|
|
@@ -4997,6 +5495,7 @@ function timeline(container, options) {
|
|
|
4997
5495
|
let speed = options.speed ?? 1;
|
|
4998
5496
|
let repeat = options.repeat ?? true;
|
|
4999
5497
|
const arrows = options.arrows ?? "frames";
|
|
5498
|
+
const lane = options.variant === "lane";
|
|
5000
5499
|
let time = Math.min(duration, Math.max(0, options.time ?? 0));
|
|
5001
5500
|
let playing = false;
|
|
5002
5501
|
let markers = [...options.markers ?? []];
|
|
@@ -5030,27 +5529,27 @@ function timeline(container, options) {
|
|
|
5030
5529
|
root.setAttribute("aria-label", options.label ?? "Timeline");
|
|
5031
5530
|
root.setAttribute("aria-keyshortcuts", "Space ArrowLeft ArrowRight , . Home End [ ] I O M");
|
|
5032
5531
|
applyLook2(root, options);
|
|
5532
|
+
if (lane)
|
|
5533
|
+
root.dataset.variant = "lane";
|
|
5033
5534
|
const transport = el("div", "knobs-tl-transport");
|
|
5034
5535
|
const playBtn = el("button", "knobs-tl-play");
|
|
5035
5536
|
playBtn.type = "button";
|
|
5036
5537
|
playBtn.tabIndex = -1;
|
|
5037
|
-
|
|
5038
|
-
const now = el("span", "knobs-tl-now");
|
|
5039
|
-
const sub = el("span", "knobs-tl-sub");
|
|
5040
|
-
readout.append(now, sub);
|
|
5041
|
-
transport.append(playBtn, readout);
|
|
5538
|
+
transport.append(playBtn);
|
|
5042
5539
|
const track = el("div", "knobs-tl-track");
|
|
5043
5540
|
const canvas = el("canvas", "knobs-tl-ruler");
|
|
5044
5541
|
canvas.setAttribute("aria-hidden", "true");
|
|
5045
|
-
const
|
|
5542
|
+
const markerLane = el("div", "knobs-tl-lane");
|
|
5046
5543
|
const hover = el("div", "knobs-tl-hover");
|
|
5544
|
+
const tag = el("span", "knobs-tl-tag");
|
|
5545
|
+
tag.setAttribute("aria-hidden", "true");
|
|
5047
5546
|
const head = el("div", "knobs-tl-head");
|
|
5048
5547
|
head.id = `${id}-head`;
|
|
5049
5548
|
head.setAttribute("role", "slider");
|
|
5050
5549
|
head.setAttribute("aria-label", "Playhead");
|
|
5051
5550
|
head.setAttribute("aria-valuemin", "0");
|
|
5052
5551
|
head.setAttribute("aria-valuemax", String(duration));
|
|
5053
|
-
track.append(canvas,
|
|
5552
|
+
track.append(canvas, markerLane, hover, head, tag);
|
|
5054
5553
|
root.append(transport, track);
|
|
5055
5554
|
container.append(root);
|
|
5056
5555
|
let width = 1;
|
|
@@ -5097,13 +5596,14 @@ function timeline(container, options) {
|
|
|
5097
5596
|
let drawn = "";
|
|
5098
5597
|
const drawRuler = () => {
|
|
5099
5598
|
const v = view();
|
|
5100
|
-
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${units}:${fps}`;
|
|
5599
|
+
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${height}:${units}:${fps}`;
|
|
5101
5600
|
if (key === drawn)
|
|
5102
5601
|
return;
|
|
5103
5602
|
drawn = key;
|
|
5104
5603
|
const dpr = win.devicePixelRatio || 1;
|
|
5105
5604
|
const w = Math.max(1, Math.round(width * dpr));
|
|
5106
|
-
const
|
|
5605
|
+
const rh = lane ? height : RULER;
|
|
5606
|
+
const h = Math.round(rh * dpr);
|
|
5107
5607
|
if (canvas.width !== w || canvas.height !== h) {
|
|
5108
5608
|
canvas.width = w;
|
|
5109
5609
|
canvas.height = h;
|
|
@@ -5112,8 +5612,19 @@ function timeline(container, options) {
|
|
|
5112
5612
|
if (!ctx)
|
|
5113
5613
|
return;
|
|
5114
5614
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
5115
|
-
ctx.clearRect(0, 0, width,
|
|
5615
|
+
ctx.clearRect(0, 0, width, rh);
|
|
5116
5616
|
const ticks = rulerTicks(v, width, { fps, units });
|
|
5617
|
+
if (lane) {
|
|
5618
|
+
ctx.fillStyle = colors.tick;
|
|
5619
|
+
for (const t of ticks.minor)
|
|
5620
|
+
if (t >= -0.000000001 && t <= duration + 0.000000001)
|
|
5621
|
+
ctx.fillRect(xOf(t) - 0.5, rh - 4, 1, 4);
|
|
5622
|
+
ctx.fillStyle = colors.major;
|
|
5623
|
+
for (const m of ticks.major)
|
|
5624
|
+
if (m.t >= -0.000000001 && m.t <= duration + 0.000000001)
|
|
5625
|
+
ctx.fillRect(xOf(m.t) - 0.5, rh - 7, 1, 7);
|
|
5626
|
+
return;
|
|
5627
|
+
}
|
|
5117
5628
|
const px = (t) => Math.round(xOf(t)) + 0.5;
|
|
5118
5629
|
ctx.fillStyle = colors.line;
|
|
5119
5630
|
ctx.fillRect(0, RULER - 1, width, 1);
|
|
@@ -5153,18 +5664,21 @@ function timeline(container, options) {
|
|
|
5153
5664
|
n.dataset.id = m.id;
|
|
5154
5665
|
const pin = el("span", "knobs-tl-pin");
|
|
5155
5666
|
const label = el("span", "knobs-tl-mlabel");
|
|
5667
|
+
label.append(el("span", "knobs-tl-mtext knobs-scroll-fade-x"));
|
|
5156
5668
|
n.append(pin, label);
|
|
5157
|
-
|
|
5669
|
+
markerLane.append(n);
|
|
5158
5670
|
markerEls.set(m.id, n);
|
|
5159
5671
|
if (built)
|
|
5160
5672
|
enter(n);
|
|
5161
5673
|
}
|
|
5162
5674
|
const label = n.querySelector(".knobs-tl-mlabel");
|
|
5163
|
-
|
|
5164
|
-
|
|
5675
|
+
const text = label.firstElementChild;
|
|
5676
|
+
if (text.textContent !== (m.label ?? ""))
|
|
5677
|
+
text.textContent = m.label ?? "";
|
|
5165
5678
|
label.hidden = !m.label;
|
|
5166
5679
|
n.style.setProperty("--knobs-tl-color", m.color ?? "");
|
|
5167
5680
|
n.toggleAttribute("data-selected", selected?.kind === "marker" && selected.id === m.id);
|
|
5681
|
+
n.toggleAttribute("data-current", m.id === currentId);
|
|
5168
5682
|
n.title = `${m.label ? `${m.label} · ` : ""}${clock(m.time)}`;
|
|
5169
5683
|
}
|
|
5170
5684
|
placeMarkers();
|
|
@@ -5192,7 +5706,7 @@ function timeline(container, options) {
|
|
|
5192
5706
|
b.dataset.edge = "end";
|
|
5193
5707
|
const label = el("span", "knobs-tl-rlabel");
|
|
5194
5708
|
n.append(label, a, b);
|
|
5195
|
-
track.insertBefore(n,
|
|
5709
|
+
track.insertBefore(n, markerLane);
|
|
5196
5710
|
rangeEls.set(r.id, n);
|
|
5197
5711
|
if (built)
|
|
5198
5712
|
enter(n);
|
|
@@ -5241,16 +5755,17 @@ function timeline(container, options) {
|
|
|
5241
5755
|
};
|
|
5242
5756
|
const clock = (t) => units === "frames" ? `f${toFrame(t, fps)}` : `${timeLabel(t, "seconds", fps, 0.01)}`;
|
|
5243
5757
|
let shownHead = time;
|
|
5758
|
+
let currentId = null;
|
|
5244
5759
|
const renderHead = () => {
|
|
5245
5760
|
head.style.transform = `translateX(${xOf(shownHead).toFixed(2)}px)`;
|
|
5246
|
-
const main = units === "frames" ? `f${toFrame(time, fps)}` : `${time.toFixed(2)}s`;
|
|
5247
|
-
const minor = units === "frames" ? `${time.toFixed(2)}s` : `f${toFrame(time, fps)}`;
|
|
5248
|
-
if (now.textContent !== main)
|
|
5249
|
-
now.textContent = main;
|
|
5250
|
-
if (sub.textContent !== minor)
|
|
5251
|
-
sub.textContent = minor;
|
|
5252
5761
|
head.setAttribute("aria-valuenow", time.toFixed(3));
|
|
5253
5762
|
head.setAttribute("aria-valuetext", `${time.toFixed(2)} seconds, frame ${toFrame(time, fps)}`);
|
|
5763
|
+
const cur = currentMarker(markers, time, fps)?.id ?? null;
|
|
5764
|
+
if (cur !== currentId) {
|
|
5765
|
+
markerEls.get(currentId ?? "")?.removeAttribute("data-current");
|
|
5766
|
+
currentId = cur;
|
|
5767
|
+
markerEls.get(cur ?? "")?.setAttribute("data-current", "");
|
|
5768
|
+
}
|
|
5254
5769
|
};
|
|
5255
5770
|
let viewSent = "";
|
|
5256
5771
|
const render = () => {
|
|
@@ -5276,18 +5791,27 @@ function timeline(container, options) {
|
|
|
5276
5791
|
};
|
|
5277
5792
|
const caret = new Spring(time, GLIDE.omega, GLIDE.zeta, 0.00001);
|
|
5278
5793
|
let gliding = false;
|
|
5279
|
-
const
|
|
5280
|
-
const
|
|
5281
|
-
|
|
5794
|
+
const headTo = (shown, motion) => {
|
|
5795
|
+
const from = gliding ? { x: caret.x, target: caret.target } : { x: shownHead, target: shownHead };
|
|
5796
|
+
const jump = motion === "jump" && !reducedMotion(win);
|
|
5797
|
+
const next = moveHead(from, shown, jump ? "jump" : "follow", gliding, 2 / pxPerSec());
|
|
5798
|
+
if (next.catching) {
|
|
5282
5799
|
if (!gliding)
|
|
5283
|
-
caret.snap(
|
|
5284
|
-
caret.
|
|
5800
|
+
caret.snap(from.x);
|
|
5801
|
+
caret.x = next.x;
|
|
5802
|
+
caret.target = next.target;
|
|
5285
5803
|
gliding = true;
|
|
5804
|
+
shownHead = caret.x;
|
|
5286
5805
|
loop.wake();
|
|
5287
5806
|
} else {
|
|
5288
5807
|
gliding = false;
|
|
5289
|
-
|
|
5808
|
+
caret.snap(next.x);
|
|
5809
|
+
shownHead = next.x;
|
|
5290
5810
|
}
|
|
5811
|
+
};
|
|
5812
|
+
const setTime = (t, source, shown = t, glide = false) => {
|
|
5813
|
+
const next = Math.min(duration, Math.max(0, t));
|
|
5814
|
+
headTo(Math.min(duration, Math.max(0, shown)), glide ? "jump" : "follow");
|
|
5291
5815
|
const moved = next !== time;
|
|
5292
5816
|
time = next;
|
|
5293
5817
|
renderHead();
|
|
@@ -5328,8 +5852,7 @@ function timeline(container, options) {
|
|
|
5328
5852
|
options.onCross?.(m);
|
|
5329
5853
|
}
|
|
5330
5854
|
time = step.t;
|
|
5331
|
-
|
|
5332
|
-
gliding = false;
|
|
5855
|
+
headTo(time, step.wrapped ? "jump" : "follow");
|
|
5333
5856
|
emitSeek(time, "play");
|
|
5334
5857
|
keepInView();
|
|
5335
5858
|
if (step.ended) {
|
|
@@ -5342,7 +5865,7 @@ function timeline(container, options) {
|
|
|
5342
5865
|
shownHead = caret.step(dt);
|
|
5343
5866
|
if (caret.resting) {
|
|
5344
5867
|
gliding = false;
|
|
5345
|
-
shownHead =
|
|
5868
|
+
shownHead = caret.target;
|
|
5346
5869
|
}
|
|
5347
5870
|
}
|
|
5348
5871
|
vStart.step(dt);
|
|
@@ -5355,9 +5878,9 @@ function timeline(container, options) {
|
|
|
5355
5878
|
return;
|
|
5356
5879
|
const r = loopRange();
|
|
5357
5880
|
if (r && (time < r.start || time >= r.end - 0.5 / fps))
|
|
5358
|
-
setTime(r.start, "code");
|
|
5881
|
+
setTime(r.start, "code", r.start, true);
|
|
5359
5882
|
else if (!r && time >= duration - 0.5 / fps)
|
|
5360
|
-
setTime(0, "code");
|
|
5883
|
+
setTime(0, "code", 0, true);
|
|
5361
5884
|
playing = true;
|
|
5362
5885
|
syncPlay();
|
|
5363
5886
|
emitPlay(true);
|
|
@@ -5486,24 +6009,35 @@ function timeline(container, options) {
|
|
|
5486
6009
|
};
|
|
5487
6010
|
const localX = (e) => e.clientX - track.getBoundingClientRect().left;
|
|
5488
6011
|
let drag = null;
|
|
5489
|
-
const scrubTo = (x) => {
|
|
6012
|
+
const scrubTo = (x, press = false) => {
|
|
5490
6013
|
const shownX = softClamp(x, xOf(0), xOf(duration), 10);
|
|
5491
6014
|
const s = scrubTime(tOf(shownX), {
|
|
5492
6015
|
duration,
|
|
5493
6016
|
fps,
|
|
5494
6017
|
pxPerSec: pxPerSec(),
|
|
5495
|
-
stops: snapMarkers ? markers.map((m) => m.time) : [],
|
|
6018
|
+
stops: snapMarkers && !lane ? markers.map((m) => m.time) : [],
|
|
5496
6019
|
frames: snapFrames
|
|
5497
6020
|
});
|
|
5498
|
-
setTime(s.t, "scrub", s.shown);
|
|
6021
|
+
setTime(s.t, "scrub", s.shown, press);
|
|
5499
6022
|
root.toggleAttribute("data-stuck", s.stop !== null);
|
|
5500
6023
|
};
|
|
6024
|
+
const showTag = (x) => {
|
|
6025
|
+
const at = Math.min(duration, Math.max(0, tOf(x)));
|
|
6026
|
+
const text = `${at.toFixed(2)} s`;
|
|
6027
|
+
if (tag.textContent !== text)
|
|
6028
|
+
tag.textContent = text;
|
|
6029
|
+
const cx = Math.min(width, Math.max(0, x));
|
|
6030
|
+
const flip = cx > width - tag.offsetWidth - 12;
|
|
6031
|
+
tag.style.transform = `translateX(${cx.toFixed(1)}px) translateX(${flip ? "calc(-100% - 4px)" : "4px"})`;
|
|
6032
|
+
tag.dataset.on = "";
|
|
6033
|
+
};
|
|
6034
|
+
const hideTag = () => delete tag.dataset.on;
|
|
5501
6035
|
track.addEventListener("pointerdown", (e) => {
|
|
5502
6036
|
if (e.button !== 0 || editing)
|
|
5503
6037
|
return;
|
|
5504
6038
|
root.focus({ preventScroll: true });
|
|
5505
6039
|
const t = e.target;
|
|
5506
|
-
const markerEl = t.closest(".knobs-tl-marker");
|
|
6040
|
+
const markerEl = lane ? null : t.closest(".knobs-tl-marker");
|
|
5507
6041
|
const edgeEl = t.closest(".knobs-tl-edge");
|
|
5508
6042
|
const rangeEl = t.closest(".knobs-tl-range");
|
|
5509
6043
|
track.setPointerCapture(e.pointerId);
|
|
@@ -5548,13 +6082,16 @@ function timeline(container, options) {
|
|
|
5548
6082
|
root.dataset.scrubbing = "";
|
|
5549
6083
|
for (const l of listeners)
|
|
5550
6084
|
l.onScrub?.(true);
|
|
5551
|
-
scrubTo(localX(e));
|
|
6085
|
+
scrubTo(localX(e), true);
|
|
6086
|
+
showTag(localX(e));
|
|
5552
6087
|
}
|
|
5553
6088
|
e.preventDefault();
|
|
5554
6089
|
});
|
|
5555
6090
|
track.addEventListener("pointermove", (e) => {
|
|
5556
6091
|
const x = localX(e);
|
|
5557
6092
|
hover.style.transform = `translateX(${x.toFixed(1)}px)`;
|
|
6093
|
+
if (!drag || drag.kind === "scrub")
|
|
6094
|
+
showTag(x);
|
|
5558
6095
|
if (!drag)
|
|
5559
6096
|
return;
|
|
5560
6097
|
if (drag.kind === "scrub")
|
|
@@ -5600,8 +6137,10 @@ function timeline(container, options) {
|
|
|
5600
6137
|
delete root.dataset.dragging;
|
|
5601
6138
|
root.removeAttribute("data-stuck");
|
|
5602
6139
|
if (d.kind === "scrub") {
|
|
5603
|
-
|
|
6140
|
+
headTo(time, "follow");
|
|
5604
6141
|
renderHead();
|
|
6142
|
+
if (!track.matches(":hover"))
|
|
6143
|
+
hideTag();
|
|
5605
6144
|
for (const l of listeners)
|
|
5606
6145
|
l.onScrub?.(false);
|
|
5607
6146
|
if (d.wasPlaying)
|
|
@@ -5614,7 +6153,7 @@ function timeline(container, options) {
|
|
|
5614
6153
|
} else {
|
|
5615
6154
|
const m = markers.find((x) => x.id === d.id);
|
|
5616
6155
|
if (m)
|
|
5617
|
-
setTime(m.time, "marker");
|
|
6156
|
+
setTime(m.time, "marker", m.time, true);
|
|
5618
6157
|
}
|
|
5619
6158
|
} else if (d.kind === "edge" || d.moved)
|
|
5620
6159
|
emitRanges();
|
|
@@ -5623,10 +6162,14 @@ function timeline(container, options) {
|
|
|
5623
6162
|
track.addEventListener("pointercancel", endDrag);
|
|
5624
6163
|
track.addEventListener("lostpointercapture", endDrag);
|
|
5625
6164
|
track.addEventListener("pointerleave", () => {
|
|
5626
|
-
if (
|
|
5627
|
-
|
|
6165
|
+
if (drag)
|
|
6166
|
+
return;
|
|
6167
|
+
hover.style.transform = "translateX(-100px)";
|
|
6168
|
+
hideTag();
|
|
5628
6169
|
});
|
|
5629
6170
|
track.addEventListener("dblclick", (e) => {
|
|
6171
|
+
if (lane)
|
|
6172
|
+
return;
|
|
5630
6173
|
const markerEl = e.target.closest(".knobs-tl-marker");
|
|
5631
6174
|
if (markerEl)
|
|
5632
6175
|
return rename(markerEl.dataset.id);
|
|
@@ -5637,6 +6180,8 @@ function timeline(container, options) {
|
|
|
5637
6180
|
rename(m.id);
|
|
5638
6181
|
});
|
|
5639
6182
|
track.addEventListener("wheel", (e) => {
|
|
6183
|
+
if (lane)
|
|
6184
|
+
return;
|
|
5640
6185
|
e.preventDefault();
|
|
5641
6186
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? height : 1;
|
|
5642
6187
|
if (e.ctrlKey || e.metaKey) {
|
|
@@ -5700,7 +6245,7 @@ function timeline(container, options) {
|
|
|
5700
6245
|
if (!m)
|
|
5701
6246
|
return;
|
|
5702
6247
|
select({ kind: "marker", id: m.id });
|
|
5703
|
-
return setTime(m.time, "marker");
|
|
6248
|
+
return setTime(m.time, "marker", m.time, true);
|
|
5704
6249
|
}
|
|
5705
6250
|
case "i":
|
|
5706
6251
|
case "I":
|
|
@@ -5712,11 +6257,13 @@ function timeline(container, options) {
|
|
|
5712
6257
|
return setEdge("end", time);
|
|
5713
6258
|
case "m":
|
|
5714
6259
|
case "M":
|
|
6260
|
+
if (lane)
|
|
6261
|
+
return;
|
|
5715
6262
|
claim();
|
|
5716
6263
|
addMarker(time);
|
|
5717
6264
|
return;
|
|
5718
6265
|
case "Enter":
|
|
5719
|
-
if (selected?.kind === "marker") {
|
|
6266
|
+
if (selected?.kind === "marker" && !lane) {
|
|
5720
6267
|
claim();
|
|
5721
6268
|
rename(selected.id);
|
|
5722
6269
|
}
|
|
@@ -5734,19 +6281,25 @@ function timeline(container, options) {
|
|
|
5734
6281
|
return;
|
|
5735
6282
|
case "=":
|
|
5736
6283
|
case "+":
|
|
6284
|
+
if (lane)
|
|
6285
|
+
return;
|
|
5737
6286
|
claim();
|
|
5738
6287
|
return zoom(1.5);
|
|
5739
6288
|
case "-":
|
|
6289
|
+
if (lane)
|
|
6290
|
+
return;
|
|
5740
6291
|
claim();
|
|
5741
6292
|
return zoom(1 / 1.5);
|
|
5742
6293
|
case "0":
|
|
6294
|
+
if (lane)
|
|
6295
|
+
return;
|
|
5743
6296
|
claim();
|
|
5744
6297
|
return fit();
|
|
5745
6298
|
}
|
|
5746
6299
|
});
|
|
5747
6300
|
const unregisterHints = options.hints === false ? undefined : hints.register(root, () => [
|
|
5748
6301
|
{ el: playBtn, label: playing ? "Pause" : "Play", activate: toggle },
|
|
5749
|
-
...markers.flatMap((m) => {
|
|
6302
|
+
...(lane ? [] : markers).flatMap((m) => {
|
|
5750
6303
|
const n = markerEls.get(m.id);
|
|
5751
6304
|
if (!n || n.dataset.leaving !== undefined)
|
|
5752
6305
|
return [];
|
|
@@ -5758,7 +6311,7 @@ function timeline(container, options) {
|
|
|
5758
6311
|
...label && !label.hidden ? { labelEl: label } : {},
|
|
5759
6312
|
activate: () => {
|
|
5760
6313
|
select({ kind: "marker", id: m.id });
|
|
5761
|
-
setTime(m.time, "marker");
|
|
6314
|
+
setTime(m.time, "marker", m.time, true);
|
|
5762
6315
|
root.focus({ preventScroll: true });
|
|
5763
6316
|
}
|
|
5764
6317
|
}
|
|
@@ -5770,7 +6323,7 @@ function timeline(container, options) {
|
|
|
5770
6323
|
activate: () => root.focus({ preventScroll: true })
|
|
5771
6324
|
}
|
|
5772
6325
|
], { listen: false, rank: 1 });
|
|
5773
|
-
const menu = contextMenu(track, (e) => {
|
|
6326
|
+
const menu = lane ? null : contextMenu(track, (e) => {
|
|
5774
6327
|
const t = e?.target ?? null;
|
|
5775
6328
|
const markerEl = t?.closest(".knobs-tl-marker");
|
|
5776
6329
|
const rangeEl = t?.closest(".knobs-tl-range");
|
|
@@ -5785,7 +6338,7 @@ function timeline(container, options) {
|
|
|
5785
6338
|
run: () => {
|
|
5786
6339
|
const m = markers.find((x) => x.id === mid);
|
|
5787
6340
|
if (m)
|
|
5788
|
-
setTime(m.time, "marker");
|
|
6341
|
+
setTime(m.time, "marker", m.time, true);
|
|
5789
6342
|
}
|
|
5790
6343
|
},
|
|
5791
6344
|
{ label: "Rename…", shortcut: "Enter", run: () => rename(mid) },
|
|
@@ -5949,7 +6502,7 @@ function timeline(container, options) {
|
|
|
5949
6502
|
listeners.clear();
|
|
5950
6503
|
loop.stop();
|
|
5951
6504
|
ro.disconnect();
|
|
5952
|
-
menu
|
|
6505
|
+
menu?.dispose();
|
|
5953
6506
|
root.remove();
|
|
5954
6507
|
}
|
|
5955
6508
|
};
|
|
@@ -5966,10 +6519,21 @@ var init_timeline = __esm(() => {
|
|
|
5966
6519
|
init_timeline_model();
|
|
5967
6520
|
INSTANT = springMotion(SPRINGS.instant);
|
|
5968
6521
|
CALM = springMotion(SPRINGS.calm);
|
|
5969
|
-
GLIDE = springMotion(
|
|
6522
|
+
GLIDE = springMotion(CATCH_UP);
|
|
5970
6523
|
});
|
|
5971
6524
|
|
|
5972
6525
|
// src/ui/compare-model.ts
|
|
6526
|
+
function compareModes(modes, mode) {
|
|
6527
|
+
const list = [...new Set((modes ?? ["side", "wipe"]).filter((m) => ALL_MODES.includes(m)))];
|
|
6528
|
+
const offered = list.length ? list : ["side", "wipe"];
|
|
6529
|
+
return { modes: offered, mode: mode && offered.includes(mode) ? mode : offered[0] };
|
|
6530
|
+
}
|
|
6531
|
+
function modeForKey(key, modes) {
|
|
6532
|
+
const k = key.toLowerCase();
|
|
6533
|
+
if (/^[1-9]$/.test(k))
|
|
6534
|
+
return modes[Number(k) - 1] ?? null;
|
|
6535
|
+
return modes.find((m) => MODE_KEYS[m] === k) ?? null;
|
|
6536
|
+
}
|
|
5973
6537
|
function mediaKind(src, kind) {
|
|
5974
6538
|
if (kind)
|
|
5975
6539
|
return kind;
|
|
@@ -6048,6 +6612,18 @@ function wipeGrab(x, rect, wipe, slop = 12) {
|
|
|
6048
6612
|
const onLine = Math.abs(x - line) <= slop;
|
|
6049
6613
|
return { onLine, offset: onLine ? x - line : 0 };
|
|
6050
6614
|
}
|
|
6615
|
+
function seamLabels(x, left, right, wb, wa, gap = 8) {
|
|
6616
|
+
const room = (space, w) => Math.min(1, Math.max(0, (space - w - 2 * gap) / gap));
|
|
6617
|
+
return {
|
|
6618
|
+
before: { x: x - gap - wb, opacity: room(x - left, wb) },
|
|
6619
|
+
after: { x: x + gap, opacity: room(right - x, wa) }
|
|
6620
|
+
};
|
|
6621
|
+
}
|
|
6622
|
+
function gripTop(y, rect, grip, margin = 8) {
|
|
6623
|
+
const lo = rect.y + margin;
|
|
6624
|
+
const hi = rect.y + rect.h - margin - grip;
|
|
6625
|
+
return hi < lo ? rect.y + (rect.h - grip) / 2 : Math.min(hi, Math.max(lo, y - grip / 2));
|
|
6626
|
+
}
|
|
6051
6627
|
function stripColumns(view, width, o) {
|
|
6052
6628
|
const { fps } = o;
|
|
6053
6629
|
const total = Math.max(1, Math.round(o.duration * fps));
|
|
@@ -6098,7 +6674,7 @@ function stripPeaks(diffs, o = {}) {
|
|
|
6098
6674
|
});
|
|
6099
6675
|
return out;
|
|
6100
6676
|
}
|
|
6101
|
-
var VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), lastFrame = (duration, fps) => Math.max(0, Math.ceil(duration * fps - 0.0001) - 1), seekTime = (t, fps, duration) => frameMidpoint(frameOf(t, fps), fps, duration), sameFrame = (a, b, fps) => frameOf(a, fps) === frameOf(b, fps), SEEK_IDLE, splitHeight = (w, media) => media.w > 0 && media.h > 0 ? w / 2 * (media.h / media.w) : w / 2 * (9 / 16), ZOOM_FIT, ZOOM_MAX = 16, panBy = (r, dx, dy, base) => clampZoom({
|
|
6677
|
+
var ALL_MODES, MODE_KEYS, modeKey = (mode) => MODE_KEYS[mode].toUpperCase(), VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), lastFrame = (duration, fps) => Math.max(0, Math.ceil(duration * fps - 0.0001) - 1), seekTime = (t, fps, duration) => frameMidpoint(frameOf(t, fps), fps, duration), sameFrame = (a, b, fps) => frameOf(a, fps) === frameOf(b, fps), SEEK_IDLE, splitHeight = (w, media) => media.w > 0 && media.h > 0 ? w / 2 * (media.h / media.w) : w / 2 * (9 / 16), ZOOM_FIT, ZOOM_MAX = 16, panBy = (r, dx, dy, base) => clampZoom({
|
|
6102
6678
|
u: r.u - dx / Math.max(1, base.w) * r.w,
|
|
6103
6679
|
v: r.v - dy / Math.max(1, base.h) * r.h,
|
|
6104
6680
|
w: r.w
|
|
@@ -6117,6 +6693,8 @@ var VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), last
|
|
|
6117
6693
|
h: a.h + (b.h - a.h) * k
|
|
6118
6694
|
}), wipeX = (rect, wipe) => rect.x + Math.min(1, Math.max(0, wipe)) * rect.w, wipeAt = (x, rect, offset = 0) => rect.w <= 0 ? 0.5 : Math.min(1, Math.max(0, (x - offset - rect.x) / rect.w)), wipeKey = (wipe, dir, big = false) => Math.min(1, Math.max(0, Math.round((wipe + dir * (big ? 0.1 : 0.01)) * 1000) / 1000));
|
|
6119
6695
|
var init_compare_model = __esm(() => {
|
|
6696
|
+
ALL_MODES = ["side", "wipe", "difference"];
|
|
6697
|
+
MODE_KEYS = { side: "s", wipe: "w", difference: "d" };
|
|
6120
6698
|
VIDEO = /\.(mp4|m4v|mov|webm|ogv|mkv)$/i;
|
|
6121
6699
|
SEEK_IDLE = { seeking: false, pending: null };
|
|
6122
6700
|
ZOOM_FIT = { u: 0, v: 0, w: 1, h: 1 };
|
|
@@ -6916,8 +7494,8 @@ async function createCompareGpu(canvas, onLost) {
|
|
|
6916
7494
|
r(0, f.before);
|
|
6917
7495
|
r(4, f.after);
|
|
6918
7496
|
data.set([f.width, f.height, f.dpr, 0], 8);
|
|
6919
|
-
data.set([f.wipeX, f.soft, 0,
|
|
6920
|
-
data.set([f.from, f.to, f.mix,
|
|
7497
|
+
data.set([f.wipeX, f.soft, 0, 0], 12);
|
|
7498
|
+
data.set([f.from, f.to, f.mix, 0], 16);
|
|
6921
7499
|
data.set([f.threshold, f.gain, ready[0], ready[1]], 20);
|
|
6922
7500
|
data.set([f.accent[0], f.accent[1], f.accent[2], 1], 24);
|
|
6923
7501
|
const l = f.loupe;
|
|
@@ -6959,8 +7537,8 @@ var MODE_INDEX, WGSL = `
|
|
|
6959
7537
|
struct U {
|
|
6960
7538
|
ra: vec4f, rb: vec4f,
|
|
6961
7539
|
view: vec4f, // w, h, dpr, _
|
|
6962
|
-
wipe: vec4f, // x, soft, _,
|
|
6963
|
-
modes: vec4f, // from, to, mix,
|
|
7540
|
+
wipe: vec4f, // x, soft, _, _
|
|
7541
|
+
modes: vec4f, // from, to, mix, _
|
|
6964
7542
|
diff: vec4f, // threshold, gain, readyA, readyB
|
|
6965
7543
|
accent: vec4f,
|
|
6966
7544
|
loupe: vec4f, // x, y, r, zoom (0: none)
|
|
@@ -7011,21 +7589,14 @@ fn takeB(p: vec2f, r: vec4f, c0: vec4f, near: bool) -> vec4f {
|
|
|
7011
7589
|
|
|
7012
7590
|
fn pm(c: vec4f) -> vec4f { return vec4f(c.rgb * c.a, c.a); }
|
|
7013
7591
|
|
|
7014
|
-
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f
|
|
7015
|
-
let flick = u.modes.w > 0.5;
|
|
7592
|
+
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
7016
7593
|
switch mode {
|
|
7017
|
-
case 0u: {
|
|
7018
|
-
let bb = select(b, vec4f(a2.rgb, b.a), flick);
|
|
7019
|
-
return vec4f(a.rgb * a.a + bb.rgb * bb.a * (1.0 - a.a), a.a + bb.a * (1.0 - a.a));
|
|
7020
|
-
}
|
|
7021
7594
|
case 1u: {
|
|
7022
|
-
if (flick) { return pm(a); }
|
|
7023
7595
|
let s = max(u.wipe.y, 0.5);
|
|
7024
7596
|
let m = smoothstep(u.wipe.x - s, u.wipe.x + s, p.x);
|
|
7025
7597
|
return pm(vec4f(mix(a.rgb, b.rgb, m), mix(a.a, b.a, m)));
|
|
7026
7598
|
}
|
|
7027
7599
|
case 2u: {
|
|
7028
|
-
if (flick) { return pm(a); }
|
|
7029
7600
|
let d = abs(a.rgb - b.rgb);
|
|
7030
7601
|
let h = smoothstep(u.diff.x, u.diff.x + 0.06, max(d.r, max(d.g, d.b)) * u.diff.y) * min(a.a, b.a);
|
|
7031
7602
|
let c = mix(vec3f(luma(b.rgb) * 0.35), u.accent.rgb, h);
|
|
@@ -7033,8 +7604,8 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f, a2: vec4f) -> vec4f {
|
|
|
7033
7604
|
}
|
|
7034
7605
|
default: {}
|
|
7035
7606
|
}
|
|
7036
|
-
//
|
|
7037
|
-
return
|
|
7607
|
+
// Side by side: each side in its own place, Before over After where they meet.
|
|
7608
|
+
return vec4f(a.rgb * a.a + b.rgb * b.a * (1.0 - a.a), a.a + b.a * (1.0 - a.a));
|
|
7038
7609
|
}
|
|
7039
7610
|
|
|
7040
7611
|
@fragment fn fs(@builtin(position) q: vec4f) -> @location(0) vec4f {
|
|
@@ -7052,16 +7623,14 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f, a2: vec4f) -> vec4f {
|
|
|
7052
7623
|
}
|
|
7053
7624
|
let a = takeA(p, u.ra, u.ca, near);
|
|
7054
7625
|
let b = takeB(p, u.rb, u.cb, near);
|
|
7055
|
-
|
|
7056
|
-
let a2 = takeA(p, u.rb, u.cb, near);
|
|
7057
|
-
var o = mix(composite(u32(u.modes.x), p, a, b, a2), composite(u32(u.modes.y), p, a, b, a2), u.modes.z);
|
|
7626
|
+
var o = mix(composite(u32(u.modes.x), p, a, b), composite(u32(u.modes.y), p, a, b), u.modes.z);
|
|
7058
7627
|
if (near) { o = o + vec4f(0.05, 0.05, 0.06, 1.0) * (1.0 - o.a); }
|
|
7059
7628
|
o = mix(o, vec4f(0.92), ring * 0.9);
|
|
7060
7629
|
return o;
|
|
7061
7630
|
}
|
|
7062
7631
|
`, TEXTURE_BINDING = 4, COPY_DST = 2, RENDER_ATTACHMENT = 16, shared = null, lostListeners;
|
|
7063
7632
|
var init_compare_gpu = __esm(() => {
|
|
7064
|
-
MODE_INDEX = { side: 0, wipe: 1, difference: 2
|
|
7633
|
+
MODE_INDEX = { side: 0, wipe: 1, difference: 2 };
|
|
7065
7634
|
lostListeners = new Set;
|
|
7066
7635
|
});
|
|
7067
7636
|
|
|
@@ -7447,7 +8016,9 @@ function compare(container, options) {
|
|
|
7447
8016
|
...options.theme ? { theme: options.theme } : {},
|
|
7448
8017
|
...options.appearance ? { appearance: options.appearance } : {}
|
|
7449
8018
|
};
|
|
7450
|
-
|
|
8019
|
+
const offered = compareModes(options.modes, options.mode);
|
|
8020
|
+
const modeList = offered.modes;
|
|
8021
|
+
let mode = offered.mode;
|
|
7451
8022
|
let wipe = Math.min(1, Math.max(0, options.wipe ?? 0.5));
|
|
7452
8023
|
let loupeOn = options.loupe ?? false;
|
|
7453
8024
|
let threshold = options.threshold ?? 4 / 255;
|
|
@@ -7465,7 +8036,7 @@ function compare(container, options) {
|
|
|
7465
8036
|
root.setAttribute("role", "group");
|
|
7466
8037
|
root.setAttribute("aria-roledescription", "compare");
|
|
7467
8038
|
root.setAttribute("aria-label", options.label ?? "Compare");
|
|
7468
|
-
root.setAttribute("aria-keyshortcuts",
|
|
8039
|
+
root.setAttribute("aria-keyshortcuts", `Space ArrowLeft ArrowRight Shift+ArrowLeft Shift+ArrowRight , . ${modeList.map((m, i) => `${i + 1} ${modeKey(m)}`).join(" ")} Z L 0 = -`);
|
|
7469
8040
|
applyLook2(root, options);
|
|
7470
8041
|
root.dataset.mode = mode;
|
|
7471
8042
|
if (auto)
|
|
@@ -7474,35 +8045,37 @@ function compare(container, options) {
|
|
|
7474
8045
|
const modes = el("div", "knobs-cmp-modes");
|
|
7475
8046
|
modes.setAttribute("role", "radiogroup");
|
|
7476
8047
|
modes.setAttribute("aria-label", "Mode");
|
|
7477
|
-
|
|
8048
|
+
modes.hidden = modeList.length < 2;
|
|
8049
|
+
const modeBtns = modeList.map((m, i) => {
|
|
7478
8050
|
const b = el("button", "knobs-cmp-mode");
|
|
7479
8051
|
b.type = "button";
|
|
7480
8052
|
b.tabIndex = -1;
|
|
7481
|
-
b.textContent = m.
|
|
7482
|
-
b.title = `${m.
|
|
8053
|
+
b.textContent = MODE_LABEL[m].short;
|
|
8054
|
+
b.title = `${MODE_LABEL[m].long} · ${i + 1} or ${modeKey(m)}`;
|
|
7483
8055
|
b.setAttribute("role", "radio");
|
|
7484
|
-
b.setAttribute("aria-keyshortcuts",
|
|
8056
|
+
b.setAttribute("aria-keyshortcuts", `${i + 1} ${modeKey(m)}`);
|
|
7485
8057
|
b.addEventListener("click", () => {
|
|
7486
|
-
setMode(m
|
|
8058
|
+
setMode(m);
|
|
7487
8059
|
root.focus({ preventScroll: true });
|
|
7488
8060
|
});
|
|
7489
8061
|
modes.append(b);
|
|
7490
8062
|
return b;
|
|
7491
8063
|
});
|
|
7492
|
-
const
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
8064
|
+
const toggleBtn = (name, label, title) => {
|
|
8065
|
+
const b = el("button", "knobs-cmp-toggle");
|
|
8066
|
+
b.type = "button";
|
|
8067
|
+
b.tabIndex = -1;
|
|
8068
|
+
b.innerHTML = icon(name);
|
|
8069
|
+
b.setAttribute("aria-label", label);
|
|
8070
|
+
b.title = title;
|
|
8071
|
+
return b;
|
|
8072
|
+
};
|
|
8073
|
+
const loupeBtn = toggleBtn("magnifyingGlass", "Loupe", "Loupe · hold Z");
|
|
7497
8074
|
loupeBtn.addEventListener("click", () => {
|
|
7498
8075
|
setLoupe(!loupeOn);
|
|
7499
8076
|
root.focus({ preventScroll: true });
|
|
7500
8077
|
});
|
|
7501
|
-
const loopBtn =
|
|
7502
|
-
loopBtn.type = "button";
|
|
7503
|
-
loopBtn.tabIndex = -1;
|
|
7504
|
-
loopBtn.textContent = "Loop";
|
|
7505
|
-
loopBtn.title = "Loop · L (drag its ends on the timeline)";
|
|
8078
|
+
const loopBtn = toggleBtn("repeat", "Loop", "Loop · L (drag its ends on the timeline)");
|
|
7506
8079
|
loopBtn.setAttribute("aria-keyshortcuts", "L");
|
|
7507
8080
|
loopBtn.addEventListener("click", () => {
|
|
7508
8081
|
api.setLoop(!loopNow());
|
|
@@ -7519,7 +8092,8 @@ function compare(container, options) {
|
|
|
7519
8092
|
const zoomReset = el("button", "knobs-cmp-zoom-reset");
|
|
7520
8093
|
zoomReset.type = "button";
|
|
7521
8094
|
zoomReset.tabIndex = -1;
|
|
7522
|
-
zoomReset.
|
|
8095
|
+
zoomReset.innerHTML = icon("arrowCounterClockwise", { small: true });
|
|
8096
|
+
zoomReset.setAttribute("aria-label", "Reset zoom");
|
|
7523
8097
|
zoomReset.title = "Fit · 0 or double-click";
|
|
7524
8098
|
zoomReset.addEventListener("click", () => {
|
|
7525
8099
|
api.setZoom(null);
|
|
@@ -7529,11 +8103,25 @@ function compare(container, options) {
|
|
|
7529
8103
|
const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
|
|
7530
8104
|
labels[0].dataset.side = "before";
|
|
7531
8105
|
labels[1].dataset.side = "after";
|
|
8106
|
+
const setLabel = (index, text) => {
|
|
8107
|
+
const l = labels[index];
|
|
8108
|
+
if (!l.firstElementChild) {
|
|
8109
|
+
const mark = el("span", "knobs-cmp-mark");
|
|
8110
|
+
mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
|
|
8111
|
+
l.append(mark, el("span", "knobs-cmp-name"));
|
|
8112
|
+
}
|
|
8113
|
+
const name = l.lastElementChild;
|
|
8114
|
+
if (name.textContent !== text)
|
|
8115
|
+
name.textContent = text;
|
|
8116
|
+
};
|
|
7532
8117
|
const handle = el("div", "knobs-cmp-handle");
|
|
7533
8118
|
handle.setAttribute("role", "slider");
|
|
7534
8119
|
handle.setAttribute("aria-label", "Wipe");
|
|
7535
8120
|
handle.setAttribute("aria-valuemin", "0");
|
|
7536
8121
|
handle.setAttribute("aria-valuemax", "100");
|
|
8122
|
+
const grip = el("span", "knobs-cmp-grip");
|
|
8123
|
+
grip.setAttribute("aria-hidden", "true");
|
|
8124
|
+
handle.append(grip);
|
|
7537
8125
|
const note = el("div", "knobs-cmp-note");
|
|
7538
8126
|
stage.append(canvas, split, labels[0], labels[1], handle, zoomPill, note);
|
|
7539
8127
|
root.append(bar, stage);
|
|
@@ -7550,6 +8138,7 @@ function compare(container, options) {
|
|
|
7550
8138
|
root.append(host);
|
|
7551
8139
|
tl = timeline(host, {
|
|
7552
8140
|
...look,
|
|
8141
|
+
variant: "lane",
|
|
7553
8142
|
duration: 1,
|
|
7554
8143
|
fps: fps(),
|
|
7555
8144
|
arrows: { step: 0.5, shift: 2 },
|
|
@@ -7568,9 +8157,9 @@ function compare(container, options) {
|
|
|
7568
8157
|
const fade = new Spring(1, FADE2.omega, FADE2.zeta, 0.001);
|
|
7569
8158
|
let fromMode = mode;
|
|
7570
8159
|
let toMode = mode;
|
|
7571
|
-
|
|
7572
|
-
let
|
|
7573
|
-
let
|
|
8160
|
+
const wipeLine = new Spring(wipe, WIPE_CATCH.omega, WIPE_CATCH.zeta, 0.0001);
|
|
8161
|
+
let wipeCatching = false;
|
|
8162
|
+
let gripY = null;
|
|
7574
8163
|
let loupeHeld = false;
|
|
7575
8164
|
let pointer = null;
|
|
7576
8165
|
let drag = null;
|
|
@@ -7888,25 +8477,16 @@ function compare(container, options) {
|
|
|
7888
8477
|
gpu = g;
|
|
7889
8478
|
setRenderer("gpu");
|
|
7890
8479
|
};
|
|
7891
|
-
const syncFlicker = () => {
|
|
7892
|
-
win.clearInterval(flickerTimer);
|
|
7893
|
-
flickerTimer = 0;
|
|
7894
|
-
phase = false;
|
|
7895
|
-
if (mode === "flicker")
|
|
7896
|
-
flickerTimer = win.setInterval(() => {
|
|
7897
|
-
phase = !phase;
|
|
7898
|
-
requestDraw();
|
|
7899
|
-
}, FLICKER_MS);
|
|
7900
|
-
};
|
|
7901
8480
|
const syncModeUi = () => {
|
|
7902
8481
|
root.dataset.mode = mode;
|
|
7903
|
-
|
|
7904
|
-
modeBtns[i].setAttribute("aria-checked", String(m
|
|
8482
|
+
modeList.forEach((m, i) => {
|
|
8483
|
+
modeBtns[i].setAttribute("aria-checked", String(m === mode));
|
|
7905
8484
|
});
|
|
7906
8485
|
handle.tabIndex = mode === "wipe" ? 0 : -1;
|
|
8486
|
+
modePill?.update();
|
|
7907
8487
|
};
|
|
7908
8488
|
const setMode = (next, emit = true) => {
|
|
7909
|
-
if (next === mode)
|
|
8489
|
+
if (next === mode || !modeList.includes(next))
|
|
7910
8490
|
return;
|
|
7911
8491
|
mode = next;
|
|
7912
8492
|
const reduced = reducedMotion(win);
|
|
@@ -7922,19 +8502,29 @@ function compare(container, options) {
|
|
|
7922
8502
|
else
|
|
7923
8503
|
lay.set(next === "side" ? 0 : 1);
|
|
7924
8504
|
syncModeUi();
|
|
7925
|
-
syncFlicker();
|
|
7926
8505
|
if (emit)
|
|
7927
8506
|
options.onMode?.(next);
|
|
7928
8507
|
requestDraw();
|
|
7929
8508
|
};
|
|
7930
|
-
const setWipe = (next, emit = true) => {
|
|
8509
|
+
const setWipe = (next, emit = true, jump = false) => {
|
|
7931
8510
|
const w = Math.min(1, Math.max(0, next));
|
|
7932
|
-
if (w === wipe)
|
|
8511
|
+
if (w === wipe && !jump)
|
|
7933
8512
|
return;
|
|
7934
8513
|
wipe = w;
|
|
8514
|
+
const minGap = 2 / Math.max(1, wipeRect(layoutNow().L.overlay).w);
|
|
8515
|
+
const head = moveHead({ x: wipeLine.x, target: wipeLine.target }, w, jump && !reducedMotion(win) ? "jump" : "follow", wipeCatching, minGap);
|
|
8516
|
+
wipeCatching = head.catching;
|
|
8517
|
+
if (head.catching) {
|
|
8518
|
+
wipeLine.x = head.x;
|
|
8519
|
+
wipeLine.target = head.target;
|
|
8520
|
+
} else
|
|
8521
|
+
wipeLine.snap(head.x);
|
|
7935
8522
|
if (emit)
|
|
7936
8523
|
options.onWipe?.(w);
|
|
7937
|
-
|
|
8524
|
+
if (head.catching)
|
|
8525
|
+
requestDraw();
|
|
8526
|
+
else
|
|
8527
|
+
drawNow();
|
|
7938
8528
|
};
|
|
7939
8529
|
const setLoupe = (on) => {
|
|
7940
8530
|
loupeOn = on;
|
|
@@ -8087,28 +8677,44 @@ function compare(container, options) {
|
|
|
8087
8677
|
viewSent = key;
|
|
8088
8678
|
options.onView({ zoom: clampZoom(z), loop: l });
|
|
8089
8679
|
};
|
|
8680
|
+
const labelsIn = (m, r, wr, wx) => {
|
|
8681
|
+
if (m === "wipe") {
|
|
8682
|
+
const at = seamLabels(wx, wr.x, wr.x + wr.w, labelW[0], labelW[1], INSET);
|
|
8683
|
+
return [at.before, at.after];
|
|
8684
|
+
}
|
|
8685
|
+
const ax = r.after.x + INSET + (r.after.w - labelW[1] - INSET * 2) * lay.x;
|
|
8686
|
+
return [
|
|
8687
|
+
{ x: r.before.x + INSET, opacity: 1 },
|
|
8688
|
+
{ x: ax, opacity: 1 }
|
|
8689
|
+
];
|
|
8690
|
+
};
|
|
8691
|
+
const placeGrip = (wr) => {
|
|
8692
|
+
const gy = gripTop(gripY ?? wr.y + wr.h / 2, wr, GRIP.h) - wr.y;
|
|
8693
|
+
grip.style.transform = `translate3d(0,${gy.toFixed(2)}px,0)`;
|
|
8694
|
+
};
|
|
8090
8695
|
const draw = () => {
|
|
8091
8696
|
dirty = false;
|
|
8092
8697
|
const r = layoutNow();
|
|
8093
8698
|
const wr = wipeRect(r.L.overlay);
|
|
8094
|
-
const wx = wipeX(wr,
|
|
8699
|
+
const wx = wipeX(wr, wipeLine.x);
|
|
8095
8700
|
const k = lay.x;
|
|
8096
|
-
const
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
const
|
|
8100
|
-
const
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8701
|
+
const a = labelsIn(fromMode, r, wr, wx);
|
|
8702
|
+
const b = labelsIn(toMode, r, wr, wx);
|
|
8703
|
+
const f = Math.min(1, Math.max(0, fade.x));
|
|
8704
|
+
const ys = [r.before.y + INSET, r.after.y + INSET];
|
|
8705
|
+
for (const i of [0, 1]) {
|
|
8706
|
+
const x = a[i].x + (b[i].x - a[i].x) * f;
|
|
8707
|
+
labels[i].style.transform = `translate(${x.toFixed(2)}px,${ys[i].toFixed(2)}px)`;
|
|
8708
|
+
labels[i].style.opacity = (a[i].opacity + (b[i].opacity - a[i].opacity) * f).toFixed(3);
|
|
8709
|
+
}
|
|
8105
8710
|
const top = Math.min(r.L.side.before.y, r.L.side.after.y);
|
|
8106
8711
|
split.style.transform = `translate(${r.L.side.split.toFixed(2)}px,${top.toFixed(2)}px)`;
|
|
8107
8712
|
split.style.height = `${Math.max(0, r.L.side.after.h).toFixed(2)}px`;
|
|
8108
8713
|
split.style.opacity = String(Math.max(0, 1 - k * 2));
|
|
8109
|
-
handle.toggleAttribute("data-on", mode === "wipe"
|
|
8714
|
+
handle.toggleAttribute("data-on", mode === "wipe");
|
|
8110
8715
|
handle.style.transform = `translate(${wx.toFixed(2)}px,${wr.y.toFixed(2)}px)`;
|
|
8111
8716
|
handle.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
8717
|
+
placeGrip(wr);
|
|
8112
8718
|
handle.setAttribute("aria-valuenow", String(Math.round(wipe * 100)));
|
|
8113
8719
|
handle.setAttribute("aria-valuetext", `${Math.round(wipe * 100)}% Before`);
|
|
8114
8720
|
const pct = `${Math.round(100 / zw.x)}%`;
|
|
@@ -8131,7 +8737,7 @@ function compare(container, options) {
|
|
|
8131
8737
|
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w, cutAt));
|
|
8132
8738
|
st.clipPath = t + l + b + right > 0.01 ? `inset(${t.toFixed(2)}px ${right.toFixed(2)}px ${b.toFixed(2)}px ${l.toFixed(2)}px)` : "";
|
|
8133
8739
|
};
|
|
8134
|
-
const cut = mode === "wipe"
|
|
8740
|
+
const cut = mode === "wipe" ? wx : Number.POSITIVE_INFINITY;
|
|
8135
8741
|
for (const s of sides) {
|
|
8136
8742
|
const rect = s.index === 0 ? r.zBefore : r.zAfter;
|
|
8137
8743
|
const clip = s.index === 0 ? r.before : r.after;
|
|
@@ -8140,10 +8746,8 @@ function compare(container, options) {
|
|
|
8140
8746
|
place(s.preview, rect, clip, at);
|
|
8141
8747
|
if (s.index !== 0)
|
|
8142
8748
|
continue;
|
|
8143
|
-
for (const n of [s.el, s.preview])
|
|
8144
|
-
n.style.mixBlendMode = mode === "difference"
|
|
8145
|
-
n.style.opacity = mode === "flicker" && !showsBefore ? "0" : "";
|
|
8146
|
-
}
|
|
8749
|
+
for (const n of [s.el, s.preview])
|
|
8750
|
+
n.style.mixBlendMode = mode === "difference" ? "difference" : "";
|
|
8147
8751
|
}
|
|
8148
8752
|
return;
|
|
8149
8753
|
}
|
|
@@ -8164,8 +8768,6 @@ function compare(container, options) {
|
|
|
8164
8768
|
from: MODE_INDEX[fromMode],
|
|
8165
8769
|
to: MODE_INDEX[toMode],
|
|
8166
8770
|
mix: Math.min(1, Math.max(0, fade.x)),
|
|
8167
|
-
flick: flickHeld,
|
|
8168
|
-
phase,
|
|
8169
8771
|
threshold,
|
|
8170
8772
|
gain: 1,
|
|
8171
8773
|
accent,
|
|
@@ -8181,6 +8783,11 @@ function compare(container, options) {
|
|
|
8181
8783
|
const loop = frameLoop(win, (dt) => {
|
|
8182
8784
|
lay.step(dt);
|
|
8183
8785
|
fade.step(dt);
|
|
8786
|
+
if (wipeCatching) {
|
|
8787
|
+
wipeLine.step(dt);
|
|
8788
|
+
if (wipeLine.resting)
|
|
8789
|
+
wipeCatching = false;
|
|
8790
|
+
}
|
|
8184
8791
|
zu.step(dt);
|
|
8185
8792
|
zv.step(dt);
|
|
8186
8793
|
zw.step(dt);
|
|
@@ -8214,7 +8821,7 @@ function compare(container, options) {
|
|
|
8214
8821
|
pushFrame(s);
|
|
8215
8822
|
}
|
|
8216
8823
|
}
|
|
8217
|
-
const moving = !lay.resting || !fade.resting || !zoomResting();
|
|
8824
|
+
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching;
|
|
8218
8825
|
if (moving)
|
|
8219
8826
|
dirty = true;
|
|
8220
8827
|
if (auto && !lay.resting)
|
|
@@ -8357,16 +8964,19 @@ function compare(container, options) {
|
|
|
8357
8964
|
e.preventDefault();
|
|
8358
8965
|
return startPinch();
|
|
8359
8966
|
}
|
|
8360
|
-
if (mode === "wipe"
|
|
8967
|
+
if (mode === "wipe") {
|
|
8361
8968
|
const wr = wipeRect(layoutNow().L.overlay);
|
|
8362
8969
|
const inside = p.x >= wr.x - SLOP && p.x <= wr.x + wr.w + SLOP && p.y >= wr.y && p.y <= wr.y + wr.h;
|
|
8363
|
-
const grab = wipeGrab(p.x, wr,
|
|
8970
|
+
const grab = wipeGrab(p.x, wr, wipeLine.x, SLOP);
|
|
8364
8971
|
if (inside && (grab.onLine || !zoomed())) {
|
|
8365
8972
|
drag = { kind: "wipe", offset: grab.offset };
|
|
8366
8973
|
root.dataset.dragging = "";
|
|
8974
|
+
gripY = p.y;
|
|
8367
8975
|
e.preventDefault();
|
|
8368
8976
|
if (!grab.onLine)
|
|
8369
|
-
setWipe(wipeAt(p.x, wr));
|
|
8977
|
+
setWipe(wipeAt(p.x, wr), true, true);
|
|
8978
|
+
else
|
|
8979
|
+
drawNow();
|
|
8370
8980
|
return;
|
|
8371
8981
|
}
|
|
8372
8982
|
}
|
|
@@ -8392,6 +9002,11 @@ function compare(container, options) {
|
|
|
8392
9002
|
pinch = { d, x: mid.x, y: mid.y };
|
|
8393
9003
|
return handZoom(zoomAbout(panned, k, q.pu, q.pv));
|
|
8394
9004
|
}
|
|
9005
|
+
if (mode === "wipe" && drag?.kind !== "pan") {
|
|
9006
|
+
gripY = p.y;
|
|
9007
|
+
if (!drag)
|
|
9008
|
+
placeGrip(wipeRect(layoutNow().L.overlay));
|
|
9009
|
+
}
|
|
8395
9010
|
if (drag?.kind === "wipe")
|
|
8396
9011
|
setWipe(wipeAt(p.x, wipeRect(layoutNow().L.overlay), drag.offset));
|
|
8397
9012
|
else if (drag?.kind === "pan") {
|
|
@@ -8464,12 +9079,6 @@ function compare(container, options) {
|
|
|
8464
9079
|
const z = { u: zu.target, v: zv.target, w: zw.target, h: zw.target };
|
|
8465
9080
|
glideZoom(zoomAbout(z, factor, 0.5, 0.5));
|
|
8466
9081
|
};
|
|
8467
|
-
const holdFlick = (on) => {
|
|
8468
|
-
if (flickHeld === on)
|
|
8469
|
-
return;
|
|
8470
|
-
flickHeld = on;
|
|
8471
|
-
drawNow();
|
|
8472
|
-
};
|
|
8473
9082
|
const holdLoupe = (on) => {
|
|
8474
9083
|
if (loupeHeld === on)
|
|
8475
9084
|
return;
|
|
@@ -8515,25 +9124,17 @@ function compare(container, options) {
|
|
|
8515
9124
|
case "s":
|
|
8516
9125
|
case "w":
|
|
8517
9126
|
case "d":
|
|
8518
|
-
if (e.altKey || e.shiftKey || key === "s" && claimsHintKey(doc, key))
|
|
8519
|
-
return;
|
|
8520
|
-
claim();
|
|
8521
|
-
return setMode(KEY_MODE[key]);
|
|
8522
9127
|
case "1":
|
|
8523
9128
|
case "2":
|
|
8524
|
-
case "3":
|
|
8525
|
-
|
|
8526
|
-
if (e.altKey || e.shiftKey)
|
|
9129
|
+
case "3": {
|
|
9130
|
+
if (e.altKey || e.shiftKey || key === "s" && claimsHintKey(doc, key))
|
|
8527
9131
|
return;
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
case "x":
|
|
8531
|
-
if (e.altKey)
|
|
9132
|
+
const m = modeForKey(key, modeList);
|
|
9133
|
+
if (!m)
|
|
8532
9134
|
return;
|
|
8533
9135
|
claim();
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
return;
|
|
9136
|
+
return setMode(m);
|
|
9137
|
+
}
|
|
8537
9138
|
case "z":
|
|
8538
9139
|
if (e.altKey)
|
|
8539
9140
|
return;
|
|
@@ -8574,7 +9175,7 @@ function compare(container, options) {
|
|
|
8574
9175
|
old.preview.replaceWith(s.preview);
|
|
8575
9176
|
sides[index] = s;
|
|
8576
9177
|
note.textContent = "";
|
|
8577
|
-
|
|
9178
|
+
setLabel(index, labelOf(index));
|
|
8578
9179
|
if (near)
|
|
8579
9180
|
loadSide(s);
|
|
8580
9181
|
readColors();
|
|
@@ -8585,12 +9186,15 @@ function compare(container, options) {
|
|
|
8585
9186
|
stage.insertBefore(sides[1].preview, labels[0]);
|
|
8586
9187
|
stage.insertBefore(sides[0].el, labels[0]);
|
|
8587
9188
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
8588
|
-
|
|
8589
|
-
|
|
9189
|
+
setLabel(0, labelOf(0));
|
|
9190
|
+
setLabel(1, labelOf(1));
|
|
8590
9191
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
8591
9192
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
9193
|
+
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
9194
|
+
rows: () => modeBtns,
|
|
9195
|
+
selected: () => modeBtns[modeList.indexOf(mode)] ?? null
|
|
9196
|
+
}) : null;
|
|
8592
9197
|
syncModeUi();
|
|
8593
|
-
syncFlicker();
|
|
8594
9198
|
const unlisten = tl?.listen({
|
|
8595
9199
|
onSeek: (t, source) => {
|
|
8596
9200
|
if (source === "play") {
|
|
@@ -8648,24 +9252,20 @@ function compare(container, options) {
|
|
|
8648
9252
|
});
|
|
8649
9253
|
root.addEventListener("keydown", onKey);
|
|
8650
9254
|
root.addEventListener("keyup", (e) => {
|
|
8651
|
-
|
|
8652
|
-
if (key === "x")
|
|
8653
|
-
holdFlick(false);
|
|
8654
|
-
else if (key === "z")
|
|
9255
|
+
if (e.key.toLowerCase() === "z")
|
|
8655
9256
|
holdLoupe(false);
|
|
8656
9257
|
});
|
|
8657
9258
|
root.addEventListener("focusout", (e) => {
|
|
8658
9259
|
if (root.contains(e.relatedTarget))
|
|
8659
9260
|
return;
|
|
8660
|
-
holdFlick(false);
|
|
8661
9261
|
holdLoupe(false);
|
|
8662
9262
|
});
|
|
8663
9263
|
const unregisterHints = options.hints === false ? undefined : hints.register(root, () => [
|
|
8664
|
-
...
|
|
9264
|
+
...modeList.length > 1 ? modeList.map((m, i) => ({
|
|
8665
9265
|
el: modeBtns[i],
|
|
8666
|
-
label: m.
|
|
8667
|
-
activate: () => setMode(m
|
|
8668
|
-
})),
|
|
9266
|
+
label: MODE_LABEL[m].long,
|
|
9267
|
+
activate: () => setMode(m)
|
|
9268
|
+
})) : [],
|
|
8669
9269
|
{ el: loopBtn, label: "Loop", activate: () => api.setLoop(!loopNow()) },
|
|
8670
9270
|
...loupeBtn.hidden ? [] : [{ el: loupeBtn, label: "Loupe", activate: () => setLoupe(!loupeOn) }],
|
|
8671
9271
|
...zoomed() ? [{ el: zoomReset, label: "Reset zoom", activate: () => api.setZoom(null) }] : [],
|
|
@@ -8690,6 +9290,7 @@ function compare(container, options) {
|
|
|
8690
9290
|
get mode() {
|
|
8691
9291
|
return mode;
|
|
8692
9292
|
},
|
|
9293
|
+
modes: modeList,
|
|
8693
9294
|
get wipe() {
|
|
8694
9295
|
return wipe;
|
|
8695
9296
|
},
|
|
@@ -8726,11 +9327,11 @@ function compare(container, options) {
|
|
|
8726
9327
|
if (before)
|
|
8727
9328
|
replace(0, before);
|
|
8728
9329
|
else if (next.before)
|
|
8729
|
-
|
|
9330
|
+
setLabel(0, next.before.label ?? "Before");
|
|
8730
9331
|
if (after)
|
|
8731
9332
|
replace(1, after);
|
|
8732
9333
|
else if (next.after)
|
|
8733
|
-
|
|
9334
|
+
setLabel(1, next.after.label ?? "After");
|
|
8734
9335
|
if (before || after)
|
|
8735
9336
|
strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
|
|
8736
9337
|
if (next.before || next.after)
|
|
@@ -8745,7 +9346,7 @@ function compare(container, options) {
|
|
|
8745
9346
|
tl?.update({ fps: next.fps });
|
|
8746
9347
|
requestDraw();
|
|
8747
9348
|
},
|
|
8748
|
-
seek: (t) => tl ? tl.seek(t) : ownSeek(t),
|
|
9349
|
+
seek: (t, o) => tl ? tl.seek(t, o?.glide ? { glide: true } : undefined) : ownSeek(t),
|
|
8749
9350
|
seekBy(d) {
|
|
8750
9351
|
const total = duration || tl?.duration || 0;
|
|
8751
9352
|
const t = Math.min(total, Math.max(0, now() + d));
|
|
@@ -8786,7 +9387,7 @@ function compare(container, options) {
|
|
|
8786
9387
|
dispose() {
|
|
8787
9388
|
disposed = true;
|
|
8788
9389
|
loop.stop();
|
|
8789
|
-
|
|
9390
|
+
modePill?.dispose();
|
|
8790
9391
|
win.clearTimeout(releaseTimer);
|
|
8791
9392
|
ro.disconnect();
|
|
8792
9393
|
nearIo?.disconnect();
|
|
@@ -8816,7 +9417,7 @@ function compare(container, options) {
|
|
|
8816
9417
|
wake();
|
|
8817
9418
|
return api;
|
|
8818
9419
|
}
|
|
8819
|
-
var COMPARE_FFMPEG = "ffmpeg -i in.mov -vf fps=30 -fps_mode cfr -c:v libx264 -preset slow -crf 18 -g 15 -keyint_min 15 -pix_fmt yuv420p -movflags +faststart -an out.mp4", LAYOUT, FADE2, FADE_REDUCED, ZOOM,
|
|
9420
|
+
var COMPARE_FFMPEG = "ffmpeg -i in.mov -vf fps=30 -fps_mode cfr -c:v libx264 -preset slow -crf 18 -g 15 -keyint_min 15 -pix_fmt yuv420p -movflags +faststart -an out.mp4", LAYOUT, FADE2, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
8820
9421
|
var init_compare = __esm(() => {
|
|
8821
9422
|
init_motion();
|
|
8822
9423
|
init_page_hints();
|
|
@@ -8824,21 +9425,24 @@ var init_compare = __esm(() => {
|
|
|
8824
9425
|
init_compare_gpu();
|
|
8825
9426
|
init_compare_model();
|
|
8826
9427
|
init_compare_strip();
|
|
9428
|
+
init_icons();
|
|
8827
9429
|
init_look();
|
|
8828
9430
|
init_rgba();
|
|
9431
|
+
init_selection_pill();
|
|
8829
9432
|
init_timeline();
|
|
9433
|
+
init_timeline_model();
|
|
8830
9434
|
LAYOUT = springMotion({ duration: 0.35, bounce: 0 });
|
|
8831
9435
|
FADE2 = springMotion(SPRINGS.snappy);
|
|
8832
9436
|
FADE_REDUCED = springMotion(FADE);
|
|
8833
9437
|
ZOOM = springMotion({ duration: 0.35, bounce: 0 });
|
|
9438
|
+
WIPE_CATCH = springMotion(CATCH_UP);
|
|
9439
|
+
GRIP = { w: 16, h: 28 };
|
|
8834
9440
|
LOUPE = { r: 88, zoom: 4 };
|
|
8835
|
-
|
|
8836
|
-
{
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
];
|
|
8841
|
-
KEY_MODE = { s: "side", w: "wipe", d: "difference" };
|
|
9441
|
+
MODE_LABEL = {
|
|
9442
|
+
side: { short: "Side", long: "Side by side" },
|
|
9443
|
+
wipe: { short: "Wipe", long: "Wipe" },
|
|
9444
|
+
difference: { short: "Difference", long: "Difference" }
|
|
9445
|
+
};
|
|
8842
9446
|
});
|
|
8843
9447
|
|
|
8844
9448
|
// src/ui/scrollbar.ts
|
|
@@ -8960,34 +9564,27 @@ function tree(container, options) {
|
|
|
8960
9564
|
const empty = doc.createElement("div");
|
|
8961
9565
|
empty.className = "knobs-tree-empty";
|
|
8962
9566
|
empty.hidden = true;
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
9567
|
+
root.append(space, line, empty);
|
|
9568
|
+
let pill = null;
|
|
9569
|
+
let picked = null;
|
|
9570
|
+
let travelUntil = 0;
|
|
9571
|
+
const pickedRow = () => {
|
|
9572
|
+
const id = sel.ids.length === 1 ? sel.ids[0] : null;
|
|
9573
|
+
const v = id === null ? undefined : views.get(id);
|
|
9574
|
+
return v && !v.leaving && rowIndex.has(v.id) ? v : null;
|
|
8970
9575
|
};
|
|
8971
9576
|
const placeCursor = (animate) => {
|
|
8972
|
-
if (!
|
|
9577
|
+
if (!pill)
|
|
8973
9578
|
return;
|
|
8974
9579
|
const id = sel.ids.length === 1 ? sel.ids[0] : null;
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
}
|
|
8982
|
-
|
|
8983
|
-
cursorY.set(i * h);
|
|
8984
|
-
else
|
|
8985
|
-
cursorY.snap(i * h);
|
|
8986
|
-
cursorOn = true;
|
|
8987
|
-
cursor.setAttribute("data-on", "");
|
|
8988
|
-
drawCursor();
|
|
8989
|
-
if (!cursorY.resting)
|
|
8990
|
-
loop.wake();
|
|
9580
|
+
root.toggleAttribute("data-glide", id !== null && rowIndex.has(id));
|
|
9581
|
+
const fresh = id !== picked;
|
|
9582
|
+
picked = id;
|
|
9583
|
+
if (animate && fresh) {
|
|
9584
|
+
travelUntil = performance.now() + 450;
|
|
9585
|
+
pill.update();
|
|
9586
|
+
} else if (performance.now() >= travelUntil)
|
|
9587
|
+
pill.update({ snap: true });
|
|
8991
9588
|
};
|
|
8992
9589
|
container.append(root);
|
|
8993
9590
|
const scrollbar = overlayScrollbar(root, space);
|
|
@@ -9016,6 +9613,12 @@ function tree(container, options) {
|
|
|
9016
9613
|
};
|
|
9017
9614
|
const views = new Map;
|
|
9018
9615
|
const pool = [];
|
|
9616
|
+
if (options.glide)
|
|
9617
|
+
pill = selectionPill(root, {
|
|
9618
|
+
rows: () => [...views.values()].filter((v) => !v.leaving).map((v) => v.el),
|
|
9619
|
+
selected: () => pickedRow()?.el ?? null,
|
|
9620
|
+
radius: (row) => Number.parseFloat(win.getComputedStyle(row, "::before").borderTopLeftRadius) || 0
|
|
9621
|
+
});
|
|
9019
9622
|
const makeView = (id) => {
|
|
9020
9623
|
const v = pool.pop() ?? createView();
|
|
9021
9624
|
v.id = id;
|
|
@@ -9196,12 +9799,6 @@ function tree(container, options) {
|
|
|
9196
9799
|
function frame(dt) {
|
|
9197
9800
|
let moving = false;
|
|
9198
9801
|
let bottom = rows.length * h;
|
|
9199
|
-
if (options.glide && !cursorY.resting) {
|
|
9200
|
-
cursorY.step(dt);
|
|
9201
|
-
drawCursor();
|
|
9202
|
-
if (!cursorY.resting)
|
|
9203
|
-
moving = true;
|
|
9204
|
-
}
|
|
9205
9802
|
for (const v of views.values()) {
|
|
9206
9803
|
v.y.step(dt);
|
|
9207
9804
|
if (!v.y.resting)
|
|
@@ -9221,6 +9818,8 @@ function tree(container, options) {
|
|
|
9221
9818
|
}
|
|
9222
9819
|
setSpace(moving ? bottom : rows.length * h);
|
|
9223
9820
|
trim();
|
|
9821
|
+
if (pill && moving && performance.now() >= travelUntil)
|
|
9822
|
+
pill.update({ snap: true });
|
|
9224
9823
|
return moving;
|
|
9225
9824
|
}
|
|
9226
9825
|
const trim = () => {
|
|
@@ -9849,6 +10448,7 @@ function tree(container, options) {
|
|
|
9849
10448
|
autoScroll.stop();
|
|
9850
10449
|
ro.disconnect();
|
|
9851
10450
|
scrollbar.dispose();
|
|
10451
|
+
pill?.dispose();
|
|
9852
10452
|
dragging?.ghost.remove();
|
|
9853
10453
|
root.remove();
|
|
9854
10454
|
}
|
|
@@ -9867,6 +10467,7 @@ var init_tree = __esm(() => {
|
|
|
9867
10467
|
init_motion();
|
|
9868
10468
|
init_page_hints();
|
|
9869
10469
|
init_look();
|
|
10470
|
+
init_selection_pill();
|
|
9870
10471
|
init_tree_model();
|
|
9871
10472
|
MOVE = springMotion(SPRINGS.default);
|
|
9872
10473
|
});
|
|
@@ -9916,33 +10517,29 @@ var init_diff_css = __esm(() => {
|
|
|
9916
10517
|
.knobs-diff-fill{flex:1}
|
|
9917
10518
|
.knobs-diff-nav{flex:none;display:inline-flex;align-items:center;gap:1px;color:var(--_k-fg-3);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums}
|
|
9918
10519
|
.knobs-diff-nav>span{min-width:3.6em;text-align:center}
|
|
9919
|
-
:where(.knobs-ui) :is(.knobs-diff-btn,.knobs-diff-
|
|
10520
|
+
: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;
|
|
9920
10521
|
margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
9921
|
-
.knobs-ui .knobs-diff-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;width:
|
|
10522
|
+
.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-3);cursor:pointer;
|
|
9922
10523
|
transition:background .15s,color .15s,opacity .15s}
|
|
9923
10524
|
.knobs-ui .knobs-diff-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
9924
10525
|
.knobs-ui .knobs-diff-btn[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
9925
10526
|
.knobs-ui .knobs-diff-btn:disabled{opacity:.35;cursor:default;background:transparent}
|
|
9926
|
-
.knobs-diff-btn svg{width:
|
|
10527
|
+
.knobs-diff-btn svg{width:16px;height:16px}
|
|
9927
10528
|
/* Viewed: a check with its word, as on GitHub; the path dims once it's ticked. */
|
|
9928
10529
|
.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);
|
|
9929
10530
|
font-size:var(--_k-text-meta);font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:background .15s,color .15s}
|
|
9930
10531
|
.knobs-ui .knobs-diff-viewed:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
9931
10532
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
9932
|
-
.knobs-diff-viewed svg{width:
|
|
10533
|
+
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
9933
10534
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
9934
10535
|
.knobs-diff-path{transition:opacity .2s}
|
|
9935
10536
|
.knobs-diff[data-viewed]>.knobs-diff-head .knobs-diff-path,.knobs-diff-part[data-viewed] .knobs-diff-path{opacity:.6}
|
|
9936
|
-
/* Split | Unified:
|
|
9937
|
-
|
|
9938
|
-
.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-
|
|
9939
|
-
.knobs-ui .knobs-diff-
|
|
9940
|
-
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:color
|
|
9941
|
-
.knobs-ui .knobs-diff-
|
|
9942
|
-
.knobs-diff-pill{position:absolute;top:2px;bottom:2px;left:2px;width:calc(50% - 2px);border-radius:max(0px,calc(var(--kd-ctl) - 2px));background:color-mix(in srgb,var(--_k-accent) 18%,var(--_k-segmented-active));
|
|
9943
|
-
box-shadow:0 1px 2px rgba(0,0,0,calc(.16 * var(--k-lift,1)));transition:transform var(--_ku-ease-ms) var(--_ku-ease)}
|
|
9944
|
-
.knobs-diff-seg[data-value="unified"]>.knobs-diff-pill{transform:translateX(100%)}
|
|
9945
|
-
.knobs-diff[data-frame="flat"] .knobs-diff-pill{box-shadow:none}
|
|
10537
|
+
/* Split | Unified: the selection pill on the one picked, its bright copy the picked one's text; a
|
|
10538
|
+
choice isn't brighter for being picked. Choices are styled by class, as the copy holds them too. */
|
|
10539
|
+
.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)}
|
|
10540
|
+
.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);
|
|
10541
|
+
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
10542
|
+
.knobs-ui .knobs-diff-choice:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
9946
10543
|
/* The diff: one layer per file or layout on show, the old fading under the new. */
|
|
9947
10544
|
.knobs-diff-body{position:relative;flex:1;min-height:0}
|
|
9948
10545
|
.knobs-diff-probe{position:absolute;left:0;top:0;width:0;height:var(--kd-line);visibility:hidden;pointer-events:none}
|
|
@@ -10037,7 +10634,7 @@ var init_diff_css = __esm(() => {
|
|
|
10037
10634
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
10038
10635
|
.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:pointer;transition:background .12s,color .12s,opacity .12s}
|
|
10039
10636
|
.knobs-ui .knobs-diff-filter>button:hover{background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
10040
|
-
.knobs-diff-filter>button svg{width:
|
|
10637
|
+
.knobs-diff-filter>button svg{width:12px;height:12px}
|
|
10041
10638
|
.knobs-diff-list{position:relative;flex:1;min-height:0}
|
|
10042
10639
|
.knobs-diff-files .knobs-diff-counts{font-size:var(--_k-text-meta);align-items:center}
|
|
10043
10640
|
.knobs-diff-files .knobs-diff-counts{gap:5px}
|
|
@@ -10843,7 +11440,7 @@ function codeDiff(container, options) {
|
|
|
10843
11440
|
};
|
|
10844
11441
|
const nav = make("span", "knobs-diff-nav");
|
|
10845
11442
|
const prev = button("Previous file", PREV);
|
|
10846
|
-
const next = button("Next file",
|
|
11443
|
+
const next = button("Next file", NEXT);
|
|
10847
11444
|
const place = make("span", "");
|
|
10848
11445
|
nav.append(prev, place, next);
|
|
10849
11446
|
const wrapButton = button("Wrap lines", WRAP);
|
|
@@ -10864,9 +11461,8 @@ function codeDiff(container, options) {
|
|
|
10864
11461
|
const seg = make("div", "knobs-diff-seg");
|
|
10865
11462
|
seg.setAttribute("role", "radiogroup");
|
|
10866
11463
|
seg.setAttribute("aria-label", "Layout");
|
|
10867
|
-
const pill = make("i", "knobs-diff-pill");
|
|
10868
11464
|
const choice = (value, label) => {
|
|
10869
|
-
const b = make("button", "");
|
|
11465
|
+
const b = make("button", "knobs-diff-choice");
|
|
10870
11466
|
b.type = "button";
|
|
10871
11467
|
b.setAttribute("role", "radio");
|
|
10872
11468
|
b.dataset.value = value;
|
|
@@ -10875,7 +11471,7 @@ function codeDiff(container, options) {
|
|
|
10875
11471
|
};
|
|
10876
11472
|
const splitButton = choice("split", "Split");
|
|
10877
11473
|
const unifiedButton = choice("unified", "Unified");
|
|
10878
|
-
seg.append(
|
|
11474
|
+
seg.append(splitButton, unifiedButton);
|
|
10879
11475
|
if (options.lead)
|
|
10880
11476
|
head.append(options.lead);
|
|
10881
11477
|
head.append(path, stat, make("span", "knobs-diff-fill"), nav, wrapButton, seg, viewedButton);
|
|
@@ -10886,6 +11482,11 @@ function codeDiff(container, options) {
|
|
|
10886
11482
|
body.append(note, probe);
|
|
10887
11483
|
root.append(head, body);
|
|
10888
11484
|
container.append(root);
|
|
11485
|
+
const segPill = selectionPill(seg, {
|
|
11486
|
+
rows: () => [splitButton, unifiedButton],
|
|
11487
|
+
selected: () => layout === "split" ? splitButton : unifiedButton
|
|
11488
|
+
});
|
|
11489
|
+
let pilled = layout;
|
|
10889
11490
|
const fileNow = () => files.find((f) => f.name === current) ?? null;
|
|
10890
11491
|
const paintHead = () => {
|
|
10891
11492
|
const file = fileNow();
|
|
@@ -10918,6 +11519,10 @@ function codeDiff(container, options) {
|
|
|
10918
11519
|
next.disabled = at >= files.length - 1;
|
|
10919
11520
|
wrapButton.setAttribute("aria-pressed", String(wrap));
|
|
10920
11521
|
seg.dataset.value = layout;
|
|
11522
|
+
if (pilled !== layout) {
|
|
11523
|
+
pilled = layout;
|
|
11524
|
+
segPill.update();
|
|
11525
|
+
}
|
|
10921
11526
|
splitButton.setAttribute("aria-checked", String(layout === "split"));
|
|
10922
11527
|
unifiedButton.setAttribute("aria-checked", String(layout === "unified"));
|
|
10923
11528
|
splitButton.tabIndex = layout === "split" ? 0 : -1;
|
|
@@ -11752,6 +12357,7 @@ function codeDiff(container, options) {
|
|
|
11752
12357
|
dispose() {
|
|
11753
12358
|
disposed = true;
|
|
11754
12359
|
loop.stop();
|
|
12360
|
+
segPill.dispose();
|
|
11755
12361
|
sizes.disconnect();
|
|
11756
12362
|
attaching.disconnect();
|
|
11757
12363
|
resized.disconnect();
|
|
@@ -12107,7 +12713,7 @@ function diffReview(container, options) {
|
|
|
12107
12713
|
}
|
|
12108
12714
|
};
|
|
12109
12715
|
}
|
|
12110
|
-
var lib, load = () => lib ??= import("@pierre/diffs"), SYNTAX, IN, OUT, FADE3, HEIGHT, DRAWER, BLUR = 3, WRAP, PREV, UNVIEWED, VIEWED, SEARCH, CLEAR, SIDEBAR, SEPARATOR = 32;
|
|
12716
|
+
var lib, load = () => lib ??= import("@pierre/diffs"), SYNTAX, IN, OUT, FADE3, HEIGHT, DRAWER, BLUR = 3, WRAP, PREV, NEXT, UNVIEWED, VIEWED, SEARCH, CLEAR, SIDEBAR, SEPARATOR = 32;
|
|
12111
12717
|
var init_diff = __esm(() => {
|
|
12112
12718
|
init_glide();
|
|
12113
12719
|
init_motion();
|
|
@@ -12115,6 +12721,8 @@ var init_diff = __esm(() => {
|
|
|
12115
12721
|
init_diff_model();
|
|
12116
12722
|
init_look();
|
|
12117
12723
|
init_rgba();
|
|
12724
|
+
init_icons();
|
|
12725
|
+
init_selection_pill();
|
|
12118
12726
|
init_tree();
|
|
12119
12727
|
SYNTAX = { dark: "pierre-dark", light: "pierre-light" };
|
|
12120
12728
|
IN = springMotion(SPRINGS.default);
|
|
@@ -12122,13 +12730,14 @@ var init_diff = __esm(() => {
|
|
|
12122
12730
|
FADE3 = springMotion(FADE);
|
|
12123
12731
|
HEIGHT = springMotion(SPRINGS.calm);
|
|
12124
12732
|
DRAWER = springMotion(SPRINGS.calm);
|
|
12125
|
-
WRAP =
|
|
12126
|
-
PREV =
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12733
|
+
WRAP = icon("arrowUDownLeft");
|
|
12734
|
+
PREV = icon("caretLeft");
|
|
12735
|
+
NEXT = icon("caretRight");
|
|
12736
|
+
UNVIEWED = icon("circle");
|
|
12737
|
+
VIEWED = icon("checkCircle");
|
|
12738
|
+
SEARCH = icon("magnifyingGlass", { small: true });
|
|
12739
|
+
CLEAR = icon("x", { small: true });
|
|
12740
|
+
SIDEBAR = icon("sidebar");
|
|
12132
12741
|
});
|
|
12133
12742
|
|
|
12134
12743
|
// src/ui/index.ts
|
|
@@ -14629,6 +15238,11 @@ function readout(field, options = {}) {
|
|
|
14629
15238
|
dispose: () => view.dispose()
|
|
14630
15239
|
};
|
|
14631
15240
|
}
|
|
15241
|
+
|
|
15242
|
+
// src/ui/index.ts
|
|
15243
|
+
init_icons();
|
|
15244
|
+
init_selection_pill();
|
|
15245
|
+
|
|
14632
15246
|
// src/ui/tooltip.ts
|
|
14633
15247
|
init_keys();
|
|
14634
15248
|
init_layer();
|
|
@@ -18390,6 +19004,7 @@ function activity(container, options) {
|
|
|
18390
19004
|
// src/ui/picker.ts
|
|
18391
19005
|
init_motion();
|
|
18392
19006
|
init_look();
|
|
19007
|
+
init_icons();
|
|
18393
19008
|
|
|
18394
19009
|
// src/ui/picker-model.ts
|
|
18395
19010
|
function digitPick(ids, key) {
|
|
@@ -18444,7 +19059,7 @@ var CLOSE3 = springMotion(CLOSE);
|
|
|
18444
19059
|
var CARD = springMotion(SPRINGS.default);
|
|
18445
19060
|
var FADE6 = springMotion(FADE);
|
|
18446
19061
|
var DRIFT = 6;
|
|
18447
|
-
var CHECK2 =
|
|
19062
|
+
var CHECK2 = icon("check", { small: true });
|
|
18448
19063
|
function optionPicker(container, options) {
|
|
18449
19064
|
const doc = container.ownerDocument;
|
|
18450
19065
|
const win = doc.defaultView;
|
|
@@ -18947,401 +19562,15 @@ function optionPicker(container, options) {
|
|
|
18947
19562
|
// src/ui/walkthrough.ts
|
|
18948
19563
|
init_motion();
|
|
18949
19564
|
init_page_hints();
|
|
19565
|
+
init_icons();
|
|
18950
19566
|
init_look();
|
|
19567
|
+
init_selection_pill();
|
|
18951
19568
|
|
|
18952
|
-
// src/ui/walkthrough-
|
|
18953
|
-
init_compare_model();
|
|
18954
|
-
init_glide();
|
|
18955
|
-
init_look();
|
|
18956
|
-
|
|
18957
|
-
// src/ui/walkthrough-css.ts
|
|
19569
|
+
// src/ui/walkthrough-blocks.ts
|
|
18958
19570
|
init_motion();
|
|
18959
|
-
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
18963
|
-
.knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;
|
|
18964
|
-
--kw-text:var(--k-walkthrough-text,14px);--kw-measure:var(--k-walkthrough-measure,68ch);--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info));
|
|
18965
|
-
--kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-pad:16px;--kw-ink:var(--k-walkthrough-ink,#ff375f);
|
|
18966
|
-
container:knobs-wt / inline-size;display:block;width:100%;color:var(--_k-fg);font:var(--_k-weight) var(--kw-text)/1.5 var(--_k-font);text-align:left;
|
|
18967
|
-
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
18968
|
-
.knobs-walkthrough [hidden]{display:none!important}
|
|
18969
|
-
.knobs-walkthrough :is(h1,h2,h3,p){margin:0;font:inherit;letter-spacing:inherit}
|
|
18970
|
-
.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 .15s}
|
|
18971
|
-
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
18972
|
-
.knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
|
|
18973
|
-
:where(.knobs-ui) :is(.knobs-wt-btn,.knobs-wt-pick,.knobs-wt-toc-step,button.knobs-wt-stitle,.knobs-wt-chapter){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;
|
|
18974
|
-
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
18975
|
-
|
|
18976
|
-
/* ——— layout: the rail beside the column; one column where it's narrow ——— */
|
|
18977
|
-
.knobs-wt-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;align-items:start}
|
|
18978
|
-
.knobs-wt-main{display:flex;flex-direction:column;gap:56px;min-width:0;max-width:1120px;padding-bottom:40vh}
|
|
18979
|
-
@container knobs-wt (max-width:880px){.knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:0}.knobs-wt-main{gap:44px}}
|
|
18980
|
-
|
|
18981
|
-
/* ——— the page's head ——— */
|
|
18982
|
-
.knobs-wt-head{display:flex;flex-direction:column;gap:10px}
|
|
18983
|
-
.knobs-wt-title{font-size:calc(var(--kw-text) + 10px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.2;letter-spacing:-.01em!important}
|
|
18984
|
-
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
18985
|
-
.knobs-wt-meta{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2px)}
|
|
18986
|
-
.knobs-wt-meta>span{display:inline-flex;gap:6px;white-space:nowrap}
|
|
18987
|
-
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono);font-size:calc(1em - .5px)}
|
|
18988
|
-
|
|
18989
|
-
/* ——— a section: a PR or topic ——— */
|
|
18990
|
-
.knobs-wt-section{display:flex;flex-direction:column;gap:14px;min-width:0}
|
|
18991
|
-
.knobs-wt-shead{display:flex;flex-direction:column;gap:6px;scroll-margin-top:16px}
|
|
18992
|
-
.knobs-wt-kicker{display:flex;align-items:center;gap:10px;font-size:calc(var(--kw-text) - 2px);color:var(--_k-fg-3)}
|
|
18993
|
-
.knobs-wt-kicker a{font-family:var(--_k-mono);color:var(--_k-fg-2);text-decoration:none}
|
|
18994
|
-
.knobs-wt-kicker a:hover{color:var(--_k-fg)}
|
|
18995
|
-
.knobs-wt-stitle{font-size:calc(var(--kw-text) + 4px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.3}
|
|
18996
|
-
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
18997
|
-
.knobs-wt-chip{display:inline-flex;align-items:center;gap:6px;height:20px;padding:0 8px;border-radius:999px;font-size:calc(var(--kw-text) - 3px);font-weight:var(--_k-weight-label);white-space:nowrap;
|
|
18998
|
-
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
18999
|
-
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
19000
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19001
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19002
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19003
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
19004
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
19005
|
-
|
|
19006
|
-
/* ——— a step: one card ——— */
|
|
19007
|
-
.knobs-wt-step{position:relative;display:flex;flex-direction:column;gap:12px;padding:var(--kw-pad);border-radius:var(--_k-radius-panel);background:var(--kw-card);box-shadow:var(--kw-card-ring);
|
|
19008
|
-
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
19009
|
-
.knobs-walkthrough[data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
19010
|
-
.knobs-wt-step-head{display:flex;align-items:baseline;gap:10px;min-width:0}
|
|
19011
|
-
.knobs-wt-num{flex:none;font:var(--_k-weight) calc(var(--kw-text) - 2px)/1 var(--_k-mono);color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
|
|
19012
|
-
.knobs-wt-stepTitle{flex:1;min-width:0;font-weight:var(--_k-weight-title)!important}
|
|
19013
|
-
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);margin-top:-6px!important}
|
|
19014
|
-
.knobs-wt-question{font-weight:var(--_k-weight-label)!important}
|
|
19015
|
-
/* The step Kit is on: its number lights, and its choices show their keys. */
|
|
19016
|
-
.knobs-wt-step[data-current] .knobs-wt-num{color:var(--_k-fg)}
|
|
19017
|
-
.knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:12px;min-width:0}
|
|
19018
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
19019
|
-
|
|
19020
|
-
/* ——— the feed: the agent's updates and answers, newest first, compact ——— */
|
|
19021
|
-
.knobs-wt-feed{margin-top:-24px}
|
|
19022
|
-
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;max-height:260px;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column}
|
|
19023
|
-
.knobs-wt-feed-list::-webkit-scrollbar{display:none}
|
|
19024
|
-
.knobs-wt-fi{display:grid;grid-template-columns:64px 56px minmax(0,1fr) auto;gap:10px;align-items:baseline;padding:6px 0;font-size:calc(var(--kw-text) - 1px)}
|
|
19025
|
-
.knobs-wt-fi+.knobs-wt-fi{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19026
|
-
.knobs-wt-fi-when{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
19027
|
-
.knobs-wt-fi-kind{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 2.5px);font-weight:var(--_k-weight-label)}
|
|
19028
|
-
.knobs-wt-fi[data-kind="qa"] .knobs-wt-fi-kind{color:var(--kw-info)}
|
|
19029
|
-
.knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
19030
|
-
.knobs-wt-fi-q{color:var(--_k-fg-2)}
|
|
19031
|
-
.knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
|
|
19032
|
-
:where(.knobs-ui) :is(.knobs-wt-fi-step,.knobs-wt-steplink){all:revert;box-sizing:border-box;font:var(--_k-weight) calc(var(--k-walkthrough-text,14px) - 2.5px)/1 var(--_k-mono);color:var(--_k-fg-2);background:transparent;border:0;
|
|
19033
|
-
padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
|
|
19034
|
-
.knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19035
|
-
|
|
19036
|
-
/* ——— a step's sent notes ——— */
|
|
19037
|
-
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
19038
|
-
.knobs-wt-notes:empty{display:none}
|
|
19039
|
-
.knobs-wt-n{display:flex;align-items:flex-start;gap:10px;padding:6px 0;overflow:hidden;
|
|
19040
|
-
transition:height var(--kw-snappy-ms) var(--kw-snappy),opacity var(--kw-snappy-ms) var(--kw-snappy),filter var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19041
|
-
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
19042
|
-
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
19043
|
-
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19044
|
-
.knobs-wt-n-meta{flex:none;min-width:44px;padding-top:2px;color:var(--_k-fg-3);font:var(--_k-weight) calc(var(--kw-text) - 2.5px)/1.4 var(--_k-mono);font-variant-numeric:tabular-nums}
|
|
19045
|
-
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
19046
|
-
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
19047
|
-
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;font-size:calc(var(--kw-text) - 1px)}
|
|
19048
|
-
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
19049
|
-
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:6px;background:var(--_k-fill)}
|
|
19050
|
-
.knobs-wt-n-ink path{fill:none;stroke:var(--kw-ink);stroke-width:2px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
19051
|
-
|
|
19052
|
-
/* ——— the note bar, docked at the bottom of the column ——— */
|
|
19053
|
-
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;margin-top:-24px}
|
|
19054
|
-
.knobs-wt-notebar{display:flex;flex-direction:column;gap:2px;padding:6px 6px 6px 14px;border-radius:calc(var(--_k-radius-panel) + 2px);background:var(--_k-bg);
|
|
19055
|
-
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
19056
|
-
.knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap;overflow:hidden;
|
|
19057
|
-
-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)}
|
|
19058
|
-
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
19059
|
-
:where(.knobs-ui) :is(.knobs-wt-input,.knobs-wt-tool,.knobs-wt-x,.knobs-wt-back){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;
|
|
19060
|
-
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
19061
|
-
.knobs-ui .knobs-wt-input{flex:1;min-width:0;height:32px;max-height:140px;padding:6px 0;resize:none;color:var(--_k-fg);caret-color:var(--_k-accent);line-height:20px;font-size:var(--kw-text)}
|
|
19062
|
-
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
19063
|
-
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
19064
|
-
.knobs-wt-attach:empty{display:none}
|
|
19065
|
-
.knobs-wt-chip-a{display:inline-flex;align-items:center;gap:2px;height:24px;padding:0 2px 0 9px;border-radius:999px;background:var(--_k-fill-selected);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap}
|
|
19066
|
-
.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:pointer;transition:background .15s,color .15s}
|
|
19067
|
-
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19068
|
-
.knobs-wt-x svg{width:10px;height:10px}
|
|
19069
|
-
.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);
|
|
19070
|
-
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
19071
|
-
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19072
|
-
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
19073
|
-
.knobs-wt-tool svg{width:15px;height:15px}
|
|
19074
|
-
.knobs-wt-rec{font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums}
|
|
19075
|
-
.knobs-wt-rec:empty{display:none}
|
|
19076
|
-
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
19077
|
-
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
19078
|
-
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
19079
|
-
.knobs-ui .knobs-wt-back{position:absolute;left:8px;bottom:calc(100% + 8px);height:28px;padding:0 12px;border-radius:999px;background:var(--_k-bg);color:var(--_k-fg);
|
|
19080
|
-
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);font-size:calc(var(--kw-text) - 1.5px);font-weight:var(--_k-weight-label);cursor:pointer;
|
|
19081
|
-
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)}
|
|
19082
|
-
.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)}
|
|
19083
|
-
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
19084
|
-
|
|
19085
|
-
/* ——— ink over a step's media ——— */
|
|
19086
|
-
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
19087
|
-
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
19088
|
-
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
19089
|
-
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
19090
|
-
|
|
19091
|
-
/* ——— full-window: the step over the page, its media filling it; its place held in the page ——— */
|
|
19092
|
-
.knobs-wt-scrim{position:fixed;inset:0;z-index:30;background:color-mix(in srgb,var(--_k-bg-page) 82%,transparent);opacity:0;pointer-events:none}
|
|
19093
|
-
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
19094
|
-
.knobs-wt-hold-card{flex:none}
|
|
19095
|
-
.knobs-wt-step[data-full]{position:fixed;z-index:35;margin:0;overflow:hidden;overscroll-behavior:contain;padding-bottom:84px;box-shadow:var(--kw-card-ring),var(--_k-shadow-overlay);background:var(--_k-bg)}
|
|
19096
|
-
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
19097
|
-
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
19098
|
-
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
19099
|
-
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
19100
|
-
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
19101
|
-
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
19102
|
-
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
19103
|
-
|
|
19104
|
-
/* ——— a taste test: the options side by side, Kit's pick lit and the rest stepping back ——— */
|
|
19105
|
-
.knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:10px}
|
|
19106
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
19107
|
-
.knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:8px;min-width:0;padding:8px;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_ku-wash);
|
|
19108
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19109
|
-
.knobs-wt-option[data-picked]{background:color-mix(in srgb,var(--_k-accent) 12%,var(--_ku-wash))}
|
|
19110
|
-
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19111
|
-
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
19112
|
-
.knobs-ui .knobs-wt-pick{display:flex;align-items:center;gap:8px;width:100%;min-height:28px;padding:0 4px;border-radius:calc(var(--_k-radius) - 2px);cursor:pointer;color:var(--_k-fg-2);text-align:left}
|
|
19113
|
-
.knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
19114
|
-
.knobs-wt-letter{flex:none;font:var(--_k-weight-title) calc(var(--kw-text) - 1px)/1 var(--_k-font);color:var(--_k-fg)}
|
|
19115
|
-
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
19116
|
-
.knobs-wt-suggested{flex:none;font-size:calc(var(--kw-text) - 3px);color:var(--_k-fg-3)}
|
|
19117
|
-
.knobs-wt-check{flex:none;display:flex;width:18px;height:18px;align-items:center;justify-content:center;border-radius:50%;background:var(--_k-fill);color:transparent;
|
|
19118
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19119
|
-
.knobs-wt-check svg{width:12px;height:12px}
|
|
19120
|
-
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
19121
|
-
.knobs-wt-key{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;padding:0 3px;border-radius:4px;background:var(--_k-fill);color:var(--_k-fg-3);
|
|
19122
|
-
font:var(--_k-weight-label) calc(var(--kw-text) - 4px)/1 var(--_k-font);font-variant-numeric:tabular-nums;opacity:.5;transition:opacity .15s}
|
|
19123
|
-
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
19124
|
-
.knobs-wt-ocap{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 1px);padding:0 4px}
|
|
19125
|
-
|
|
19126
|
-
/* ——— the rail: progress, contents, export ——— */
|
|
19127
|
-
.knobs-wt-rail{position:sticky;top:16px;display:flex;flex-direction:column;gap:14px;max-height:calc(100vh - 32px);min-height:0;font-size:calc(var(--kw-text) - 1.5px)}
|
|
19128
|
-
.knobs-wt-progress{display:flex;flex-direction:column;gap:7px}
|
|
19129
|
-
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2);font-variant-numeric:tabular-nums}
|
|
19130
|
-
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
19131
|
-
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
19132
|
-
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
19133
|
-
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
19134
|
-
/* The contents: no box, one text spine for sections and steps (the steps' dots hang in the
|
|
19135
|
-
gutter left of it), and one pill behind the current step that springs between rows. */
|
|
19136
|
-
.knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;margin:0 -8px;padding:0 0 8px}
|
|
19137
|
-
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
19138
|
-
.knobs-wt-toc-section{display:block;padding:12px 8px 4px 26px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);font-weight:var(--_k-weight-label);white-space:nowrap;overflow:hidden;
|
|
19139
|
-
-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)}
|
|
19140
|
-
.knobs-wt-toc-section:first-of-type{padding-top:2px}
|
|
19141
|
-
.knobs-wt-toc-mark{position:absolute;left:0;right:0;top:0;height:0;border-radius:calc(var(--_k-radius) - 1px);background:var(--_ku-wash-hi);pointer-events:none;opacity:0;will-change:transform}
|
|
19142
|
-
.knobs-wt-toc-mark[data-on]{opacity:1}
|
|
19143
|
-
.knobs-walkthrough[data-settled] .knobs-wt-toc-mark{transition:opacity .15s}
|
|
19144
|
-
.knobs-ui .knobs-wt-toc-step{position:relative;display:flex;align-items:center;width:100%;text-align:left;height:26px;padding:0 8px 0 26px;color:var(--_k-fg-2);cursor:pointer;white-space:nowrap}
|
|
19145
|
-
.knobs-ui .knobs-wt-toc-step:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
19146
|
-
.knobs-wt-toc-step[aria-current="step"]{color:var(--_k-fg)}
|
|
19147
|
-
.knobs-wt-toc-label{flex:1;min-width:0;overflow:hidden;-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)}
|
|
19148
|
-
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
19149
|
-
.knobs-wt-toc-glyph{--kw-tone:var(--_k-fg-3);position:absolute;left:11px;top:50%;width:7px;height:7px;margin-top:-3.5px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--kw-tone);
|
|
19150
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19151
|
-
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
19152
|
-
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
19153
|
-
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
19154
|
-
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
19155
|
-
.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:pointer;white-space:nowrap;
|
|
19156
|
-
transition:background .15s,color .15s}
|
|
19157
|
-
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19158
|
-
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
19159
|
-
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
19160
|
-
.knobs-wt-keys{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);line-height:1.6}
|
|
19161
|
-
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
19162
|
-
/* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
|
|
19163
|
-
@container knobs-wt (max-width:880px){
|
|
19164
|
-
.knobs-wt-rail{z-index:4;flex-direction:row;align-items:center;gap:12px;max-height:none;margin:0 calc(var(--kw-pad) * -1) 20px;padding:8px var(--kw-pad);top:0;background:var(--_k-bg-page)}
|
|
19165
|
-
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
19166
|
-
.knobs-wt-step,.knobs-wt-shead{scroll-margin-top:60px}
|
|
19167
|
-
}
|
|
19168
|
-
|
|
19169
|
-
/* ——— media slots ——— */
|
|
19170
|
-
.knobs-ui.knobs-wt-slot{position:relative;min-width:0;container:knobs-wt-slot / inline-size;color:var(--_k-fg);font:var(--_k-weight) var(--k-walkthrough-text,14px)/1.5 var(--_k-font);
|
|
19171
|
-
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
19172
|
-
.knobs-wt-slot-label{display:block;margin:0 0 6px 2px;font:var(--_k-weight-label) calc(var(--k-walkthrough-text,14px) - 3px)/1.3 var(--_k-font);color:var(--_k-fg-2);letter-spacing:.04em;text-transform:uppercase}
|
|
19173
|
-
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
19174
|
-
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
19175
|
-
(92 px), and the frame strip with its gap (158 px). */
|
|
19176
|
-
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
19177
|
-
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
19178
|
-
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
19179
|
-
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
19180
|
-
.knobs-wt-frame{position:relative;width:100%;overflow:hidden;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);aspect-ratio:var(--kw-aspect,16/9)}
|
|
19181
|
-
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
19182
|
-
.knobs-wt-frame[data-natural]{aspect-ratio:auto}
|
|
19183
|
-
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
19184
|
-
.knobs-wt-code{margin:0;padding:12px 14px;max-height:420px;overflow:auto;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);color:var(--_k-fg);
|
|
19185
|
-
font:calc(var(--k-walkthrough-text,14px) - 2px)/1.55 var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
19186
|
-
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
19187
|
-
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
19188
|
-
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
19189
|
-
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
19190
|
-
.knobs-wt-metric{display:flex;flex-direction:column;gap:8px;padding:12px 14px;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
19191
|
-
.knobs-wt-mlabel{color:var(--_k-fg-2);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
|
|
19192
|
-
.knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
19193
|
-
.knobs-wt-mfrom{color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) + 2px)}
|
|
19194
|
-
.knobs-wt-mto{font-size:calc(var(--k-walkthrough-text,14px) + 12px);font-weight:var(--_k-weight-title);line-height:1}
|
|
19195
|
-
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
19196
|
-
.knobs-wt-mdelta{--kw-tone:var(--_k-fg-2);padding:1px 7px;border-radius:999px;font-size:calc(var(--k-walkthrough-text,14px) - 3px);font-weight:var(--_k-weight-label);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
19197
|
-
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19198
|
-
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19199
|
-
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
19200
|
-
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
19201
|
-
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
19202
|
-
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
19203
|
-
.knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:10px;padding:10px 14px;border-radius:calc(var(--_k-radius-panel) - 4px);background:color-mix(in srgb,var(--kw-tone) 11%,transparent);color:var(--_k-fg)}
|
|
19204
|
-
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:.62em;border-radius:50%;background:var(--kw-tone)}
|
|
19205
|
-
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19206
|
-
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19207
|
-
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19208
|
-
.knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19209
|
-
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
19210
|
-
.knobs-wt-failed{display:flex;align-items:center;justify-content:center;min-height:80px;color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
|
|
19211
|
-
|
|
19212
|
-
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
19213
|
-
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
19214
|
-
:where(.knobs-wt-history,.knobs-wt-stack,.knobs-wt-table,.knobs-wt-chapters){--kw-t:var(--k-walkthrough-text,14px);--kw-line:calc(var(--kw-t) + 6px);--kw-rail:var(--_k-border-strong)}
|
|
19215
|
-
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19216
|
-
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19217
|
-
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19218
|
-
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
19219
|
-
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
19220
|
-
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
19221
|
-
.knobs-ui .knobs-wt-tag{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-2);font:var(--_k-weight) calc(var(--kw-t) - 3px)/1 var(--_k-mono);
|
|
19222
|
-
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
19223
|
-
.knobs-ui a.knobs-wt-tag:is(:hover,:focus-visible){background:var(--_k-fill-selected);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19224
|
-
|
|
19225
|
-
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
19226
|
-
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
19227
|
-
.knobs-wt-history{--kw-hy:calc(5px + var(--kw-line) / 2);display:flex;flex-direction:column;gap:18px;font-size:calc(var(--kw-t) - 1px);line-height:var(--kw-line);color:var(--_k-fg)}
|
|
19228
|
-
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
19229
|
-
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
19230
|
-
.knobs-ui .knobs-wt-hheading{margin:0;font:var(--_k-weight-label) calc(var(--kw-t) - 3px)/1.3 var(--_k-font);letter-spacing:.04em;text-transform:uppercase;color:var(--_k-fg-2)}
|
|
19231
|
-
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
|
|
19232
|
-
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
19233
|
-
.knobs-wt-hev{display:grid;grid-template-columns:var(--kw-hw,11ch) 14px minmax(0,1fr);grid-template-areas:"when spine main";column-gap:10px;align-items:baseline;padding:5px 0}
|
|
19234
|
-
.knobs-wt-hwhen{grid-area:when;display:flex;flex-direction:column;min-width:0;font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
|
|
19235
|
-
.knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
|
|
19236
|
-
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
19237
|
-
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
19238
|
-
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
19239
|
-
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
19240
|
-
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
19241
|
-
.knobs-wt-hdot{position:absolute;left:3.5px;top:calc(var(--kw-hy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--kw-tone,var(--_k-fg-3))}
|
|
19242
|
-
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
19243
|
-
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
19244
|
-
.knobs-wt-hev[data-provenance="inferred"] .knobs-wt-hdot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--kw-tone,var(--_k-fg-3))}
|
|
19245
|
-
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
19246
|
-
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
19247
|
-
.knobs-wt-prov{padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-3);font:var(--_k-weight) calc(var(--kw-t) - 3.5px)/18px var(--_k-mono);white-space:nowrap}
|
|
19248
|
-
.knobs-wt-hev[data-provenance="inferred"] .knobs-wt-prov{background:transparent;color:var(--_k-warn);outline:1px dashed color-mix(in oklch,var(--_k-warn) 50%,transparent);outline-offset:-1px}
|
|
19249
|
-
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19250
|
-
@container knobs-wt-slot (max-width:520px){
|
|
19251
|
-
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
19252
|
-
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
19253
|
-
}
|
|
19254
|
-
|
|
19255
|
-
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
19256
|
-
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
19257
|
-
.knobs-wt-stack{--kw-spt:7px;--kw-spb:7px;--kw-sy:calc(var(--kw-spt) + var(--kw-line) / 2);display:flex;flex-direction:column;font-size:calc(var(--kw-t) - 1px);line-height:var(--kw-line);color:var(--_k-fg)}
|
|
19258
|
-
.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);
|
|
19259
|
-
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
19260
|
-
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
19261
|
-
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
19262
|
-
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19263
|
-
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
19264
|
-
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
19265
|
-
.knobs-wt-lane:is([data-rail="pass"],[data-rail="tee"],[data-down])::before{content:"";position:absolute;left:7.5px;top:0;bottom:0;width:1px;background:var(--kw-rail)}
|
|
19266
|
-
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
19267
|
-
.knobs-wt-lane:is([data-rail="tee"],[data-rail="end"])::after{content:"";position:absolute;left:7.5px;top:0;width:13px;height:calc(var(--kw-sy) + .5px);border:solid var(--kw-rail);border-width:0 0 1px 1px;border-bottom-left-radius:6px}
|
|
19268
|
-
.knobs-wt-lane[data-rail="node"]::after{content:"";position:absolute;left:4.5px;top:calc(var(--kw-sy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--_k-fg-3)}
|
|
19269
|
-
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
19270
|
-
.knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
19271
|
-
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
19272
|
-
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
19273
|
-
.knobs-wt-sord{font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3);white-space:nowrap}
|
|
19274
|
-
.knobs-ui .knobs-wt-spr{font:var(--_k-weight-label) calc(var(--kw-t) - 1.5px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2);text-decoration:none;white-space:nowrap}
|
|
19275
|
-
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
19276
|
-
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
19277
|
-
.knobs-ui button.knobs-wt-stitle{cursor:pointer;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
|
|
19278
|
-
.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)}
|
|
19279
|
-
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19280
|
-
.knobs-wt-smeta{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 12px;font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
|
|
19281
|
-
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
19282
|
-
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
19283
|
-
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
19284
|
-
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
19285
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
19286
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19287
|
-
@container knobs-wt-slot (max-width:520px){
|
|
19288
|
-
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
19289
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
19290
|
-
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
19291
|
-
}
|
|
19292
|
-
|
|
19293
|
-
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
19294
|
-
(the top one under the head), and thin bars show on hover. */
|
|
19295
|
-
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
19296
|
-
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
19297
|
-
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
19298
|
-
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
19299
|
-
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
19300
|
-
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
19301
|
-
.knobs-wt-table:is(:hover,:focus-visible){scrollbar-color:color-mix(in oklch,var(--_k-fg) 28%,transparent) transparent;transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19302
|
-
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
19303
|
-
@supports (animation-timeline:scroll()){
|
|
19304
|
-
.knobs-wt-table{animation:knobs-fade-a linear both,knobs-fade-b linear both,kw-fade-l linear both,kw-fade-r linear both;animation-duration:auto;
|
|
19305
|
-
animation-timeline:scroll(self block),scroll(self block),scroll(self inline),scroll(self inline);animation-range:0 24px,calc(100% - 24px) 100%,0 8px,calc(100% - 8px) 100%;
|
|
19306
|
-
--kw-table-mask-y:linear-gradient(to bottom,#000 var(--kw-thead,0px),rgb(0 0 0/var(--knobs-fade-a)) var(--kw-thead,0px),#000 calc(var(--kw-thead,0px) + 20px),#000 calc(100% - 20px),rgb(0 0 0/var(--knobs-fade-b)));
|
|
19307
|
-
--kw-table-mask-x:linear-gradient(to right,rgb(0 0 0/var(--kw-fade-l)),#000 24px,#000 calc(100% - 24px),rgb(0 0 0/var(--kw-fade-r)));
|
|
19308
|
-
-webkit-mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);-webkit-mask-composite:source-in;mask-composite:intersect}
|
|
19309
|
-
}
|
|
19310
|
-
.knobs-wt-table table{width:100%;margin:0;border-collapse:separate;border-spacing:0;font-size:calc(var(--kw-t) - 1.5px);line-height:1.45;font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
|
|
19311
|
-
.knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px)}
|
|
19312
|
-
.knobs-wt-table th{position:sticky;top:0;padding:0 12px 7px;text-align:left;vertical-align:bottom;font-weight:var(--_k-weight-label);font-size:calc(var(--kw-t) - 2.5px);color:var(--_k-fg-3);white-space:nowrap;
|
|
19313
|
-
background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
19314
|
-
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
19315
|
-
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
19316
|
-
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
19317
|
-
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
19318
|
-
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
19319
|
-
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
19320
|
-
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
19321
|
-
.knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:calc(var(--kw-t) - 2.5px);color:var(--_k-fg);white-space:nowrap}
|
|
19322
|
-
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
19323
|
-
.knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
|
|
19324
|
-
.knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
|
|
19325
|
-
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
19326
|
-
|
|
19327
|
-
/* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
|
|
19328
|
-
.knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
|
|
19329
|
-
.knobs-wt-chapter-mark{position:absolute;left:0;top:0;width:0;border-radius:calc(var(--_k-radius) + 2px);background:var(--_k-fill-selected);opacity:0;pointer-events:none;will-change:transform;
|
|
19330
|
-
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
|
|
19331
|
-
.knobs-wt-chapter-mark[data-on]{opacity:1}
|
|
19332
|
-
.knobs-ui .knobs-wt-chapter{position:relative;display:inline-flex;align-items:baseline;gap:6px;height:26px;padding:0 10px 0 8px;border-radius:calc(var(--_k-radius) + 2px);color:var(--_k-fg-2);
|
|
19333
|
-
font-size:calc(var(--kw-t) - 2px);line-height:26px;white-space:nowrap;cursor:pointer;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
19334
|
-
.knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19335
|
-
.knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
|
|
19336
|
-
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
|
|
19337
|
-
.knobs-wt-chapter-time{font:var(--_k-weight) calc(var(--kw-t) - 3px)/1 var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
|
|
19338
|
-
.knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
|
|
19339
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
19340
|
-
`;
|
|
19341
|
-
|
|
19342
|
-
// src/ui/walkthrough-blocks.ts
|
|
19343
|
-
init_motion();
|
|
19344
|
-
init_look();
|
|
19571
|
+
init_icons();
|
|
19572
|
+
init_look();
|
|
19573
|
+
init_selection_pill();
|
|
19345
19574
|
|
|
19346
19575
|
// src/ui/walkthrough-model.ts
|
|
19347
19576
|
var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
|
|
@@ -19548,7 +19777,15 @@ function fillTable(m) {
|
|
|
19548
19777
|
out[k] = fillCell(v);
|
|
19549
19778
|
return out;
|
|
19550
19779
|
});
|
|
19551
|
-
|
|
19780
|
+
const primary = columns.find((c) => c.key === m.primary)?.key ?? columns[0]?.key ?? "";
|
|
19781
|
+
return {
|
|
19782
|
+
kind: "table",
|
|
19783
|
+
columns,
|
|
19784
|
+
rows,
|
|
19785
|
+
...m.caption ? { caption: m.caption } : {},
|
|
19786
|
+
stack: m.stack ?? "auto",
|
|
19787
|
+
primary
|
|
19788
|
+
};
|
|
19552
19789
|
}
|
|
19553
19790
|
function fillChapters(chapters) {
|
|
19554
19791
|
const id = uniqueIds();
|
|
@@ -19621,6 +19858,8 @@ function normalizeWalkthrough(doc) {
|
|
|
19621
19858
|
...step.caption ? { caption: step.caption } : {},
|
|
19622
19859
|
...step.question ? { question: step.question } : {},
|
|
19623
19860
|
media: list.map((m) => fillMedia(m, doc.base)),
|
|
19861
|
+
columns: Math.max(1, Math.min(3, Math.round(step.columns ?? 1))),
|
|
19862
|
+
...step.more?.trim() && list.length > 1 ? { more: step.more.trim() } : {},
|
|
19624
19863
|
options,
|
|
19625
19864
|
ask
|
|
19626
19865
|
};
|
|
@@ -19632,6 +19871,7 @@ function normalizeWalkthrough(doc) {
|
|
|
19632
19871
|
id,
|
|
19633
19872
|
title: s.title,
|
|
19634
19873
|
...link ? { link } : {},
|
|
19874
|
+
...typeof s.kicker === "string" && s.kicker.trim() ? { kicker: s.kicker.trim() } : {},
|
|
19635
19875
|
...s.status ? { status: s.status } : {},
|
|
19636
19876
|
...s.summary ? { summary: s.summary } : {},
|
|
19637
19877
|
steps: own
|
|
@@ -19642,14 +19882,25 @@ function normalizeWalkthrough(doc) {
|
|
|
19642
19882
|
value
|
|
19643
19883
|
}));
|
|
19644
19884
|
const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
|
|
19885
|
+
const extra = (x) => ({
|
|
19886
|
+
...x.status?.trim() ? { status: x.status.trim() } : {},
|
|
19887
|
+
trail: (x.trail ?? []).filter((t) => typeof t === "string" && t.trim())
|
|
19888
|
+
});
|
|
19645
19889
|
const feed = sortFeed([
|
|
19646
|
-
...(doc.updates ?? []).map((u) => ({
|
|
19890
|
+
...(doc.updates ?? []).map((u) => ({
|
|
19891
|
+
kind: "update",
|
|
19892
|
+
at: parseAt(u.at),
|
|
19893
|
+
text: u.text,
|
|
19894
|
+
step: stepRef(u.step),
|
|
19895
|
+
...extra(u)
|
|
19896
|
+
})),
|
|
19647
19897
|
...(doc.qa ?? []).map((x) => ({
|
|
19648
19898
|
kind: "qa",
|
|
19649
19899
|
at: parseAt(x.at),
|
|
19650
19900
|
text: x.a,
|
|
19651
19901
|
q: x.q,
|
|
19652
|
-
step: stepRef(x.step)
|
|
19902
|
+
step: stepRef(x.step),
|
|
19903
|
+
...extra(x)
|
|
19653
19904
|
}))
|
|
19654
19905
|
]);
|
|
19655
19906
|
return {
|
|
@@ -19662,10 +19913,32 @@ function normalizeWalkthrough(doc) {
|
|
|
19662
19913
|
id: slug(v),
|
|
19663
19914
|
label: label(v)
|
|
19664
19915
|
})),
|
|
19665
|
-
sections,
|
|
19916
|
+
sections: withKickers(sections, doc.sections, doc.kickers),
|
|
19666
19917
|
steps
|
|
19667
19918
|
};
|
|
19668
19919
|
}
|
|
19920
|
+
var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
|
|
19921
|
+
function withKickers(sections, source, kickers = "pr") {
|
|
19922
|
+
if (kickers === false)
|
|
19923
|
+
return [...sections];
|
|
19924
|
+
const noun = typeof kickers === "object" ? kickers.noun.trim() : "PR";
|
|
19925
|
+
const counted = typeof kickers === "object" ? sections : sections.filter((s) => s.link && isPullRequest(s.link.href));
|
|
19926
|
+
return sections.map((s, i) => {
|
|
19927
|
+
const own = source[i]?.kicker;
|
|
19928
|
+
if (own !== undefined || s.kicker)
|
|
19929
|
+
return s;
|
|
19930
|
+
const at = counted.indexOf(s);
|
|
19931
|
+
return at < 0 ? s : { ...s, kicker: `${noun} ${at + 1} of ${counted.length}`.trim() };
|
|
19932
|
+
});
|
|
19933
|
+
}
|
|
19934
|
+
function tableStacks(stack, room, natural) {
|
|
19935
|
+
if (stack !== "auto")
|
|
19936
|
+
return stack === "always";
|
|
19937
|
+
return room > 0 && natural > room + 1;
|
|
19938
|
+
}
|
|
19939
|
+
function noteBarReserve(bar, inset, gap) {
|
|
19940
|
+
return Math.max(0, Math.ceil(bar)) + inset + gap;
|
|
19941
|
+
}
|
|
19669
19942
|
function parseAt(at) {
|
|
19670
19943
|
if (!at)
|
|
19671
19944
|
return null;
|
|
@@ -19950,6 +20223,9 @@ function feedbackMarkdown(fb, verdicts) {
|
|
|
19950
20223
|
`;
|
|
19951
20224
|
}
|
|
19952
20225
|
var escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
20226
|
+
function plainMarkdown(text) {
|
|
20227
|
+
return text.replace(/\[([^\]\n]+)\]\([^)\s]+\)/g, "$1").replace(/`([^`\n]+)`/g, "$1").replace(/\*\*([^*\n]+)\*\*/g, "$1").replace(/(^|[^*\w])\*([^*\n]+)\*(?!\w)/g, "$1$2").replace(/\s+/g, " ").trim();
|
|
20228
|
+
}
|
|
19953
20229
|
function inlineMarkdown(text) {
|
|
19954
20230
|
const codes = [];
|
|
19955
20231
|
let s = text.replace(/`([^`\n]+)`/g, (_, c) => {
|
|
@@ -19970,6 +20246,10 @@ function inlineMarkdown(text) {
|
|
|
19970
20246
|
}
|
|
19971
20247
|
|
|
19972
20248
|
// src/ui/walkthrough-blocks.ts
|
|
20249
|
+
var GLYPH = {
|
|
20250
|
+
go: icon("caretRight", { small: true }),
|
|
20251
|
+
caret: icon("caretRight", { small: true })
|
|
20252
|
+
};
|
|
19973
20253
|
var el = (doc, tag, cls) => {
|
|
19974
20254
|
const n = doc.createElement(tag);
|
|
19975
20255
|
if (cls)
|
|
@@ -19999,9 +20279,10 @@ function stepButton(doc, ref, steps) {
|
|
|
19999
20279
|
const s = ref && steps?.find(ref);
|
|
20000
20280
|
if (!s || !steps)
|
|
20001
20281
|
return null;
|
|
20002
|
-
const b =
|
|
20282
|
+
const b = el(doc, "button", "knobs-wt-steplink");
|
|
20283
|
+
b.innerHTML = GLYPH.go;
|
|
20003
20284
|
b.type = "button";
|
|
20004
|
-
b.title = `Go to
|
|
20285
|
+
b.title = `Go to “${s.title}”`;
|
|
20005
20286
|
b.setAttribute("aria-label", b.title);
|
|
20006
20287
|
b.addEventListener("click", (e) => {
|
|
20007
20288
|
e.stopPropagation();
|
|
@@ -20126,7 +20407,7 @@ function mountStack(host, m, steps) {
|
|
|
20126
20407
|
if (target && steps) {
|
|
20127
20408
|
const title = text(doc, "button", "knobs-wt-stitle", it.title);
|
|
20128
20409
|
title.type = "button";
|
|
20129
|
-
title.title = `Go to
|
|
20410
|
+
title.title = `Go to “${target.title}”`;
|
|
20130
20411
|
title.addEventListener("click", (e) => {
|
|
20131
20412
|
e.stopPropagation();
|
|
20132
20413
|
steps.go(target.key);
|
|
@@ -20181,175 +20462,775 @@ function delta(doc, d) {
|
|
|
20181
20462
|
s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
|
|
20182
20463
|
return s;
|
|
20183
20464
|
}
|
|
20184
|
-
function
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20188
|
-
|
|
20189
|
-
|
|
20190
|
-
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
|
|
20196
|
-
|
|
20197
|
-
|
|
20198
|
-
|
|
20199
|
-
|
|
20200
|
-
|
|
20201
|
-
|
|
20202
|
-
|
|
20203
|
-
|
|
20204
|
-
|
|
20205
|
-
|
|
20206
|
-
|
|
20207
|
-
|
|
20208
|
-
|
|
20209
|
-
|
|
20210
|
-
|
|
20211
|
-
|
|
20212
|
-
|
|
20213
|
-
|
|
20214
|
-
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
|
|
20218
|
-
|
|
20219
|
-
|
|
20220
|
-
|
|
20221
|
-
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
|
|
20253
|
-
|
|
20254
|
-
|
|
20255
|
-
|
|
20256
|
-
|
|
20257
|
-
|
|
20258
|
-
|
|
20259
|
-
|
|
20260
|
-
|
|
20261
|
-
}
|
|
20262
|
-
|
|
20263
|
-
|
|
20465
|
+
function cellContent(doc, into, cell, steps) {
|
|
20466
|
+
let content;
|
|
20467
|
+
if (cell.badge) {
|
|
20468
|
+
content = link(doc, "knobs-wt-chip", cell.text, cell.href);
|
|
20469
|
+
content.dataset.tone = cell.badge;
|
|
20470
|
+
} else {
|
|
20471
|
+
const inner = cell.code ? text(doc, "code", "", cell.text) : null;
|
|
20472
|
+
if (cell.href) {
|
|
20473
|
+
content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
|
|
20474
|
+
if (inner)
|
|
20475
|
+
content.append(inner);
|
|
20476
|
+
} else
|
|
20477
|
+
content = inner ?? text(doc, "span", "", cell.text);
|
|
20478
|
+
if (cell.tone) {
|
|
20479
|
+
content.classList.add("knobs-wt-ctone");
|
|
20480
|
+
content.dataset.tone = cell.tone;
|
|
20481
|
+
}
|
|
20482
|
+
}
|
|
20483
|
+
into.append(content);
|
|
20484
|
+
const go = stepButton(doc, cell.step, steps);
|
|
20485
|
+
if (go)
|
|
20486
|
+
into.append(go);
|
|
20487
|
+
}
|
|
20488
|
+
var cellAttrs = (td, c) => {
|
|
20489
|
+
td.dataset.align = c.align;
|
|
20490
|
+
if (c.mono)
|
|
20491
|
+
td.dataset.mono = "";
|
|
20492
|
+
};
|
|
20493
|
+
function mountTable(host, m, steps) {
|
|
20494
|
+
const doc = host.ownerDocument;
|
|
20495
|
+
const win = doc.defaultView;
|
|
20496
|
+
const box = el(doc, "div", "knobs-wt-tablebox");
|
|
20497
|
+
const scroller = el(doc, "div", "knobs-wt-table");
|
|
20498
|
+
const table = el(doc, "table");
|
|
20499
|
+
if (m.caption)
|
|
20500
|
+
table.append(text(doc, "caption", "", m.caption));
|
|
20501
|
+
const head = el(doc, "thead");
|
|
20502
|
+
const hr = el(doc, "tr");
|
|
20503
|
+
for (const c of m.columns) {
|
|
20504
|
+
const th = text(doc, "th", "", c.label);
|
|
20505
|
+
th.scope = "col";
|
|
20506
|
+
th.dataset.align = c.align;
|
|
20507
|
+
hr.append(th);
|
|
20508
|
+
}
|
|
20509
|
+
head.append(hr);
|
|
20510
|
+
const body = el(doc, "tbody");
|
|
20511
|
+
for (const r of m.rows) {
|
|
20512
|
+
const tr = el(doc, "tr");
|
|
20513
|
+
for (const c of m.columns) {
|
|
20514
|
+
const td = el(doc, "td");
|
|
20515
|
+
cellAttrs(td, c);
|
|
20516
|
+
const cell = r[c.key];
|
|
20517
|
+
if (cell) {
|
|
20518
|
+
if (cell.text.length > 40 && !c.mono && !cell.code)
|
|
20519
|
+
td.dataset.long = "";
|
|
20520
|
+
cellContent(doc, td, cell, steps);
|
|
20521
|
+
}
|
|
20522
|
+
tr.append(td);
|
|
20523
|
+
}
|
|
20524
|
+
body.append(tr);
|
|
20525
|
+
}
|
|
20526
|
+
table.append(head, body);
|
|
20527
|
+
scroller.append(table);
|
|
20528
|
+
const stack = el(doc, "div", "knobs-wt-tstack");
|
|
20529
|
+
stack.setAttribute("role", "list");
|
|
20530
|
+
if (m.caption)
|
|
20531
|
+
stack.setAttribute("aria-label", m.caption);
|
|
20532
|
+
const primary = m.columns.find((c) => c.key === m.primary) ?? m.columns[0];
|
|
20533
|
+
for (const r of m.rows) {
|
|
20534
|
+
const item = el(doc, "div", "knobs-wt-trow");
|
|
20535
|
+
item.setAttribute("role", "listitem");
|
|
20536
|
+
const title = el(doc, "div", "knobs-wt-ttitle");
|
|
20537
|
+
if (primary) {
|
|
20538
|
+
cellAttrs(title, primary);
|
|
20539
|
+
const cell = r[primary.key];
|
|
20540
|
+
if (cell)
|
|
20541
|
+
cellContent(doc, title, cell, steps);
|
|
20542
|
+
}
|
|
20543
|
+
const line = el(doc, "div", "knobs-wt-tline");
|
|
20544
|
+
line.append(title);
|
|
20545
|
+
const badges = el(doc, "div", "knobs-wt-tbadges");
|
|
20546
|
+
for (const c of m.columns) {
|
|
20547
|
+
const cell = r[c.key];
|
|
20548
|
+
if (c !== primary && cell?.badge)
|
|
20549
|
+
cellContent(doc, badges, cell, steps);
|
|
20550
|
+
}
|
|
20551
|
+
if (badges.childNodes.length)
|
|
20552
|
+
line.append(badges);
|
|
20553
|
+
item.append(line);
|
|
20554
|
+
const terms = el(doc, "dl", "knobs-wt-tterms");
|
|
20555
|
+
for (const c of m.columns) {
|
|
20556
|
+
if (c === primary)
|
|
20557
|
+
continue;
|
|
20558
|
+
const cell = r[c.key];
|
|
20559
|
+
if (!cell || cell.text === "" || cell.badge)
|
|
20560
|
+
continue;
|
|
20561
|
+
const dd = el(doc, "dd");
|
|
20562
|
+
cellAttrs(dd, c);
|
|
20563
|
+
dd.removeAttribute("data-align");
|
|
20564
|
+
cellContent(doc, dd, cell, steps);
|
|
20565
|
+
terms.append(text(doc, "dt", "", c.label), dd);
|
|
20566
|
+
}
|
|
20567
|
+
if (terms.childNodes.length)
|
|
20568
|
+
item.append(terms);
|
|
20569
|
+
stack.append(item);
|
|
20570
|
+
}
|
|
20571
|
+
if (m.caption)
|
|
20572
|
+
stack.append(text(doc, "p", "knobs-wt-tcaption", m.caption));
|
|
20573
|
+
box.append(scroller, stack);
|
|
20574
|
+
host.append(box);
|
|
20575
|
+
let natural = 0;
|
|
20576
|
+
const measureNatural = () => {
|
|
20577
|
+
if (!box.isConnected)
|
|
20578
|
+
return 0;
|
|
20579
|
+
const was = box.dataset.stacked;
|
|
20580
|
+
delete box.dataset.stacked;
|
|
20581
|
+
box.dataset.measure = "";
|
|
20582
|
+
const w = table.getBoundingClientRect().width;
|
|
20583
|
+
delete box.dataset.measure;
|
|
20584
|
+
if (was !== undefined)
|
|
20585
|
+
box.dataset.stacked = was;
|
|
20586
|
+
return w;
|
|
20587
|
+
};
|
|
20588
|
+
const measure = () => {
|
|
20589
|
+
if (!natural)
|
|
20590
|
+
natural = measureNatural();
|
|
20591
|
+
const stacked = tableStacks(m.stack, box.clientWidth, natural);
|
|
20592
|
+
box.toggleAttribute("data-stacked", stacked);
|
|
20593
|
+
scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
|
|
20594
|
+
const scrolls = !stacked && (scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1);
|
|
20595
|
+
if (scrolls) {
|
|
20596
|
+
scroller.tabIndex = 0;
|
|
20597
|
+
scroller.setAttribute("role", "region");
|
|
20598
|
+
scroller.setAttribute("aria-label", m.caption ?? "Table");
|
|
20599
|
+
} else {
|
|
20600
|
+
scroller.removeAttribute("tabindex");
|
|
20601
|
+
scroller.removeAttribute("role");
|
|
20602
|
+
scroller.removeAttribute("aria-label");
|
|
20603
|
+
}
|
|
20604
|
+
};
|
|
20605
|
+
if (m.stack === "always")
|
|
20606
|
+
box.dataset.stacked = "";
|
|
20607
|
+
const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
|
|
20608
|
+
ro?.observe(box);
|
|
20609
|
+
measure();
|
|
20610
|
+
doc.fonts?.ready.then(() => {
|
|
20611
|
+
if (!box.isConnected)
|
|
20612
|
+
return;
|
|
20613
|
+
natural = 0;
|
|
20614
|
+
measure();
|
|
20615
|
+
});
|
|
20616
|
+
return {
|
|
20617
|
+
dispose: () => {
|
|
20618
|
+
ro?.disconnect();
|
|
20619
|
+
box.remove();
|
|
20620
|
+
},
|
|
20621
|
+
context: () => ({ kind: "table" })
|
|
20622
|
+
};
|
|
20623
|
+
}
|
|
20624
|
+
function chapterPills(host, chapters, io) {
|
|
20625
|
+
const doc = host.ownerDocument;
|
|
20626
|
+
const list = el(doc, "div", "knobs-wt-chapters");
|
|
20627
|
+
list.setAttribute("role", "group");
|
|
20628
|
+
list.setAttribute("aria-label", "Chapters");
|
|
20629
|
+
let at = -2;
|
|
20630
|
+
const rows = chapters.map((c, i) => {
|
|
20631
|
+
const b = el(doc, "button", "knobs-wt-chapter");
|
|
20632
|
+
b.type = "button";
|
|
20633
|
+
b.append(text(doc, "span", "knobs-wt-chapter-n", String(i + 1)));
|
|
20634
|
+
b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
|
|
20635
|
+
b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
|
|
20636
|
+
b.addEventListener("click", () => {
|
|
20637
|
+
io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
|
|
20638
|
+
io.seek(c.start);
|
|
20639
|
+
select(i);
|
|
20640
|
+
});
|
|
20641
|
+
list.append(b);
|
|
20642
|
+
return b;
|
|
20643
|
+
});
|
|
20644
|
+
host.append(list);
|
|
20645
|
+
const pill = selectionPill(list, {
|
|
20646
|
+
selected: () => rows[at] ?? null,
|
|
20647
|
+
rows: () => rows
|
|
20648
|
+
});
|
|
20649
|
+
const select = (i) => {
|
|
20650
|
+
if (i === at)
|
|
20651
|
+
return;
|
|
20652
|
+
at = i;
|
|
20653
|
+
rows.forEach((b, k) => k === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
20654
|
+
pill.update();
|
|
20655
|
+
};
|
|
20656
|
+
const sync = () => select(chapterAt(chapters, io.now()));
|
|
20657
|
+
sync();
|
|
20658
|
+
return {
|
|
20659
|
+
sync,
|
|
20660
|
+
get current() {
|
|
20661
|
+
return chapters[at] ?? null;
|
|
20662
|
+
},
|
|
20663
|
+
dispose() {
|
|
20664
|
+
pill.dispose();
|
|
20665
|
+
list.remove();
|
|
20666
|
+
}
|
|
20667
|
+
};
|
|
20668
|
+
}
|
|
20669
|
+
function disclosure(host, options) {
|
|
20670
|
+
const doc = host.ownerDocument;
|
|
20671
|
+
const win = doc.defaultView;
|
|
20672
|
+
let open = options.open === true;
|
|
20673
|
+
const root = el(doc, "div", "knobs-wt-disc");
|
|
20674
|
+
const toggle = el(doc, "button", "knobs-wt-disc-toggle");
|
|
20675
|
+
toggle.type = "button";
|
|
20676
|
+
toggle.innerHTML = GLYPH.caret;
|
|
20677
|
+
toggle.append(text(doc, "span", "", options.label));
|
|
20678
|
+
if (options.count !== undefined)
|
|
20679
|
+
toggle.append(text(doc, "span", "knobs-wt-disc-count", String(options.count)));
|
|
20680
|
+
const viewport = el(doc, "div", "knobs-wt-disc-body");
|
|
20681
|
+
const content = el(doc, "div", "knobs-wt-disc-content");
|
|
20682
|
+
content.append(options.content);
|
|
20683
|
+
viewport.append(content);
|
|
20684
|
+
root.append(toggle, viewport);
|
|
20685
|
+
host.append(root);
|
|
20686
|
+
const STATE = springMotion(SPRINGS.default);
|
|
20687
|
+
const h = new Spring(0, STATE.omega, STATE.zeta, 0.25);
|
|
20688
|
+
let full = 0;
|
|
20689
|
+
const paint = (moving) => {
|
|
20690
|
+
const k = full > 0 ? Math.max(0, Math.min(1, h.x / full)) : open ? 1 : 0;
|
|
20691
|
+
viewport.style.height = !moving && open ? "" : `${Math.max(0, h.x).toFixed(2)}px`;
|
|
20692
|
+
viewport.toggleAttribute("data-moving", moving);
|
|
20693
|
+
content.style.opacity = (open ? Math.min(1, k * 1.25) : Math.max(0, k * 1.5 - 0.5)).toFixed(3);
|
|
20694
|
+
};
|
|
20695
|
+
const loop = frameLoop(win, (dt) => {
|
|
20696
|
+
h.step(dt);
|
|
20697
|
+
const moving = !h.resting;
|
|
20698
|
+
paint(moving);
|
|
20699
|
+
return moving;
|
|
20700
|
+
});
|
|
20701
|
+
const sync = () => {
|
|
20702
|
+
root.toggleAttribute("data-open", open);
|
|
20703
|
+
toggle.setAttribute("aria-expanded", String(open));
|
|
20704
|
+
viewport.inert = !open;
|
|
20705
|
+
};
|
|
20706
|
+
sync();
|
|
20707
|
+
h.snap(0);
|
|
20708
|
+
paint(false);
|
|
20709
|
+
if (open) {
|
|
20710
|
+
viewport.style.height = "";
|
|
20711
|
+
content.style.opacity = "1";
|
|
20712
|
+
}
|
|
20713
|
+
const api = {
|
|
20714
|
+
element: root,
|
|
20715
|
+
get open() {
|
|
20716
|
+
return open;
|
|
20717
|
+
},
|
|
20718
|
+
toggle(next = !open) {
|
|
20719
|
+
if (next === open)
|
|
20720
|
+
return;
|
|
20721
|
+
open = next;
|
|
20722
|
+
sync();
|
|
20723
|
+
full = content.offsetHeight;
|
|
20724
|
+
if (reducedMotion(win)) {
|
|
20725
|
+
loop.stop();
|
|
20726
|
+
h.snap(open ? full : 0);
|
|
20727
|
+
viewport.style.height = open ? "" : "0px";
|
|
20728
|
+
content.style.opacity = open ? "1" : "0";
|
|
20729
|
+
return;
|
|
20730
|
+
}
|
|
20731
|
+
if (h.resting)
|
|
20732
|
+
h.snap(open ? 0 : full);
|
|
20733
|
+
h.set(open ? full : 0);
|
|
20734
|
+
paint(true);
|
|
20735
|
+
loop.wake();
|
|
20736
|
+
},
|
|
20737
|
+
dispose() {
|
|
20738
|
+
loop.stop();
|
|
20739
|
+
root.remove();
|
|
20740
|
+
}
|
|
20741
|
+
};
|
|
20742
|
+
toggle.addEventListener("click", () => api.toggle());
|
|
20743
|
+
return api;
|
|
20744
|
+
}
|
|
20745
|
+
|
|
20746
|
+
// src/ui/walkthrough-media.ts
|
|
20747
|
+
init_compare_model();
|
|
20748
|
+
init_glide();
|
|
20749
|
+
init_icons();
|
|
20750
|
+
init_look();
|
|
20751
|
+
|
|
20752
|
+
// src/ui/walkthrough-css.ts
|
|
20753
|
+
init_motion();
|
|
20754
|
+
var snappy3 = springCss(SPRINGS.snappy);
|
|
20755
|
+
var calm = springCss(SPRINGS.calm);
|
|
20756
|
+
var state = springCss(SPRINGS.default);
|
|
20757
|
+
var quick = springCss(FADE);
|
|
20758
|
+
var fade2 = "-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 1.5em),transparent)";
|
|
20759
|
+
var walkthroughCss = `
|
|
20760
|
+
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
20761
|
+
.knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;--kw-state:${state.easing};--kw-state-ms:${state.duration}ms;--kw-quick:${quick.easing};--kw-quick-ms:${quick.duration}ms;
|
|
20762
|
+
--kw-measure:var(--k-walkthrough-measure,68ch);--kw-width:var(--k-walkthrough-width,680px);--kw-rail-w:220px;--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info));
|
|
20763
|
+
--kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-under:var(--_k-bg-page);--kw-ink:var(--k-walkthrough-ink,#ff375f);--kw-strong:var(--_k-weight-label);
|
|
20764
|
+
container:knobs-wt / inline-size;display:block;width:100%;color:var(--_k-fg);font:var(--_k-weight) var(--_k-type-body)/var(--_k-leading-body) var(--_k-font);font-variant-numeric:tabular-nums;text-align:left;
|
|
20765
|
+
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
20766
|
+
.knobs-walkthrough [hidden]{display:none!important}
|
|
20767
|
+
/* (0,0,1): a host's element rules stop here, and every class rule below wins over it. */
|
|
20768
|
+
:where(.knobs-walkthrough) :is(h1,h2,h3,p,ol,ul,dl,dd){margin:0;font:inherit;letter-spacing:inherit}
|
|
20769
|
+
.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 .15s}
|
|
20770
|
+
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
20771
|
+
.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)}
|
|
20772
|
+
: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;
|
|
20773
|
+
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
20774
|
+
|
|
20775
|
+
/* ——— layout: a readable column, centred, with a slim contents rail beside it (right by default);
|
|
20776
|
+
one column where it's narrow ——— */
|
|
20777
|
+
.knobs-wt-layout{display:grid;grid-template-columns:minmax(0,var(--kw-width)) var(--kw-rail-w);justify-content:center;gap:var(--_k-space-column);align-items:start}
|
|
20778
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-main{grid-column:1;grid-row:1}
|
|
20779
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-rail{grid-column:2;grid-row:1}
|
|
20780
|
+
.knobs-walkthrough[data-rail="left"] .knobs-wt-layout{grid-template-columns:var(--kw-rail-w) minmax(0,var(--kw-width))}
|
|
20781
|
+
.knobs-walkthrough[data-rail="none"] .knobs-wt-layout{grid-template-columns:minmax(0,var(--kw-width))}
|
|
20782
|
+
.knobs-wt-main{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0;padding-bottom:12px}
|
|
20783
|
+
/* The intro, the updates and each section: a section's room apart, the hairline in the middle. */
|
|
20784
|
+
.knobs-wt-flow{display:flex;flex-direction:column;gap:calc(var(--_k-space-section) / 2);min-width:0}
|
|
20785
|
+
.knobs-wt-flow>*+*{padding-top:calc(var(--_k-space-section) / 2);box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
20786
|
+
@container knobs-wt (max-width:940px){.knobs-walkthrough .knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:var(--_k-space-title)}
|
|
20787
|
+
.knobs-walkthrough[data-rail] .knobs-wt-layout>*{grid-column:auto;grid-row:auto}}
|
|
20788
|
+
|
|
20789
|
+
/* ——— one line of facts: small, faint, joined by ·, its trailing edge fading ——— */
|
|
20790
|
+
.knobs-wt-metaline{display:flex;align-items:baseline;gap:var(--_k-space-inside);min-width:0;overflow:hidden;white-space:nowrap;font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3);${fade2}}
|
|
20791
|
+
.knobs-wt-metaline>*{flex:none}
|
|
20792
|
+
.knobs-wt-metaline>*+*::before{content:"·";margin-right:var(--_k-space-inside);color:var(--_k-fg-3)}
|
|
20793
|
+
.knobs-walkthrough .knobs-wt-metaline a{display:inline-flex;align-items:baseline;color:inherit;text-decoration:none;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
20794
|
+
.knobs-walkthrough .knobs-wt-metaline a:hover{color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
20795
|
+
.knobs-wt-metaline svg{align-self:center;width:12px;height:12px;margin-left:2px}
|
|
20796
|
+
.knobs-wt-kicker-lead{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
20797
|
+
.knobs-wt-metaline [data-status="on"]{color:var(--_k-fg)}
|
|
20798
|
+
.knobs-wt-metaline [data-status="warn"]{color:var(--_k-warn)}
|
|
20799
|
+
|
|
20800
|
+
/* ——— the page's head ——— */
|
|
20801
|
+
.knobs-wt-head{display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
20802
|
+
.knobs-wt-title{font-size:var(--_k-type-title)!important;line-height:var(--_k-leading-title);font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
20803
|
+
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
20804
|
+
.knobs-wt-meta{display:flex;flex-wrap:wrap;gap:var(--_k-space-inside) var(--_k-space-title);color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
20805
|
+
.knobs-wt-meta>span{display:inline-flex;gap:var(--_k-space-inside);white-space:nowrap}
|
|
20806
|
+
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono)}
|
|
20807
|
+
|
|
20808
|
+
/* ——— a section: a PR or topic. Its kicker leads the meta line; its title outranks the page's ——— */
|
|
20809
|
+
.knobs-wt-section{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
20810
|
+
.knobs-wt-sintro{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0}
|
|
20811
|
+
.knobs-wt-shead{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0;scroll-margin-top:16px}
|
|
20812
|
+
.knobs-wt-heading{font-size:var(--_k-type-heading)!important;line-height:var(--_k-leading-heading);font-weight:var(--kw-strong)!important;letter-spacing:-.01em!important;text-wrap:balance}
|
|
20813
|
+
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
20814
|
+
.knobs-wt-chip{display:inline-flex;align-items:center;gap:6px;height:20px;padding:0 8px;border-radius:var(--_k-round);font-size:var(--_k-type-small);font-weight:var(--kw-strong);white-space:nowrap;
|
|
20815
|
+
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
20816
|
+
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
20817
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
20818
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
20819
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
20820
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
20821
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
20822
|
+
|
|
20823
|
+
/* ——— a step: on the page by default, a group's room between steps with a hairline in the middle;
|
|
20824
|
+
or (cards) one card each, the one surface its pieces sit on ——— */
|
|
20825
|
+
.knobs-walkthrough:not([data-cards]) .knobs-wt-step:not([data-full]){padding:0;border-radius:0;background:transparent;box-shadow:none}
|
|
20826
|
+
.knobs-walkthrough:not([data-cards]) .knobs-wt-step+.knobs-wt-step::before{content:"";position:absolute;left:0;right:0;top:calc(var(--_k-space-group) / -2);height:1px;background:var(--_k-border-subtle);pointer-events:none}
|
|
20827
|
+
.knobs-wt-step{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-title);padding:var(--_k-pad-card);border-radius:var(--_k-radius-panel);background:var(--kw-card);box-shadow:var(--kw-card-ring);
|
|
20828
|
+
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
20829
|
+
.knobs-walkthrough[data-cards]{--kw-under:var(--kw-card)}
|
|
20830
|
+
.knobs-walkthrough[data-cards][data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
20831
|
+
.knobs-wt-step-head{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
20832
|
+
.knobs-wt-stepTitle{min-width:0;font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
20833
|
+
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
20834
|
+
.knobs-wt-question{font-weight:var(--kw-strong)!important;max-width:var(--kw-measure)}
|
|
20835
|
+
.knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:var(--_k-space-group) var(--_k-space-column);min-width:0}
|
|
20836
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
20837
|
+
|
|
20838
|
+
/* ——— the feed: updates and answers, newest first. Tight inside an item (4 / 8 / 4), a group's
|
|
20839
|
+
room between items with the hairline in the middle; no boxes ——— */
|
|
20840
|
+
.knobs-wt-feed{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0;scroll-margin-top:16px}
|
|
20841
|
+
.knobs-wt-feed-head{display:flex;align-items:baseline;gap:var(--_k-space-sibling)}
|
|
20842
|
+
.knobs-wt-feed-title{font-weight:var(--kw-strong)!important}
|
|
20843
|
+
.knobs-wt-feed-count{font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}
|
|
20844
|
+
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
20845
|
+
.knobs-wt-fi{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
20846
|
+
.knobs-wt-fi+.knobs-wt-fi::before{content:"";position:absolute;left:0;right:0;top:calc(var(--_k-space-group) / -2);height:1px;background:var(--_k-border-subtle)}
|
|
20847
|
+
.knobs-wt-fi-q,.knobs-wt-fi-a{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
20848
|
+
.knobs-wt-fi-ask{max-width:var(--kw-measure);color:var(--_k-fg);font-weight:var(--kw-strong);text-wrap:pretty}
|
|
20849
|
+
.knobs-wt-fi-text{max-width:var(--kw-measure);color:var(--_k-fg);text-wrap:pretty}
|
|
20850
|
+
.knobs-wt-fi-answer{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
20851
|
+
: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:pointer;outline:none;
|
|
20852
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
20853
|
+
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
20854
|
+
:where(.knobs-ui) .knobs-wt-steplink{all:revert;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0 0 0 2px;padding:0;vertical-align:-5px;border:0;
|
|
20855
|
+
border-radius:calc(var(--_k-radius) / 2);background:transparent;color:var(--_k-fg-3);cursor:pointer;outline:none;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
20856
|
+
.knobs-ui .knobs-wt-steplink:is(:hover,:focus-visible){background:var(--_k-fill);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
20857
|
+
.knobs-wt-steplink svg{width:12px;height:12px}
|
|
20858
|
+
|
|
20859
|
+
/* ——— a disclosure: a small faint toggle with a caret, no fill. The body's height springs (in
|
|
20860
|
+
script) and its content fades in place, top-anchored, under a soft bottom mask ——— */
|
|
20861
|
+
.knobs-wt-disc{display:flex;flex-direction:column;min-width:0}
|
|
20862
|
+
.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:pointer;
|
|
20863
|
+
border-radius:calc(var(--_k-radius) / 2);transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
20864
|
+
.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)}
|
|
20865
|
+
.knobs-ui .knobs-wt-disc-toggle:focus-visible{box-shadow:0 0 0 2px var(--_k-focus)}
|
|
20866
|
+
.knobs-wt-disc-toggle svg{flex:none;width:12px;height:12px;transition:rotate var(--kw-state-ms) var(--kw-state)}
|
|
20867
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-toggle svg{rotate:90deg}
|
|
20868
|
+
.knobs-wt-disc-count{color:var(--_k-fg-3)}
|
|
20869
|
+
.knobs-wt-disc-body{overflow:hidden}
|
|
20870
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-body:not([data-moving]){overflow:visible}
|
|
20871
|
+
.knobs-wt-disc-body[data-moving]{-webkit-mask-image:linear-gradient(#000 calc(100% - 16px),transparent);mask-image:linear-gradient(#000 calc(100% - 16px),transparent)}
|
|
20872
|
+
.knobs-wt-disc-content{padding-top:var(--_k-space-inside)}
|
|
20873
|
+
/* A trail sits on the toggle's label edge: faint lines, the time trailing. */
|
|
20874
|
+
.knobs-wt-trail{display:flex;flex-direction:column;list-style:none;padding:0 0 0 calc(12px + var(--_k-space-inside));font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3);min-width:0}
|
|
20875
|
+
.knobs-wt-trail li{display:flex;align-items:baseline;gap:var(--_k-space-sibling);min-width:0;white-space:nowrap}
|
|
20876
|
+
.knobs-wt-trail-text{flex:0 1 auto;min-width:0;overflow:hidden;${fade2}}
|
|
20877
|
+
.knobs-wt-trail-at{flex:none}
|
|
20878
|
+
|
|
20879
|
+
/* ——— a step's sent notes ——— */
|
|
20880
|
+
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
20881
|
+
.knobs-wt-notes:empty{display:none}
|
|
20882
|
+
.knobs-wt-n{display:flex;align-items:flex-start;gap:var(--_k-space-sibling);padding:6px 0;overflow:hidden;
|
|
20883
|
+
transition:height var(--kw-snappy-ms) var(--kw-snappy),opacity var(--kw-snappy-ms) var(--kw-snappy),filter var(--kw-snappy-ms) var(--kw-snappy)}
|
|
20884
|
+
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
20885
|
+
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
20886
|
+
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
20887
|
+
.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)}
|
|
20888
|
+
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
20889
|
+
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
20890
|
+
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
20891
|
+
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
20892
|
+
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
|
|
20893
|
+
.knobs-wt-n-ink path{fill:none;stroke:var(--kw-ink);stroke-width:2px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
20894
|
+
|
|
20895
|
+
/* ——— the note bar, docked at the bottom of the column. It holds its own place at the page's end
|
|
20896
|
+
(so the last step stays clear of it), and script keeps its height as the scroller's
|
|
20897
|
+
scroll-padding-bottom ——— */
|
|
20898
|
+
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;display:grid;pointer-events:none}
|
|
20899
|
+
.knobs-wt-dock>*{pointer-events:auto}
|
|
20900
|
+
.knobs-wt-dock>:is(.knobs-wt-notebar,.knobs-wt-launch){grid-area:1/1}
|
|
20901
|
+
.knobs-wt-dock[data-mode="docked"]>.knobs-wt-launch{display:none}
|
|
20902
|
+
/* Collapsed: the launcher and the bar swap in place, a quick fade with a little scale and blur
|
|
20903
|
+
from the launcher's corner; the exit is the shorter. */
|
|
20904
|
+
: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);
|
|
20905
|
+
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:pointer;outline:none;transform-origin:100% 100%;
|
|
20906
|
+
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)}
|
|
20907
|
+
.knobs-ui .knobs-wt-launch:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
20908
|
+
.knobs-ui .knobs-wt-launch:focus-visible{box-shadow:var(--_k-focus-ring)}
|
|
20909
|
+
.knobs-wt-launch svg{width:16px;height:16px}
|
|
20910
|
+
.knobs-wt-launch kbd{font:inherit;font-weight:var(--_k-weight);color:var(--_k-fg-3)}
|
|
20911
|
+
.knobs-wt-dock[data-mode="collapsed"] .knobs-wt-notebar{transform-origin:100% 100%;transition:opacity var(--kw-quick-ms) var(--kw-quick),scale var(--kw-quick-ms) var(--kw-quick),filter var(--kw-quick-ms) var(--kw-quick)}
|
|
20912
|
+
.knobs-wt-dock[data-mode="collapsed"]:not([data-open])>.knobs-wt-notebar,.knobs-wt-dock[data-mode="collapsed"][data-open]>.knobs-wt-launch{opacity:0;scale:.98;filter:blur(3px);pointer-events:none;
|
|
20913
|
+
transition-duration:calc(var(--kw-quick-ms) * .8)}
|
|
20914
|
+
.knobs-wt-notebar{display:flex;flex-direction:column;gap:2px;padding:6px 6px 6px 14px;border-radius:calc(var(--_k-radius-panel) + 2px);background:var(--_k-bg);
|
|
20915
|
+
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
20916
|
+
.knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small);white-space:nowrap;overflow:hidden;${fade2}}
|
|
20917
|
+
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
20918
|
+
:where(.knobs-ui) :is(.knobs-wt-input,.knobs-wt-tool,.knobs-wt-x,.knobs-wt-back){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;
|
|
20919
|
+
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
20920
|
+
.knobs-ui .knobs-wt-input{flex:1;min-width:0;height:32px;max-height:140px;padding:6px 0;resize:none;color:var(--_k-fg);caret-color:var(--_k-accent);line-height:var(--_k-leading-body);font-size:var(--_k-type-body)}
|
|
20921
|
+
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
20922
|
+
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
20923
|
+
.knobs-wt-attach:empty{display:none}
|
|
20924
|
+
.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}
|
|
20925
|
+
.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:pointer;transition:background .15s,color .15s}
|
|
20926
|
+
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
20927
|
+
.knobs-wt-x svg{width:12px;height:12px}
|
|
20928
|
+
.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);
|
|
20929
|
+
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
20930
|
+
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
20931
|
+
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
20932
|
+
.knobs-wt-tool svg{width:16px;height:16px}
|
|
20933
|
+
.knobs-wt-rec{font-size:var(--_k-type-small)}
|
|
20934
|
+
.knobs-wt-rec:empty{display:none}
|
|
20935
|
+
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
20936
|
+
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
20937
|
+
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
20938
|
+
.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;
|
|
20939
|
+
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:pointer;
|
|
20940
|
+
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)}
|
|
20941
|
+
.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)}
|
|
20942
|
+
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
20943
|
+
.knobs-wt-back svg{flex:none;width:12px;height:12px}
|
|
20944
|
+
.knobs-wt-back-label{min-width:0;overflow:hidden;white-space:nowrap;${fade2}}
|
|
20945
|
+
|
|
20946
|
+
/* ——— ink over a step's media ——— */
|
|
20947
|
+
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
20948
|
+
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
20949
|
+
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
20950
|
+
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
20951
|
+
|
|
20952
|
+
/* ——— full-window: the step over the page above the note bar, its media filling it; its place held
|
|
20953
|
+
in the page. The one raised surface ——— */
|
|
20954
|
+
.knobs-wt-scrim{position:fixed;inset:0;z-index:30;background:color-mix(in srgb,var(--_k-bg-page) 82%,transparent);opacity:0;pointer-events:none}
|
|
20955
|
+
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
20956
|
+
.knobs-wt-hold-card{flex:none}
|
|
20957
|
+
.knobs-wt-step[data-full]{position:fixed;z-index:35;margin:0;overflow:hidden;overscroll-behavior:contain;padding:var(--_k-pad-card);border-radius:var(--_k-radius-panel);box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay);background:var(--_k-bg)}
|
|
20958
|
+
.knobs-wt-step[data-full]::before{content:none}
|
|
20959
|
+
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
20960
|
+
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
20961
|
+
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
20962
|
+
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
20963
|
+
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
20964
|
+
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
20965
|
+
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
20966
|
+
|
|
20967
|
+
/* ——— a taste test: the options side by side, Kit's pick checked and the rest stepping back. On
|
|
20968
|
+
the step's card, so no fill of their own ——— */
|
|
20969
|
+
.knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:var(--_k-space-group) var(--_k-space-column)}
|
|
20970
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
20971
|
+
.knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
20972
|
+
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
20973
|
+
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
20974
|
+
.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:pointer;color:var(--_k-fg-2);text-align:left;
|
|
20975
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
20976
|
+
.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)}
|
|
20977
|
+
.knobs-wt-letter{flex:none;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
20978
|
+
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
20979
|
+
.knobs-wt-suggested{flex:none;font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
20980
|
+
.knobs-wt-check{flex:none;display:flex;width:18px;height:18px;align-items:center;justify-content:center;border-radius:50%;background:var(--_k-fill);color:transparent;
|
|
20981
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
20982
|
+
.knobs-wt-check svg{width:12px;height:12px}
|
|
20983
|
+
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
20984
|
+
.knobs-wt-key{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;padding:0 3px;border-radius:4px;background:var(--_k-fill);color:var(--_k-fg-3);
|
|
20985
|
+
font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);opacity:.5;transition:opacity .15s}
|
|
20986
|
+
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
20987
|
+
.knobs-wt-ocap{color:var(--_k-fg-2);max-width:var(--kw-measure)}
|
|
20988
|
+
|
|
20989
|
+
/* ——— the rail: progress, contents, export ——— */
|
|
20990
|
+
.knobs-wt-rail{position:sticky;top:16px;display:flex;flex-direction:column;gap:var(--_k-space-title);max-height:calc(100vh - 32px);min-height:0;font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
20991
|
+
.knobs-wt-progress{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
20992
|
+
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2)}
|
|
20993
|
+
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
20994
|
+
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
20995
|
+
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
20996
|
+
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
20997
|
+
/* The contents: rows centred on one spine, title rows (32 high, the control radius) and the
|
|
20998
|
+
steps under them (20 high, half of it), bled out so their text sits on the rail's edge; the
|
|
20999
|
+
selection pill slides to the current step, and base rows never brighten for being current. */
|
|
21000
|
+
.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:0 calc(var(--_k-space-sibling) * -1);padding:0 0 8px}
|
|
21001
|
+
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
21002
|
+
.knobs-wt-toc-group{display:flex;flex-direction:column;min-width:0}
|
|
21003
|
+
.knobs-ui .knobs-wt-toc-row{position:relative;display:grid;grid-template-columns:var(--kw-toc-n,0px) minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;flex:none;width:100%;height:32px;
|
|
21004
|
+
padding:0 var(--_k-space-sibling);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(--kw-strong);text-align:left;white-space:nowrap;cursor:pointer;
|
|
21005
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21006
|
+
.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);color:var(--_k-fg-3)}
|
|
21007
|
+
.knobs-wt-toc[data-bare] .knobs-wt-toc-row{grid-template-columns:minmax(0,1fr) auto}
|
|
21008
|
+
.knobs-wt-toc[data-bare] .knobs-wt-toc-n{display:none}
|
|
21009
|
+
.knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21010
|
+
.knobs-ui .knobs-wt-toc-sub:is(:hover,:focus-visible){color:var(--_k-fg-2)}
|
|
21011
|
+
.knobs-ui .knobs-wt-toc-row:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
21012
|
+
.knobs-wt-toc-n,.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)}
|
|
21013
|
+
.knobs-wt-toc-row[data-active] .knobs-wt-toc-n{color:var(--_k-fg-2)}
|
|
21014
|
+
.knobs-wt-toc-label{min-width:0;overflow:hidden;${fade2}}
|
|
21015
|
+
.knobs-pick-copy .knobs-wt-toc-n,.knobs-pick-copy .knobs-wt-toc-end{color:var(--_k-fg-2)}
|
|
21016
|
+
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
21017
|
+
.knobs-wt-toc-glyph{--kw-tone:var(--_k-fg-3);display:block;width:6px;height:6px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--kw-tone);
|
|
21018
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
21019
|
+
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
21020
|
+
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
21021
|
+
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
21022
|
+
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
21023
|
+
.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:pointer;white-space:nowrap;
|
|
21024
|
+
transition:background .15s,color .15s}
|
|
21025
|
+
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
21026
|
+
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
21027
|
+
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
21028
|
+
.knobs-wt-keys{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
21029
|
+
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
21030
|
+
/* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
|
|
21031
|
+
@container knobs-wt (max-width:940px){
|
|
21032
|
+
.knobs-wt-rail{z-index:4;flex-direction:row;align-items:center;gap:var(--_k-space-title);max-height:none;margin:0 calc(var(--_k-pad-page) * -1);padding:8px var(--_k-pad-page);top:0;background:var(--_k-bg-page)}
|
|
21033
|
+
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
21034
|
+
.knobs-wt-step,.knobs-wt-shead,.knobs-wt-feed{scroll-margin-top:60px}
|
|
21035
|
+
}
|
|
21036
|
+
|
|
21037
|
+
/* ——— media slots. Only a picture's frame (a quiet fill while it loads or letterboxes) and a code
|
|
21038
|
+
block (a well) are bounded; a metric, a callout, a table, a stack and a history sit on the page,
|
|
21039
|
+
set apart by space, hairlines and their own colours. On a card (.knobs-surface) code drops its
|
|
21040
|
+
well for hairlines, so nothing draws a fill and a ring of its own there ——— */
|
|
21041
|
+
.knobs-ui.knobs-wt-slot{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0;container:knobs-wt-slot / inline-size;color:var(--_k-fg);
|
|
21042
|
+
font:var(--_k-weight) var(--_k-type-body)/var(--_k-leading-body) var(--_k-font);font-variant-numeric:tabular-nums;--kw-measure:var(--k-walkthrough-measure,68ch);
|
|
21043
|
+
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
21044
|
+
.knobs-wt-slot-label{display:block;font:var(--_k-weight-label) var(--_k-type-label)/var(--_k-leading-label) var(--_k-font);color:var(--_k-fg-2)}
|
|
21045
|
+
.knobs-wt-body{min-width:0}
|
|
21046
|
+
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
21047
|
+
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
21048
|
+
(92 px), and the frame strip with its gap (158 px). */
|
|
21049
|
+
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
21050
|
+
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
21051
|
+
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
21052
|
+
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
21053
|
+
.knobs-wt-frame{position:relative;width:100%;overflow:hidden;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);aspect-ratio:var(--kw-aspect,16/9)}
|
|
21054
|
+
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
21055
|
+
.knobs-wt-frame[data-natural]{aspect-ratio:auto;background:transparent}
|
|
21056
|
+
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
21057
|
+
.knobs-wt-code{margin:0;padding:var(--_k-pad-card);max-height:420px;overflow:auto;border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill);color:var(--_k-fg);
|
|
21058
|
+
font:var(--_k-type-label)/var(--_k-leading-body) var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
21059
|
+
.knobs-surface .knobs-wt-code{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)}
|
|
21060
|
+
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
21061
|
+
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
21062
|
+
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
21063
|
+
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
21064
|
+
.knobs-wt-metric{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
21065
|
+
.knobs-wt-mlabel{color:var(--_k-fg-2)}
|
|
21066
|
+
.knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--_k-space-sibling);font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
21067
|
+
.knobs-wt-mfrom{color:var(--_k-fg-3);font-size:var(--_k-type-title);line-height:var(--_k-leading-title)}
|
|
21068
|
+
.knobs-wt-mto{font-size:var(--_k-type-heading);line-height:var(--_k-leading-heading);font-weight:var(--_k-weight-label)}
|
|
21069
|
+
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
21070
|
+
.knobs-wt-mdelta{--kw-tone:var(--_k-fg-2);font-size:var(--_k-type-small);font-weight:var(--_k-weight-label);color:var(--kw-tone)}
|
|
21071
|
+
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21072
|
+
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21073
|
+
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
21074
|
+
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
21075
|
+
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
21076
|
+
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
21077
|
+
.knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:var(--_k-space-sibling);max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
21078
|
+
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:7px;border-radius:50%;background:var(--kw-tone)}
|
|
21079
|
+
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21080
|
+
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
21081
|
+
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21082
|
+
.knobs-wt-text{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
21083
|
+
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
21084
|
+
.knobs-wt-failed{display:flex;align-items:center;justify-content:center;min-height:80px;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21085
|
+
|
|
21086
|
+
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
21087
|
+
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
21088
|
+
:where(.knobs-wt-history,.knobs-wt-stack,.knobs-wt-tablebox,.knobs-wt-chapters){--kw-line:var(--_k-leading-body);--kw-rail:var(--_k-border-strong)}
|
|
21089
|
+
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21090
|
+
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
21091
|
+
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21092
|
+
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
21093
|
+
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
21094
|
+
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
21095
|
+
.knobs-ui .knobs-wt-tag{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-2);font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);
|
|
21096
|
+
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
21097
|
+
.knobs-ui a.knobs-wt-tag:is(:hover,:focus-visible){background:var(--_k-fill-selected);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21098
|
+
|
|
21099
|
+
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
21100
|
+
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
21101
|
+
.knobs-wt-history{--kw-hy:calc(5px + var(--kw-line) / 2);display:flex;flex-direction:column;gap:18px;font-size:var(--_k-type-body);line-height:var(--kw-line);color:var(--_k-fg)}
|
|
21102
|
+
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
21103
|
+
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
21104
|
+
.knobs-ui .knobs-wt-hheading{margin:0;font:var(--_k-weight-label) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);letter-spacing:.04em;text-transform:uppercase;color:var(--_k-fg-2)}
|
|
21105
|
+
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:var(--_k-type-small);font-variant-numeric:tabular-nums}
|
|
21106
|
+
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
21107
|
+
.knobs-wt-hev{display:grid;grid-template-columns:var(--kw-hw,11ch) 14px minmax(0,1fr);grid-template-areas:"when spine main";column-gap:10px;align-items:baseline;padding:5px 0}
|
|
21108
|
+
.knobs-wt-hwhen{grid-area:when;display:flex;flex-direction:column;min-width:0;font:var(--_k-weight) var(--_k-type-label)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
|
|
21109
|
+
.knobs-wt-hage{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
21110
|
+
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
21111
|
+
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
21112
|
+
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
21113
|
+
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
21114
|
+
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
21115
|
+
.knobs-wt-hdot{position:absolute;left:3.5px;top:calc(var(--kw-hy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--kw-tone,var(--_k-fg-3))}
|
|
21116
|
+
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
21117
|
+
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
21118
|
+
.knobs-wt-hev[data-provenance="inferred"] .knobs-wt-hdot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--kw-tone,var(--_k-fg-3))}
|
|
21119
|
+
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
21120
|
+
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
21121
|
+
.knobs-wt-prov{padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-3);font:var(--_k-weight) var(--_k-type-small)/18px var(--_k-mono);white-space:nowrap}
|
|
21122
|
+
.knobs-wt-hev[data-provenance="inferred"] .knobs-wt-prov{background:transparent;color:var(--_k-warn);outline:1px dashed color-mix(in oklch,var(--_k-warn) 50%,transparent);outline-offset:-1px}
|
|
21123
|
+
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
21124
|
+
@container knobs-wt-slot (max-width:520px){
|
|
21125
|
+
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
21126
|
+
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
21127
|
+
}
|
|
21128
|
+
|
|
21129
|
+
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
21130
|
+
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
21131
|
+
.knobs-wt-stack{--kw-spt:7px;--kw-spb:7px;--kw-sy:calc(var(--kw-spt) + var(--kw-line) / 2);display:flex;flex-direction:column;font-size:var(--_k-type-body);line-height:var(--kw-line);color:var(--_k-fg)}
|
|
21132
|
+
.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);
|
|
21133
|
+
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
21134
|
+
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
21135
|
+
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
21136
|
+
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21137
|
+
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
21138
|
+
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
21139
|
+
.knobs-wt-lane:is([data-rail="pass"],[data-rail="tee"],[data-down])::before{content:"";position:absolute;left:7.5px;top:0;bottom:0;width:1px;background:var(--kw-rail)}
|
|
21140
|
+
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
21141
|
+
.knobs-wt-lane:is([data-rail="tee"],[data-rail="end"])::after{content:"";position:absolute;left:7.5px;top:0;width:13px;height:calc(var(--kw-sy) + .5px);border:solid var(--kw-rail);border-width:0 0 1px 1px;border-bottom-left-radius:6px}
|
|
21142
|
+
.knobs-wt-lane[data-rail="node"]::after{content:"";position:absolute;left:4.5px;top:calc(var(--kw-sy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--_k-fg-3)}
|
|
21143
|
+
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
21144
|
+
.knobs-wt-trunk{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
21145
|
+
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
21146
|
+
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
21147
|
+
.knobs-wt-sord{font:var(--_k-weight) var(--_k-type-label)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3);white-space:nowrap}
|
|
21148
|
+
.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}
|
|
21149
|
+
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
21150
|
+
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
21151
|
+
.knobs-ui button.knobs-wt-stitle{cursor:pointer;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
|
|
21152
|
+
.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)}
|
|
21153
|
+
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
21154
|
+
.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)}
|
|
21155
|
+
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
21156
|
+
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
21157
|
+
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
21158
|
+
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
21159
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
21160
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
21161
|
+
@container knobs-wt-slot (max-width:520px){
|
|
21162
|
+
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
21163
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
21164
|
+
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
20264
21165
|
}
|
|
20265
|
-
|
|
20266
|
-
|
|
20267
|
-
|
|
20268
|
-
|
|
20269
|
-
|
|
20270
|
-
|
|
20271
|
-
|
|
20272
|
-
|
|
20273
|
-
|
|
20274
|
-
|
|
20275
|
-
|
|
20276
|
-
|
|
20277
|
-
|
|
20278
|
-
|
|
20279
|
-
|
|
20280
|
-
|
|
20281
|
-
|
|
20282
|
-
|
|
20283
|
-
|
|
20284
|
-
|
|
20285
|
-
|
|
20286
|
-
|
|
20287
|
-
|
|
20288
|
-
|
|
20289
|
-
|
|
20290
|
-
|
|
20291
|
-
|
|
20292
|
-
|
|
20293
|
-
|
|
20294
|
-
|
|
20295
|
-
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
|
|
20299
|
-
|
|
20300
|
-
|
|
20301
|
-
draw();
|
|
20302
|
-
return !x.resting || !y.resting || !w.resting;
|
|
20303
|
-
});
|
|
20304
|
-
let at = -2;
|
|
20305
|
-
let shown = false;
|
|
20306
|
-
const place = (snap) => {
|
|
20307
|
-
const p = pills[at];
|
|
20308
|
-
if (!p) {
|
|
20309
|
-
mark.removeAttribute("data-on");
|
|
20310
|
-
pills.forEach((b) => b.removeAttribute("aria-current"));
|
|
20311
|
-
shown = false;
|
|
20312
|
-
return;
|
|
20313
|
-
}
|
|
20314
|
-
pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
20315
|
-
const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
|
|
20316
|
-
if (snap || !shown || reducedMotion(win)) {
|
|
20317
|
-
x.snap(to[0]);
|
|
20318
|
-
y.snap(to[1]);
|
|
20319
|
-
w.snap(to[2]);
|
|
20320
|
-
draw();
|
|
20321
|
-
} else {
|
|
20322
|
-
x.set(to[0]);
|
|
20323
|
-
y.set(to[1]);
|
|
20324
|
-
w.set(to[2]);
|
|
20325
|
-
loop.wake();
|
|
20326
|
-
}
|
|
20327
|
-
mark.style.height = `${p.offsetHeight}px`;
|
|
20328
|
-
mark.dataset.on = "";
|
|
20329
|
-
shown = true;
|
|
20330
|
-
};
|
|
20331
|
-
const sync = () => {
|
|
20332
|
-
const next = chapterAt(chapters, io.now());
|
|
20333
|
-
if (next === at)
|
|
20334
|
-
return;
|
|
20335
|
-
at = next;
|
|
20336
|
-
place(false);
|
|
20337
|
-
};
|
|
20338
|
-
sync();
|
|
20339
|
-
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
|
|
20340
|
-
ro?.observe(bar);
|
|
20341
|
-
return {
|
|
20342
|
-
sync,
|
|
20343
|
-
get current() {
|
|
20344
|
-
return chapters[at] ?? null;
|
|
20345
|
-
},
|
|
20346
|
-
dispose() {
|
|
20347
|
-
loop.stop();
|
|
20348
|
-
ro?.disconnect();
|
|
20349
|
-
bar.remove();
|
|
20350
|
-
}
|
|
20351
|
-
};
|
|
21166
|
+
|
|
21167
|
+
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
21168
|
+
(the top one under the head), and thin bars show on hover. */
|
|
21169
|
+
/* Too narrow for its columns, each row becomes a block: its primary cell titling the rest as term
|
|
21170
|
+
and value, the blocks parted by hairlines. Scrolling sideways is the last resort (stack: never). */
|
|
21171
|
+
.knobs-wt-tablebox{min-width:0}
|
|
21172
|
+
.knobs-wt-tablebox[data-measure] table{width:min-content}
|
|
21173
|
+
.knobs-wt-tstack{display:none;flex-direction:column;min-width:0}
|
|
21174
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-table{display:none}
|
|
21175
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-tstack{display:flex}
|
|
21176
|
+
.knobs-wt-trow{display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0;padding-block:var(--_k-space-title);box-shadow:inset 0 -1px 0 var(--_k-border-subtle)}
|
|
21177
|
+
.knobs-wt-trow:first-child{padding-top:0}
|
|
21178
|
+
.knobs-wt-trow:last-of-type{padding-bottom:0;box-shadow:none}
|
|
21179
|
+
.knobs-wt-tline{display:flex;align-items:baseline;justify-content:space-between;gap:var(--_k-space-title);min-width:0}
|
|
21180
|
+
.knobs-wt-tbadges{flex:none;display:flex;align-items:center;gap:var(--_k-space-inside)}
|
|
21181
|
+
.knobs-wt-ttitle{flex:1 1 auto;min-width:0;color:var(--_k-fg);font-weight:var(--_k-weight-label);overflow-wrap:anywhere}
|
|
21182
|
+
.knobs-wt-ttitle[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label)}
|
|
21183
|
+
.knobs-wt-tterms{display:grid;grid-template-columns:minmax(6ch,max-content) minmax(0,1fr);gap:var(--_k-space-inside) var(--_k-space-title);min-width:0}
|
|
21184
|
+
.knobs-wt-tterms dt{color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21185
|
+
.knobs-wt-tterms dd{min-width:0;color:var(--_k-fg-2);overflow-wrap:anywhere}
|
|
21186
|
+
.knobs-wt-tterms dd[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg)}
|
|
21187
|
+
.knobs-wt-tcaption{padding-top:var(--_k-space-sibling);color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21188
|
+
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
21189
|
+
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
21190
|
+
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
21191
|
+
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
21192
|
+
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
21193
|
+
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
21194
|
+
.knobs-wt-table:is(:hover,:focus-visible){scrollbar-color:color-mix(in oklch,var(--_k-fg) 28%,transparent) transparent;transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21195
|
+
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
21196
|
+
@supports (animation-timeline:scroll()){
|
|
21197
|
+
.knobs-wt-table{animation:knobs-fade-a linear both,knobs-fade-b linear both,kw-fade-l linear both,kw-fade-r linear both;animation-duration:auto;
|
|
21198
|
+
animation-timeline:scroll(self block),scroll(self block),scroll(self inline),scroll(self inline);animation-range:0 24px,calc(100% - 24px) 100%,0 8px,calc(100% - 8px) 100%;
|
|
21199
|
+
--kw-table-mask-y:linear-gradient(to bottom,#000 var(--kw-thead,0px),rgb(0 0 0/var(--knobs-fade-a)) var(--kw-thead,0px),#000 calc(var(--kw-thead,0px) + 20px),#000 calc(100% - 20px),rgb(0 0 0/var(--knobs-fade-b)));
|
|
21200
|
+
--kw-table-mask-x:linear-gradient(to right,rgb(0 0 0/var(--kw-fade-l)),#000 24px,#000 calc(100% - 24px),rgb(0 0 0/var(--kw-fade-r)));
|
|
21201
|
+
-webkit-mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);-webkit-mask-composite:source-in;mask-composite:intersect}
|
|
20352
21202
|
}
|
|
21203
|
+
.knobs-wt-table table{width:100%;margin:0;border-collapse:separate;border-spacing:0;font-size:var(--_k-type-body);line-height:var(--_k-leading-body);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
|
|
21204
|
+
.knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21205
|
+
.knobs-wt-table th{position:sticky;top:0;padding:0 12px 7px;text-align:left;vertical-align:bottom;font-weight:var(--_k-weight-label);font-size:var(--_k-type-small);color:var(--_k-fg-3);white-space:nowrap;
|
|
21206
|
+
background:var(--kw-under,var(--_k-pane-bg));box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
21207
|
+
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
21208
|
+
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
21209
|
+
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
21210
|
+
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
21211
|
+
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
21212
|
+
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
21213
|
+
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
21214
|
+
.knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg);white-space:nowrap}
|
|
21215
|
+
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
21216
|
+
.knobs-ui :is(.knobs-wt-table,.knobs-wt-tstack) a.knobs-wt-chip{text-decoration:none}
|
|
21217
|
+
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
21218
|
+
|
|
21219
|
+
/* Chapters: a readout list under a video or compare: number, label, start; the selection pill
|
|
21220
|
+
on the one playing, its rows bled out so their text sits on the media's edge. */
|
|
21221
|
+
.knobs-wt-body:has(>.knobs-wt-chapters){display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
21222
|
+
.knobs-wt-chapters{position:relative;display:flex;flex-direction:column;margin:0 calc(var(--_k-space-sibling) * -1)}
|
|
21223
|
+
.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);
|
|
21224
|
+
border-radius:var(--_k-radius);color:var(--_k-fg-2);text-align:left;white-space:nowrap;cursor:pointer;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21225
|
+
.knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21226
|
+
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
21227
|
+
.knobs-wt-chapter-n{font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
21228
|
+
.knobs-wt-chapter-label{min-width:0;overflow:hidden;${fade2}}
|
|
21229
|
+
.knobs-wt-chapter-time{font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);color:var(--_k-fg-3)}
|
|
21230
|
+
.knobs-pick-copy :is(.knobs-wt-chapter-n,.knobs-wt-chapter-time){color:var(--_k-fg-2)}
|
|
21231
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
21232
|
+
@media(prefers-reduced-motion:reduce){.knobs-wt-disc-content{transition:opacity .15s}}
|
|
21233
|
+
`;
|
|
20353
21234
|
|
|
20354
21235
|
// src/ui/walkthrough-media.ts
|
|
20355
21236
|
function injectWalkthroughStyles(doc) {
|
|
@@ -20878,7 +21759,7 @@ function mediaSlot(container, options) {
|
|
|
20878
21759
|
}
|
|
20879
21760
|
};
|
|
20880
21761
|
}
|
|
20881
|
-
var CHECK3 =
|
|
21762
|
+
var CHECK3 = icon("check", { small: true });
|
|
20882
21763
|
|
|
20883
21764
|
// src/ui/walkthrough.ts
|
|
20884
21765
|
var el2 = (doc, tag, cls) => {
|
|
@@ -20898,14 +21779,18 @@ var lookOf2 = (o) => ({
|
|
|
20898
21779
|
});
|
|
20899
21780
|
var grid2 = (v) => Math.round(v * 64) / 64;
|
|
20900
21781
|
var ICON = {
|
|
20901
|
-
full:
|
|
20902
|
-
exit:
|
|
20903
|
-
pen:
|
|
20904
|
-
mic:
|
|
21782
|
+
full: icon("cornersOut"),
|
|
21783
|
+
exit: icon("cornersIn"),
|
|
21784
|
+
pen: icon("pencilSimple"),
|
|
21785
|
+
mic: icon("microphone"),
|
|
20905
21786
|
stop: svg('<rect x="4.5" y="4.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none"/>'),
|
|
20906
|
-
send:
|
|
20907
|
-
close:
|
|
21787
|
+
send: icon("paperPlaneRight"),
|
|
21788
|
+
close: icon("x", { small: true }),
|
|
21789
|
+
back: icon("arrowLeft", { small: true }),
|
|
21790
|
+
out: icon("arrowUpRight", { small: true })
|
|
20908
21791
|
};
|
|
21792
|
+
var DOCK_INSET = 12;
|
|
21793
|
+
var DOCK_GAP = 12;
|
|
20909
21794
|
var CALM2 = springMotion(SPRINGS.calm);
|
|
20910
21795
|
var SMOOTH = springMotion(SPRINGS.smooth);
|
|
20911
21796
|
var BACK_MS = 4500;
|
|
@@ -21038,8 +21923,12 @@ function walkthrough(container, options) {
|
|
|
21038
21923
|
let count = null;
|
|
21039
21924
|
let fill = null;
|
|
21040
21925
|
let tocEl = null;
|
|
21041
|
-
let
|
|
21926
|
+
let pill = null;
|
|
21927
|
+
let tocRows = [];
|
|
21928
|
+
let discs = [];
|
|
21042
21929
|
let full = null;
|
|
21930
|
+
const noteMode = options.noteBar ?? "collapsed";
|
|
21931
|
+
let reserve = noteBarReserve(52, DOCK_INSET, DOCK_GAP);
|
|
21043
21932
|
const viewOf = (key) => views.find((v) => v.step.key === key);
|
|
21044
21933
|
const feedback = () => collectFeedback(page, state);
|
|
21045
21934
|
const markdown = () => feedbackMarkdown(feedback(), page.verdicts);
|
|
@@ -21063,9 +21952,6 @@ function walkthrough(container, options) {
|
|
|
21063
21952
|
else
|
|
21064
21953
|
run();
|
|
21065
21954
|
};
|
|
21066
|
-
const pillY = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
21067
|
-
const pillH = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
21068
|
-
let pillPlaced = false;
|
|
21069
21955
|
const scroll = {
|
|
21070
21956
|
spring: new Spring(0, CALM2.omega, CALM2.zeta, 0.5),
|
|
21071
21957
|
to: null,
|
|
@@ -21073,13 +21959,6 @@ function walkthrough(container, options) {
|
|
|
21073
21959
|
};
|
|
21074
21960
|
const motion = frameLoop(win, (dt) => {
|
|
21075
21961
|
let more = false;
|
|
21076
|
-
if (mark) {
|
|
21077
|
-
pillY.step(dt);
|
|
21078
|
-
pillH.step(dt);
|
|
21079
|
-
mark.style.transform = `translateY(${grid2(pillY.x)}px)`;
|
|
21080
|
-
mark.style.height = `${grid2(pillY.x + pillH.x) - grid2(pillY.x)}px`;
|
|
21081
|
-
more ||= !pillY.resting || !pillH.resting;
|
|
21082
|
-
}
|
|
21083
21962
|
if (scroll.to && scroll.el) {
|
|
21084
21963
|
scroll.spring.set(scrollTarget(scroll.to, scroll.el));
|
|
21085
21964
|
scroll.spring.step(dt);
|
|
@@ -21143,21 +22022,12 @@ function walkthrough(container, options) {
|
|
|
21143
22022
|
v.glyph.dataset.tone = v.step.ask === "none" ? "none" : verdict ? verdictTone(verdict, page.verdicts.findIndex((x) => x.id === verdict)) : done ? "accent" : "dim";
|
|
21144
22023
|
};
|
|
21145
22024
|
const placeMark = () => {
|
|
21146
|
-
if (!
|
|
22025
|
+
if (!pill || !tocEl)
|
|
21147
22026
|
return;
|
|
22027
|
+
pill.update();
|
|
21148
22028
|
const row = viewOf(current)?.toc;
|
|
21149
22029
|
if (!row)
|
|
21150
|
-
return
|
|
21151
|
-
mark.dataset.on = "";
|
|
21152
|
-
if (!pillPlaced || reduced()) {
|
|
21153
|
-
pillY.snap(row.offsetTop);
|
|
21154
|
-
pillH.snap(row.offsetHeight);
|
|
21155
|
-
pillPlaced = true;
|
|
21156
|
-
} else {
|
|
21157
|
-
pillY.set(row.offsetTop);
|
|
21158
|
-
pillH.set(row.offsetHeight);
|
|
21159
|
-
}
|
|
21160
|
-
motion.wake();
|
|
22030
|
+
return;
|
|
21161
22031
|
const top = row.offsetTop;
|
|
21162
22032
|
const bottom = top + row.offsetHeight;
|
|
21163
22033
|
if (top < tocEl.scrollTop + 8)
|
|
@@ -21174,6 +22044,9 @@ function walkthrough(container, options) {
|
|
|
21174
22044
|
const v = viewOf(key);
|
|
21175
22045
|
v?.card.setAttribute("data-current", "");
|
|
21176
22046
|
v?.toc?.setAttribute("aria-current", "step");
|
|
22047
|
+
for (const r of tocRows)
|
|
22048
|
+
if (r.dataset.section)
|
|
22049
|
+
r.toggleAttribute("data-active", r.dataset.section === v?.step.section);
|
|
21177
22050
|
if (key)
|
|
21178
22051
|
record({ what: "step", step: key });
|
|
21179
22052
|
placeMark();
|
|
@@ -21190,6 +22063,16 @@ function walkthrough(container, options) {
|
|
|
21190
22063
|
else
|
|
21191
22064
|
break;
|
|
21192
22065
|
}
|
|
22066
|
+
const s = scrollerOf(root);
|
|
22067
|
+
if (s.scrollTop > 0 && s.scrollTop >= s.scrollHeight - s.clientHeight - 2) {
|
|
22068
|
+
const bottom = (s === doc.scrollingElement ? win.innerHeight : s.getBoundingClientRect().bottom) - reserve;
|
|
22069
|
+
for (let i = views.length - 1;i >= 0; i--) {
|
|
22070
|
+
if (views[i].card.getBoundingClientRect().top < bottom) {
|
|
22071
|
+
pick = views[i].step.key;
|
|
22072
|
+
break;
|
|
22073
|
+
}
|
|
22074
|
+
}
|
|
22075
|
+
}
|
|
21193
22076
|
setCurrent(pick);
|
|
21194
22077
|
};
|
|
21195
22078
|
let scrollRaf = 0;
|
|
@@ -21232,7 +22115,12 @@ function walkthrough(container, options) {
|
|
|
21232
22115
|
};
|
|
21233
22116
|
const scrim = el2(doc, "div", "knobs-wt-scrim");
|
|
21234
22117
|
scrim.addEventListener("click", () => setFull(false));
|
|
21235
|
-
const fullRect = () => ({
|
|
22118
|
+
const fullRect = () => ({
|
|
22119
|
+
x: DOCK_INSET,
|
|
22120
|
+
y: DOCK_INSET,
|
|
22121
|
+
w: win.innerWidth - DOCK_INSET * 2,
|
|
22122
|
+
h: win.innerHeight - DOCK_INSET - reserve
|
|
22123
|
+
});
|
|
21236
22124
|
const placeFull = (f) => {
|
|
21237
22125
|
const a = f.hold.getBoundingClientRect();
|
|
21238
22126
|
const b = fullRect();
|
|
@@ -21377,6 +22265,7 @@ function walkthrough(container, options) {
|
|
|
21377
22265
|
ink.on = true;
|
|
21378
22266
|
ink.layer.dataset.on = "";
|
|
21379
22267
|
root.dataset.inking = "";
|
|
22268
|
+
bar.setOpen(true);
|
|
21380
22269
|
bar.sync();
|
|
21381
22270
|
};
|
|
21382
22271
|
const voice = {
|
|
@@ -21416,6 +22305,7 @@ function walkthrough(container, options) {
|
|
|
21416
22305
|
});
|
|
21417
22306
|
voice.recorder = rec;
|
|
21418
22307
|
voice.started = performance.now();
|
|
22308
|
+
bar.setOpen(true);
|
|
21419
22309
|
rec.start();
|
|
21420
22310
|
voice.timer = win.setInterval(() => bar.sync(), 250);
|
|
21421
22311
|
bar.sync();
|
|
@@ -21442,7 +22332,10 @@ function walkthrough(container, options) {
|
|
|
21442
22332
|
if (!v)
|
|
21443
22333
|
return;
|
|
21444
22334
|
backTo = key;
|
|
21445
|
-
backPill.
|
|
22335
|
+
backPill.innerHTML = ICON.back;
|
|
22336
|
+
const words = el2(doc, "span", "knobs-wt-back-label");
|
|
22337
|
+
words.textContent = `Back to ${plainMarkdown(v.step.title)}`;
|
|
22338
|
+
backPill.append(words);
|
|
21446
22339
|
backPill.dataset.on = "";
|
|
21447
22340
|
win.clearTimeout(backTimer);
|
|
21448
22341
|
backTimer = win.setTimeout(hideBack, BACK_MS);
|
|
@@ -21474,7 +22367,41 @@ function walkthrough(container, options) {
|
|
|
21474
22367
|
sendBtn.dataset.send = "";
|
|
21475
22368
|
row.append(input, attach, fullBtn, penBtn, micBtn, sendBtn);
|
|
21476
22369
|
box.append(on, row);
|
|
21477
|
-
|
|
22370
|
+
const launch = el2(doc, "button", "knobs-wt-launch");
|
|
22371
|
+
launch.type = "button";
|
|
22372
|
+
launch.innerHTML = ICON.pen;
|
|
22373
|
+
launch.append("Note");
|
|
22374
|
+
const kbd = el2(doc, "kbd");
|
|
22375
|
+
kbd.textContent = "n";
|
|
22376
|
+
launch.append(kbd);
|
|
22377
|
+
launch.setAttribute("aria-label", "Write a note (n)");
|
|
22378
|
+
launch.addEventListener("click", () => setOpen(true, true));
|
|
22379
|
+
dock.dataset.mode = noteMode;
|
|
22380
|
+
dock.append(backPill, box, launch);
|
|
22381
|
+
let open = noteMode !== "collapsed";
|
|
22382
|
+
const setOpen = (on, focus = false) => {
|
|
22383
|
+
if (noteMode === "collapsed" && on !== open) {
|
|
22384
|
+
open = on;
|
|
22385
|
+
dock.toggleAttribute("data-open", on);
|
|
22386
|
+
box.inert = !on;
|
|
22387
|
+
launch.inert = on;
|
|
22388
|
+
syncReserve();
|
|
22389
|
+
}
|
|
22390
|
+
if (on && focus)
|
|
22391
|
+
input.focus({ preventScroll: true });
|
|
22392
|
+
};
|
|
22393
|
+
dock.toggleAttribute("data-open", open);
|
|
22394
|
+
box.inert = !open;
|
|
22395
|
+
launch.inert = open;
|
|
22396
|
+
const empty = () => !input.value.trim() && !voice.pending && !voice.recorder && !ink.on && !ink.paths.length;
|
|
22397
|
+
const onOutside = (e) => {
|
|
22398
|
+
if (open && noteMode === "collapsed" && !dock.contains(e.target) && empty())
|
|
22399
|
+
setOpen(false);
|
|
22400
|
+
};
|
|
22401
|
+
doc.addEventListener("pointerdown", onOutside, true);
|
|
22402
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => syncReserve()) : null;
|
|
22403
|
+
ro?.observe(box);
|
|
22404
|
+
ro?.observe(launch);
|
|
21478
22405
|
const fit = () => {
|
|
21479
22406
|
input.style.height = "auto";
|
|
21480
22407
|
input.style.height = `${Math.min(140, input.scrollHeight)}px`;
|
|
@@ -21490,6 +22417,8 @@ function walkthrough(container, options) {
|
|
|
21490
22417
|
} else if (e.key === "Escape") {
|
|
21491
22418
|
e.preventDefault();
|
|
21492
22419
|
input.blur();
|
|
22420
|
+
if (empty())
|
|
22421
|
+
setOpen(false);
|
|
21493
22422
|
viewOf(current)?.card.focus({ preventScroll: true });
|
|
21494
22423
|
}
|
|
21495
22424
|
});
|
|
@@ -21509,13 +22438,13 @@ function walkthrough(container, options) {
|
|
|
21509
22438
|
const sync = () => {
|
|
21510
22439
|
const v = viewOf(current);
|
|
21511
22440
|
const ctx = describeMedia(mediaContext(v));
|
|
21512
|
-
const where = v ?
|
|
22441
|
+
const where = v ? plainMarkdown(v.step.title) : "General note";
|
|
21513
22442
|
const text = ctx ? `${where} · ${ctx}` : where;
|
|
21514
22443
|
if (text !== lastOn) {
|
|
21515
22444
|
on.textContent = text;
|
|
21516
22445
|
lastOn = text;
|
|
21517
22446
|
}
|
|
21518
|
-
input.placeholder = v ?
|
|
22447
|
+
input.placeholder = v ? "A note on this step… (n)" : "A note on the whole page… (n)";
|
|
21519
22448
|
const attached = `${voice.pending?.url ?? ""}|${ink.paths.length}`;
|
|
21520
22449
|
if (attached !== lastAttached) {
|
|
21521
22450
|
lastAttached = attached;
|
|
@@ -21554,14 +22483,45 @@ function walkthrough(container, options) {
|
|
|
21554
22483
|
};
|
|
21555
22484
|
return {
|
|
21556
22485
|
dock,
|
|
22486
|
+
box,
|
|
22487
|
+
launch,
|
|
21557
22488
|
input,
|
|
21558
22489
|
sync,
|
|
22490
|
+
get open() {
|
|
22491
|
+
return open;
|
|
22492
|
+
},
|
|
22493
|
+
setOpen,
|
|
22494
|
+
empty,
|
|
22495
|
+
unobserve: () => {
|
|
22496
|
+
ro?.disconnect();
|
|
22497
|
+
doc.removeEventListener("pointerdown", onOutside, true);
|
|
22498
|
+
},
|
|
21559
22499
|
clear() {
|
|
21560
22500
|
input.value = "";
|
|
21561
22501
|
fit();
|
|
21562
22502
|
}
|
|
21563
22503
|
};
|
|
21564
22504
|
})();
|
|
22505
|
+
let padded = null;
|
|
22506
|
+
function syncReserve() {
|
|
22507
|
+
if (disposed)
|
|
22508
|
+
return;
|
|
22509
|
+
const h = (bar.open ? bar.box : bar.launch).offsetHeight;
|
|
22510
|
+
if (noteMode === "hidden")
|
|
22511
|
+
reserve = 0;
|
|
22512
|
+
else if (h)
|
|
22513
|
+
reserve = noteBarReserve(h, DOCK_INSET, DOCK_GAP);
|
|
22514
|
+
root.style.setProperty("--kw-reserve", `${reserve}px`);
|
|
22515
|
+
const s = scrollerOf(root);
|
|
22516
|
+
if (padded?.el !== s) {
|
|
22517
|
+
if (padded)
|
|
22518
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
22519
|
+
padded = { el: s, was: s.style.scrollPaddingBottom };
|
|
22520
|
+
}
|
|
22521
|
+
s.style.scrollPaddingBottom = `${reserve}px`;
|
|
22522
|
+
if (full)
|
|
22523
|
+
placeFull(full);
|
|
22524
|
+
}
|
|
21565
22525
|
const ticker = win.setInterval(() => !doc.hidden && bar.sync(), 500);
|
|
21566
22526
|
const send = (text = bar.input.value) => {
|
|
21567
22527
|
if (voice.recorder)
|
|
@@ -21597,6 +22557,10 @@ function walkthrough(container, options) {
|
|
|
21597
22557
|
syncProgress();
|
|
21598
22558
|
emit();
|
|
21599
22559
|
bar.sync();
|
|
22560
|
+
if (noteMode === "collapsed") {
|
|
22561
|
+
bar.input.blur();
|
|
22562
|
+
bar.setOpen(false);
|
|
22563
|
+
}
|
|
21600
22564
|
if (v && options.advance !== false) {
|
|
21601
22565
|
const to = adjacentStep(views.map((x) => x.step.key), v.step.key, 1);
|
|
21602
22566
|
if (to && to !== v.step.key) {
|
|
@@ -21604,7 +22568,8 @@ function walkthrough(container, options) {
|
|
|
21604
22568
|
setFull(false);
|
|
21605
22569
|
go(to);
|
|
21606
22570
|
showBack(v.step.key);
|
|
21607
|
-
|
|
22571
|
+
if (noteMode === "docked")
|
|
22572
|
+
bar.input.focus({ preventScroll: true });
|
|
21608
22573
|
}
|
|
21609
22574
|
}
|
|
21610
22575
|
};
|
|
@@ -21691,22 +22656,105 @@ function walkthrough(container, options) {
|
|
|
21691
22656
|
row.addEventListener("transitionend", done, { once: true });
|
|
21692
22657
|
win.setTimeout(done, 600);
|
|
21693
22658
|
};
|
|
22659
|
+
const metaLine = (cls) => el2(doc, "div", `knobs-wt-metaline ${cls}`);
|
|
22660
|
+
const metaText = (line, text, cls) => {
|
|
22661
|
+
const s = el2(doc, "span", cls);
|
|
22662
|
+
s.textContent = text;
|
|
22663
|
+
line.append(s);
|
|
22664
|
+
return s;
|
|
22665
|
+
};
|
|
22666
|
+
const metaLink = (line, text, href) => {
|
|
22667
|
+
const a = el2(doc, "a");
|
|
22668
|
+
a.href = href;
|
|
22669
|
+
a.target = "_blank";
|
|
22670
|
+
a.rel = "noreferrer";
|
|
22671
|
+
a.textContent = text;
|
|
22672
|
+
a.insertAdjacentHTML("beforeend", ICON.out);
|
|
22673
|
+
line.append(a);
|
|
22674
|
+
return a;
|
|
22675
|
+
};
|
|
22676
|
+
const feedItem = (f, now) => {
|
|
22677
|
+
const li = el2(doc, "li", "knobs-wt-fi");
|
|
22678
|
+
li.dataset.kind = f.kind;
|
|
22679
|
+
const q = el2(doc, "div", "knobs-wt-fi-q");
|
|
22680
|
+
const meta = metaLine("knobs-wt-fi-meta");
|
|
22681
|
+
if (f.at !== null) {
|
|
22682
|
+
const when = metaText(meta, ago(f.at, now));
|
|
22683
|
+
when.title = new Date(f.at).toLocaleString();
|
|
22684
|
+
} else
|
|
22685
|
+
metaText(meta, f.kind === "qa" ? "Answer" : "Update");
|
|
22686
|
+
const step = f.step ? page.steps.find((s) => s.key === f.step) : undefined;
|
|
22687
|
+
if (step) {
|
|
22688
|
+
const section = page.sections.find((s) => s.id === step.section);
|
|
22689
|
+
const b = el2(doc, "button", "knobs-wt-fi-step");
|
|
22690
|
+
b.type = "button";
|
|
22691
|
+
b.textContent = section?.link?.label ?? plainMarkdown(step.title);
|
|
22692
|
+
b.title = `Go to “${plainMarkdown(step.title)}”`;
|
|
22693
|
+
b.addEventListener("click", () => go(step.key));
|
|
22694
|
+
meta.append(b);
|
|
22695
|
+
}
|
|
22696
|
+
if (f.status) {
|
|
22697
|
+
const id = f.status.toLowerCase();
|
|
22698
|
+
const shipped = /^(ship|shipped|merged|done)$/.test(id);
|
|
22699
|
+
const changes = /^(changes?|changes queued)$/.test(id);
|
|
22700
|
+
const s = metaText(meta, shipped ? "Shipped" : changes ? "Changes queued" : f.status);
|
|
22701
|
+
s.dataset.status = shipped ? "on" : changes ? "warn" : "";
|
|
22702
|
+
}
|
|
22703
|
+
q.append(meta);
|
|
22704
|
+
if (f.q)
|
|
22705
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-ask", f.q));
|
|
22706
|
+
else
|
|
22707
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
22708
|
+
li.append(q);
|
|
22709
|
+
if (f.q || f.trail.length) {
|
|
22710
|
+
const a = el2(doc, "div", "knobs-wt-fi-a");
|
|
22711
|
+
if (f.q)
|
|
22712
|
+
a.append(prose2(doc, "div", "knobs-wt-fi-answer", f.text));
|
|
22713
|
+
if (f.trail.length) {
|
|
22714
|
+
const list = el2(doc, "ol", "knobs-wt-trail");
|
|
22715
|
+
for (const line of f.trail) {
|
|
22716
|
+
const i = line.indexOf(" · ");
|
|
22717
|
+
const row = el2(doc, "li");
|
|
22718
|
+
const words = el2(doc, "span", "knobs-wt-trail-text");
|
|
22719
|
+
words.textContent = i < 0 ? line : line.slice(i + 3);
|
|
22720
|
+
row.append(words);
|
|
22721
|
+
if (i >= 0) {
|
|
22722
|
+
const at = el2(doc, "span", "knobs-wt-trail-at");
|
|
22723
|
+
at.textContent = line.slice(0, i);
|
|
22724
|
+
row.append(at);
|
|
22725
|
+
}
|
|
22726
|
+
list.append(row);
|
|
22727
|
+
}
|
|
22728
|
+
discs.push(disclosure(a, { label: "Context", count: f.trail.length, content: list }));
|
|
22729
|
+
}
|
|
22730
|
+
li.append(a);
|
|
22731
|
+
}
|
|
22732
|
+
return li;
|
|
22733
|
+
};
|
|
21694
22734
|
const build = () => {
|
|
21695
22735
|
for (const v of views) {
|
|
21696
22736
|
v.slots.forEach((s) => s.dispose());
|
|
21697
22737
|
v.taste?.dispose();
|
|
21698
22738
|
}
|
|
22739
|
+
for (const d of discs)
|
|
22740
|
+
d.dispose();
|
|
22741
|
+
discs = [];
|
|
22742
|
+
pill?.dispose();
|
|
22743
|
+
pill = null;
|
|
22744
|
+
tocRows = [];
|
|
21699
22745
|
if (full) {
|
|
21700
22746
|
full.p.snap(0);
|
|
21701
22747
|
closeFull();
|
|
21702
22748
|
}
|
|
21703
22749
|
clearInk();
|
|
21704
22750
|
views = [];
|
|
21705
|
-
pillPlaced = false;
|
|
21706
22751
|
root.textContent = "";
|
|
21707
22752
|
root.removeAttribute("data-settled");
|
|
22753
|
+
root.dataset.rail = options.rail === false ? "none" : options.rail === "left" ? "left" : "right";
|
|
22754
|
+
root.toggleAttribute("data-cards", options.cards === true);
|
|
21708
22755
|
const layout = el2(doc, "div", "knobs-wt-layout");
|
|
21709
22756
|
const main = el2(doc, "div", "knobs-wt-main");
|
|
22757
|
+
const flow = el2(doc, "div", "knobs-wt-flow");
|
|
21710
22758
|
const head = el2(doc, "header", "knobs-wt-head");
|
|
21711
22759
|
const h1 = el2(doc, "h1", "knobs-wt-title");
|
|
21712
22760
|
h1.textContent = page.title;
|
|
@@ -21733,42 +22781,27 @@ function walkthrough(container, options) {
|
|
|
21733
22781
|
}
|
|
21734
22782
|
head.append(meta);
|
|
21735
22783
|
}
|
|
21736
|
-
|
|
22784
|
+
flow.append(head);
|
|
22785
|
+
let feedEl = null;
|
|
21737
22786
|
if (page.feed.length) {
|
|
21738
|
-
|
|
21739
|
-
|
|
21740
|
-
|
|
22787
|
+
feedEl = el2(doc, "section", "knobs-wt-feed");
|
|
22788
|
+
feedEl.id = "wt-latest";
|
|
22789
|
+
feedEl.setAttribute("aria-label", "Updates and answers");
|
|
22790
|
+
const fh = el2(doc, "header", "knobs-wt-feed-head");
|
|
22791
|
+
const h = el2(doc, "h2", "knobs-wt-feed-title");
|
|
22792
|
+
h.textContent = page.feed.some((f) => f.kind === "qa") ? "Updates & Q&A" : "Updates";
|
|
22793
|
+
const n = el2(doc, "span", "knobs-wt-feed-count");
|
|
22794
|
+
n.textContent = String(page.feed.length);
|
|
22795
|
+
fh.append(h, n);
|
|
22796
|
+
const list = el2(doc, "ol", "knobs-wt-feed-list");
|
|
21741
22797
|
const now = Date.now();
|
|
21742
|
-
for (const f of page.feed)
|
|
21743
|
-
|
|
21744
|
-
|
|
21745
|
-
|
|
21746
|
-
when.textContent = f.at === null ? "" : ago(f.at, now);
|
|
21747
|
-
if (f.at !== null)
|
|
21748
|
-
when.title = new Date(f.at).toLocaleString();
|
|
21749
|
-
const kind = el2(doc, "span", "knobs-wt-fi-kind");
|
|
21750
|
-
kind.textContent = f.kind === "qa" ? "Answer" : "Update";
|
|
21751
|
-
const body = el2(doc, "div", "knobs-wt-fi-body");
|
|
21752
|
-
if (f.q)
|
|
21753
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
|
|
21754
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
21755
|
-
li.append(when, kind, body);
|
|
21756
|
-
if (f.step) {
|
|
21757
|
-
const target = f.step;
|
|
21758
|
-
const link = el2(doc, "button", "knobs-wt-fi-step");
|
|
21759
|
-
link.type = "button";
|
|
21760
|
-
link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
|
|
21761
|
-
link.title = "Go to the step";
|
|
21762
|
-
link.addEventListener("click", () => go(target));
|
|
21763
|
-
li.append(link);
|
|
21764
|
-
}
|
|
21765
|
-
list.append(li);
|
|
21766
|
-
}
|
|
21767
|
-
feed.append(list);
|
|
21768
|
-
main.append(feed);
|
|
22798
|
+
for (const f of page.feed)
|
|
22799
|
+
list.append(feedItem(f, now));
|
|
22800
|
+
feedEl.append(fh, list);
|
|
22801
|
+
flow.append(feedEl);
|
|
21769
22802
|
}
|
|
21770
22803
|
let rail = null;
|
|
21771
|
-
count = fill = tocEl =
|
|
22804
|
+
count = fill = tocEl = null;
|
|
21772
22805
|
if (options.rail !== false) {
|
|
21773
22806
|
rail = el2(doc, "aside", "knobs-wt-rail");
|
|
21774
22807
|
rail.setAttribute("aria-label", "Progress");
|
|
@@ -21780,8 +22813,17 @@ function walkthrough(container, options) {
|
|
|
21780
22813
|
progress.append(count, meter);
|
|
21781
22814
|
tocEl = el2(doc, "nav", "knobs-wt-toc");
|
|
21782
22815
|
tocEl.setAttribute("aria-label", "Contents");
|
|
21783
|
-
|
|
21784
|
-
|
|
22816
|
+
const ns = page.sections.map((s) => s.kicker && s.link ? s.link.label : "");
|
|
22817
|
+
const nw = Math.max(0, ...ns.map((n) => n.length));
|
|
22818
|
+
tocEl.style.setProperty("--kw-toc-n", nw ? `${nw + 0.5}ch` : "0px");
|
|
22819
|
+
if (!nw)
|
|
22820
|
+
tocEl.dataset.bare = "";
|
|
22821
|
+
if (feedEl) {
|
|
22822
|
+
const group = el2(doc, "div", "knobs-wt-toc-group");
|
|
22823
|
+
const target = feedEl;
|
|
22824
|
+
group.append(tocRow("Latest", "", String(page.feed.length), false, () => target.scrollIntoView({ block: "start", behavior: reduced() ? "auto" : "smooth" })));
|
|
22825
|
+
tocEl.append(group);
|
|
22826
|
+
}
|
|
21785
22827
|
rail.append(progress, tocEl, actions(true));
|
|
21786
22828
|
if (options.keys !== false) {
|
|
21787
22829
|
const keys = el2(doc, "div", "knobs-wt-keys");
|
|
@@ -21793,45 +22835,44 @@ function walkthrough(container, options) {
|
|
|
21793
22835
|
const sec = el2(doc, "section", "knobs-wt-section");
|
|
21794
22836
|
sec.id = `wt-${section.id}`;
|
|
21795
22837
|
const sh = el2(doc, "header", "knobs-wt-shead");
|
|
21796
|
-
if (section.link || section.status) {
|
|
21797
|
-
const
|
|
21798
|
-
if (section.
|
|
21799
|
-
|
|
21800
|
-
|
|
21801
|
-
|
|
21802
|
-
a.rel = "noreferrer";
|
|
21803
|
-
a.textContent = `${section.link.label} ↗`;
|
|
21804
|
-
kicker.append(a);
|
|
21805
|
-
}
|
|
22838
|
+
if (section.kicker || section.link || section.status) {
|
|
22839
|
+
const meta = metaLine("knobs-wt-kicker");
|
|
22840
|
+
if (section.kicker)
|
|
22841
|
+
metaText(meta, section.kicker, "knobs-wt-kicker-lead");
|
|
22842
|
+
if (section.link)
|
|
22843
|
+
metaLink(meta, section.link.label, section.link.href);
|
|
21806
22844
|
if (section.status) {
|
|
21807
22845
|
const s = statusLook(section.status);
|
|
21808
|
-
|
|
21809
|
-
chip.dataset.tone = s.tone;
|
|
21810
|
-
chip.textContent = s.label;
|
|
21811
|
-
kicker.append(chip);
|
|
22846
|
+
metaText(meta, s.label, "knobs-wt-status").dataset.tone = s.tone;
|
|
21812
22847
|
}
|
|
21813
|
-
sh.append(
|
|
22848
|
+
sh.append(meta);
|
|
21814
22849
|
}
|
|
21815
|
-
const h2 = el2(doc, "h2", "knobs-wt-
|
|
21816
|
-
h2.
|
|
22850
|
+
const h2 = el2(doc, "h2", "knobs-wt-heading");
|
|
22851
|
+
h2.innerHTML = inlineMarkdown(section.title);
|
|
21817
22852
|
sh.append(h2);
|
|
22853
|
+
const intro = el2(doc, "div", "knobs-wt-sintro");
|
|
22854
|
+
intro.append(sh);
|
|
21818
22855
|
if (section.summary)
|
|
21819
|
-
|
|
21820
|
-
sec.append(
|
|
22856
|
+
intro.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
|
|
22857
|
+
sec.append(intro);
|
|
22858
|
+
let group = null;
|
|
21821
22859
|
if (tocEl) {
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21825
|
-
|
|
22860
|
+
group = el2(doc, "div", "knobs-wt-toc-group");
|
|
22861
|
+
const first = section.steps[0]?.key;
|
|
22862
|
+
const n = section.kicker && section.link ? section.link.label : "";
|
|
22863
|
+
group.append(tocRow(plainMarkdown(section.title), n, "", false, () => first ? go(first) : undefined, section.id));
|
|
22864
|
+
tocEl.append(group);
|
|
21826
22865
|
}
|
|
21827
22866
|
for (const step of section.steps) {
|
|
21828
|
-
const v = stepView(step);
|
|
22867
|
+
const v = stepView(step, group);
|
|
21829
22868
|
sec.append(v.card);
|
|
21830
22869
|
views.push(v);
|
|
21831
22870
|
}
|
|
21832
|
-
|
|
22871
|
+
flow.append(sec);
|
|
21833
22872
|
}
|
|
21834
|
-
main.append(
|
|
22873
|
+
main.append(flow);
|
|
22874
|
+
if (noteMode !== "hidden")
|
|
22875
|
+
main.append(bar.dock);
|
|
21835
22876
|
if (rail)
|
|
21836
22877
|
layout.append(rail);
|
|
21837
22878
|
layout.append(main);
|
|
@@ -21841,16 +22882,40 @@ function walkthrough(container, options) {
|
|
|
21841
22882
|
for (const n of notesOn(state, v.step.key))
|
|
21842
22883
|
renderNote(v, n);
|
|
21843
22884
|
}
|
|
22885
|
+
if (tocEl)
|
|
22886
|
+
pill = selectionPill(tocEl, {
|
|
22887
|
+
selected: () => viewOf(current)?.toc ?? null,
|
|
22888
|
+
rows: () => tocRows
|
|
22889
|
+
});
|
|
21844
22890
|
syncProgress();
|
|
21845
22891
|
current = null;
|
|
21846
22892
|
fromScroll();
|
|
21847
22893
|
placeMark();
|
|
21848
22894
|
bar.sync();
|
|
22895
|
+
syncReserve();
|
|
21849
22896
|
win.requestAnimationFrame(() => win.requestAnimationFrame(() => {
|
|
21850
22897
|
if (!disposed && !reduced())
|
|
21851
22898
|
root.dataset.settled = "";
|
|
21852
22899
|
}));
|
|
21853
22900
|
};
|
|
22901
|
+
const tocRow = (label, n, end, sub, run, section) => {
|
|
22902
|
+
const b = el2(doc, "button", sub ? "knobs-wt-toc-row knobs-wt-toc-sub" : "knobs-wt-toc-row");
|
|
22903
|
+
b.type = "button";
|
|
22904
|
+
if (section)
|
|
22905
|
+
b.dataset.section = section;
|
|
22906
|
+
const ncol = el2(doc, "span", "knobs-wt-toc-n");
|
|
22907
|
+
ncol.textContent = n;
|
|
22908
|
+
const t = el2(doc, "span", "knobs-wt-toc-label");
|
|
22909
|
+
t.textContent = label;
|
|
22910
|
+
const e = el2(doc, "span", "knobs-wt-toc-end");
|
|
22911
|
+
e.textContent = end;
|
|
22912
|
+
b.title = label;
|
|
22913
|
+
b.append(ncol, t, e);
|
|
22914
|
+
b.addEventListener("mousedown", (ev) => ev.preventDefault());
|
|
22915
|
+
b.addEventListener("click", run);
|
|
22916
|
+
tocRows.push(b);
|
|
22917
|
+
return b;
|
|
22918
|
+
};
|
|
21854
22919
|
const actions = (rail) => {
|
|
21855
22920
|
const row = el2(doc, "div", "knobs-wt-actions");
|
|
21856
22921
|
const btn = (text, run, primary = false) => {
|
|
@@ -21891,30 +22956,38 @@ function walkthrough(container, options) {
|
|
|
21891
22956
|
toast("Couldn't reach the clipboard", { tone: "warn", look, doc });
|
|
21892
22957
|
}
|
|
21893
22958
|
};
|
|
21894
|
-
const stepView = (step) => {
|
|
21895
|
-
const card = el2(doc, "article", "knobs-wt-step knobs-surface");
|
|
22959
|
+
const stepView = (step, group) => {
|
|
22960
|
+
const card = el2(doc, "article", options.cards ? "knobs-wt-step knobs-surface" : "knobs-wt-step");
|
|
21896
22961
|
card.id = `wt-${step.key.replace("/", "--")}`;
|
|
21897
22962
|
card.tabIndex = -1;
|
|
21898
22963
|
card.dataset.key = step.key;
|
|
21899
|
-
card.setAttribute("aria-label",
|
|
22964
|
+
card.setAttribute("aria-label", plainMarkdown(step.title));
|
|
21900
22965
|
const head = el2(doc, "header", "knobs-wt-step-head");
|
|
21901
|
-
const num = el2(doc, "span", "knobs-wt-num");
|
|
21902
|
-
num.textContent = step.number;
|
|
21903
22966
|
const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
|
|
21904
|
-
h3.
|
|
21905
|
-
head.append(
|
|
21906
|
-
card.append(head);
|
|
22967
|
+
h3.innerHTML = inlineMarkdown(step.title);
|
|
22968
|
+
head.append(h3);
|
|
21907
22969
|
if (step.caption)
|
|
21908
|
-
|
|
22970
|
+
head.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
|
|
22971
|
+
card.append(head);
|
|
21909
22972
|
const slots = [];
|
|
21910
22973
|
const onEvent = (e) => record({ ...e, step: step.key });
|
|
21911
22974
|
let media = null;
|
|
21912
22975
|
if (step.media.length) {
|
|
21913
|
-
|
|
21914
|
-
|
|
21915
|
-
|
|
21916
|
-
|
|
22976
|
+
const grid = (list) => {
|
|
22977
|
+
const g = el2(doc, "div", "knobs-wt-media");
|
|
22978
|
+
g.style.setProperty("--kw-n", String(Math.min(list.length, step.columns)));
|
|
22979
|
+
for (const m of list)
|
|
22980
|
+
slots.push(mediaSlot(g, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
22981
|
+
return g;
|
|
22982
|
+
};
|
|
22983
|
+
const [first, ...rest] = step.media;
|
|
22984
|
+
media = grid(step.more ? [first] : step.media);
|
|
21917
22985
|
card.append(media);
|
|
22986
|
+
if (step.more && rest.length) {
|
|
22987
|
+
const holder = el2(doc, "div", "knobs-wt-more");
|
|
22988
|
+
discs.push(disclosure(holder, { label: step.more, count: rest.length, content: grid(rest) }));
|
|
22989
|
+
card.append(holder);
|
|
22990
|
+
}
|
|
21918
22991
|
}
|
|
21919
22992
|
let taste = null;
|
|
21920
22993
|
if (step.question)
|
|
@@ -21939,16 +23012,11 @@ function walkthrough(container, options) {
|
|
|
21939
23012
|
});
|
|
21940
23013
|
let toc = null;
|
|
21941
23014
|
let glyph = null;
|
|
21942
|
-
if (
|
|
21943
|
-
toc =
|
|
21944
|
-
toc.type = "button";
|
|
23015
|
+
if (group) {
|
|
23016
|
+
toc = tocRow(plainMarkdown(step.title), "", "", true, () => go(step.key));
|
|
21945
23017
|
glyph = el2(doc, "span", "knobs-wt-toc-glyph");
|
|
21946
|
-
|
|
21947
|
-
|
|
21948
|
-
toc.title = `${step.number} ${step.title}`;
|
|
21949
|
-
toc.append(glyph, label);
|
|
21950
|
-
toc.addEventListener("click", () => go(step.key));
|
|
21951
|
-
tocEl.append(toc);
|
|
23018
|
+
toc.querySelector(".knobs-wt-toc-end").append(glyph);
|
|
23019
|
+
group.append(toc);
|
|
21952
23020
|
}
|
|
21953
23021
|
return { step, card, media, notes, toc, glyph, taste, slots };
|
|
21954
23022
|
};
|
|
@@ -22007,15 +23075,21 @@ function walkthrough(container, options) {
|
|
|
22007
23075
|
setFull(false);
|
|
22008
23076
|
return go(next);
|
|
22009
23077
|
}
|
|
23078
|
+
if ((key === "Home" || key === "End") && views.length) {
|
|
23079
|
+
claim();
|
|
23080
|
+
if (full)
|
|
23081
|
+
setFull(false);
|
|
23082
|
+
return go(views[key === "Home" ? 0 : views.length - 1].step.key);
|
|
23083
|
+
}
|
|
22010
23084
|
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
22011
23085
|
const d = (key === "ArrowLeft" ? -1 : 1) * (e.shiftKey ? 2 : 0.5);
|
|
22012
23086
|
if (seekBy(d))
|
|
22013
23087
|
claim();
|
|
22014
23088
|
return;
|
|
22015
23089
|
}
|
|
22016
|
-
if (key === "n") {
|
|
23090
|
+
if (key === "n" && noteMode !== "hidden") {
|
|
22017
23091
|
claim();
|
|
22018
|
-
bar.
|
|
23092
|
+
bar.setOpen(true, true);
|
|
22019
23093
|
return;
|
|
22020
23094
|
}
|
|
22021
23095
|
const v = viewOf(current);
|
|
@@ -22094,6 +23168,12 @@ function walkthrough(container, options) {
|
|
|
22094
23168
|
win.removeEventListener(type, stopScroll);
|
|
22095
23169
|
doc.removeEventListener("keydown", onKey);
|
|
22096
23170
|
unregisterHints();
|
|
23171
|
+
bar.unobserve();
|
|
23172
|
+
pill?.dispose();
|
|
23173
|
+
for (const d of discs)
|
|
23174
|
+
d.dispose();
|
|
23175
|
+
if (padded)
|
|
23176
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
22097
23177
|
for (const v of views) {
|
|
22098
23178
|
v.slots.forEach((s) => s.dispose());
|
|
22099
23179
|
v.taste?.dispose();
|
|
@@ -22104,9 +23184,11 @@ function walkthrough(container, options) {
|
|
|
22104
23184
|
return api;
|
|
22105
23185
|
}
|
|
22106
23186
|
export {
|
|
23187
|
+
CATCH_UP,
|
|
22107
23188
|
COLLAPSE_PAST,
|
|
22108
23189
|
COMPARE_FFMPEG,
|
|
22109
23190
|
FIT_MAX,
|
|
23191
|
+
ICON_NAMES,
|
|
22110
23192
|
activity,
|
|
22111
23193
|
adjacentMarker,
|
|
22112
23194
|
advance,
|
|
@@ -22123,12 +23205,14 @@ export {
|
|
|
22123
23205
|
commandsFrom,
|
|
22124
23206
|
compare,
|
|
22125
23207
|
compareLayout,
|
|
23208
|
+
compareModes,
|
|
22126
23209
|
comparePaths,
|
|
22127
23210
|
compareStrip,
|
|
22128
23211
|
compareText,
|
|
22129
23212
|
confirm,
|
|
22130
23213
|
contextMenu,
|
|
22131
23214
|
countChanges,
|
|
23215
|
+
currentMarker,
|
|
22132
23216
|
diffActivity,
|
|
22133
23217
|
diffBar,
|
|
22134
23218
|
diffCounts,
|
|
@@ -22153,7 +23237,9 @@ export {
|
|
|
22153
23237
|
frameOf,
|
|
22154
23238
|
frameTime,
|
|
22155
23239
|
fuzzy,
|
|
23240
|
+
gripTop,
|
|
22156
23241
|
hints,
|
|
23242
|
+
icon,
|
|
22157
23243
|
inTriangle,
|
|
22158
23244
|
indexActivity,
|
|
22159
23245
|
indexTree,
|
|
@@ -22172,7 +23258,9 @@ export {
|
|
|
22172
23258
|
mediaKind,
|
|
22173
23259
|
mediaSlot,
|
|
22174
23260
|
menu,
|
|
23261
|
+
modeForKey,
|
|
22175
23262
|
motionBlur,
|
|
23263
|
+
moveHead,
|
|
22176
23264
|
navigate,
|
|
22177
23265
|
navigateActivity,
|
|
22178
23266
|
normalizeWalkthrough,
|
|
@@ -22181,9 +23269,14 @@ export {
|
|
|
22181
23269
|
pageHints,
|
|
22182
23270
|
parseLayout,
|
|
22183
23271
|
parsePatch,
|
|
23272
|
+
pillBoxOf,
|
|
23273
|
+
pillProgress,
|
|
23274
|
+
pillRadius,
|
|
23275
|
+
pillSpring,
|
|
22184
23276
|
place,
|
|
22185
23277
|
plainAccess,
|
|
22186
23278
|
planBento,
|
|
23279
|
+
planPill,
|
|
22187
23280
|
popover,
|
|
22188
23281
|
railSegments,
|
|
22189
23282
|
rank,
|
|
@@ -22195,9 +23288,11 @@ export {
|
|
|
22195
23288
|
rulerTicks,
|
|
22196
23289
|
safeTriangle,
|
|
22197
23290
|
scrubTime,
|
|
23291
|
+
seamLabels,
|
|
22198
23292
|
seekTime,
|
|
22199
23293
|
seeked,
|
|
22200
23294
|
select,
|
|
23295
|
+
selectionPill,
|
|
22201
23296
|
showsSelection,
|
|
22202
23297
|
softClamp,
|
|
22203
23298
|
solve2 as solveSplit,
|