@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-react.js
CHANGED
|
@@ -571,12 +571,20 @@ var compareCss = `
|
|
|
571
571
|
display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;
|
|
572
572
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
573
573
|
: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}
|
|
574
|
-
.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
.knobs-
|
|
579
|
-
.knobs-ui .knobs-cmp-mode
|
|
574
|
+
.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:var(--_k-gap);height:var(--_k-control-h)}
|
|
575
|
+
/* The modes: one fill, the selection pill on the one picked; a mode isn't brighter for being
|
|
576
|
+
picked: the pill's bright copy is. */
|
|
577
|
+
.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}
|
|
578
|
+
.knobs-cmp-modes[hidden]{display:none}
|
|
579
|
+
.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
|
|
580
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
581
|
+
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
582
|
+
/* Toggles: icon buttons, the accent's wash when on. */
|
|
583
|
+
.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-3);cursor:pointer;
|
|
584
|
+
transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
585
|
+
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}
|
|
586
|
+
.knobs-ui .knobs-cmp-toggle[aria-pressed="true"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}
|
|
587
|
+
.knobs-cmp-toggle svg{display:block}
|
|
580
588
|
.knobs-cmp-fill{flex:1}
|
|
581
589
|
.knobs-cmp-toggle[hidden]{display:none}
|
|
582
590
|
/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked
|
|
@@ -591,7 +599,8 @@ var compareCss = `
|
|
|
591
599
|
/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */
|
|
592
600
|
.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}
|
|
593
601
|
.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}
|
|
594
|
-
.
|
|
602
|
+
/* Wiping, the grip stands in for the cursor. */
|
|
603
|
+
.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}
|
|
595
604
|
.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}
|
|
596
605
|
.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}
|
|
597
606
|
.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}
|
|
@@ -599,18 +608,26 @@ var compareCss = `
|
|
|
599
608
|
/* Glass: what's behind shows through, blurred, on the knobs tokens. */
|
|
600
609
|
.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);
|
|
601
610
|
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)))}
|
|
602
|
-
|
|
603
|
-
.knobs-cmp-label
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
611
|
+
/* ✗ Before · ✓ After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */
|
|
612
|
+
.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);
|
|
613
|
+
white-space:nowrap;pointer-events:none;will-change:transform}
|
|
614
|
+
.knobs-cmp-label[data-side="before"]{color:var(--_k-fg-3)}
|
|
615
|
+
.knobs-cmp-label[data-side="after"]{color:var(--_k-fg)}
|
|
616
|
+
.knobs-cmp-mark svg{display:block;width:12px;height:12px}
|
|
617
|
+
/* The wipe: a hairline down the line with a raised grip at the pointer's height; a wider strip
|
|
618
|
+
takes the hand and the keys (a slider). It fades with the mode; wiping, line and grip brighten. */
|
|
607
619
|
.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)}
|
|
608
620
|
.knobs-cmp-handle[data-on]{opacity:1;pointer-events:auto;transition:opacity .22s cubic-bezier(.2,.8,.2,1)}
|
|
609
|
-
.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)}
|
|
610
|
-
.knobs-cmp-handle::
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
.knobs-cmp-
|
|
621
|
+
.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)}
|
|
622
|
+
.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}
|
|
623
|
+
.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);
|
|
624
|
+
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)}
|
|
625
|
+
.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)}
|
|
626
|
+
.knobs-cmp-grip::before{left:6px}
|
|
627
|
+
.knobs-cmp-grip::after{left:9px}
|
|
628
|
+
.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)}
|
|
629
|
+
.knobs-compare[data-dragging] .knobs-cmp-grip::before,.knobs-compare[data-dragging] .knobs-cmp-grip::after{background:var(--_k-fg)}
|
|
630
|
+
.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)}
|
|
614
631
|
/* The split's hairline, down the middle side by side. */
|
|
615
632
|
.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}
|
|
616
633
|
/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */
|
|
@@ -619,12 +636,12 @@ var compareCss = `
|
|
|
619
636
|
opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}
|
|
620
637
|
.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)}
|
|
621
638
|
: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;
|
|
622
|
-
height:20px;padding:0
|
|
639
|
+
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}
|
|
623
640
|
: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)}
|
|
624
641
|
.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}
|
|
625
642
|
.knobs-cmp-note:empty{display:none}
|
|
626
643
|
.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}
|
|
627
|
-
.knobs-cmp-timeline-host{flex:none;
|
|
644
|
+
.knobs-cmp-timeline-host{flex:none;min-height:0}
|
|
628
645
|
/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */
|
|
629
646
|
.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;
|
|
630
647
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg)}
|
|
@@ -767,7 +784,7 @@ var init_picker_css = __esm(() => {
|
|
|
767
784
|
.knobs-picker-suggested{flex:none;color:var(--_k-fg-3);font-size:var(--_k-text-meta)}
|
|
768
785
|
.knobs-picker-check{flex:none;display:flex;width:14px;height:14px;color:var(--_k-accent);opacity:0;scale:.6;filter:blur(2px);
|
|
769
786
|
transition:opacity .11s ease-in,scale .11s ease-in,filter .11s ease-in}
|
|
770
|
-
.knobs-picker-check svg{display:block;width:
|
|
787
|
+
.knobs-picker-check svg{display:block;width:12px;height:12px}
|
|
771
788
|
.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}
|
|
772
789
|
.knobs-picker-body{position:relative;overflow:visible}
|
|
773
790
|
.knobs-picker-body[data-moving]{overflow:hidden}
|
|
@@ -871,6 +888,15 @@ var readoutCss = `
|
|
|
871
888
|
@media(prefers-reduced-motion:reduce){.knobs-rd :where(*){transition:none!important}}
|
|
872
889
|
`;
|
|
873
890
|
|
|
891
|
+
// src/ui/selection-pill-css.ts
|
|
892
|
+
var selectionPillCss = `
|
|
893
|
+
.knobs-pick-pill,.knobs-pick-copy{position:absolute;left:0;top:0;width:0;height:0;pointer-events:none;transition:opacity .1s linear}
|
|
894
|
+
.knobs-pick-pill{background:var(--_k-fill-selected);will-change:transform}
|
|
895
|
+
.knobs-pick-copy{overflow:hidden;will-change:transform}
|
|
896
|
+
.knobs-pick-copy-rows{position:absolute;left:0;top:0;width:0;height:0}
|
|
897
|
+
:is(.knobs-pick-pill,.knobs-pick-copy)[data-off]{opacity:0}
|
|
898
|
+
`;
|
|
899
|
+
|
|
874
900
|
// src/tokens/color.ts
|
|
875
901
|
function linearToOklch([r, g, b, a]) {
|
|
876
902
|
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
@@ -1311,6 +1337,22 @@ var init_schema = __esm(() => {
|
|
|
1311
1337
|
source: css("var(--k-warn)"),
|
|
1312
1338
|
doc: "Modified lines."
|
|
1313
1339
|
},
|
|
1340
|
+
{
|
|
1341
|
+
name: "before",
|
|
1342
|
+
tier: "semantic",
|
|
1343
|
+
type: "color",
|
|
1344
|
+
group: "Data",
|
|
1345
|
+
source: css("var(--k-fg-3)"),
|
|
1346
|
+
doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
name: "after",
|
|
1350
|
+
tier: "semantic",
|
|
1351
|
+
type: "color",
|
|
1352
|
+
group: "Data",
|
|
1353
|
+
source: css("var(--k-fg)"),
|
|
1354
|
+
doc: "After in a comparison, and only After."
|
|
1355
|
+
},
|
|
1314
1356
|
{
|
|
1315
1357
|
name: "series-1",
|
|
1316
1358
|
tier: "semantic",
|
|
@@ -1401,6 +1443,150 @@ var init_schema = __esm(() => {
|
|
|
1401
1443
|
source: value("288px"),
|
|
1402
1444
|
doc: "Panel width."
|
|
1403
1445
|
},
|
|
1446
|
+
{
|
|
1447
|
+
name: "space-inside",
|
|
1448
|
+
tier: "semantic",
|
|
1449
|
+
type: "length",
|
|
1450
|
+
group: "Space",
|
|
1451
|
+
source: css("var(--k-unit)"),
|
|
1452
|
+
doc: "Parts of one thing: an icon and its label, a meta line and its title."
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
name: "space-sibling",
|
|
1456
|
+
tier: "semantic",
|
|
1457
|
+
type: "length",
|
|
1458
|
+
group: "Space",
|
|
1459
|
+
source: css("calc(var(--k-unit) * 2)"),
|
|
1460
|
+
doc: "Siblings in a group: buttons in a row, a list item's lines."
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
name: "space-title",
|
|
1464
|
+
tier: "semantic",
|
|
1465
|
+
type: "length",
|
|
1466
|
+
group: "Space",
|
|
1467
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1468
|
+
doc: "A heading and what it heads."
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
name: "space-group",
|
|
1472
|
+
tier: "semantic",
|
|
1473
|
+
type: "length",
|
|
1474
|
+
group: "Space",
|
|
1475
|
+
source: css("calc(var(--k-unit) * 12)"),
|
|
1476
|
+
doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
name: "space-section",
|
|
1480
|
+
tier: "semantic",
|
|
1481
|
+
type: "length",
|
|
1482
|
+
group: "Space",
|
|
1483
|
+
source: css("calc(var(--k-unit) * 24)"),
|
|
1484
|
+
doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
name: "space-column",
|
|
1488
|
+
tier: "semantic",
|
|
1489
|
+
type: "length",
|
|
1490
|
+
group: "Space",
|
|
1491
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1492
|
+
doc: "Columns: a contents rail and the page, media side by side."
|
|
1493
|
+
},
|
|
1494
|
+
{
|
|
1495
|
+
name: "pad-page",
|
|
1496
|
+
tier: "semantic",
|
|
1497
|
+
type: "length",
|
|
1498
|
+
group: "Space",
|
|
1499
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1500
|
+
doc: "A page's edge; 16px under 640px wide."
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
name: "pad-card",
|
|
1504
|
+
tier: "semantic",
|
|
1505
|
+
type: "length",
|
|
1506
|
+
group: "Space",
|
|
1507
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1508
|
+
doc: "Inside a card or popover."
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
name: "type-heading",
|
|
1512
|
+
tier: "semantic",
|
|
1513
|
+
type: "length",
|
|
1514
|
+
group: "Type",
|
|
1515
|
+
source: value("20px"),
|
|
1516
|
+
doc: "Section headings (a PR's title, under its kicker), weight 500."
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
name: "leading-heading",
|
|
1520
|
+
tier: "semantic",
|
|
1521
|
+
type: "length",
|
|
1522
|
+
group: "Type",
|
|
1523
|
+
source: value("28px"),
|
|
1524
|
+
doc: "Line height for type-heading."
|
|
1525
|
+
},
|
|
1526
|
+
{
|
|
1527
|
+
name: "type-title",
|
|
1528
|
+
tier: "semantic",
|
|
1529
|
+
type: "length",
|
|
1530
|
+
group: "Type",
|
|
1531
|
+
source: value("16px"),
|
|
1532
|
+
doc: "A page's title, weight 500."
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
name: "leading-title",
|
|
1536
|
+
tier: "semantic",
|
|
1537
|
+
type: "length",
|
|
1538
|
+
group: "Type",
|
|
1539
|
+
source: value("24px"),
|
|
1540
|
+
doc: "Line height for type-title."
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
name: "type-body",
|
|
1544
|
+
tier: "semantic",
|
|
1545
|
+
type: "length",
|
|
1546
|
+
group: "Type",
|
|
1547
|
+
source: value("13px"),
|
|
1548
|
+
doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
name: "leading-body",
|
|
1552
|
+
tier: "semantic",
|
|
1553
|
+
type: "length",
|
|
1554
|
+
group: "Type",
|
|
1555
|
+
source: value("20px"),
|
|
1556
|
+
doc: "Line height for type-body."
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
name: "type-label",
|
|
1560
|
+
tier: "semantic",
|
|
1561
|
+
type: "length",
|
|
1562
|
+
group: "Type",
|
|
1563
|
+
source: value("12px"),
|
|
1564
|
+
doc: "Labels over media, weight 500; mono inside body text."
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
name: "leading-label",
|
|
1568
|
+
tier: "semantic",
|
|
1569
|
+
type: "length",
|
|
1570
|
+
group: "Type",
|
|
1571
|
+
source: value("16px"),
|
|
1572
|
+
doc: "Line height for type-label."
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
name: "type-small",
|
|
1576
|
+
tier: "semantic",
|
|
1577
|
+
type: "length",
|
|
1578
|
+
group: "Type",
|
|
1579
|
+
source: value("11px"),
|
|
1580
|
+
doc: "Meta, controls, keys, timestamps; mono inside labels."
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
name: "leading-small",
|
|
1584
|
+
tier: "semantic",
|
|
1585
|
+
type: "length",
|
|
1586
|
+
group: "Type",
|
|
1587
|
+
source: value("16px"),
|
|
1588
|
+
doc: "Line height for type-small."
|
|
1589
|
+
},
|
|
1404
1590
|
{
|
|
1405
1591
|
name: "font-size",
|
|
1406
1592
|
tier: "semantic",
|
|
@@ -2365,16 +2551,18 @@ function injectTokens(doc) {
|
|
|
2365
2551
|
style.textContent = rootCss;
|
|
2366
2552
|
doc.head.append(style);
|
|
2367
2553
|
}
|
|
2368
|
-
var ROOT_CLASS = "knobs-root", extras, spring, rootCss;
|
|
2554
|
+
var ROOT_CLASS = "knobs-root", extras, narrow, spring, rootCss;
|
|
2369
2555
|
var init_root = __esm(() => {
|
|
2370
2556
|
init_knobs();
|
|
2371
2557
|
init_css();
|
|
2372
2558
|
init_glide();
|
|
2373
2559
|
init_motion();
|
|
2374
2560
|
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))}`;
|
|
2561
|
+
narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`;
|
|
2375
2562
|
spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`;
|
|
2376
2563
|
rootCss = `${tokensCss(knobs)}
|
|
2377
2564
|
${extras}
|
|
2565
|
+
${narrow}
|
|
2378
2566
|
${spring}
|
|
2379
2567
|
${DRIVERS}
|
|
2380
2568
|
${motionCss}`;
|
|
@@ -2585,6 +2773,12 @@ var css2 = `
|
|
|
2585
2773
|
--_ku-pane-bg and --_ku-pane-ring so this reaches them. */
|
|
2586
2774
|
: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;
|
|
2587
2775
|
--_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
|
|
2776
|
+
/* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
|
|
2777
|
+
ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
|
|
2778
|
+
card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
|
|
2779
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
|
|
2780
|
+
: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)}
|
|
2781
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
|
|
2588
2782
|
/* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
|
|
2589
2783
|
.knobs-ui{box-sizing:border-box}
|
|
2590
2784
|
: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}
|
|
@@ -2719,11 +2913,9 @@ var css2 = `
|
|
|
2719
2913
|
.knobs-tree:focus .knobs-tree-row[data-active][aria-selected="true"]::before{background:var(--_ku-select-focus)}
|
|
2720
2914
|
.knobs-tree-row[data-drop="into"]::before{opacity:1;background:color-mix(in srgb,var(--_k-accent) 30%,transparent)}
|
|
2721
2915
|
.knobs-tree-row[data-dragged]{opacity:.38}
|
|
2722
|
-
/* glide:
|
|
2723
|
-
.knobs-tree-
|
|
2724
|
-
|
|
2725
|
-
.knobs-tree-cursor[data-on]{opacity:1}
|
|
2726
|
-
.knobs-tree:focus .knobs-tree-cursor{background:var(--_ku-select-focus)}
|
|
2916
|
+
/* glide: the selection pill on the selected row, in the selection's colour (the row's own stays off). */
|
|
2917
|
+
.knobs-tree>.knobs-pick-pill{background:var(--_ku-select)}
|
|
2918
|
+
.knobs-tree:focus>.knobs-pick-pill{background:var(--_ku-select-focus)}
|
|
2727
2919
|
.knobs-tree[data-glide] .knobs-tree-row[aria-selected="true"]::before{opacity:0!important}
|
|
2728
2920
|
.knobs-tree-row>*{position:relative}
|
|
2729
2921
|
.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)}
|
|
@@ -2755,22 +2947,20 @@ var css2 = `
|
|
|
2755
2947
|
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)}
|
|
2756
2948
|
.knobs-tree-empty{padding:10px var(--_k-inset);color:var(--_k-fg-3)}
|
|
2757
2949
|
|
|
2758
|
-
/* Timeline:
|
|
2759
|
-
|
|
2950
|
+
/* Timeline: play beside a track: the ruler's canvas over a lane of markers, ranges as soft bands,
|
|
2951
|
+
and the playhead, a hairline in the accent with a cap. No clock: the time shows under the
|
|
2952
|
+
pointer on the track (the tag), in seconds, while hovering or scrubbing. */
|
|
2760
2953
|
:where(.knobs-timeline,.knobs-timeline *){box-sizing:border-box}
|
|
2761
2954
|
.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;
|
|
2762
2955
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
2763
2956
|
: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}
|
|
2764
|
-
.knobs-tl-transport{flex:none;display:flex;align-items:center
|
|
2957
|
+
.knobs-tl-transport{flex:none;display:flex;align-items:center}
|
|
2765
2958
|
.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);
|
|
2766
2959
|
background:var(--_k-fill-selected);color:var(--_k-fg);cursor:pointer;transition:background .15s,transform .15s var(--_ku-ease)}
|
|
2767
2960
|
.knobs-ui .knobs-tl-play:hover{background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
2768
2961
|
.knobs-ui .knobs-tl-play:active{transform:scale(.94)}
|
|
2769
2962
|
.knobs-tl-play svg{width:12px;height:12px}
|
|
2770
2963
|
.knobs-timeline[data-playing] .knobs-tl-play{background:var(--_k-accent);color:var(--_k-bg)}
|
|
2771
|
-
.knobs-tl-time{display:flex;flex-direction:column;line-height:1.2;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
2772
|
-
.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}
|
|
2773
|
-
.knobs-tl-sub{font-size:var(--_k-text-meta);color:var(--_k-fg-3);white-space:nowrap}
|
|
2774
2964
|
.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;
|
|
2775
2965
|
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
2776
2966
|
.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)}
|
|
@@ -2794,7 +2984,8 @@ var css2 = `
|
|
|
2794
2984
|
.knobs-tl-pin{position:absolute;top:13px;left:-5px;width:10px;height:10px;pointer-events:auto;cursor:grab}
|
|
2795
2985
|
.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)}
|
|
2796
2986
|
.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);
|
|
2797
|
-
font-size:var(--_k-text-meta);line-height:17px;white-space:nowrap;
|
|
2987
|
+
font-size:var(--_k-text-meta);line-height:17px;white-space:nowrap;pointer-events:auto;cursor:grab;transition:background .15s,color .15s}
|
|
2988
|
+
.knobs-tl-mtext{display:block;overflow:hidden;white-space:nowrap}
|
|
2798
2989
|
.knobs-tl-marker[data-selected]{--knobs-tl-c:var(--_k-accent)}
|
|
2799
2990
|
.knobs-tl-marker[data-selected] .knobs-tl-mlabel{background:color-mix(in srgb,var(--_k-accent) 24%,var(--_k-fill-selected))}
|
|
2800
2991
|
.knobs-tl-marker[data-selected] .knobs-tl-pin::after{scale:1.2}
|
|
@@ -2815,7 +3006,22 @@ var css2 = `
|
|
|
2815
3006
|
.knobs-timeline[data-scrubbing] .knobs-tl-hover{opacity:0}
|
|
2816
3007
|
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
2817
3008
|
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
2818
|
-
|
|
3009
|
+
.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}
|
|
3010
|
+
.knobs-tl-tag[data-on]{opacity:1}
|
|
3011
|
+
/* The lane (variant: "lane"): one slim track of ticks under a compare or a video; markers are
|
|
3012
|
+
faint chapter ticks, the current one in text colour; nothing to edit. */
|
|
3013
|
+
.knobs-ui.knobs-timeline[data-variant="lane"]{height:auto;min-height:0;padding:0;gap:var(--_k-gap)}
|
|
3014
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-track{height:var(--_k-control-h)}
|
|
3015
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-ruler{height:100%}
|
|
3016
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-lane{top:0}
|
|
3017
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker{top:0}
|
|
3018
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker::before{top:0;bottom:50%;left:-.75px;width:1.5px;background:var(--_k-fg-3)}
|
|
3019
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker[data-current]::before{background:var(--_k-fg)}
|
|
3020
|
+
.knobs-timeline[data-variant="lane"] :is(.knobs-tl-pin,.knobs-tl-mlabel,.knobs-tl-rlabel){display:none}
|
|
3021
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-head::before{top:0}
|
|
3022
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-head::after{content:none}
|
|
3023
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-tag{top:2px;bottom:auto}
|
|
3024
|
+
`, uiCss = () => aliased(css2 + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + compareCss + selectionPillCss) + rolling_css_default, lookDefaults, tune = (s, m) => {
|
|
2819
3025
|
s.omega = m.omega;
|
|
2820
3026
|
s.zeta = m.zeta;
|
|
2821
3027
|
return s;
|
|
@@ -2973,33 +3179,29 @@ var init_diff_css = __esm(() => {
|
|
|
2973
3179
|
.knobs-diff-fill{flex:1}
|
|
2974
3180
|
.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}
|
|
2975
3181
|
.knobs-diff-nav>span{min-width:3.6em;text-align:center}
|
|
2976
|
-
:where(.knobs-ui) :is(.knobs-diff-btn,.knobs-diff-
|
|
3182
|
+
: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;
|
|
2977
3183
|
margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
2978
|
-
.knobs-ui .knobs-diff-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;width:
|
|
3184
|
+
.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;
|
|
2979
3185
|
transition:background .15s,color .15s,opacity .15s}
|
|
2980
3186
|
.knobs-ui .knobs-diff-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
2981
3187
|
.knobs-ui .knobs-diff-btn[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
2982
3188
|
.knobs-ui .knobs-diff-btn:disabled{opacity:.35;cursor:default;background:transparent}
|
|
2983
|
-
.knobs-diff-btn svg{width:
|
|
3189
|
+
.knobs-diff-btn svg{width:16px;height:16px}
|
|
2984
3190
|
/* Viewed: a check with its word, as on GitHub; the path dims once it's ticked. */
|
|
2985
3191
|
.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);
|
|
2986
3192
|
font-size:var(--_k-text-meta);font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:background .15s,color .15s}
|
|
2987
3193
|
.knobs-ui .knobs-diff-viewed:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
2988
3194
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
2989
|
-
.knobs-diff-viewed svg{width:
|
|
3195
|
+
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
2990
3196
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
2991
3197
|
.knobs-diff-path{transition:opacity .2s}
|
|
2992
3198
|
.knobs-diff[data-viewed]>.knobs-diff-head .knobs-diff-path,.knobs-diff-part[data-viewed] .knobs-diff-path{opacity:.6}
|
|
2993
|
-
/* Split | Unified:
|
|
2994
|
-
|
|
2995
|
-
.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-
|
|
2996
|
-
.knobs-ui .knobs-diff-
|
|
2997
|
-
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:color
|
|
2998
|
-
.knobs-ui .knobs-diff-
|
|
2999
|
-
.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));
|
|
3000
|
-
box-shadow:0 1px 2px rgba(0,0,0,calc(.16 * var(--k-lift,1)));transition:transform var(--_ku-ease-ms) var(--_ku-ease)}
|
|
3001
|
-
.knobs-diff-seg[data-value="unified"]>.knobs-diff-pill{transform:translateX(100%)}
|
|
3002
|
-
.knobs-diff[data-frame="flat"] .knobs-diff-pill{box-shadow:none}
|
|
3199
|
+
/* Split | Unified: the selection pill on the one picked, its bright copy the picked one's text; a
|
|
3200
|
+
choice isn't brighter for being picked. Choices are styled by class, as the copy holds them too. */
|
|
3201
|
+
.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)}
|
|
3202
|
+
.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);
|
|
3203
|
+
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
3204
|
+
.knobs-ui .knobs-diff-choice:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
3003
3205
|
/* The diff: one layer per file or layout on show, the old fading under the new. */
|
|
3004
3206
|
.knobs-diff-body{position:relative;flex:1;min-height:0}
|
|
3005
3207
|
.knobs-diff-probe{position:absolute;left:0;top:0;width:0;height:var(--kd-line);visibility:hidden;pointer-events:none}
|
|
@@ -3094,7 +3296,7 @@ var init_diff_css = __esm(() => {
|
|
|
3094
3296
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
3095
3297
|
.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}
|
|
3096
3298
|
.knobs-ui .knobs-diff-filter>button:hover{background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
3097
|
-
.knobs-diff-filter>button svg{width:
|
|
3299
|
+
.knobs-diff-filter>button svg{width:12px;height:12px}
|
|
3098
3300
|
.knobs-diff-list{position:relative;flex:1;min-height:0}
|
|
3099
3301
|
.knobs-diff-files .knobs-diff-counts{font-size:var(--_k-text-meta);align-items:center}
|
|
3100
3302
|
.knobs-diff-files .knobs-diff-counts{gap:5px}
|
|
@@ -3861,6 +4063,283 @@ var init_rgba = __esm(() => {
|
|
|
3861
4063
|
cache = new Map;
|
|
3862
4064
|
});
|
|
3863
4065
|
|
|
4066
|
+
// src/ui/icons.ts
|
|
4067
|
+
function icon(name, options = {}) {
|
|
4068
|
+
const size = options.small ? 12 : 16;
|
|
4069
|
+
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>`;
|
|
4070
|
+
}
|
|
4071
|
+
var PATHS, ICON_NAMES;
|
|
4072
|
+
var init_icons = __esm(() => {
|
|
4073
|
+
PATHS = {
|
|
4074
|
+
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",
|
|
4075
|
+
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",
|
|
4076
|
+
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",
|
|
4077
|
+
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",
|
|
4078
|
+
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",
|
|
4079
|
+
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",
|
|
4080
|
+
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",
|
|
4081
|
+
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",
|
|
4082
|
+
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",
|
|
4083
|
+
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",
|
|
4084
|
+
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",
|
|
4085
|
+
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",
|
|
4086
|
+
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",
|
|
4087
|
+
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",
|
|
4088
|
+
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",
|
|
4089
|
+
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",
|
|
4090
|
+
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",
|
|
4091
|
+
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",
|
|
4092
|
+
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",
|
|
4093
|
+
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",
|
|
4094
|
+
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",
|
|
4095
|
+
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",
|
|
4096
|
+
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",
|
|
4097
|
+
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",
|
|
4098
|
+
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",
|
|
4099
|
+
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",
|
|
4100
|
+
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"
|
|
4101
|
+
};
|
|
4102
|
+
ICON_NAMES = Object.keys(PATHS);
|
|
4103
|
+
});
|
|
4104
|
+
|
|
4105
|
+
// src/ui/selection-pill.ts
|
|
4106
|
+
function pillSpring(distance, base = SPRINGS.default) {
|
|
4107
|
+
return distance > 400 ? { duration: base.duration * 1.4, bounce: base.bounce } : base;
|
|
4108
|
+
}
|
|
4109
|
+
function pillBoxOf(row, container) {
|
|
4110
|
+
return {
|
|
4111
|
+
x: row.left - container.left - container.clientLeft + container.scrollLeft,
|
|
4112
|
+
y: row.top - container.top - container.clientTop + container.scrollTop,
|
|
4113
|
+
w: row.width,
|
|
4114
|
+
h: row.height
|
|
4115
|
+
};
|
|
4116
|
+
}
|
|
4117
|
+
function pillRadius(from, to, h, k) {
|
|
4118
|
+
const t = Math.abs(to.h - from.h) > 0.5 ? (h - from.h) / (to.h - from.h) : Number.isFinite(k) ? k : 1;
|
|
4119
|
+
return from.r + (to.r - from.r) * Math.min(1, Math.max(0, t));
|
|
4120
|
+
}
|
|
4121
|
+
function pillProgress(from, to, at) {
|
|
4122
|
+
const d = Math.hypot(to.x - from.x, to.y - from.y);
|
|
4123
|
+
if (d < 0.5)
|
|
4124
|
+
return 1;
|
|
4125
|
+
const p = ((at.x - from.x) * (to.x - from.x) + (at.y - from.y) * (to.y - from.y)) / (d * d);
|
|
4126
|
+
return Math.min(1, Math.max(0, p));
|
|
4127
|
+
}
|
|
4128
|
+
function planPill(state, next, flags = {}) {
|
|
4129
|
+
if (!next)
|
|
4130
|
+
return { kind: "hide" };
|
|
4131
|
+
if (!state.shown || !state.at || flags.first || flags.reduced || flags.snap)
|
|
4132
|
+
return { kind: "land", box: next };
|
|
4133
|
+
const t = state.target;
|
|
4134
|
+
if (t && t.x === next.x && t.y === next.y && t.w === next.w && t.h === next.h)
|
|
4135
|
+
return { kind: "stay" };
|
|
4136
|
+
const d = Math.hypot(next.x - state.at.x, next.y - state.at.y);
|
|
4137
|
+
return { kind: "travel", box: next, spring: pillSpring(d) };
|
|
4138
|
+
}
|
|
4139
|
+
function selectionPill(container, options) {
|
|
4140
|
+
const doc = container.ownerDocument;
|
|
4141
|
+
const win = doc.defaultView;
|
|
4142
|
+
injectUiStyles(doc);
|
|
4143
|
+
if (win.getComputedStyle(container).position === "static")
|
|
4144
|
+
container.style.position = "relative";
|
|
4145
|
+
const pill = doc.createElement("i");
|
|
4146
|
+
pill.className = "knobs-pick-pill";
|
|
4147
|
+
pill.setAttribute("aria-hidden", "true");
|
|
4148
|
+
pill.dataset.off = "";
|
|
4149
|
+
const copyOn = options.copy !== false;
|
|
4150
|
+
const copy = doc.createElement("div");
|
|
4151
|
+
copy.className = "knobs-pick-copy";
|
|
4152
|
+
copy.setAttribute("aria-hidden", "true");
|
|
4153
|
+
copy.inert = true;
|
|
4154
|
+
copy.dataset.off = "";
|
|
4155
|
+
const copyRows = doc.createElement("div");
|
|
4156
|
+
copyRows.className = "knobs-pick-copy-rows";
|
|
4157
|
+
copy.append(copyRows);
|
|
4158
|
+
container.prepend(pill);
|
|
4159
|
+
if (copyOn)
|
|
4160
|
+
container.append(copy);
|
|
4161
|
+
const { omega, zeta } = springMotion(SPRINGS.default);
|
|
4162
|
+
const springs = [0, 0, 0, 0].map(() => new Spring(0, omega, zeta, 0.01));
|
|
4163
|
+
const [sx, sy, sw, sh] = springs;
|
|
4164
|
+
let shown = false;
|
|
4165
|
+
let first = true;
|
|
4166
|
+
let target = null;
|
|
4167
|
+
let from = { x: 0, y: 0, w: 0, h: 0 };
|
|
4168
|
+
let fromR = 0;
|
|
4169
|
+
let toR = 0;
|
|
4170
|
+
let rowBoxes = [];
|
|
4171
|
+
const clones = new Map;
|
|
4172
|
+
let disposed = false;
|
|
4173
|
+
const radiusOf = (row) => options.radius?.(row) ?? (Number.parseFloat(win.getComputedStyle(row).borderTopLeftRadius) || 0);
|
|
4174
|
+
const rowsNow = () => options.rows ? [...options.rows()] : [...container.children].filter((n) => n !== pill && n !== copy);
|
|
4175
|
+
const measure = (row) => {
|
|
4176
|
+
const c = container.getBoundingClientRect();
|
|
4177
|
+
const r = row.getBoundingClientRect();
|
|
4178
|
+
return pillBoxOf(r, {
|
|
4179
|
+
left: c.left,
|
|
4180
|
+
top: c.top,
|
|
4181
|
+
scrollLeft: container.scrollLeft,
|
|
4182
|
+
scrollTop: container.scrollTop,
|
|
4183
|
+
clientLeft: container.clientLeft,
|
|
4184
|
+
clientTop: container.clientTop
|
|
4185
|
+
});
|
|
4186
|
+
};
|
|
4187
|
+
const at = () => ({ x: sx.x, y: sy.x, w: sw.x, h: sh.x });
|
|
4188
|
+
const syncCopy = (span) => {
|
|
4189
|
+
if (!copyOn)
|
|
4190
|
+
return;
|
|
4191
|
+
const keep = new Set;
|
|
4192
|
+
for (const { row, box } of rowBoxes) {
|
|
4193
|
+
if (!boxesMeet(box, span))
|
|
4194
|
+
continue;
|
|
4195
|
+
keep.add(row);
|
|
4196
|
+
let n = clones.get(row);
|
|
4197
|
+
if (!n) {
|
|
4198
|
+
n = row.cloneNode(true);
|
|
4199
|
+
n.removeAttribute("id");
|
|
4200
|
+
for (const d of n.querySelectorAll("[id]"))
|
|
4201
|
+
d.removeAttribute("id");
|
|
4202
|
+
clones.set(row, n);
|
|
4203
|
+
copyRows.append(n);
|
|
4204
|
+
}
|
|
4205
|
+
const s = n.style;
|
|
4206
|
+
s.position = "absolute";
|
|
4207
|
+
s.inset = "auto";
|
|
4208
|
+
s.left = `${box.x}px`;
|
|
4209
|
+
s.top = `${box.y}px`;
|
|
4210
|
+
s.width = `${box.w}px`;
|
|
4211
|
+
s.height = `${box.h}px`;
|
|
4212
|
+
s.margin = "0";
|
|
4213
|
+
s.transform = "none";
|
|
4214
|
+
s.clipPath = "";
|
|
4215
|
+
s.opacity = "";
|
|
4216
|
+
s.boxSizing = "border-box";
|
|
4217
|
+
s.color = options.color ?? "var(--_k-fg)";
|
|
4218
|
+
}
|
|
4219
|
+
for (const [row, n] of clones)
|
|
4220
|
+
if (!keep.has(row)) {
|
|
4221
|
+
n.remove();
|
|
4222
|
+
clones.delete(row);
|
|
4223
|
+
}
|
|
4224
|
+
};
|
|
4225
|
+
const paint = () => {
|
|
4226
|
+
const b = at();
|
|
4227
|
+
const x0 = grid(b.x);
|
|
4228
|
+
const y0 = grid(b.y);
|
|
4229
|
+
const w = grid(b.x + b.w) - x0;
|
|
4230
|
+
const h = grid(b.y + b.h) - y0;
|
|
4231
|
+
const r = target ? pillRadius({ h: from.h, r: fromR }, { h: target.h, r: toR }, b.h, pillProgress(from, target, b)) : toR;
|
|
4232
|
+
const radius = `${Math.max(0, Math.min(r, h / 2, w / 2)).toFixed(2)}px`;
|
|
4233
|
+
for (const n of copyOn ? [pill, copy] : [pill]) {
|
|
4234
|
+
n.style.transform = `translate3d(${x0}px,${y0}px,0)`;
|
|
4235
|
+
n.style.width = `${w}px`;
|
|
4236
|
+
n.style.height = `${h}px`;
|
|
4237
|
+
n.style.borderRadius = radius;
|
|
4238
|
+
}
|
|
4239
|
+
if (copyOn)
|
|
4240
|
+
copyRows.style.transform = `translate3d(${-x0}px,${-y0}px,0)`;
|
|
4241
|
+
};
|
|
4242
|
+
const loop = frameLoop(win, (dt) => {
|
|
4243
|
+
for (const s of springs)
|
|
4244
|
+
s.step(dt);
|
|
4245
|
+
paint();
|
|
4246
|
+
return springs.some((s) => !s.resting);
|
|
4247
|
+
});
|
|
4248
|
+
const show = (on) => {
|
|
4249
|
+
shown = on;
|
|
4250
|
+
pill.toggleAttribute("data-off", !on);
|
|
4251
|
+
copy.toggleAttribute("data-off", !on);
|
|
4252
|
+
container.toggleAttribute("data-pick-empty", !on);
|
|
4253
|
+
};
|
|
4254
|
+
const update = (o) => {
|
|
4255
|
+
if (disposed)
|
|
4256
|
+
return;
|
|
4257
|
+
const row = options.selected();
|
|
4258
|
+
const next = row?.isConnected ? measure(row) : null;
|
|
4259
|
+
const plan = planPill({ shown, at: shown ? at() : null, target }, next, {
|
|
4260
|
+
first,
|
|
4261
|
+
reduced: reducedMotion(win),
|
|
4262
|
+
...o?.snap ? { snap: true } : {}
|
|
4263
|
+
});
|
|
4264
|
+
first = false;
|
|
4265
|
+
for (const n of clones.values())
|
|
4266
|
+
n.remove();
|
|
4267
|
+
clones.clear();
|
|
4268
|
+
rowBoxes = copyOn ? rowsNow().filter((r) => r.isConnected).map((r) => ({ row: r, box: measure(r) })) : [];
|
|
4269
|
+
if (plan.kind === "hide") {
|
|
4270
|
+
if (shown)
|
|
4271
|
+
show(false);
|
|
4272
|
+
return;
|
|
4273
|
+
}
|
|
4274
|
+
if (plan.kind === "stay") {
|
|
4275
|
+
syncCopy(boxUnion(at(), target));
|
|
4276
|
+
return;
|
|
4277
|
+
}
|
|
4278
|
+
const r = radiusOf(row);
|
|
4279
|
+
if (plan.kind === "land") {
|
|
4280
|
+
sx.snap(plan.box.x);
|
|
4281
|
+
sy.snap(plan.box.y);
|
|
4282
|
+
sw.snap(plan.box.w);
|
|
4283
|
+
sh.snap(plan.box.h);
|
|
4284
|
+
from = plan.box;
|
|
4285
|
+
fromR = r;
|
|
4286
|
+
toR = r;
|
|
4287
|
+
target = plan.box;
|
|
4288
|
+
syncCopy(plan.box);
|
|
4289
|
+
paint();
|
|
4290
|
+
loop.stop();
|
|
4291
|
+
if (!shown)
|
|
4292
|
+
show(true);
|
|
4293
|
+
return;
|
|
4294
|
+
}
|
|
4295
|
+
const m = springMotion(plan.spring);
|
|
4296
|
+
for (const s of springs) {
|
|
4297
|
+
s.omega = m.omega;
|
|
4298
|
+
s.zeta = m.zeta;
|
|
4299
|
+
}
|
|
4300
|
+
const now = at();
|
|
4301
|
+
fromR = target ? pillRadius({ h: from.h, r: fromR }, { h: target.h, r: toR }, now.h, pillProgress(from, target, now)) : r;
|
|
4302
|
+
from = now;
|
|
4303
|
+
toR = r;
|
|
4304
|
+
target = plan.box;
|
|
4305
|
+
sx.set(plan.box.x);
|
|
4306
|
+
sy.set(plan.box.y);
|
|
4307
|
+
sw.set(plan.box.w);
|
|
4308
|
+
sh.set(plan.box.h);
|
|
4309
|
+
syncCopy(boxUnion(now, plan.box));
|
|
4310
|
+
loop.wake();
|
|
4311
|
+
};
|
|
4312
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => update({ snap: true })) : null;
|
|
4313
|
+
ro?.observe(container);
|
|
4314
|
+
update();
|
|
4315
|
+
return {
|
|
4316
|
+
element: pill,
|
|
4317
|
+
update,
|
|
4318
|
+
dispose() {
|
|
4319
|
+
disposed = true;
|
|
4320
|
+
loop.stop();
|
|
4321
|
+
ro?.disconnect();
|
|
4322
|
+
pill.remove();
|
|
4323
|
+
copy.remove();
|
|
4324
|
+
container.removeAttribute("data-pick-empty");
|
|
4325
|
+
}
|
|
4326
|
+
};
|
|
4327
|
+
}
|
|
4328
|
+
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) => {
|
|
4329
|
+
const x = Math.min(a.x, b.x);
|
|
4330
|
+
const y = Math.min(a.y, b.y);
|
|
4331
|
+
return {
|
|
4332
|
+
x,
|
|
4333
|
+
y,
|
|
4334
|
+
w: Math.max(a.x + a.w, b.x + b.w) - x,
|
|
4335
|
+
h: Math.max(a.y + a.h, b.y + b.h) - y
|
|
4336
|
+
};
|
|
4337
|
+
}, grid = (v) => Math.round(v * 64) / 64;
|
|
4338
|
+
var init_selection_pill = __esm(() => {
|
|
4339
|
+
init_motion();
|
|
4340
|
+
init_look();
|
|
4341
|
+
});
|
|
4342
|
+
|
|
3864
4343
|
// src/panel/hints.ts
|
|
3865
4344
|
function extractWords(text) {
|
|
3866
4345
|
return text.toLowerCase().match(/[a-z]+/g) ?? [];
|
|
@@ -4689,34 +5168,27 @@ function tree(container, options) {
|
|
|
4689
5168
|
const empty = doc.createElement("div");
|
|
4690
5169
|
empty.className = "knobs-tree-empty";
|
|
4691
5170
|
empty.hidden = true;
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
5171
|
+
root.append(space, line, empty);
|
|
5172
|
+
let pill = null;
|
|
5173
|
+
let picked = null;
|
|
5174
|
+
let travelUntil = 0;
|
|
5175
|
+
const pickedRow = () => {
|
|
5176
|
+
const id = sel.ids.length === 1 ? sel.ids[0] : null;
|
|
5177
|
+
const v = id === null ? undefined : views.get(id);
|
|
5178
|
+
return v && !v.leaving && rowIndex.has(v.id) ? v : null;
|
|
4699
5179
|
};
|
|
4700
5180
|
const placeCursor = (animate) => {
|
|
4701
|
-
if (!
|
|
5181
|
+
if (!pill)
|
|
4702
5182
|
return;
|
|
4703
5183
|
const id = sel.ids.length === 1 ? sel.ids[0] : null;
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
}
|
|
4711
|
-
|
|
4712
|
-
cursorY.set(i * h);
|
|
4713
|
-
else
|
|
4714
|
-
cursorY.snap(i * h);
|
|
4715
|
-
cursorOn = true;
|
|
4716
|
-
cursor.setAttribute("data-on", "");
|
|
4717
|
-
drawCursor();
|
|
4718
|
-
if (!cursorY.resting)
|
|
4719
|
-
loop.wake();
|
|
5184
|
+
root.toggleAttribute("data-glide", id !== null && rowIndex.has(id));
|
|
5185
|
+
const fresh = id !== picked;
|
|
5186
|
+
picked = id;
|
|
5187
|
+
if (animate && fresh) {
|
|
5188
|
+
travelUntil = performance.now() + 450;
|
|
5189
|
+
pill.update();
|
|
5190
|
+
} else if (performance.now() >= travelUntil)
|
|
5191
|
+
pill.update({ snap: true });
|
|
4720
5192
|
};
|
|
4721
5193
|
container.append(root);
|
|
4722
5194
|
const scrollbar = overlayScrollbar(root, space);
|
|
@@ -4745,6 +5217,12 @@ function tree(container, options) {
|
|
|
4745
5217
|
};
|
|
4746
5218
|
const views = new Map;
|
|
4747
5219
|
const pool = [];
|
|
5220
|
+
if (options.glide)
|
|
5221
|
+
pill = selectionPill(root, {
|
|
5222
|
+
rows: () => [...views.values()].filter((v) => !v.leaving).map((v) => v.el),
|
|
5223
|
+
selected: () => pickedRow()?.el ?? null,
|
|
5224
|
+
radius: (row) => Number.parseFloat(win.getComputedStyle(row, "::before").borderTopLeftRadius) || 0
|
|
5225
|
+
});
|
|
4748
5226
|
const makeView = (id) => {
|
|
4749
5227
|
const v = pool.pop() ?? createView();
|
|
4750
5228
|
v.id = id;
|
|
@@ -4925,12 +5403,6 @@ function tree(container, options) {
|
|
|
4925
5403
|
function frame(dt) {
|
|
4926
5404
|
let moving = false;
|
|
4927
5405
|
let bottom = rows.length * h;
|
|
4928
|
-
if (options.glide && !cursorY.resting) {
|
|
4929
|
-
cursorY.step(dt);
|
|
4930
|
-
drawCursor();
|
|
4931
|
-
if (!cursorY.resting)
|
|
4932
|
-
moving = true;
|
|
4933
|
-
}
|
|
4934
5406
|
for (const v of views.values()) {
|
|
4935
5407
|
v.y.step(dt);
|
|
4936
5408
|
if (!v.y.resting)
|
|
@@ -4950,6 +5422,8 @@ function tree(container, options) {
|
|
|
4950
5422
|
}
|
|
4951
5423
|
setSpace(moving ? bottom : rows.length * h);
|
|
4952
5424
|
trim();
|
|
5425
|
+
if (pill && moving && performance.now() >= travelUntil)
|
|
5426
|
+
pill.update({ snap: true });
|
|
4953
5427
|
return moving;
|
|
4954
5428
|
}
|
|
4955
5429
|
const trim = () => {
|
|
@@ -5578,6 +6052,7 @@ function tree(container, options) {
|
|
|
5578
6052
|
autoScroll.stop();
|
|
5579
6053
|
ro.disconnect();
|
|
5580
6054
|
scrollbar.dispose();
|
|
6055
|
+
pill?.dispose();
|
|
5581
6056
|
dragging?.ghost.remove();
|
|
5582
6057
|
root.remove();
|
|
5583
6058
|
}
|
|
@@ -5596,6 +6071,7 @@ var init_tree = __esm(() => {
|
|
|
5596
6071
|
init_motion();
|
|
5597
6072
|
init_page_hints();
|
|
5598
6073
|
init_look();
|
|
6074
|
+
init_selection_pill();
|
|
5599
6075
|
init_tree_model();
|
|
5600
6076
|
MOVE = springMotion(SPRINGS.default);
|
|
5601
6077
|
});
|
|
@@ -5732,7 +6208,7 @@ function codeDiff(container, options) {
|
|
|
5732
6208
|
};
|
|
5733
6209
|
const nav = make("span", "knobs-diff-nav");
|
|
5734
6210
|
const prev = button("Previous file", PREV);
|
|
5735
|
-
const next = button("Next file",
|
|
6211
|
+
const next = button("Next file", NEXT);
|
|
5736
6212
|
const place = make("span", "");
|
|
5737
6213
|
nav.append(prev, place, next);
|
|
5738
6214
|
const wrapButton = button("Wrap lines", WRAP);
|
|
@@ -5753,9 +6229,8 @@ function codeDiff(container, options) {
|
|
|
5753
6229
|
const seg = make("div", "knobs-diff-seg");
|
|
5754
6230
|
seg.setAttribute("role", "radiogroup");
|
|
5755
6231
|
seg.setAttribute("aria-label", "Layout");
|
|
5756
|
-
const pill = make("i", "knobs-diff-pill");
|
|
5757
6232
|
const choice = (value, label) => {
|
|
5758
|
-
const b = make("button", "");
|
|
6233
|
+
const b = make("button", "knobs-diff-choice");
|
|
5759
6234
|
b.type = "button";
|
|
5760
6235
|
b.setAttribute("role", "radio");
|
|
5761
6236
|
b.dataset.value = value;
|
|
@@ -5764,7 +6239,7 @@ function codeDiff(container, options) {
|
|
|
5764
6239
|
};
|
|
5765
6240
|
const splitButton = choice("split", "Split");
|
|
5766
6241
|
const unifiedButton = choice("unified", "Unified");
|
|
5767
|
-
seg.append(
|
|
6242
|
+
seg.append(splitButton, unifiedButton);
|
|
5768
6243
|
if (options.lead)
|
|
5769
6244
|
head.append(options.lead);
|
|
5770
6245
|
head.append(path, stat, make("span", "knobs-diff-fill"), nav, wrapButton, seg, viewedButton);
|
|
@@ -5775,6 +6250,11 @@ function codeDiff(container, options) {
|
|
|
5775
6250
|
body.append(note, probe);
|
|
5776
6251
|
root.append(head, body);
|
|
5777
6252
|
container.append(root);
|
|
6253
|
+
const segPill = selectionPill(seg, {
|
|
6254
|
+
rows: () => [splitButton, unifiedButton],
|
|
6255
|
+
selected: () => layout === "split" ? splitButton : unifiedButton
|
|
6256
|
+
});
|
|
6257
|
+
let pilled = layout;
|
|
5778
6258
|
const fileNow = () => files.find((f) => f.name === current) ?? null;
|
|
5779
6259
|
const paintHead = () => {
|
|
5780
6260
|
const file = fileNow();
|
|
@@ -5807,6 +6287,10 @@ function codeDiff(container, options) {
|
|
|
5807
6287
|
next.disabled = at >= files.length - 1;
|
|
5808
6288
|
wrapButton.setAttribute("aria-pressed", String(wrap));
|
|
5809
6289
|
seg.dataset.value = layout;
|
|
6290
|
+
if (pilled !== layout) {
|
|
6291
|
+
pilled = layout;
|
|
6292
|
+
segPill.update();
|
|
6293
|
+
}
|
|
5810
6294
|
splitButton.setAttribute("aria-checked", String(layout === "split"));
|
|
5811
6295
|
unifiedButton.setAttribute("aria-checked", String(layout === "unified"));
|
|
5812
6296
|
splitButton.tabIndex = layout === "split" ? 0 : -1;
|
|
@@ -6641,6 +7125,7 @@ function codeDiff(container, options) {
|
|
|
6641
7125
|
dispose() {
|
|
6642
7126
|
disposed = true;
|
|
6643
7127
|
loop.stop();
|
|
7128
|
+
segPill.dispose();
|
|
6644
7129
|
sizes.disconnect();
|
|
6645
7130
|
attaching.disconnect();
|
|
6646
7131
|
resized.disconnect();
|
|
@@ -6996,7 +7481,7 @@ function diffReview(container, options) {
|
|
|
6996
7481
|
}
|
|
6997
7482
|
};
|
|
6998
7483
|
}
|
|
6999
|
-
var lib, load = () => lib ??= import("@pierre/diffs"), SYNTAX, IN, OUT, FADE4, HEIGHT, DRAWER, BLUR = 3, WRAP, PREV, UNVIEWED, VIEWED, SEARCH, CLEAR2, SIDEBAR, SEPARATOR = 32;
|
|
7484
|
+
var lib, load = () => lib ??= import("@pierre/diffs"), SYNTAX, IN, OUT, FADE4, HEIGHT, DRAWER, BLUR = 3, WRAP, PREV, NEXT, UNVIEWED, VIEWED, SEARCH, CLEAR2, SIDEBAR, SEPARATOR = 32;
|
|
7000
7485
|
var init_diff = __esm(() => {
|
|
7001
7486
|
init_glide();
|
|
7002
7487
|
init_motion();
|
|
@@ -7004,6 +7489,8 @@ var init_diff = __esm(() => {
|
|
|
7004
7489
|
init_diff_model();
|
|
7005
7490
|
init_look();
|
|
7006
7491
|
init_rgba();
|
|
7492
|
+
init_icons();
|
|
7493
|
+
init_selection_pill();
|
|
7007
7494
|
init_tree();
|
|
7008
7495
|
SYNTAX = { dark: "pierre-dark", light: "pierre-light" };
|
|
7009
7496
|
IN = springMotion(SPRINGS.default);
|
|
@@ -7011,13 +7498,14 @@ var init_diff = __esm(() => {
|
|
|
7011
7498
|
FADE4 = springMotion(FADE);
|
|
7012
7499
|
HEIGHT = springMotion(SPRINGS.calm);
|
|
7013
7500
|
DRAWER = springMotion(SPRINGS.calm);
|
|
7014
|
-
WRAP =
|
|
7015
|
-
PREV =
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7501
|
+
WRAP = icon("arrowUDownLeft");
|
|
7502
|
+
PREV = icon("caretLeft");
|
|
7503
|
+
NEXT = icon("caretRight");
|
|
7504
|
+
UNVIEWED = icon("circle");
|
|
7505
|
+
VIEWED = icon("checkCircle");
|
|
7506
|
+
SEARCH = icon("magnifyingGlass", { small: true });
|
|
7507
|
+
CLEAR2 = icon("x", { small: true });
|
|
7508
|
+
SIDEBAR = icon("sidebar");
|
|
7021
7509
|
});
|
|
7022
7510
|
|
|
7023
7511
|
// src/ui/layer.ts
|
|
@@ -8000,10 +8488,25 @@ function advance(t, dt, o) {
|
|
|
8000
8488
|
}
|
|
8001
8489
|
return { t: hi, ended: true, wrapped: false };
|
|
8002
8490
|
}
|
|
8003
|
-
|
|
8491
|
+
function moveHead(head, t, motion, catching, minGap = 0) {
|
|
8492
|
+
if (motion === "jump" && Math.abs(t - head.x) > minGap)
|
|
8493
|
+
return { x: head.x, target: t, catching: true };
|
|
8494
|
+
if (catching)
|
|
8495
|
+
return { x: head.x + (t - head.target), target: t, catching: true };
|
|
8496
|
+
return { x: t, target: t, catching: false };
|
|
8497
|
+
}
|
|
8498
|
+
function currentMarker(markers, t, fps) {
|
|
8499
|
+
let best = null;
|
|
8500
|
+
for (const m of markers)
|
|
8501
|
+
if (m.time <= t + 0.5 / fps && (!best || m.time >= best.time))
|
|
8502
|
+
best = m;
|
|
8503
|
+
return best;
|
|
8504
|
+
}
|
|
8505
|
+
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;
|
|
8004
8506
|
var init_timeline_model = __esm(() => {
|
|
8005
8507
|
SECOND_STEPS = [0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600];
|
|
8006
8508
|
FRAME_STEPS = [1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 9000, 18000];
|
|
8509
|
+
CATCH_UP = { duration: 0.15, bounce: 0 };
|
|
8007
8510
|
});
|
|
8008
8511
|
|
|
8009
8512
|
// src/ui/timeline.ts
|
|
@@ -8016,6 +8519,7 @@ function timeline(container, options) {
|
|
|
8016
8519
|
let speed = options.speed ?? 1;
|
|
8017
8520
|
let repeat = options.repeat ?? true;
|
|
8018
8521
|
const arrows = options.arrows ?? "frames";
|
|
8522
|
+
const lane = options.variant === "lane";
|
|
8019
8523
|
let time = Math.min(duration, Math.max(0, options.time ?? 0));
|
|
8020
8524
|
let playing = false;
|
|
8021
8525
|
let markers = [...options.markers ?? []];
|
|
@@ -8049,27 +8553,27 @@ function timeline(container, options) {
|
|
|
8049
8553
|
root.setAttribute("aria-label", options.label ?? "Timeline");
|
|
8050
8554
|
root.setAttribute("aria-keyshortcuts", "Space ArrowLeft ArrowRight , . Home End [ ] I O M");
|
|
8051
8555
|
applyLook2(root, options);
|
|
8556
|
+
if (lane)
|
|
8557
|
+
root.dataset.variant = "lane";
|
|
8052
8558
|
const transport = el("div", "knobs-tl-transport");
|
|
8053
8559
|
const playBtn = el("button", "knobs-tl-play");
|
|
8054
8560
|
playBtn.type = "button";
|
|
8055
8561
|
playBtn.tabIndex = -1;
|
|
8056
|
-
|
|
8057
|
-
const now = el("span", "knobs-tl-now");
|
|
8058
|
-
const sub = el("span", "knobs-tl-sub");
|
|
8059
|
-
readout.append(now, sub);
|
|
8060
|
-
transport.append(playBtn, readout);
|
|
8562
|
+
transport.append(playBtn);
|
|
8061
8563
|
const track = el("div", "knobs-tl-track");
|
|
8062
8564
|
const canvas = el("canvas", "knobs-tl-ruler");
|
|
8063
8565
|
canvas.setAttribute("aria-hidden", "true");
|
|
8064
|
-
const
|
|
8566
|
+
const markerLane = el("div", "knobs-tl-lane");
|
|
8065
8567
|
const hover = el("div", "knobs-tl-hover");
|
|
8568
|
+
const tag = el("span", "knobs-tl-tag");
|
|
8569
|
+
tag.setAttribute("aria-hidden", "true");
|
|
8066
8570
|
const head = el("div", "knobs-tl-head");
|
|
8067
8571
|
head.id = `${id}-head`;
|
|
8068
8572
|
head.setAttribute("role", "slider");
|
|
8069
8573
|
head.setAttribute("aria-label", "Playhead");
|
|
8070
8574
|
head.setAttribute("aria-valuemin", "0");
|
|
8071
8575
|
head.setAttribute("aria-valuemax", String(duration));
|
|
8072
|
-
track.append(canvas,
|
|
8576
|
+
track.append(canvas, markerLane, hover, head, tag);
|
|
8073
8577
|
root.append(transport, track);
|
|
8074
8578
|
container.append(root);
|
|
8075
8579
|
let width = 1;
|
|
@@ -8116,13 +8620,14 @@ function timeline(container, options) {
|
|
|
8116
8620
|
let drawn = "";
|
|
8117
8621
|
const drawRuler = () => {
|
|
8118
8622
|
const v = view();
|
|
8119
|
-
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${units}:${fps}`;
|
|
8623
|
+
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${height}:${units}:${fps}`;
|
|
8120
8624
|
if (key === drawn)
|
|
8121
8625
|
return;
|
|
8122
8626
|
drawn = key;
|
|
8123
8627
|
const dpr = win.devicePixelRatio || 1;
|
|
8124
8628
|
const w = Math.max(1, Math.round(width * dpr));
|
|
8125
|
-
const
|
|
8629
|
+
const rh = lane ? height : RULER;
|
|
8630
|
+
const h = Math.round(rh * dpr);
|
|
8126
8631
|
if (canvas.width !== w || canvas.height !== h) {
|
|
8127
8632
|
canvas.width = w;
|
|
8128
8633
|
canvas.height = h;
|
|
@@ -8131,8 +8636,19 @@ function timeline(container, options) {
|
|
|
8131
8636
|
if (!ctx)
|
|
8132
8637
|
return;
|
|
8133
8638
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
8134
|
-
ctx.clearRect(0, 0, width,
|
|
8639
|
+
ctx.clearRect(0, 0, width, rh);
|
|
8135
8640
|
const ticks = rulerTicks(v, width, { fps, units });
|
|
8641
|
+
if (lane) {
|
|
8642
|
+
ctx.fillStyle = colors.tick;
|
|
8643
|
+
for (const t of ticks.minor)
|
|
8644
|
+
if (t >= -0.000000001 && t <= duration + 0.000000001)
|
|
8645
|
+
ctx.fillRect(xOf(t) - 0.5, rh - 4, 1, 4);
|
|
8646
|
+
ctx.fillStyle = colors.major;
|
|
8647
|
+
for (const m of ticks.major)
|
|
8648
|
+
if (m.t >= -0.000000001 && m.t <= duration + 0.000000001)
|
|
8649
|
+
ctx.fillRect(xOf(m.t) - 0.5, rh - 7, 1, 7);
|
|
8650
|
+
return;
|
|
8651
|
+
}
|
|
8136
8652
|
const px = (t) => Math.round(xOf(t)) + 0.5;
|
|
8137
8653
|
ctx.fillStyle = colors.line;
|
|
8138
8654
|
ctx.fillRect(0, RULER - 1, width, 1);
|
|
@@ -8172,18 +8688,21 @@ function timeline(container, options) {
|
|
|
8172
8688
|
n.dataset.id = m.id;
|
|
8173
8689
|
const pin = el("span", "knobs-tl-pin");
|
|
8174
8690
|
const label = el("span", "knobs-tl-mlabel");
|
|
8691
|
+
label.append(el("span", "knobs-tl-mtext knobs-scroll-fade-x"));
|
|
8175
8692
|
n.append(pin, label);
|
|
8176
|
-
|
|
8693
|
+
markerLane.append(n);
|
|
8177
8694
|
markerEls.set(m.id, n);
|
|
8178
8695
|
if (built)
|
|
8179
8696
|
enter(n);
|
|
8180
8697
|
}
|
|
8181
8698
|
const label = n.querySelector(".knobs-tl-mlabel");
|
|
8182
|
-
|
|
8183
|
-
|
|
8699
|
+
const text = label.firstElementChild;
|
|
8700
|
+
if (text.textContent !== (m.label ?? ""))
|
|
8701
|
+
text.textContent = m.label ?? "";
|
|
8184
8702
|
label.hidden = !m.label;
|
|
8185
8703
|
n.style.setProperty("--knobs-tl-color", m.color ?? "");
|
|
8186
8704
|
n.toggleAttribute("data-selected", selected?.kind === "marker" && selected.id === m.id);
|
|
8705
|
+
n.toggleAttribute("data-current", m.id === currentId);
|
|
8187
8706
|
n.title = `${m.label ? `${m.label} · ` : ""}${clock(m.time)}`;
|
|
8188
8707
|
}
|
|
8189
8708
|
placeMarkers();
|
|
@@ -8211,7 +8730,7 @@ function timeline(container, options) {
|
|
|
8211
8730
|
b.dataset.edge = "end";
|
|
8212
8731
|
const label = el("span", "knobs-tl-rlabel");
|
|
8213
8732
|
n.append(label, a, b);
|
|
8214
|
-
track.insertBefore(n,
|
|
8733
|
+
track.insertBefore(n, markerLane);
|
|
8215
8734
|
rangeEls.set(r.id, n);
|
|
8216
8735
|
if (built)
|
|
8217
8736
|
enter(n);
|
|
@@ -8260,16 +8779,17 @@ function timeline(container, options) {
|
|
|
8260
8779
|
};
|
|
8261
8780
|
const clock = (t) => units === "frames" ? `f${toFrame(t, fps)}` : `${timeLabel(t, "seconds", fps, 0.01)}`;
|
|
8262
8781
|
let shownHead = time;
|
|
8782
|
+
let currentId = null;
|
|
8263
8783
|
const renderHead = () => {
|
|
8264
8784
|
head.style.transform = `translateX(${xOf(shownHead).toFixed(2)}px)`;
|
|
8265
|
-
const main = units === "frames" ? `f${toFrame(time, fps)}` : `${time.toFixed(2)}s`;
|
|
8266
|
-
const minor = units === "frames" ? `${time.toFixed(2)}s` : `f${toFrame(time, fps)}`;
|
|
8267
|
-
if (now.textContent !== main)
|
|
8268
|
-
now.textContent = main;
|
|
8269
|
-
if (sub.textContent !== minor)
|
|
8270
|
-
sub.textContent = minor;
|
|
8271
8785
|
head.setAttribute("aria-valuenow", time.toFixed(3));
|
|
8272
8786
|
head.setAttribute("aria-valuetext", `${time.toFixed(2)} seconds, frame ${toFrame(time, fps)}`);
|
|
8787
|
+
const cur = currentMarker(markers, time, fps)?.id ?? null;
|
|
8788
|
+
if (cur !== currentId) {
|
|
8789
|
+
markerEls.get(currentId ?? "")?.removeAttribute("data-current");
|
|
8790
|
+
currentId = cur;
|
|
8791
|
+
markerEls.get(cur ?? "")?.setAttribute("data-current", "");
|
|
8792
|
+
}
|
|
8273
8793
|
};
|
|
8274
8794
|
let viewSent = "";
|
|
8275
8795
|
const render = () => {
|
|
@@ -8295,18 +8815,27 @@ function timeline(container, options) {
|
|
|
8295
8815
|
};
|
|
8296
8816
|
const caret = new Spring(time, GLIDE.omega, GLIDE.zeta, 0.00001);
|
|
8297
8817
|
let gliding = false;
|
|
8298
|
-
const
|
|
8299
|
-
const
|
|
8300
|
-
|
|
8818
|
+
const headTo = (shown, motion) => {
|
|
8819
|
+
const from = gliding ? { x: caret.x, target: caret.target } : { x: shownHead, target: shownHead };
|
|
8820
|
+
const jump = motion === "jump" && !reducedMotion(win);
|
|
8821
|
+
const next = moveHead(from, shown, jump ? "jump" : "follow", gliding, 2 / pxPerSec());
|
|
8822
|
+
if (next.catching) {
|
|
8301
8823
|
if (!gliding)
|
|
8302
|
-
caret.snap(
|
|
8303
|
-
caret.
|
|
8824
|
+
caret.snap(from.x);
|
|
8825
|
+
caret.x = next.x;
|
|
8826
|
+
caret.target = next.target;
|
|
8304
8827
|
gliding = true;
|
|
8828
|
+
shownHead = caret.x;
|
|
8305
8829
|
loop.wake();
|
|
8306
8830
|
} else {
|
|
8307
8831
|
gliding = false;
|
|
8308
|
-
|
|
8832
|
+
caret.snap(next.x);
|
|
8833
|
+
shownHead = next.x;
|
|
8309
8834
|
}
|
|
8835
|
+
};
|
|
8836
|
+
const setTime = (t, source, shown = t, glide = false) => {
|
|
8837
|
+
const next = Math.min(duration, Math.max(0, t));
|
|
8838
|
+
headTo(Math.min(duration, Math.max(0, shown)), glide ? "jump" : "follow");
|
|
8310
8839
|
const moved = next !== time;
|
|
8311
8840
|
time = next;
|
|
8312
8841
|
renderHead();
|
|
@@ -8347,8 +8876,7 @@ function timeline(container, options) {
|
|
|
8347
8876
|
options.onCross?.(m);
|
|
8348
8877
|
}
|
|
8349
8878
|
time = step.t;
|
|
8350
|
-
|
|
8351
|
-
gliding = false;
|
|
8879
|
+
headTo(time, step.wrapped ? "jump" : "follow");
|
|
8352
8880
|
emitSeek(time, "play");
|
|
8353
8881
|
keepInView();
|
|
8354
8882
|
if (step.ended) {
|
|
@@ -8361,7 +8889,7 @@ function timeline(container, options) {
|
|
|
8361
8889
|
shownHead = caret.step(dt);
|
|
8362
8890
|
if (caret.resting) {
|
|
8363
8891
|
gliding = false;
|
|
8364
|
-
shownHead =
|
|
8892
|
+
shownHead = caret.target;
|
|
8365
8893
|
}
|
|
8366
8894
|
}
|
|
8367
8895
|
vStart.step(dt);
|
|
@@ -8374,9 +8902,9 @@ function timeline(container, options) {
|
|
|
8374
8902
|
return;
|
|
8375
8903
|
const r = loopRange();
|
|
8376
8904
|
if (r && (time < r.start || time >= r.end - 0.5 / fps))
|
|
8377
|
-
setTime(r.start, "code");
|
|
8905
|
+
setTime(r.start, "code", r.start, true);
|
|
8378
8906
|
else if (!r && time >= duration - 0.5 / fps)
|
|
8379
|
-
setTime(0, "code");
|
|
8907
|
+
setTime(0, "code", 0, true);
|
|
8380
8908
|
playing = true;
|
|
8381
8909
|
syncPlay();
|
|
8382
8910
|
emitPlay(true);
|
|
@@ -8505,24 +9033,35 @@ function timeline(container, options) {
|
|
|
8505
9033
|
};
|
|
8506
9034
|
const localX = (e) => e.clientX - track.getBoundingClientRect().left;
|
|
8507
9035
|
let drag = null;
|
|
8508
|
-
const scrubTo = (x) => {
|
|
9036
|
+
const scrubTo = (x, press = false) => {
|
|
8509
9037
|
const shownX = softClamp(x, xOf(0), xOf(duration), 10);
|
|
8510
9038
|
const s = scrubTime(tOf(shownX), {
|
|
8511
9039
|
duration,
|
|
8512
9040
|
fps,
|
|
8513
9041
|
pxPerSec: pxPerSec(),
|
|
8514
|
-
stops: snapMarkers ? markers.map((m) => m.time) : [],
|
|
9042
|
+
stops: snapMarkers && !lane ? markers.map((m) => m.time) : [],
|
|
8515
9043
|
frames: snapFrames
|
|
8516
9044
|
});
|
|
8517
|
-
setTime(s.t, "scrub", s.shown);
|
|
9045
|
+
setTime(s.t, "scrub", s.shown, press);
|
|
8518
9046
|
root.toggleAttribute("data-stuck", s.stop !== null);
|
|
8519
9047
|
};
|
|
9048
|
+
const showTag = (x) => {
|
|
9049
|
+
const at = Math.min(duration, Math.max(0, tOf(x)));
|
|
9050
|
+
const text = `${at.toFixed(2)} s`;
|
|
9051
|
+
if (tag.textContent !== text)
|
|
9052
|
+
tag.textContent = text;
|
|
9053
|
+
const cx = Math.min(width, Math.max(0, x));
|
|
9054
|
+
const flip = cx > width - tag.offsetWidth - 12;
|
|
9055
|
+
tag.style.transform = `translateX(${cx.toFixed(1)}px) translateX(${flip ? "calc(-100% - 4px)" : "4px"})`;
|
|
9056
|
+
tag.dataset.on = "";
|
|
9057
|
+
};
|
|
9058
|
+
const hideTag = () => delete tag.dataset.on;
|
|
8520
9059
|
track.addEventListener("pointerdown", (e) => {
|
|
8521
9060
|
if (e.button !== 0 || editing)
|
|
8522
9061
|
return;
|
|
8523
9062
|
root.focus({ preventScroll: true });
|
|
8524
9063
|
const t = e.target;
|
|
8525
|
-
const markerEl = t.closest(".knobs-tl-marker");
|
|
9064
|
+
const markerEl = lane ? null : t.closest(".knobs-tl-marker");
|
|
8526
9065
|
const edgeEl = t.closest(".knobs-tl-edge");
|
|
8527
9066
|
const rangeEl = t.closest(".knobs-tl-range");
|
|
8528
9067
|
track.setPointerCapture(e.pointerId);
|
|
@@ -8567,13 +9106,16 @@ function timeline(container, options) {
|
|
|
8567
9106
|
root.dataset.scrubbing = "";
|
|
8568
9107
|
for (const l of listeners)
|
|
8569
9108
|
l.onScrub?.(true);
|
|
8570
|
-
scrubTo(localX(e));
|
|
9109
|
+
scrubTo(localX(e), true);
|
|
9110
|
+
showTag(localX(e));
|
|
8571
9111
|
}
|
|
8572
9112
|
e.preventDefault();
|
|
8573
9113
|
});
|
|
8574
9114
|
track.addEventListener("pointermove", (e) => {
|
|
8575
9115
|
const x = localX(e);
|
|
8576
9116
|
hover.style.transform = `translateX(${x.toFixed(1)}px)`;
|
|
9117
|
+
if (!drag || drag.kind === "scrub")
|
|
9118
|
+
showTag(x);
|
|
8577
9119
|
if (!drag)
|
|
8578
9120
|
return;
|
|
8579
9121
|
if (drag.kind === "scrub")
|
|
@@ -8619,8 +9161,10 @@ function timeline(container, options) {
|
|
|
8619
9161
|
delete root.dataset.dragging;
|
|
8620
9162
|
root.removeAttribute("data-stuck");
|
|
8621
9163
|
if (d.kind === "scrub") {
|
|
8622
|
-
|
|
9164
|
+
headTo(time, "follow");
|
|
8623
9165
|
renderHead();
|
|
9166
|
+
if (!track.matches(":hover"))
|
|
9167
|
+
hideTag();
|
|
8624
9168
|
for (const l of listeners)
|
|
8625
9169
|
l.onScrub?.(false);
|
|
8626
9170
|
if (d.wasPlaying)
|
|
@@ -8633,7 +9177,7 @@ function timeline(container, options) {
|
|
|
8633
9177
|
} else {
|
|
8634
9178
|
const m = markers.find((x) => x.id === d.id);
|
|
8635
9179
|
if (m)
|
|
8636
|
-
setTime(m.time, "marker");
|
|
9180
|
+
setTime(m.time, "marker", m.time, true);
|
|
8637
9181
|
}
|
|
8638
9182
|
} else if (d.kind === "edge" || d.moved)
|
|
8639
9183
|
emitRanges();
|
|
@@ -8642,10 +9186,14 @@ function timeline(container, options) {
|
|
|
8642
9186
|
track.addEventListener("pointercancel", endDrag);
|
|
8643
9187
|
track.addEventListener("lostpointercapture", endDrag);
|
|
8644
9188
|
track.addEventListener("pointerleave", () => {
|
|
8645
|
-
if (
|
|
8646
|
-
|
|
9189
|
+
if (drag)
|
|
9190
|
+
return;
|
|
9191
|
+
hover.style.transform = "translateX(-100px)";
|
|
9192
|
+
hideTag();
|
|
8647
9193
|
});
|
|
8648
9194
|
track.addEventListener("dblclick", (e) => {
|
|
9195
|
+
if (lane)
|
|
9196
|
+
return;
|
|
8649
9197
|
const markerEl = e.target.closest(".knobs-tl-marker");
|
|
8650
9198
|
if (markerEl)
|
|
8651
9199
|
return rename(markerEl.dataset.id);
|
|
@@ -8656,6 +9204,8 @@ function timeline(container, options) {
|
|
|
8656
9204
|
rename(m.id);
|
|
8657
9205
|
});
|
|
8658
9206
|
track.addEventListener("wheel", (e) => {
|
|
9207
|
+
if (lane)
|
|
9208
|
+
return;
|
|
8659
9209
|
e.preventDefault();
|
|
8660
9210
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? height : 1;
|
|
8661
9211
|
if (e.ctrlKey || e.metaKey) {
|
|
@@ -8719,7 +9269,7 @@ function timeline(container, options) {
|
|
|
8719
9269
|
if (!m)
|
|
8720
9270
|
return;
|
|
8721
9271
|
select({ kind: "marker", id: m.id });
|
|
8722
|
-
return setTime(m.time, "marker");
|
|
9272
|
+
return setTime(m.time, "marker", m.time, true);
|
|
8723
9273
|
}
|
|
8724
9274
|
case "i":
|
|
8725
9275
|
case "I":
|
|
@@ -8731,11 +9281,13 @@ function timeline(container, options) {
|
|
|
8731
9281
|
return setEdge("end", time);
|
|
8732
9282
|
case "m":
|
|
8733
9283
|
case "M":
|
|
9284
|
+
if (lane)
|
|
9285
|
+
return;
|
|
8734
9286
|
claim();
|
|
8735
9287
|
addMarker(time);
|
|
8736
9288
|
return;
|
|
8737
9289
|
case "Enter":
|
|
8738
|
-
if (selected?.kind === "marker") {
|
|
9290
|
+
if (selected?.kind === "marker" && !lane) {
|
|
8739
9291
|
claim();
|
|
8740
9292
|
rename(selected.id);
|
|
8741
9293
|
}
|
|
@@ -8753,19 +9305,25 @@ function timeline(container, options) {
|
|
|
8753
9305
|
return;
|
|
8754
9306
|
case "=":
|
|
8755
9307
|
case "+":
|
|
9308
|
+
if (lane)
|
|
9309
|
+
return;
|
|
8756
9310
|
claim();
|
|
8757
9311
|
return zoom(1.5);
|
|
8758
9312
|
case "-":
|
|
9313
|
+
if (lane)
|
|
9314
|
+
return;
|
|
8759
9315
|
claim();
|
|
8760
9316
|
return zoom(1 / 1.5);
|
|
8761
9317
|
case "0":
|
|
9318
|
+
if (lane)
|
|
9319
|
+
return;
|
|
8762
9320
|
claim();
|
|
8763
9321
|
return fit();
|
|
8764
9322
|
}
|
|
8765
9323
|
});
|
|
8766
9324
|
const unregisterHints = options.hints === false ? undefined : hints.register(root, () => [
|
|
8767
9325
|
{ el: playBtn, label: playing ? "Pause" : "Play", activate: toggle },
|
|
8768
|
-
...markers.flatMap((m) => {
|
|
9326
|
+
...(lane ? [] : markers).flatMap((m) => {
|
|
8769
9327
|
const n = markerEls.get(m.id);
|
|
8770
9328
|
if (!n || n.dataset.leaving !== undefined)
|
|
8771
9329
|
return [];
|
|
@@ -8777,7 +9335,7 @@ function timeline(container, options) {
|
|
|
8777
9335
|
...label && !label.hidden ? { labelEl: label } : {},
|
|
8778
9336
|
activate: () => {
|
|
8779
9337
|
select({ kind: "marker", id: m.id });
|
|
8780
|
-
setTime(m.time, "marker");
|
|
9338
|
+
setTime(m.time, "marker", m.time, true);
|
|
8781
9339
|
root.focus({ preventScroll: true });
|
|
8782
9340
|
}
|
|
8783
9341
|
}
|
|
@@ -8789,7 +9347,7 @@ function timeline(container, options) {
|
|
|
8789
9347
|
activate: () => root.focus({ preventScroll: true })
|
|
8790
9348
|
}
|
|
8791
9349
|
], { listen: false, rank: 1 });
|
|
8792
|
-
const menu = contextMenu(track, (e) => {
|
|
9350
|
+
const menu = lane ? null : contextMenu(track, (e) => {
|
|
8793
9351
|
const t = e?.target ?? null;
|
|
8794
9352
|
const markerEl = t?.closest(".knobs-tl-marker");
|
|
8795
9353
|
const rangeEl = t?.closest(".knobs-tl-range");
|
|
@@ -8804,7 +9362,7 @@ function timeline(container, options) {
|
|
|
8804
9362
|
run: () => {
|
|
8805
9363
|
const m = markers.find((x) => x.id === mid);
|
|
8806
9364
|
if (m)
|
|
8807
|
-
setTime(m.time, "marker");
|
|
9365
|
+
setTime(m.time, "marker", m.time, true);
|
|
8808
9366
|
}
|
|
8809
9367
|
},
|
|
8810
9368
|
{ label: "Rename…", shortcut: "Enter", run: () => rename(mid) },
|
|
@@ -8968,7 +9526,7 @@ function timeline(container, options) {
|
|
|
8968
9526
|
listeners.clear();
|
|
8969
9527
|
loop.stop();
|
|
8970
9528
|
ro.disconnect();
|
|
8971
|
-
menu
|
|
9529
|
+
menu?.dispose();
|
|
8972
9530
|
root.remove();
|
|
8973
9531
|
}
|
|
8974
9532
|
};
|
|
@@ -8985,10 +9543,21 @@ var init_timeline = __esm(() => {
|
|
|
8985
9543
|
init_timeline_model();
|
|
8986
9544
|
INSTANT2 = springMotion(SPRINGS.instant);
|
|
8987
9545
|
CALM = springMotion(SPRINGS.calm);
|
|
8988
|
-
GLIDE = springMotion(
|
|
9546
|
+
GLIDE = springMotion(CATCH_UP);
|
|
8989
9547
|
});
|
|
8990
9548
|
|
|
8991
9549
|
// src/ui/compare-model.ts
|
|
9550
|
+
function compareModes(modes, mode) {
|
|
9551
|
+
const list = [...new Set((modes ?? ["side", "wipe"]).filter((m) => ALL_MODES.includes(m)))];
|
|
9552
|
+
const offered = list.length ? list : ["side", "wipe"];
|
|
9553
|
+
return { modes: offered, mode: mode && offered.includes(mode) ? mode : offered[0] };
|
|
9554
|
+
}
|
|
9555
|
+
function modeForKey(key, modes) {
|
|
9556
|
+
const k = key.toLowerCase();
|
|
9557
|
+
if (/^[1-9]$/.test(k))
|
|
9558
|
+
return modes[Number(k) - 1] ?? null;
|
|
9559
|
+
return modes.find((m) => MODE_KEYS[m] === k) ?? null;
|
|
9560
|
+
}
|
|
8992
9561
|
function mediaKind(src, kind) {
|
|
8993
9562
|
if (kind)
|
|
8994
9563
|
return kind;
|
|
@@ -9067,6 +9636,18 @@ function wipeGrab(x, rect, wipe, slop = 12) {
|
|
|
9067
9636
|
const onLine = Math.abs(x - line) <= slop;
|
|
9068
9637
|
return { onLine, offset: onLine ? x - line : 0 };
|
|
9069
9638
|
}
|
|
9639
|
+
function seamLabels(x, left, right, wb, wa, gap = 8) {
|
|
9640
|
+
const room = (space, w) => Math.min(1, Math.max(0, (space - w - 2 * gap) / gap));
|
|
9641
|
+
return {
|
|
9642
|
+
before: { x: x - gap - wb, opacity: room(x - left, wb) },
|
|
9643
|
+
after: { x: x + gap, opacity: room(right - x, wa) }
|
|
9644
|
+
};
|
|
9645
|
+
}
|
|
9646
|
+
function gripTop(y, rect, grip, margin = 8) {
|
|
9647
|
+
const lo = rect.y + margin;
|
|
9648
|
+
const hi = rect.y + rect.h - margin - grip;
|
|
9649
|
+
return hi < lo ? rect.y + (rect.h - grip) / 2 : Math.min(hi, Math.max(lo, y - grip / 2));
|
|
9650
|
+
}
|
|
9070
9651
|
function stripColumns(view, width, o) {
|
|
9071
9652
|
const { fps } = o;
|
|
9072
9653
|
const total = Math.max(1, Math.round(o.duration * fps));
|
|
@@ -9117,7 +9698,7 @@ function stripPeaks(diffs, o = {}) {
|
|
|
9117
9698
|
});
|
|
9118
9699
|
return out;
|
|
9119
9700
|
}
|
|
9120
|
-
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), 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({
|
|
9701
|
+
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), 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({
|
|
9121
9702
|
u: r.u - dx / Math.max(1, base.w) * r.w,
|
|
9122
9703
|
v: r.v - dy / Math.max(1, base.h) * r.h,
|
|
9123
9704
|
w: r.w
|
|
@@ -9136,6 +9717,8 @@ var VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), last
|
|
|
9136
9717
|
h: a.h + (b.h - a.h) * k
|
|
9137
9718
|
}), 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));
|
|
9138
9719
|
var init_compare_model = __esm(() => {
|
|
9720
|
+
ALL_MODES = ["side", "wipe", "difference"];
|
|
9721
|
+
MODE_KEYS = { side: "s", wipe: "w", difference: "d" };
|
|
9139
9722
|
VIDEO = /\.(mp4|m4v|mov|webm|ogv|mkv)$/i;
|
|
9140
9723
|
SEEK_IDLE = { seeking: false, pending: null };
|
|
9141
9724
|
ZOOM_FIT = { u: 0, v: 0, w: 1, h: 1 };
|
|
@@ -9935,8 +10518,8 @@ async function createCompareGpu(canvas, onLost) {
|
|
|
9935
10518
|
r(0, f.before);
|
|
9936
10519
|
r(4, f.after);
|
|
9937
10520
|
data.set([f.width, f.height, f.dpr, 0], 8);
|
|
9938
|
-
data.set([f.wipeX, f.soft, 0,
|
|
9939
|
-
data.set([f.from, f.to, f.mix,
|
|
10521
|
+
data.set([f.wipeX, f.soft, 0, 0], 12);
|
|
10522
|
+
data.set([f.from, f.to, f.mix, 0], 16);
|
|
9940
10523
|
data.set([f.threshold, f.gain, ready[0], ready[1]], 20);
|
|
9941
10524
|
data.set([f.accent[0], f.accent[1], f.accent[2], 1], 24);
|
|
9942
10525
|
const l = f.loupe;
|
|
@@ -9978,8 +10561,8 @@ var MODE_INDEX, WGSL = `
|
|
|
9978
10561
|
struct U {
|
|
9979
10562
|
ra: vec4f, rb: vec4f,
|
|
9980
10563
|
view: vec4f, // w, h, dpr, _
|
|
9981
|
-
wipe: vec4f, // x, soft, _,
|
|
9982
|
-
modes: vec4f, // from, to, mix,
|
|
10564
|
+
wipe: vec4f, // x, soft, _, _
|
|
10565
|
+
modes: vec4f, // from, to, mix, _
|
|
9983
10566
|
diff: vec4f, // threshold, gain, readyA, readyB
|
|
9984
10567
|
accent: vec4f,
|
|
9985
10568
|
loupe: vec4f, // x, y, r, zoom (0: none)
|
|
@@ -10030,21 +10613,14 @@ fn takeB(p: vec2f, r: vec4f, c0: vec4f, near: bool) -> vec4f {
|
|
|
10030
10613
|
|
|
10031
10614
|
fn pm(c: vec4f) -> vec4f { return vec4f(c.rgb * c.a, c.a); }
|
|
10032
10615
|
|
|
10033
|
-
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f
|
|
10034
|
-
let flick = u.modes.w > 0.5;
|
|
10616
|
+
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
10035
10617
|
switch mode {
|
|
10036
|
-
case 0u: {
|
|
10037
|
-
let bb = select(b, vec4f(a2.rgb, b.a), flick);
|
|
10038
|
-
return vec4f(a.rgb * a.a + bb.rgb * bb.a * (1.0 - a.a), a.a + bb.a * (1.0 - a.a));
|
|
10039
|
-
}
|
|
10040
10618
|
case 1u: {
|
|
10041
|
-
if (flick) { return pm(a); }
|
|
10042
10619
|
let s = max(u.wipe.y, 0.5);
|
|
10043
10620
|
let m = smoothstep(u.wipe.x - s, u.wipe.x + s, p.x);
|
|
10044
10621
|
return pm(vec4f(mix(a.rgb, b.rgb, m), mix(a.a, b.a, m)));
|
|
10045
10622
|
}
|
|
10046
10623
|
case 2u: {
|
|
10047
|
-
if (flick) { return pm(a); }
|
|
10048
10624
|
let d = abs(a.rgb - b.rgb);
|
|
10049
10625
|
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);
|
|
10050
10626
|
let c = mix(vec3f(luma(b.rgb) * 0.35), u.accent.rgb, h);
|
|
@@ -10052,8 +10628,8 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f, a2: vec4f) -> vec4f {
|
|
|
10052
10628
|
}
|
|
10053
10629
|
default: {}
|
|
10054
10630
|
}
|
|
10055
|
-
//
|
|
10056
|
-
return
|
|
10631
|
+
// Side by side: each side in its own place, Before over After where they meet.
|
|
10632
|
+
return vec4f(a.rgb * a.a + b.rgb * b.a * (1.0 - a.a), a.a + b.a * (1.0 - a.a));
|
|
10057
10633
|
}
|
|
10058
10634
|
|
|
10059
10635
|
@fragment fn fs(@builtin(position) q: vec4f) -> @location(0) vec4f {
|
|
@@ -10071,16 +10647,14 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f, a2: vec4f) -> vec4f {
|
|
|
10071
10647
|
}
|
|
10072
10648
|
let a = takeA(p, u.ra, u.ca, near);
|
|
10073
10649
|
let b = takeB(p, u.rb, u.cb, near);
|
|
10074
|
-
|
|
10075
|
-
let a2 = takeA(p, u.rb, u.cb, near);
|
|
10076
|
-
var o = mix(composite(u32(u.modes.x), p, a, b, a2), composite(u32(u.modes.y), p, a, b, a2), u.modes.z);
|
|
10650
|
+
var o = mix(composite(u32(u.modes.x), p, a, b), composite(u32(u.modes.y), p, a, b), u.modes.z);
|
|
10077
10651
|
if (near) { o = o + vec4f(0.05, 0.05, 0.06, 1.0) * (1.0 - o.a); }
|
|
10078
10652
|
o = mix(o, vec4f(0.92), ring * 0.9);
|
|
10079
10653
|
return o;
|
|
10080
10654
|
}
|
|
10081
10655
|
`, TEXTURE_BINDING = 4, COPY_DST = 2, RENDER_ATTACHMENT = 16, shared = null, lostListeners;
|
|
10082
10656
|
var init_compare_gpu = __esm(() => {
|
|
10083
|
-
MODE_INDEX = { side: 0, wipe: 1, difference: 2
|
|
10657
|
+
MODE_INDEX = { side: 0, wipe: 1, difference: 2 };
|
|
10084
10658
|
lostListeners = new Set;
|
|
10085
10659
|
});
|
|
10086
10660
|
|
|
@@ -10466,7 +11040,9 @@ function compare(container, options) {
|
|
|
10466
11040
|
...options.theme ? { theme: options.theme } : {},
|
|
10467
11041
|
...options.appearance ? { appearance: options.appearance } : {}
|
|
10468
11042
|
};
|
|
10469
|
-
|
|
11043
|
+
const offered = compareModes(options.modes, options.mode);
|
|
11044
|
+
const modeList = offered.modes;
|
|
11045
|
+
let mode = offered.mode;
|
|
10470
11046
|
let wipe = Math.min(1, Math.max(0, options.wipe ?? 0.5));
|
|
10471
11047
|
let loupeOn = options.loupe ?? false;
|
|
10472
11048
|
let threshold = options.threshold ?? 4 / 255;
|
|
@@ -10484,7 +11060,7 @@ function compare(container, options) {
|
|
|
10484
11060
|
root.setAttribute("role", "group");
|
|
10485
11061
|
root.setAttribute("aria-roledescription", "compare");
|
|
10486
11062
|
root.setAttribute("aria-label", options.label ?? "Compare");
|
|
10487
|
-
root.setAttribute("aria-keyshortcuts",
|
|
11063
|
+
root.setAttribute("aria-keyshortcuts", `Space ArrowLeft ArrowRight Shift+ArrowLeft Shift+ArrowRight , . ${modeList.map((m, i) => `${i + 1} ${modeKey(m)}`).join(" ")} Z L 0 = -`);
|
|
10488
11064
|
applyLook2(root, options);
|
|
10489
11065
|
root.dataset.mode = mode;
|
|
10490
11066
|
if (auto)
|
|
@@ -10493,35 +11069,37 @@ function compare(container, options) {
|
|
|
10493
11069
|
const modes = el("div", "knobs-cmp-modes");
|
|
10494
11070
|
modes.setAttribute("role", "radiogroup");
|
|
10495
11071
|
modes.setAttribute("aria-label", "Mode");
|
|
10496
|
-
|
|
11072
|
+
modes.hidden = modeList.length < 2;
|
|
11073
|
+
const modeBtns = modeList.map((m, i) => {
|
|
10497
11074
|
const b = el("button", "knobs-cmp-mode");
|
|
10498
11075
|
b.type = "button";
|
|
10499
11076
|
b.tabIndex = -1;
|
|
10500
|
-
b.textContent = m.
|
|
10501
|
-
b.title = `${m.
|
|
11077
|
+
b.textContent = MODE_LABEL[m].short;
|
|
11078
|
+
b.title = `${MODE_LABEL[m].long} · ${i + 1} or ${modeKey(m)}`;
|
|
10502
11079
|
b.setAttribute("role", "radio");
|
|
10503
|
-
b.setAttribute("aria-keyshortcuts",
|
|
11080
|
+
b.setAttribute("aria-keyshortcuts", `${i + 1} ${modeKey(m)}`);
|
|
10504
11081
|
b.addEventListener("click", () => {
|
|
10505
|
-
setMode(m
|
|
11082
|
+
setMode(m);
|
|
10506
11083
|
root.focus({ preventScroll: true });
|
|
10507
11084
|
});
|
|
10508
11085
|
modes.append(b);
|
|
10509
11086
|
return b;
|
|
10510
11087
|
});
|
|
10511
|
-
const
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
11088
|
+
const toggleBtn = (name, label, title) => {
|
|
11089
|
+
const b = el("button", "knobs-cmp-toggle");
|
|
11090
|
+
b.type = "button";
|
|
11091
|
+
b.tabIndex = -1;
|
|
11092
|
+
b.innerHTML = icon(name);
|
|
11093
|
+
b.setAttribute("aria-label", label);
|
|
11094
|
+
b.title = title;
|
|
11095
|
+
return b;
|
|
11096
|
+
};
|
|
11097
|
+
const loupeBtn = toggleBtn("magnifyingGlass", "Loupe", "Loupe · hold Z");
|
|
10516
11098
|
loupeBtn.addEventListener("click", () => {
|
|
10517
11099
|
setLoupe(!loupeOn);
|
|
10518
11100
|
root.focus({ preventScroll: true });
|
|
10519
11101
|
});
|
|
10520
|
-
const loopBtn =
|
|
10521
|
-
loopBtn.type = "button";
|
|
10522
|
-
loopBtn.tabIndex = -1;
|
|
10523
|
-
loopBtn.textContent = "Loop";
|
|
10524
|
-
loopBtn.title = "Loop · L (drag its ends on the timeline)";
|
|
11102
|
+
const loopBtn = toggleBtn("repeat", "Loop", "Loop · L (drag its ends on the timeline)");
|
|
10525
11103
|
loopBtn.setAttribute("aria-keyshortcuts", "L");
|
|
10526
11104
|
loopBtn.addEventListener("click", () => {
|
|
10527
11105
|
api.setLoop(!loopNow());
|
|
@@ -10538,7 +11116,8 @@ function compare(container, options) {
|
|
|
10538
11116
|
const zoomReset = el("button", "knobs-cmp-zoom-reset");
|
|
10539
11117
|
zoomReset.type = "button";
|
|
10540
11118
|
zoomReset.tabIndex = -1;
|
|
10541
|
-
zoomReset.
|
|
11119
|
+
zoomReset.innerHTML = icon("arrowCounterClockwise", { small: true });
|
|
11120
|
+
zoomReset.setAttribute("aria-label", "Reset zoom");
|
|
10542
11121
|
zoomReset.title = "Fit · 0 or double-click";
|
|
10543
11122
|
zoomReset.addEventListener("click", () => {
|
|
10544
11123
|
api.setZoom(null);
|
|
@@ -10548,11 +11127,25 @@ function compare(container, options) {
|
|
|
10548
11127
|
const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
|
|
10549
11128
|
labels[0].dataset.side = "before";
|
|
10550
11129
|
labels[1].dataset.side = "after";
|
|
11130
|
+
const setLabel = (index, text) => {
|
|
11131
|
+
const l = labels[index];
|
|
11132
|
+
if (!l.firstElementChild) {
|
|
11133
|
+
const mark = el("span", "knobs-cmp-mark");
|
|
11134
|
+
mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
|
|
11135
|
+
l.append(mark, el("span", "knobs-cmp-name"));
|
|
11136
|
+
}
|
|
11137
|
+
const name = l.lastElementChild;
|
|
11138
|
+
if (name.textContent !== text)
|
|
11139
|
+
name.textContent = text;
|
|
11140
|
+
};
|
|
10551
11141
|
const handle = el("div", "knobs-cmp-handle");
|
|
10552
11142
|
handle.setAttribute("role", "slider");
|
|
10553
11143
|
handle.setAttribute("aria-label", "Wipe");
|
|
10554
11144
|
handle.setAttribute("aria-valuemin", "0");
|
|
10555
11145
|
handle.setAttribute("aria-valuemax", "100");
|
|
11146
|
+
const grip = el("span", "knobs-cmp-grip");
|
|
11147
|
+
grip.setAttribute("aria-hidden", "true");
|
|
11148
|
+
handle.append(grip);
|
|
10556
11149
|
const note = el("div", "knobs-cmp-note");
|
|
10557
11150
|
stage.append(canvas, split, labels[0], labels[1], handle, zoomPill, note);
|
|
10558
11151
|
root.append(bar, stage);
|
|
@@ -10569,6 +11162,7 @@ function compare(container, options) {
|
|
|
10569
11162
|
root.append(host);
|
|
10570
11163
|
tl = timeline(host, {
|
|
10571
11164
|
...look,
|
|
11165
|
+
variant: "lane",
|
|
10572
11166
|
duration: 1,
|
|
10573
11167
|
fps: fps(),
|
|
10574
11168
|
arrows: { step: 0.5, shift: 2 },
|
|
@@ -10587,9 +11181,9 @@ function compare(container, options) {
|
|
|
10587
11181
|
const fade = new Spring(1, FADE6.omega, FADE6.zeta, 0.001);
|
|
10588
11182
|
let fromMode = mode;
|
|
10589
11183
|
let toMode = mode;
|
|
10590
|
-
|
|
10591
|
-
let
|
|
10592
|
-
let
|
|
11184
|
+
const wipeLine = new Spring(wipe, WIPE_CATCH.omega, WIPE_CATCH.zeta, 0.0001);
|
|
11185
|
+
let wipeCatching = false;
|
|
11186
|
+
let gripY = null;
|
|
10593
11187
|
let loupeHeld = false;
|
|
10594
11188
|
let pointer = null;
|
|
10595
11189
|
let drag = null;
|
|
@@ -10907,25 +11501,16 @@ function compare(container, options) {
|
|
|
10907
11501
|
gpu = g;
|
|
10908
11502
|
setRenderer("gpu");
|
|
10909
11503
|
};
|
|
10910
|
-
const syncFlicker = () => {
|
|
10911
|
-
win.clearInterval(flickerTimer);
|
|
10912
|
-
flickerTimer = 0;
|
|
10913
|
-
phase = false;
|
|
10914
|
-
if (mode === "flicker")
|
|
10915
|
-
flickerTimer = win.setInterval(() => {
|
|
10916
|
-
phase = !phase;
|
|
10917
|
-
requestDraw();
|
|
10918
|
-
}, FLICKER_MS);
|
|
10919
|
-
};
|
|
10920
11504
|
const syncModeUi = () => {
|
|
10921
11505
|
root.dataset.mode = mode;
|
|
10922
|
-
|
|
10923
|
-
modeBtns[i].setAttribute("aria-checked", String(m
|
|
11506
|
+
modeList.forEach((m, i) => {
|
|
11507
|
+
modeBtns[i].setAttribute("aria-checked", String(m === mode));
|
|
10924
11508
|
});
|
|
10925
11509
|
handle.tabIndex = mode === "wipe" ? 0 : -1;
|
|
11510
|
+
modePill?.update();
|
|
10926
11511
|
};
|
|
10927
11512
|
const setMode = (next, emit = true) => {
|
|
10928
|
-
if (next === mode)
|
|
11513
|
+
if (next === mode || !modeList.includes(next))
|
|
10929
11514
|
return;
|
|
10930
11515
|
mode = next;
|
|
10931
11516
|
const reduced = reducedMotion(win);
|
|
@@ -10941,19 +11526,29 @@ function compare(container, options) {
|
|
|
10941
11526
|
else
|
|
10942
11527
|
lay.set(next === "side" ? 0 : 1);
|
|
10943
11528
|
syncModeUi();
|
|
10944
|
-
syncFlicker();
|
|
10945
11529
|
if (emit)
|
|
10946
11530
|
options.onMode?.(next);
|
|
10947
11531
|
requestDraw();
|
|
10948
11532
|
};
|
|
10949
|
-
const setWipe = (next, emit = true) => {
|
|
11533
|
+
const setWipe = (next, emit = true, jump = false) => {
|
|
10950
11534
|
const w = Math.min(1, Math.max(0, next));
|
|
10951
|
-
if (w === wipe)
|
|
11535
|
+
if (w === wipe && !jump)
|
|
10952
11536
|
return;
|
|
10953
11537
|
wipe = w;
|
|
11538
|
+
const minGap = 2 / Math.max(1, wipeRect(layoutNow().L.overlay).w);
|
|
11539
|
+
const head = moveHead({ x: wipeLine.x, target: wipeLine.target }, w, jump && !reducedMotion(win) ? "jump" : "follow", wipeCatching, minGap);
|
|
11540
|
+
wipeCatching = head.catching;
|
|
11541
|
+
if (head.catching) {
|
|
11542
|
+
wipeLine.x = head.x;
|
|
11543
|
+
wipeLine.target = head.target;
|
|
11544
|
+
} else
|
|
11545
|
+
wipeLine.snap(head.x);
|
|
10954
11546
|
if (emit)
|
|
10955
11547
|
options.onWipe?.(w);
|
|
10956
|
-
|
|
11548
|
+
if (head.catching)
|
|
11549
|
+
requestDraw();
|
|
11550
|
+
else
|
|
11551
|
+
drawNow();
|
|
10957
11552
|
};
|
|
10958
11553
|
const setLoupe = (on) => {
|
|
10959
11554
|
loupeOn = on;
|
|
@@ -11106,28 +11701,44 @@ function compare(container, options) {
|
|
|
11106
11701
|
viewSent = key;
|
|
11107
11702
|
options.onView({ zoom: clampZoom(z), loop: l });
|
|
11108
11703
|
};
|
|
11704
|
+
const labelsIn = (m, r, wr, wx) => {
|
|
11705
|
+
if (m === "wipe") {
|
|
11706
|
+
const at = seamLabels(wx, wr.x, wr.x + wr.w, labelW[0], labelW[1], INSET);
|
|
11707
|
+
return [at.before, at.after];
|
|
11708
|
+
}
|
|
11709
|
+
const ax = r.after.x + INSET + (r.after.w - labelW[1] - INSET * 2) * lay.x;
|
|
11710
|
+
return [
|
|
11711
|
+
{ x: r.before.x + INSET, opacity: 1 },
|
|
11712
|
+
{ x: ax, opacity: 1 }
|
|
11713
|
+
];
|
|
11714
|
+
};
|
|
11715
|
+
const placeGrip = (wr) => {
|
|
11716
|
+
const gy = gripTop(gripY ?? wr.y + wr.h / 2, wr, GRIP.h) - wr.y;
|
|
11717
|
+
grip.style.transform = `translate3d(0,${gy.toFixed(2)}px,0)`;
|
|
11718
|
+
};
|
|
11109
11719
|
const draw = () => {
|
|
11110
11720
|
dirty = false;
|
|
11111
11721
|
const r = layoutNow();
|
|
11112
11722
|
const wr = wipeRect(r.L.overlay);
|
|
11113
|
-
const wx = wipeX(wr,
|
|
11723
|
+
const wx = wipeX(wr, wipeLine.x);
|
|
11114
11724
|
const k = lay.x;
|
|
11115
|
-
const
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
const
|
|
11119
|
-
const
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11725
|
+
const a = labelsIn(fromMode, r, wr, wx);
|
|
11726
|
+
const b = labelsIn(toMode, r, wr, wx);
|
|
11727
|
+
const f = Math.min(1, Math.max(0, fade.x));
|
|
11728
|
+
const ys = [r.before.y + INSET, r.after.y + INSET];
|
|
11729
|
+
for (const i of [0, 1]) {
|
|
11730
|
+
const x = a[i].x + (b[i].x - a[i].x) * f;
|
|
11731
|
+
labels[i].style.transform = `translate(${x.toFixed(2)}px,${ys[i].toFixed(2)}px)`;
|
|
11732
|
+
labels[i].style.opacity = (a[i].opacity + (b[i].opacity - a[i].opacity) * f).toFixed(3);
|
|
11733
|
+
}
|
|
11124
11734
|
const top = Math.min(r.L.side.before.y, r.L.side.after.y);
|
|
11125
11735
|
split.style.transform = `translate(${r.L.side.split.toFixed(2)}px,${top.toFixed(2)}px)`;
|
|
11126
11736
|
split.style.height = `${Math.max(0, r.L.side.after.h).toFixed(2)}px`;
|
|
11127
11737
|
split.style.opacity = String(Math.max(0, 1 - k * 2));
|
|
11128
|
-
handle.toggleAttribute("data-on", mode === "wipe"
|
|
11738
|
+
handle.toggleAttribute("data-on", mode === "wipe");
|
|
11129
11739
|
handle.style.transform = `translate(${wx.toFixed(2)}px,${wr.y.toFixed(2)}px)`;
|
|
11130
11740
|
handle.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
11741
|
+
placeGrip(wr);
|
|
11131
11742
|
handle.setAttribute("aria-valuenow", String(Math.round(wipe * 100)));
|
|
11132
11743
|
handle.setAttribute("aria-valuetext", `${Math.round(wipe * 100)}% Before`);
|
|
11133
11744
|
const pct = `${Math.round(100 / zw.x)}%`;
|
|
@@ -11150,7 +11761,7 @@ function compare(container, options) {
|
|
|
11150
11761
|
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w, cutAt));
|
|
11151
11762
|
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)` : "";
|
|
11152
11763
|
};
|
|
11153
|
-
const cut = mode === "wipe"
|
|
11764
|
+
const cut = mode === "wipe" ? wx : Number.POSITIVE_INFINITY;
|
|
11154
11765
|
for (const s of sides) {
|
|
11155
11766
|
const rect = s.index === 0 ? r.zBefore : r.zAfter;
|
|
11156
11767
|
const clip = s.index === 0 ? r.before : r.after;
|
|
@@ -11159,10 +11770,8 @@ function compare(container, options) {
|
|
|
11159
11770
|
place(s.preview, rect, clip, at);
|
|
11160
11771
|
if (s.index !== 0)
|
|
11161
11772
|
continue;
|
|
11162
|
-
for (const n of [s.el, s.preview])
|
|
11163
|
-
n.style.mixBlendMode = mode === "difference"
|
|
11164
|
-
n.style.opacity = mode === "flicker" && !showsBefore ? "0" : "";
|
|
11165
|
-
}
|
|
11773
|
+
for (const n of [s.el, s.preview])
|
|
11774
|
+
n.style.mixBlendMode = mode === "difference" ? "difference" : "";
|
|
11166
11775
|
}
|
|
11167
11776
|
return;
|
|
11168
11777
|
}
|
|
@@ -11183,8 +11792,6 @@ function compare(container, options) {
|
|
|
11183
11792
|
from: MODE_INDEX[fromMode],
|
|
11184
11793
|
to: MODE_INDEX[toMode],
|
|
11185
11794
|
mix: Math.min(1, Math.max(0, fade.x)),
|
|
11186
|
-
flick: flickHeld,
|
|
11187
|
-
phase,
|
|
11188
11795
|
threshold,
|
|
11189
11796
|
gain: 1,
|
|
11190
11797
|
accent,
|
|
@@ -11200,6 +11807,11 @@ function compare(container, options) {
|
|
|
11200
11807
|
const loop = frameLoop(win, (dt) => {
|
|
11201
11808
|
lay.step(dt);
|
|
11202
11809
|
fade.step(dt);
|
|
11810
|
+
if (wipeCatching) {
|
|
11811
|
+
wipeLine.step(dt);
|
|
11812
|
+
if (wipeLine.resting)
|
|
11813
|
+
wipeCatching = false;
|
|
11814
|
+
}
|
|
11203
11815
|
zu.step(dt);
|
|
11204
11816
|
zv.step(dt);
|
|
11205
11817
|
zw.step(dt);
|
|
@@ -11233,7 +11845,7 @@ function compare(container, options) {
|
|
|
11233
11845
|
pushFrame(s);
|
|
11234
11846
|
}
|
|
11235
11847
|
}
|
|
11236
|
-
const moving = !lay.resting || !fade.resting || !zoomResting();
|
|
11848
|
+
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching;
|
|
11237
11849
|
if (moving)
|
|
11238
11850
|
dirty = true;
|
|
11239
11851
|
if (auto && !lay.resting)
|
|
@@ -11376,16 +11988,19 @@ function compare(container, options) {
|
|
|
11376
11988
|
e.preventDefault();
|
|
11377
11989
|
return startPinch();
|
|
11378
11990
|
}
|
|
11379
|
-
if (mode === "wipe"
|
|
11991
|
+
if (mode === "wipe") {
|
|
11380
11992
|
const wr = wipeRect(layoutNow().L.overlay);
|
|
11381
11993
|
const inside = p.x >= wr.x - SLOP && p.x <= wr.x + wr.w + SLOP && p.y >= wr.y && p.y <= wr.y + wr.h;
|
|
11382
|
-
const grab = wipeGrab(p.x, wr,
|
|
11994
|
+
const grab = wipeGrab(p.x, wr, wipeLine.x, SLOP);
|
|
11383
11995
|
if (inside && (grab.onLine || !zoomed())) {
|
|
11384
11996
|
drag = { kind: "wipe", offset: grab.offset };
|
|
11385
11997
|
root.dataset.dragging = "";
|
|
11998
|
+
gripY = p.y;
|
|
11386
11999
|
e.preventDefault();
|
|
11387
12000
|
if (!grab.onLine)
|
|
11388
|
-
setWipe(wipeAt(p.x, wr));
|
|
12001
|
+
setWipe(wipeAt(p.x, wr), true, true);
|
|
12002
|
+
else
|
|
12003
|
+
drawNow();
|
|
11389
12004
|
return;
|
|
11390
12005
|
}
|
|
11391
12006
|
}
|
|
@@ -11411,6 +12026,11 @@ function compare(container, options) {
|
|
|
11411
12026
|
pinch = { d, x: mid.x, y: mid.y };
|
|
11412
12027
|
return handZoom(zoomAbout(panned, k, q.pu, q.pv));
|
|
11413
12028
|
}
|
|
12029
|
+
if (mode === "wipe" && drag?.kind !== "pan") {
|
|
12030
|
+
gripY = p.y;
|
|
12031
|
+
if (!drag)
|
|
12032
|
+
placeGrip(wipeRect(layoutNow().L.overlay));
|
|
12033
|
+
}
|
|
11414
12034
|
if (drag?.kind === "wipe")
|
|
11415
12035
|
setWipe(wipeAt(p.x, wipeRect(layoutNow().L.overlay), drag.offset));
|
|
11416
12036
|
else if (drag?.kind === "pan") {
|
|
@@ -11483,12 +12103,6 @@ function compare(container, options) {
|
|
|
11483
12103
|
const z = { u: zu.target, v: zv.target, w: zw.target, h: zw.target };
|
|
11484
12104
|
glideZoom(zoomAbout(z, factor, 0.5, 0.5));
|
|
11485
12105
|
};
|
|
11486
|
-
const holdFlick = (on) => {
|
|
11487
|
-
if (flickHeld === on)
|
|
11488
|
-
return;
|
|
11489
|
-
flickHeld = on;
|
|
11490
|
-
drawNow();
|
|
11491
|
-
};
|
|
11492
12106
|
const holdLoupe = (on) => {
|
|
11493
12107
|
if (loupeHeld === on)
|
|
11494
12108
|
return;
|
|
@@ -11534,25 +12148,17 @@ function compare(container, options) {
|
|
|
11534
12148
|
case "s":
|
|
11535
12149
|
case "w":
|
|
11536
12150
|
case "d":
|
|
11537
|
-
if (e.altKey || e.shiftKey || key === "s" && claimsHintKey(doc, key))
|
|
11538
|
-
return;
|
|
11539
|
-
claim();
|
|
11540
|
-
return setMode(KEY_MODE[key]);
|
|
11541
12151
|
case "1":
|
|
11542
12152
|
case "2":
|
|
11543
|
-
case "3":
|
|
11544
|
-
|
|
11545
|
-
if (e.altKey || e.shiftKey)
|
|
12153
|
+
case "3": {
|
|
12154
|
+
if (e.altKey || e.shiftKey || key === "s" && claimsHintKey(doc, key))
|
|
11546
12155
|
return;
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
case "x":
|
|
11550
|
-
if (e.altKey)
|
|
12156
|
+
const m = modeForKey(key, modeList);
|
|
12157
|
+
if (!m)
|
|
11551
12158
|
return;
|
|
11552
12159
|
claim();
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
return;
|
|
12160
|
+
return setMode(m);
|
|
12161
|
+
}
|
|
11556
12162
|
case "z":
|
|
11557
12163
|
if (e.altKey)
|
|
11558
12164
|
return;
|
|
@@ -11593,7 +12199,7 @@ function compare(container, options) {
|
|
|
11593
12199
|
old.preview.replaceWith(s.preview);
|
|
11594
12200
|
sides[index] = s;
|
|
11595
12201
|
note.textContent = "";
|
|
11596
|
-
|
|
12202
|
+
setLabel(index, labelOf(index));
|
|
11597
12203
|
if (near)
|
|
11598
12204
|
loadSide(s);
|
|
11599
12205
|
readColors();
|
|
@@ -11604,12 +12210,15 @@ function compare(container, options) {
|
|
|
11604
12210
|
stage.insertBefore(sides[1].preview, labels[0]);
|
|
11605
12211
|
stage.insertBefore(sides[0].el, labels[0]);
|
|
11606
12212
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
11607
|
-
|
|
11608
|
-
|
|
12213
|
+
setLabel(0, labelOf(0));
|
|
12214
|
+
setLabel(1, labelOf(1));
|
|
11609
12215
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
11610
12216
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
12217
|
+
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
12218
|
+
rows: () => modeBtns,
|
|
12219
|
+
selected: () => modeBtns[modeList.indexOf(mode)] ?? null
|
|
12220
|
+
}) : null;
|
|
11611
12221
|
syncModeUi();
|
|
11612
|
-
syncFlicker();
|
|
11613
12222
|
const unlisten = tl?.listen({
|
|
11614
12223
|
onSeek: (t, source) => {
|
|
11615
12224
|
if (source === "play") {
|
|
@@ -11667,24 +12276,20 @@ function compare(container, options) {
|
|
|
11667
12276
|
});
|
|
11668
12277
|
root.addEventListener("keydown", onKey);
|
|
11669
12278
|
root.addEventListener("keyup", (e) => {
|
|
11670
|
-
|
|
11671
|
-
if (key === "x")
|
|
11672
|
-
holdFlick(false);
|
|
11673
|
-
else if (key === "z")
|
|
12279
|
+
if (e.key.toLowerCase() === "z")
|
|
11674
12280
|
holdLoupe(false);
|
|
11675
12281
|
});
|
|
11676
12282
|
root.addEventListener("focusout", (e) => {
|
|
11677
12283
|
if (root.contains(e.relatedTarget))
|
|
11678
12284
|
return;
|
|
11679
|
-
holdFlick(false);
|
|
11680
12285
|
holdLoupe(false);
|
|
11681
12286
|
});
|
|
11682
12287
|
const unregisterHints = options.hints === false ? undefined : hints.register(root, () => [
|
|
11683
|
-
...
|
|
12288
|
+
...modeList.length > 1 ? modeList.map((m, i) => ({
|
|
11684
12289
|
el: modeBtns[i],
|
|
11685
|
-
label: m.
|
|
11686
|
-
activate: () => setMode(m
|
|
11687
|
-
})),
|
|
12290
|
+
label: MODE_LABEL[m].long,
|
|
12291
|
+
activate: () => setMode(m)
|
|
12292
|
+
})) : [],
|
|
11688
12293
|
{ el: loopBtn, label: "Loop", activate: () => api.setLoop(!loopNow()) },
|
|
11689
12294
|
...loupeBtn.hidden ? [] : [{ el: loupeBtn, label: "Loupe", activate: () => setLoupe(!loupeOn) }],
|
|
11690
12295
|
...zoomed() ? [{ el: zoomReset, label: "Reset zoom", activate: () => api.setZoom(null) }] : [],
|
|
@@ -11709,6 +12314,7 @@ function compare(container, options) {
|
|
|
11709
12314
|
get mode() {
|
|
11710
12315
|
return mode;
|
|
11711
12316
|
},
|
|
12317
|
+
modes: modeList,
|
|
11712
12318
|
get wipe() {
|
|
11713
12319
|
return wipe;
|
|
11714
12320
|
},
|
|
@@ -11745,11 +12351,11 @@ function compare(container, options) {
|
|
|
11745
12351
|
if (before)
|
|
11746
12352
|
replace(0, before);
|
|
11747
12353
|
else if (next.before)
|
|
11748
|
-
|
|
12354
|
+
setLabel(0, next.before.label ?? "Before");
|
|
11749
12355
|
if (after)
|
|
11750
12356
|
replace(1, after);
|
|
11751
12357
|
else if (next.after)
|
|
11752
|
-
|
|
12358
|
+
setLabel(1, next.after.label ?? "After");
|
|
11753
12359
|
if (before || after)
|
|
11754
12360
|
strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
|
|
11755
12361
|
if (next.before || next.after)
|
|
@@ -11764,7 +12370,7 @@ function compare(container, options) {
|
|
|
11764
12370
|
tl?.update({ fps: next.fps });
|
|
11765
12371
|
requestDraw();
|
|
11766
12372
|
},
|
|
11767
|
-
seek: (t) => tl ? tl.seek(t) : ownSeek(t),
|
|
12373
|
+
seek: (t, o) => tl ? tl.seek(t, o?.glide ? { glide: true } : undefined) : ownSeek(t),
|
|
11768
12374
|
seekBy(d) {
|
|
11769
12375
|
const total = duration || tl?.duration || 0;
|
|
11770
12376
|
const t = Math.min(total, Math.max(0, now() + d));
|
|
@@ -11805,7 +12411,7 @@ function compare(container, options) {
|
|
|
11805
12411
|
dispose() {
|
|
11806
12412
|
disposed = true;
|
|
11807
12413
|
loop.stop();
|
|
11808
|
-
|
|
12414
|
+
modePill?.dispose();
|
|
11809
12415
|
win.clearTimeout(releaseTimer);
|
|
11810
12416
|
ro.disconnect();
|
|
11811
12417
|
nearIo?.disconnect();
|
|
@@ -11835,7 +12441,7 @@ function compare(container, options) {
|
|
|
11835
12441
|
wake();
|
|
11836
12442
|
return api;
|
|
11837
12443
|
}
|
|
11838
|
-
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM,
|
|
12444
|
+
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
11839
12445
|
var init_compare = __esm(() => {
|
|
11840
12446
|
init_motion();
|
|
11841
12447
|
init_page_hints();
|
|
@@ -11843,21 +12449,24 @@ var init_compare = __esm(() => {
|
|
|
11843
12449
|
init_compare_gpu();
|
|
11844
12450
|
init_compare_model();
|
|
11845
12451
|
init_compare_strip();
|
|
12452
|
+
init_icons();
|
|
11846
12453
|
init_look();
|
|
11847
12454
|
init_rgba();
|
|
12455
|
+
init_selection_pill();
|
|
11848
12456
|
init_timeline();
|
|
12457
|
+
init_timeline_model();
|
|
11849
12458
|
LAYOUT2 = springMotion({ duration: 0.35, bounce: 0 });
|
|
11850
12459
|
FADE6 = springMotion(SPRINGS.snappy);
|
|
11851
12460
|
FADE_REDUCED = springMotion(FADE);
|
|
11852
12461
|
ZOOM = springMotion({ duration: 0.35, bounce: 0 });
|
|
12462
|
+
WIPE_CATCH = springMotion(CATCH_UP);
|
|
12463
|
+
GRIP = { w: 16, h: 28 };
|
|
11853
12464
|
LOUPE = { r: 88, zoom: 4 };
|
|
11854
|
-
|
|
11855
|
-
{
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
];
|
|
11860
|
-
KEY_MODE = { s: "side", w: "wipe", d: "difference" };
|
|
12465
|
+
MODE_LABEL = {
|
|
12466
|
+
side: { short: "Side", long: "Side by side" },
|
|
12467
|
+
wipe: { short: "Wipe", long: "Wipe" },
|
|
12468
|
+
difference: { short: "Difference", long: "Difference" }
|
|
12469
|
+
};
|
|
11861
12470
|
});
|
|
11862
12471
|
|
|
11863
12472
|
// src/ui/react.tsx
|
|
@@ -14757,6 +15366,7 @@ function timelineChanges(now, changed) {
|
|
|
14757
15366
|
// src/ui/picker.ts
|
|
14758
15367
|
init_motion();
|
|
14759
15368
|
init_look();
|
|
15369
|
+
init_icons();
|
|
14760
15370
|
|
|
14761
15371
|
// src/ui/picker-model.ts
|
|
14762
15372
|
function digitPick(ids, key) {
|
|
@@ -14811,7 +15421,7 @@ var CLOSE3 = springMotion(CLOSE);
|
|
|
14811
15421
|
var CARD = springMotion(SPRINGS.default);
|
|
14812
15422
|
var FADE5 = springMotion(FADE);
|
|
14813
15423
|
var DRIFT = 6;
|
|
14814
|
-
var CHECK =
|
|
15424
|
+
var CHECK = icon("check", { small: true });
|
|
14815
15425
|
function optionPicker(container, options) {
|
|
14816
15426
|
const doc = container.ownerDocument;
|
|
14817
15427
|
const win = doc.defaultView;
|
|
@@ -16288,7 +16898,9 @@ function confirm(options) {
|
|
|
16288
16898
|
}
|
|
16289
16899
|
|
|
16290
16900
|
// src/ui/walkthrough.ts
|
|
16901
|
+
init_icons();
|
|
16291
16902
|
init_look();
|
|
16903
|
+
init_selection_pill();
|
|
16292
16904
|
|
|
16293
16905
|
// src/ui/toast.ts
|
|
16294
16906
|
init_look();
|
|
@@ -16354,399 +16966,11 @@ function toast(message, options = {}) {
|
|
|
16354
16966
|
};
|
|
16355
16967
|
}
|
|
16356
16968
|
|
|
16357
|
-
// src/ui/walkthrough-
|
|
16358
|
-
init_compare_model();
|
|
16359
|
-
init_glide();
|
|
16360
|
-
init_look();
|
|
16361
|
-
|
|
16362
|
-
// src/ui/walkthrough-css.ts
|
|
16969
|
+
// src/ui/walkthrough-blocks.ts
|
|
16363
16970
|
init_motion();
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
16368
|
-
.knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;
|
|
16369
|
-
--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));
|
|
16370
|
-
--kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-pad:16px;--kw-ink:var(--k-walkthrough-ink,#ff375f);
|
|
16371
|
-
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;
|
|
16372
|
-
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
16373
|
-
.knobs-walkthrough [hidden]{display:none!important}
|
|
16374
|
-
.knobs-walkthrough :is(h1,h2,h3,p){margin:0;font:inherit;letter-spacing:inherit}
|
|
16375
|
-
.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}
|
|
16376
|
-
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
16377
|
-
.knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
|
|
16378
|
-
: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;
|
|
16379
|
-
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
16380
|
-
|
|
16381
|
-
/* ——— layout: the rail beside the column; one column where it's narrow ——— */
|
|
16382
|
-
.knobs-wt-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;align-items:start}
|
|
16383
|
-
.knobs-wt-main{display:flex;flex-direction:column;gap:56px;min-width:0;max-width:1120px;padding-bottom:40vh}
|
|
16384
|
-
@container knobs-wt (max-width:880px){.knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:0}.knobs-wt-main{gap:44px}}
|
|
16385
|
-
|
|
16386
|
-
/* ——— the page's head ——— */
|
|
16387
|
-
.knobs-wt-head{display:flex;flex-direction:column;gap:10px}
|
|
16388
|
-
.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}
|
|
16389
|
-
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
16390
|
-
.knobs-wt-meta{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2px)}
|
|
16391
|
-
.knobs-wt-meta>span{display:inline-flex;gap:6px;white-space:nowrap}
|
|
16392
|
-
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono);font-size:calc(1em - .5px)}
|
|
16393
|
-
|
|
16394
|
-
/* ——— a section: a PR or topic ——— */
|
|
16395
|
-
.knobs-wt-section{display:flex;flex-direction:column;gap:14px;min-width:0}
|
|
16396
|
-
.knobs-wt-shead{display:flex;flex-direction:column;gap:6px;scroll-margin-top:16px}
|
|
16397
|
-
.knobs-wt-kicker{display:flex;align-items:center;gap:10px;font-size:calc(var(--kw-text) - 2px);color:var(--_k-fg-3)}
|
|
16398
|
-
.knobs-wt-kicker a{font-family:var(--_k-mono);color:var(--_k-fg-2);text-decoration:none}
|
|
16399
|
-
.knobs-wt-kicker a:hover{color:var(--_k-fg)}
|
|
16400
|
-
.knobs-wt-stitle{font-size:calc(var(--kw-text) + 4px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.3}
|
|
16401
|
-
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
16402
|
-
.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;
|
|
16403
|
-
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
16404
|
-
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
16405
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
16406
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
16407
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
16408
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
16409
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
16410
|
-
|
|
16411
|
-
/* ——— a step: one card ——— */
|
|
16412
|
-
.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);
|
|
16413
|
-
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
16414
|
-
.knobs-walkthrough[data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
16415
|
-
.knobs-wt-step-head{display:flex;align-items:baseline;gap:10px;min-width:0}
|
|
16416
|
-
.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}
|
|
16417
|
-
.knobs-wt-stepTitle{flex:1;min-width:0;font-weight:var(--_k-weight-title)!important}
|
|
16418
|
-
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);margin-top:-6px!important}
|
|
16419
|
-
.knobs-wt-question{font-weight:var(--_k-weight-label)!important}
|
|
16420
|
-
/* The step Kit is on: its number lights, and its choices show their keys. */
|
|
16421
|
-
.knobs-wt-step[data-current] .knobs-wt-num{color:var(--_k-fg)}
|
|
16422
|
-
.knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:12px;min-width:0}
|
|
16423
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
16424
|
-
|
|
16425
|
-
/* ——— the feed: the agent's updates and answers, newest first, compact ——— */
|
|
16426
|
-
.knobs-wt-feed{margin-top:-24px}
|
|
16427
|
-
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;max-height:260px;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column}
|
|
16428
|
-
.knobs-wt-feed-list::-webkit-scrollbar{display:none}
|
|
16429
|
-
.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)}
|
|
16430
|
-
.knobs-wt-fi+.knobs-wt-fi{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
16431
|
-
.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}
|
|
16432
|
-
.knobs-wt-fi-kind{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 2.5px);font-weight:var(--_k-weight-label)}
|
|
16433
|
-
.knobs-wt-fi[data-kind="qa"] .knobs-wt-fi-kind{color:var(--kw-info)}
|
|
16434
|
-
.knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
16435
|
-
.knobs-wt-fi-q{color:var(--_k-fg-2)}
|
|
16436
|
-
.knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
|
|
16437
|
-
: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;
|
|
16438
|
-
padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
|
|
16439
|
-
.knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16440
|
-
|
|
16441
|
-
/* ——— a step's sent notes ——— */
|
|
16442
|
-
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
16443
|
-
.knobs-wt-notes:empty{display:none}
|
|
16444
|
-
.knobs-wt-n{display:flex;align-items:flex-start;gap:10px;padding:6px 0;overflow:hidden;
|
|
16445
|
-
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)}
|
|
16446
|
-
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
16447
|
-
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
16448
|
-
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
16449
|
-
.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}
|
|
16450
|
-
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
16451
|
-
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
16452
|
-
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;font-size:calc(var(--kw-text) - 1px)}
|
|
16453
|
-
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
16454
|
-
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:6px;background:var(--_k-fill)}
|
|
16455
|
-
.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}
|
|
16456
|
-
|
|
16457
|
-
/* ——— the note bar, docked at the bottom of the column ——— */
|
|
16458
|
-
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;margin-top:-24px}
|
|
16459
|
-
.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);
|
|
16460
|
-
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
16461
|
-
.knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap;overflow:hidden;
|
|
16462
|
-
-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)}
|
|
16463
|
-
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
16464
|
-
: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;
|
|
16465
|
-
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
16466
|
-
.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)}
|
|
16467
|
-
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
16468
|
-
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
16469
|
-
.knobs-wt-attach:empty{display:none}
|
|
16470
|
-
.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}
|
|
16471
|
-
.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}
|
|
16472
|
-
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16473
|
-
.knobs-wt-x svg{width:10px;height:10px}
|
|
16474
|
-
.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);
|
|
16475
|
-
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
16476
|
-
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16477
|
-
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
16478
|
-
.knobs-wt-tool svg{width:15px;height:15px}
|
|
16479
|
-
.knobs-wt-rec{font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums}
|
|
16480
|
-
.knobs-wt-rec:empty{display:none}
|
|
16481
|
-
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
16482
|
-
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
16483
|
-
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
16484
|
-
.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);
|
|
16485
|
-
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;
|
|
16486
|
-
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)}
|
|
16487
|
-
.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)}
|
|
16488
|
-
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
16489
|
-
|
|
16490
|
-
/* ——— ink over a step's media ——— */
|
|
16491
|
-
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
16492
|
-
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
16493
|
-
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
16494
|
-
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
16495
|
-
|
|
16496
|
-
/* ——— full-window: the step over the page, its media filling it; its place held in the page ——— */
|
|
16497
|
-
.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}
|
|
16498
|
-
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
16499
|
-
.knobs-wt-hold-card{flex:none}
|
|
16500
|
-
.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)}
|
|
16501
|
-
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
16502
|
-
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
16503
|
-
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
16504
|
-
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
16505
|
-
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
16506
|
-
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
16507
|
-
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
16508
|
-
|
|
16509
|
-
/* ——— a taste test: the options side by side, Kit's pick lit and the rest stepping back ——— */
|
|
16510
|
-
.knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:10px}
|
|
16511
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
16512
|
-
.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);
|
|
16513
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16514
|
-
.knobs-wt-option[data-picked]{background:color-mix(in srgb,var(--_k-accent) 12%,var(--_ku-wash))}
|
|
16515
|
-
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16516
|
-
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
16517
|
-
.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}
|
|
16518
|
-
.knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
16519
|
-
.knobs-wt-letter{flex:none;font:var(--_k-weight-title) calc(var(--kw-text) - 1px)/1 var(--_k-font);color:var(--_k-fg)}
|
|
16520
|
-
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
16521
|
-
.knobs-wt-suggested{flex:none;font-size:calc(var(--kw-text) - 3px);color:var(--_k-fg-3)}
|
|
16522
|
-
.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;
|
|
16523
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16524
|
-
.knobs-wt-check svg{width:12px;height:12px}
|
|
16525
|
-
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
16526
|
-
.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);
|
|
16527
|
-
font:var(--_k-weight-label) calc(var(--kw-text) - 4px)/1 var(--_k-font);font-variant-numeric:tabular-nums;opacity:.5;transition:opacity .15s}
|
|
16528
|
-
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
16529
|
-
.knobs-wt-ocap{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 1px);padding:0 4px}
|
|
16530
|
-
|
|
16531
|
-
/* ——— the rail: progress, contents, export ——— */
|
|
16532
|
-
.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)}
|
|
16533
|
-
.knobs-wt-progress{display:flex;flex-direction:column;gap:7px}
|
|
16534
|
-
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2);font-variant-numeric:tabular-nums}
|
|
16535
|
-
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
16536
|
-
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
16537
|
-
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
16538
|
-
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
16539
|
-
/* The contents: no box, one text spine for sections and steps (the steps' dots hang in the
|
|
16540
|
-
gutter left of it), and one pill behind the current step that springs between rows. */
|
|
16541
|
-
.knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;margin:0 -8px;padding:0 0 8px}
|
|
16542
|
-
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
16543
|
-
.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;
|
|
16544
|
-
-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)}
|
|
16545
|
-
.knobs-wt-toc-section:first-of-type{padding-top:2px}
|
|
16546
|
-
.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}
|
|
16547
|
-
.knobs-wt-toc-mark[data-on]{opacity:1}
|
|
16548
|
-
.knobs-walkthrough[data-settled] .knobs-wt-toc-mark{transition:opacity .15s}
|
|
16549
|
-
.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}
|
|
16550
|
-
.knobs-ui .knobs-wt-toc-step:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
16551
|
-
.knobs-wt-toc-step[aria-current="step"]{color:var(--_k-fg)}
|
|
16552
|
-
.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)}
|
|
16553
|
-
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
16554
|
-
.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);
|
|
16555
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16556
|
-
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
16557
|
-
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
16558
|
-
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
16559
|
-
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
16560
|
-
.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;
|
|
16561
|
-
transition:background .15s,color .15s}
|
|
16562
|
-
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16563
|
-
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
16564
|
-
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
16565
|
-
.knobs-wt-keys{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);line-height:1.6}
|
|
16566
|
-
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
16567
|
-
/* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
|
|
16568
|
-
@container knobs-wt (max-width:880px){
|
|
16569
|
-
.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)}
|
|
16570
|
-
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
16571
|
-
.knobs-wt-step,.knobs-wt-shead{scroll-margin-top:60px}
|
|
16572
|
-
}
|
|
16573
|
-
|
|
16574
|
-
/* ——— media slots ——— */
|
|
16575
|
-
.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);
|
|
16576
|
-
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
16577
|
-
.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}
|
|
16578
|
-
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
16579
|
-
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
16580
|
-
(92 px), and the frame strip with its gap (158 px). */
|
|
16581
|
-
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
16582
|
-
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
16583
|
-
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
16584
|
-
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
16585
|
-
.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)}
|
|
16586
|
-
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
16587
|
-
.knobs-wt-frame[data-natural]{aspect-ratio:auto}
|
|
16588
|
-
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
16589
|
-
.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);
|
|
16590
|
-
font:calc(var(--k-walkthrough-text,14px) - 2px)/1.55 var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
16591
|
-
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
16592
|
-
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
16593
|
-
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
16594
|
-
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
16595
|
-
.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)}
|
|
16596
|
-
.knobs-wt-mlabel{color:var(--_k-fg-2);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
|
|
16597
|
-
.knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
16598
|
-
.knobs-wt-mfrom{color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) + 2px)}
|
|
16599
|
-
.knobs-wt-mto{font-size:calc(var(--k-walkthrough-text,14px) + 12px);font-weight:var(--_k-weight-title);line-height:1}
|
|
16600
|
-
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
16601
|
-
.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)}
|
|
16602
|
-
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
16603
|
-
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
16604
|
-
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
16605
|
-
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
16606
|
-
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
16607
|
-
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
16608
|
-
.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)}
|
|
16609
|
-
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:.62em;border-radius:50%;background:var(--kw-tone)}
|
|
16610
|
-
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
16611
|
-
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
16612
|
-
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
16613
|
-
.knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
16614
|
-
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
16615
|
-
.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)}
|
|
16616
|
-
|
|
16617
|
-
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
16618
|
-
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
16619
|
-
: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)}
|
|
16620
|
-
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
16621
|
-
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
16622
|
-
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
16623
|
-
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
16624
|
-
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
16625
|
-
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
16626
|
-
.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);
|
|
16627
|
-
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
16628
|
-
.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)}
|
|
16629
|
-
|
|
16630
|
-
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
16631
|
-
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
16632
|
-
.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)}
|
|
16633
|
-
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
16634
|
-
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
16635
|
-
.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)}
|
|
16636
|
-
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
|
|
16637
|
-
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
16638
|
-
.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}
|
|
16639
|
-
.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)}
|
|
16640
|
-
.knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
|
|
16641
|
-
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
16642
|
-
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
16643
|
-
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
16644
|
-
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
16645
|
-
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
16646
|
-
.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))}
|
|
16647
|
-
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
16648
|
-
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
16649
|
-
.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))}
|
|
16650
|
-
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
16651
|
-
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
16652
|
-
.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}
|
|
16653
|
-
.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}
|
|
16654
|
-
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
16655
|
-
@container knobs-wt-slot (max-width:520px){
|
|
16656
|
-
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
16657
|
-
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
16658
|
-
}
|
|
16659
|
-
|
|
16660
|
-
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
16661
|
-
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
16662
|
-
.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)}
|
|
16663
|
-
.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);
|
|
16664
|
-
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
16665
|
-
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
16666
|
-
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
16667
|
-
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16668
|
-
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
16669
|
-
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
16670
|
-
.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)}
|
|
16671
|
-
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
16672
|
-
.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}
|
|
16673
|
-
.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)}
|
|
16674
|
-
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
16675
|
-
.knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
16676
|
-
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
16677
|
-
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
16678
|
-
.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}
|
|
16679
|
-
.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}
|
|
16680
|
-
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
16681
|
-
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
16682
|
-
.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)}
|
|
16683
|
-
.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)}
|
|
16684
|
-
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
16685
|
-
.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)}
|
|
16686
|
-
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
16687
|
-
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
16688
|
-
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
16689
|
-
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
16690
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
16691
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
16692
|
-
@container knobs-wt-slot (max-width:520px){
|
|
16693
|
-
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
16694
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
16695
|
-
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
16696
|
-
}
|
|
16697
|
-
|
|
16698
|
-
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
16699
|
-
(the top one under the head), and thin bars show on hover. */
|
|
16700
|
-
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
16701
|
-
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
16702
|
-
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
16703
|
-
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
16704
|
-
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
16705
|
-
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
16706
|
-
.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)}
|
|
16707
|
-
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
16708
|
-
@supports (animation-timeline:scroll()){
|
|
16709
|
-
.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;
|
|
16710
|
-
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%;
|
|
16711
|
-
--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)));
|
|
16712
|
-
--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)));
|
|
16713
|
-
-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}
|
|
16714
|
-
}
|
|
16715
|
-
.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)}
|
|
16716
|
-
.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)}
|
|
16717
|
-
.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;
|
|
16718
|
-
background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
16719
|
-
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
16720
|
-
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
16721
|
-
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
16722
|
-
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
16723
|
-
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
16724
|
-
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
16725
|
-
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
16726
|
-
.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}
|
|
16727
|
-
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
16728
|
-
.knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
|
|
16729
|
-
.knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
|
|
16730
|
-
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
16731
|
-
|
|
16732
|
-
/* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
|
|
16733
|
-
.knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
|
|
16734
|
-
.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;
|
|
16735
|
-
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
|
|
16736
|
-
.knobs-wt-chapter-mark[data-on]{opacity:1}
|
|
16737
|
-
.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);
|
|
16738
|
-
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)}
|
|
16739
|
-
.knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16740
|
-
.knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
|
|
16741
|
-
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
|
|
16742
|
-
.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)}
|
|
16743
|
-
.knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
|
|
16744
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
16745
|
-
`;
|
|
16746
|
-
|
|
16747
|
-
// src/ui/walkthrough-blocks.ts
|
|
16748
|
-
init_motion();
|
|
16749
|
-
init_look();
|
|
16971
|
+
init_icons();
|
|
16972
|
+
init_look();
|
|
16973
|
+
init_selection_pill();
|
|
16750
16974
|
|
|
16751
16975
|
// src/ui/walkthrough-model.ts
|
|
16752
16976
|
var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
|
|
@@ -16953,7 +17177,15 @@ function fillTable(m) {
|
|
|
16953
17177
|
out[k] = fillCell(v);
|
|
16954
17178
|
return out;
|
|
16955
17179
|
});
|
|
16956
|
-
|
|
17180
|
+
const primary = columns.find((c) => c.key === m.primary)?.key ?? columns[0]?.key ?? "";
|
|
17181
|
+
return {
|
|
17182
|
+
kind: "table",
|
|
17183
|
+
columns,
|
|
17184
|
+
rows,
|
|
17185
|
+
...m.caption ? { caption: m.caption } : {},
|
|
17186
|
+
stack: m.stack ?? "auto",
|
|
17187
|
+
primary
|
|
17188
|
+
};
|
|
16957
17189
|
}
|
|
16958
17190
|
function fillChapters(chapters) {
|
|
16959
17191
|
const id = uniqueIds();
|
|
@@ -17026,6 +17258,8 @@ function normalizeWalkthrough(doc) {
|
|
|
17026
17258
|
...step.caption ? { caption: step.caption } : {},
|
|
17027
17259
|
...step.question ? { question: step.question } : {},
|
|
17028
17260
|
media: list.map((m) => fillMedia(m, doc.base)),
|
|
17261
|
+
columns: Math.max(1, Math.min(3, Math.round(step.columns ?? 1))),
|
|
17262
|
+
...step.more?.trim() && list.length > 1 ? { more: step.more.trim() } : {},
|
|
17029
17263
|
options,
|
|
17030
17264
|
ask
|
|
17031
17265
|
};
|
|
@@ -17037,6 +17271,7 @@ function normalizeWalkthrough(doc) {
|
|
|
17037
17271
|
id,
|
|
17038
17272
|
title: s.title,
|
|
17039
17273
|
...link ? { link } : {},
|
|
17274
|
+
...typeof s.kicker === "string" && s.kicker.trim() ? { kicker: s.kicker.trim() } : {},
|
|
17040
17275
|
...s.status ? { status: s.status } : {},
|
|
17041
17276
|
...s.summary ? { summary: s.summary } : {},
|
|
17042
17277
|
steps: own
|
|
@@ -17047,14 +17282,25 @@ function normalizeWalkthrough(doc) {
|
|
|
17047
17282
|
value
|
|
17048
17283
|
}));
|
|
17049
17284
|
const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
|
|
17285
|
+
const extra = (x) => ({
|
|
17286
|
+
...x.status?.trim() ? { status: x.status.trim() } : {},
|
|
17287
|
+
trail: (x.trail ?? []).filter((t) => typeof t === "string" && t.trim())
|
|
17288
|
+
});
|
|
17050
17289
|
const feed = sortFeed([
|
|
17051
|
-
...(doc.updates ?? []).map((u) => ({
|
|
17290
|
+
...(doc.updates ?? []).map((u) => ({
|
|
17291
|
+
kind: "update",
|
|
17292
|
+
at: parseAt(u.at),
|
|
17293
|
+
text: u.text,
|
|
17294
|
+
step: stepRef(u.step),
|
|
17295
|
+
...extra(u)
|
|
17296
|
+
})),
|
|
17052
17297
|
...(doc.qa ?? []).map((x) => ({
|
|
17053
17298
|
kind: "qa",
|
|
17054
17299
|
at: parseAt(x.at),
|
|
17055
17300
|
text: x.a,
|
|
17056
17301
|
q: x.q,
|
|
17057
|
-
step: stepRef(x.step)
|
|
17302
|
+
step: stepRef(x.step),
|
|
17303
|
+
...extra(x)
|
|
17058
17304
|
}))
|
|
17059
17305
|
]);
|
|
17060
17306
|
return {
|
|
@@ -17067,10 +17313,32 @@ function normalizeWalkthrough(doc) {
|
|
|
17067
17313
|
id: slug(v),
|
|
17068
17314
|
label: label(v)
|
|
17069
17315
|
})),
|
|
17070
|
-
sections,
|
|
17316
|
+
sections: withKickers(sections, doc.sections, doc.kickers),
|
|
17071
17317
|
steps
|
|
17072
17318
|
};
|
|
17073
17319
|
}
|
|
17320
|
+
var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
|
|
17321
|
+
function withKickers(sections, source, kickers = "pr") {
|
|
17322
|
+
if (kickers === false)
|
|
17323
|
+
return [...sections];
|
|
17324
|
+
const noun = typeof kickers === "object" ? kickers.noun.trim() : "PR";
|
|
17325
|
+
const counted = typeof kickers === "object" ? sections : sections.filter((s) => s.link && isPullRequest(s.link.href));
|
|
17326
|
+
return sections.map((s, i) => {
|
|
17327
|
+
const own = source[i]?.kicker;
|
|
17328
|
+
if (own !== undefined || s.kicker)
|
|
17329
|
+
return s;
|
|
17330
|
+
const at = counted.indexOf(s);
|
|
17331
|
+
return at < 0 ? s : { ...s, kicker: `${noun} ${at + 1} of ${counted.length}`.trim() };
|
|
17332
|
+
});
|
|
17333
|
+
}
|
|
17334
|
+
function tableStacks(stack, room, natural) {
|
|
17335
|
+
if (stack !== "auto")
|
|
17336
|
+
return stack === "always";
|
|
17337
|
+
return room > 0 && natural > room + 1;
|
|
17338
|
+
}
|
|
17339
|
+
function noteBarReserve(bar, inset, gap) {
|
|
17340
|
+
return Math.max(0, Math.ceil(bar)) + inset + gap;
|
|
17341
|
+
}
|
|
17074
17342
|
function parseAt(at) {
|
|
17075
17343
|
if (!at)
|
|
17076
17344
|
return null;
|
|
@@ -17355,6 +17623,9 @@ function feedbackMarkdown(fb, verdicts) {
|
|
|
17355
17623
|
`;
|
|
17356
17624
|
}
|
|
17357
17625
|
var escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
17626
|
+
function plainMarkdown(text) {
|
|
17627
|
+
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();
|
|
17628
|
+
}
|
|
17358
17629
|
function inlineMarkdown(text) {
|
|
17359
17630
|
const codes = [];
|
|
17360
17631
|
let s = text.replace(/`([^`\n]+)`/g, (_, c) => {
|
|
@@ -17375,6 +17646,10 @@ function inlineMarkdown(text) {
|
|
|
17375
17646
|
}
|
|
17376
17647
|
|
|
17377
17648
|
// src/ui/walkthrough-blocks.ts
|
|
17649
|
+
var GLYPH = {
|
|
17650
|
+
go: icon("caretRight", { small: true }),
|
|
17651
|
+
caret: icon("caretRight", { small: true })
|
|
17652
|
+
};
|
|
17378
17653
|
var el = (doc, tag, cls) => {
|
|
17379
17654
|
const n = doc.createElement(tag);
|
|
17380
17655
|
if (cls)
|
|
@@ -17404,9 +17679,10 @@ function stepButton(doc, ref, steps) {
|
|
|
17404
17679
|
const s = ref && steps?.find(ref);
|
|
17405
17680
|
if (!s || !steps)
|
|
17406
17681
|
return null;
|
|
17407
|
-
const b =
|
|
17682
|
+
const b = el(doc, "button", "knobs-wt-steplink");
|
|
17683
|
+
b.innerHTML = GLYPH.go;
|
|
17408
17684
|
b.type = "button";
|
|
17409
|
-
b.title = `Go to
|
|
17685
|
+
b.title = `Go to “${s.title}”`;
|
|
17410
17686
|
b.setAttribute("aria-label", b.title);
|
|
17411
17687
|
b.addEventListener("click", (e) => {
|
|
17412
17688
|
e.stopPropagation();
|
|
@@ -17531,7 +17807,7 @@ function mountStack(host, m, steps) {
|
|
|
17531
17807
|
if (target && steps) {
|
|
17532
17808
|
const title = text(doc, "button", "knobs-wt-stitle", it.title);
|
|
17533
17809
|
title.type = "button";
|
|
17534
|
-
title.title = `Go to
|
|
17810
|
+
title.title = `Go to “${target.title}”`;
|
|
17535
17811
|
title.addEventListener("click", (e) => {
|
|
17536
17812
|
e.stopPropagation();
|
|
17537
17813
|
steps.go(target.key);
|
|
@@ -17586,175 +17862,775 @@ function delta(doc, d) {
|
|
|
17586
17862
|
s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
|
|
17587
17863
|
return s;
|
|
17588
17864
|
}
|
|
17589
|
-
function
|
|
17590
|
-
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
|
|
17640
|
-
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
|
|
17650
|
-
|
|
17651
|
-
|
|
17652
|
-
|
|
17653
|
-
|
|
17654
|
-
|
|
17655
|
-
|
|
17656
|
-
|
|
17657
|
-
|
|
17658
|
-
|
|
17659
|
-
|
|
17660
|
-
|
|
17661
|
-
|
|
17662
|
-
|
|
17663
|
-
|
|
17664
|
-
|
|
17665
|
-
|
|
17666
|
-
}
|
|
17667
|
-
|
|
17668
|
-
|
|
17865
|
+
function cellContent(doc, into, cell, steps) {
|
|
17866
|
+
let content;
|
|
17867
|
+
if (cell.badge) {
|
|
17868
|
+
content = link(doc, "knobs-wt-chip", cell.text, cell.href);
|
|
17869
|
+
content.dataset.tone = cell.badge;
|
|
17870
|
+
} else {
|
|
17871
|
+
const inner = cell.code ? text(doc, "code", "", cell.text) : null;
|
|
17872
|
+
if (cell.href) {
|
|
17873
|
+
content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
|
|
17874
|
+
if (inner)
|
|
17875
|
+
content.append(inner);
|
|
17876
|
+
} else
|
|
17877
|
+
content = inner ?? text(doc, "span", "", cell.text);
|
|
17878
|
+
if (cell.tone) {
|
|
17879
|
+
content.classList.add("knobs-wt-ctone");
|
|
17880
|
+
content.dataset.tone = cell.tone;
|
|
17881
|
+
}
|
|
17882
|
+
}
|
|
17883
|
+
into.append(content);
|
|
17884
|
+
const go = stepButton(doc, cell.step, steps);
|
|
17885
|
+
if (go)
|
|
17886
|
+
into.append(go);
|
|
17887
|
+
}
|
|
17888
|
+
var cellAttrs = (td, c) => {
|
|
17889
|
+
td.dataset.align = c.align;
|
|
17890
|
+
if (c.mono)
|
|
17891
|
+
td.dataset.mono = "";
|
|
17892
|
+
};
|
|
17893
|
+
function mountTable(host, m, steps) {
|
|
17894
|
+
const doc = host.ownerDocument;
|
|
17895
|
+
const win = doc.defaultView;
|
|
17896
|
+
const box = el(doc, "div", "knobs-wt-tablebox");
|
|
17897
|
+
const scroller = el(doc, "div", "knobs-wt-table");
|
|
17898
|
+
const table = el(doc, "table");
|
|
17899
|
+
if (m.caption)
|
|
17900
|
+
table.append(text(doc, "caption", "", m.caption));
|
|
17901
|
+
const head = el(doc, "thead");
|
|
17902
|
+
const hr = el(doc, "tr");
|
|
17903
|
+
for (const c of m.columns) {
|
|
17904
|
+
const th = text(doc, "th", "", c.label);
|
|
17905
|
+
th.scope = "col";
|
|
17906
|
+
th.dataset.align = c.align;
|
|
17907
|
+
hr.append(th);
|
|
17908
|
+
}
|
|
17909
|
+
head.append(hr);
|
|
17910
|
+
const body = el(doc, "tbody");
|
|
17911
|
+
for (const r of m.rows) {
|
|
17912
|
+
const tr = el(doc, "tr");
|
|
17913
|
+
for (const c of m.columns) {
|
|
17914
|
+
const td = el(doc, "td");
|
|
17915
|
+
cellAttrs(td, c);
|
|
17916
|
+
const cell = r[c.key];
|
|
17917
|
+
if (cell) {
|
|
17918
|
+
if (cell.text.length > 40 && !c.mono && !cell.code)
|
|
17919
|
+
td.dataset.long = "";
|
|
17920
|
+
cellContent(doc, td, cell, steps);
|
|
17921
|
+
}
|
|
17922
|
+
tr.append(td);
|
|
17923
|
+
}
|
|
17924
|
+
body.append(tr);
|
|
17925
|
+
}
|
|
17926
|
+
table.append(head, body);
|
|
17927
|
+
scroller.append(table);
|
|
17928
|
+
const stack = el(doc, "div", "knobs-wt-tstack");
|
|
17929
|
+
stack.setAttribute("role", "list");
|
|
17930
|
+
if (m.caption)
|
|
17931
|
+
stack.setAttribute("aria-label", m.caption);
|
|
17932
|
+
const primary = m.columns.find((c) => c.key === m.primary) ?? m.columns[0];
|
|
17933
|
+
for (const r of m.rows) {
|
|
17934
|
+
const item = el(doc, "div", "knobs-wt-trow");
|
|
17935
|
+
item.setAttribute("role", "listitem");
|
|
17936
|
+
const title = el(doc, "div", "knobs-wt-ttitle");
|
|
17937
|
+
if (primary) {
|
|
17938
|
+
cellAttrs(title, primary);
|
|
17939
|
+
const cell = r[primary.key];
|
|
17940
|
+
if (cell)
|
|
17941
|
+
cellContent(doc, title, cell, steps);
|
|
17942
|
+
}
|
|
17943
|
+
const line = el(doc, "div", "knobs-wt-tline");
|
|
17944
|
+
line.append(title);
|
|
17945
|
+
const badges = el(doc, "div", "knobs-wt-tbadges");
|
|
17946
|
+
for (const c of m.columns) {
|
|
17947
|
+
const cell = r[c.key];
|
|
17948
|
+
if (c !== primary && cell?.badge)
|
|
17949
|
+
cellContent(doc, badges, cell, steps);
|
|
17950
|
+
}
|
|
17951
|
+
if (badges.childNodes.length)
|
|
17952
|
+
line.append(badges);
|
|
17953
|
+
item.append(line);
|
|
17954
|
+
const terms = el(doc, "dl", "knobs-wt-tterms");
|
|
17955
|
+
for (const c of m.columns) {
|
|
17956
|
+
if (c === primary)
|
|
17957
|
+
continue;
|
|
17958
|
+
const cell = r[c.key];
|
|
17959
|
+
if (!cell || cell.text === "" || cell.badge)
|
|
17960
|
+
continue;
|
|
17961
|
+
const dd = el(doc, "dd");
|
|
17962
|
+
cellAttrs(dd, c);
|
|
17963
|
+
dd.removeAttribute("data-align");
|
|
17964
|
+
cellContent(doc, dd, cell, steps);
|
|
17965
|
+
terms.append(text(doc, "dt", "", c.label), dd);
|
|
17966
|
+
}
|
|
17967
|
+
if (terms.childNodes.length)
|
|
17968
|
+
item.append(terms);
|
|
17969
|
+
stack.append(item);
|
|
17970
|
+
}
|
|
17971
|
+
if (m.caption)
|
|
17972
|
+
stack.append(text(doc, "p", "knobs-wt-tcaption", m.caption));
|
|
17973
|
+
box.append(scroller, stack);
|
|
17974
|
+
host.append(box);
|
|
17975
|
+
let natural = 0;
|
|
17976
|
+
const measureNatural = () => {
|
|
17977
|
+
if (!box.isConnected)
|
|
17978
|
+
return 0;
|
|
17979
|
+
const was = box.dataset.stacked;
|
|
17980
|
+
delete box.dataset.stacked;
|
|
17981
|
+
box.dataset.measure = "";
|
|
17982
|
+
const w = table.getBoundingClientRect().width;
|
|
17983
|
+
delete box.dataset.measure;
|
|
17984
|
+
if (was !== undefined)
|
|
17985
|
+
box.dataset.stacked = was;
|
|
17986
|
+
return w;
|
|
17987
|
+
};
|
|
17988
|
+
const measure = () => {
|
|
17989
|
+
if (!natural)
|
|
17990
|
+
natural = measureNatural();
|
|
17991
|
+
const stacked = tableStacks(m.stack, box.clientWidth, natural);
|
|
17992
|
+
box.toggleAttribute("data-stacked", stacked);
|
|
17993
|
+
scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
|
|
17994
|
+
const scrolls = !stacked && (scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1);
|
|
17995
|
+
if (scrolls) {
|
|
17996
|
+
scroller.tabIndex = 0;
|
|
17997
|
+
scroller.setAttribute("role", "region");
|
|
17998
|
+
scroller.setAttribute("aria-label", m.caption ?? "Table");
|
|
17999
|
+
} else {
|
|
18000
|
+
scroller.removeAttribute("tabindex");
|
|
18001
|
+
scroller.removeAttribute("role");
|
|
18002
|
+
scroller.removeAttribute("aria-label");
|
|
18003
|
+
}
|
|
18004
|
+
};
|
|
18005
|
+
if (m.stack === "always")
|
|
18006
|
+
box.dataset.stacked = "";
|
|
18007
|
+
const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
|
|
18008
|
+
ro?.observe(box);
|
|
18009
|
+
measure();
|
|
18010
|
+
doc.fonts?.ready.then(() => {
|
|
18011
|
+
if (!box.isConnected)
|
|
18012
|
+
return;
|
|
18013
|
+
natural = 0;
|
|
18014
|
+
measure();
|
|
18015
|
+
});
|
|
18016
|
+
return {
|
|
18017
|
+
dispose: () => {
|
|
18018
|
+
ro?.disconnect();
|
|
18019
|
+
box.remove();
|
|
18020
|
+
},
|
|
18021
|
+
context: () => ({ kind: "table" })
|
|
18022
|
+
};
|
|
18023
|
+
}
|
|
18024
|
+
function chapterPills(host, chapters, io) {
|
|
18025
|
+
const doc = host.ownerDocument;
|
|
18026
|
+
const list = el(doc, "div", "knobs-wt-chapters");
|
|
18027
|
+
list.setAttribute("role", "group");
|
|
18028
|
+
list.setAttribute("aria-label", "Chapters");
|
|
18029
|
+
let at = -2;
|
|
18030
|
+
const rows = chapters.map((c, i) => {
|
|
18031
|
+
const b = el(doc, "button", "knobs-wt-chapter");
|
|
18032
|
+
b.type = "button";
|
|
18033
|
+
b.append(text(doc, "span", "knobs-wt-chapter-n", String(i + 1)));
|
|
18034
|
+
b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
|
|
18035
|
+
b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
|
|
18036
|
+
b.addEventListener("click", () => {
|
|
18037
|
+
io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
|
|
18038
|
+
io.seek(c.start);
|
|
18039
|
+
select(i);
|
|
18040
|
+
});
|
|
18041
|
+
list.append(b);
|
|
18042
|
+
return b;
|
|
18043
|
+
});
|
|
18044
|
+
host.append(list);
|
|
18045
|
+
const pill = selectionPill(list, {
|
|
18046
|
+
selected: () => rows[at] ?? null,
|
|
18047
|
+
rows: () => rows
|
|
18048
|
+
});
|
|
18049
|
+
const select = (i) => {
|
|
18050
|
+
if (i === at)
|
|
18051
|
+
return;
|
|
18052
|
+
at = i;
|
|
18053
|
+
rows.forEach((b, k) => k === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
18054
|
+
pill.update();
|
|
18055
|
+
};
|
|
18056
|
+
const sync = () => select(chapterAt(chapters, io.now()));
|
|
18057
|
+
sync();
|
|
18058
|
+
return {
|
|
18059
|
+
sync,
|
|
18060
|
+
get current() {
|
|
18061
|
+
return chapters[at] ?? null;
|
|
18062
|
+
},
|
|
18063
|
+
dispose() {
|
|
18064
|
+
pill.dispose();
|
|
18065
|
+
list.remove();
|
|
18066
|
+
}
|
|
18067
|
+
};
|
|
18068
|
+
}
|
|
18069
|
+
function disclosure(host, options) {
|
|
18070
|
+
const doc = host.ownerDocument;
|
|
18071
|
+
const win = doc.defaultView;
|
|
18072
|
+
let open = options.open === true;
|
|
18073
|
+
const root = el(doc, "div", "knobs-wt-disc");
|
|
18074
|
+
const toggle = el(doc, "button", "knobs-wt-disc-toggle");
|
|
18075
|
+
toggle.type = "button";
|
|
18076
|
+
toggle.innerHTML = GLYPH.caret;
|
|
18077
|
+
toggle.append(text(doc, "span", "", options.label));
|
|
18078
|
+
if (options.count !== undefined)
|
|
18079
|
+
toggle.append(text(doc, "span", "knobs-wt-disc-count", String(options.count)));
|
|
18080
|
+
const viewport = el(doc, "div", "knobs-wt-disc-body");
|
|
18081
|
+
const content = el(doc, "div", "knobs-wt-disc-content");
|
|
18082
|
+
content.append(options.content);
|
|
18083
|
+
viewport.append(content);
|
|
18084
|
+
root.append(toggle, viewport);
|
|
18085
|
+
host.append(root);
|
|
18086
|
+
const STATE = springMotion(SPRINGS.default);
|
|
18087
|
+
const h = new Spring(0, STATE.omega, STATE.zeta, 0.25);
|
|
18088
|
+
let full = 0;
|
|
18089
|
+
const paint = (moving) => {
|
|
18090
|
+
const k = full > 0 ? Math.max(0, Math.min(1, h.x / full)) : open ? 1 : 0;
|
|
18091
|
+
viewport.style.height = !moving && open ? "" : `${Math.max(0, h.x).toFixed(2)}px`;
|
|
18092
|
+
viewport.toggleAttribute("data-moving", moving);
|
|
18093
|
+
content.style.opacity = (open ? Math.min(1, k * 1.25) : Math.max(0, k * 1.5 - 0.5)).toFixed(3);
|
|
18094
|
+
};
|
|
18095
|
+
const loop = frameLoop(win, (dt) => {
|
|
18096
|
+
h.step(dt);
|
|
18097
|
+
const moving = !h.resting;
|
|
18098
|
+
paint(moving);
|
|
18099
|
+
return moving;
|
|
18100
|
+
});
|
|
18101
|
+
const sync = () => {
|
|
18102
|
+
root.toggleAttribute("data-open", open);
|
|
18103
|
+
toggle.setAttribute("aria-expanded", String(open));
|
|
18104
|
+
viewport.inert = !open;
|
|
18105
|
+
};
|
|
18106
|
+
sync();
|
|
18107
|
+
h.snap(0);
|
|
18108
|
+
paint(false);
|
|
18109
|
+
if (open) {
|
|
18110
|
+
viewport.style.height = "";
|
|
18111
|
+
content.style.opacity = "1";
|
|
18112
|
+
}
|
|
18113
|
+
const api = {
|
|
18114
|
+
element: root,
|
|
18115
|
+
get open() {
|
|
18116
|
+
return open;
|
|
18117
|
+
},
|
|
18118
|
+
toggle(next = !open) {
|
|
18119
|
+
if (next === open)
|
|
18120
|
+
return;
|
|
18121
|
+
open = next;
|
|
18122
|
+
sync();
|
|
18123
|
+
full = content.offsetHeight;
|
|
18124
|
+
if (reducedMotion(win)) {
|
|
18125
|
+
loop.stop();
|
|
18126
|
+
h.snap(open ? full : 0);
|
|
18127
|
+
viewport.style.height = open ? "" : "0px";
|
|
18128
|
+
content.style.opacity = open ? "1" : "0";
|
|
18129
|
+
return;
|
|
18130
|
+
}
|
|
18131
|
+
if (h.resting)
|
|
18132
|
+
h.snap(open ? 0 : full);
|
|
18133
|
+
h.set(open ? full : 0);
|
|
18134
|
+
paint(true);
|
|
18135
|
+
loop.wake();
|
|
18136
|
+
},
|
|
18137
|
+
dispose() {
|
|
18138
|
+
loop.stop();
|
|
18139
|
+
root.remove();
|
|
18140
|
+
}
|
|
18141
|
+
};
|
|
18142
|
+
toggle.addEventListener("click", () => api.toggle());
|
|
18143
|
+
return api;
|
|
18144
|
+
}
|
|
18145
|
+
|
|
18146
|
+
// src/ui/walkthrough-media.ts
|
|
18147
|
+
init_compare_model();
|
|
18148
|
+
init_glide();
|
|
18149
|
+
init_icons();
|
|
18150
|
+
init_look();
|
|
18151
|
+
|
|
18152
|
+
// src/ui/walkthrough-css.ts
|
|
18153
|
+
init_motion();
|
|
18154
|
+
var snappy3 = springCss(SPRINGS.snappy);
|
|
18155
|
+
var calm = springCss(SPRINGS.calm);
|
|
18156
|
+
var state = springCss(SPRINGS.default);
|
|
18157
|
+
var quick = springCss(FADE);
|
|
18158
|
+
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)";
|
|
18159
|
+
var walkthroughCss = `
|
|
18160
|
+
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
18161
|
+
.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;
|
|
18162
|
+
--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));
|
|
18163
|
+
--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);
|
|
18164
|
+
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;
|
|
18165
|
+
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
18166
|
+
.knobs-walkthrough [hidden]{display:none!important}
|
|
18167
|
+
/* (0,0,1): a host's element rules stop here, and every class rule below wins over it. */
|
|
18168
|
+
:where(.knobs-walkthrough) :is(h1,h2,h3,p,ol,ul,dl,dd){margin:0;font:inherit;letter-spacing:inherit}
|
|
18169
|
+
.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}
|
|
18170
|
+
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
18171
|
+
.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)}
|
|
18172
|
+
: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;
|
|
18173
|
+
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
18174
|
+
|
|
18175
|
+
/* ——— layout: a readable column, centred, with a slim contents rail beside it (right by default);
|
|
18176
|
+
one column where it's narrow ——— */
|
|
18177
|
+
.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}
|
|
18178
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-main{grid-column:1;grid-row:1}
|
|
18179
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-rail{grid-column:2;grid-row:1}
|
|
18180
|
+
.knobs-walkthrough[data-rail="left"] .knobs-wt-layout{grid-template-columns:var(--kw-rail-w) minmax(0,var(--kw-width))}
|
|
18181
|
+
.knobs-walkthrough[data-rail="none"] .knobs-wt-layout{grid-template-columns:minmax(0,var(--kw-width))}
|
|
18182
|
+
.knobs-wt-main{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0;padding-bottom:12px}
|
|
18183
|
+
/* The intro, the updates and each section: a section's room apart, the hairline in the middle. */
|
|
18184
|
+
.knobs-wt-flow{display:flex;flex-direction:column;gap:calc(var(--_k-space-section) / 2);min-width:0}
|
|
18185
|
+
.knobs-wt-flow>*+*{padding-top:calc(var(--_k-space-section) / 2);box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
18186
|
+
@container knobs-wt (max-width:940px){.knobs-walkthrough .knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:var(--_k-space-title)}
|
|
18187
|
+
.knobs-walkthrough[data-rail] .knobs-wt-layout>*{grid-column:auto;grid-row:auto}}
|
|
18188
|
+
|
|
18189
|
+
/* ——— one line of facts: small, faint, joined by ·, its trailing edge fading ——— */
|
|
18190
|
+
.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}}
|
|
18191
|
+
.knobs-wt-metaline>*{flex:none}
|
|
18192
|
+
.knobs-wt-metaline>*+*::before{content:"·";margin-right:var(--_k-space-inside);color:var(--_k-fg-3)}
|
|
18193
|
+
.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)}
|
|
18194
|
+
.knobs-walkthrough .knobs-wt-metaline a:hover{color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18195
|
+
.knobs-wt-metaline svg{align-self:center;width:12px;height:12px;margin-left:2px}
|
|
18196
|
+
.knobs-wt-kicker-lead{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
18197
|
+
.knobs-wt-metaline [data-status="on"]{color:var(--_k-fg)}
|
|
18198
|
+
.knobs-wt-metaline [data-status="warn"]{color:var(--_k-warn)}
|
|
18199
|
+
|
|
18200
|
+
/* ——— the page's head ——— */
|
|
18201
|
+
.knobs-wt-head{display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
18202
|
+
.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}
|
|
18203
|
+
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18204
|
+
.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)}
|
|
18205
|
+
.knobs-wt-meta>span{display:inline-flex;gap:var(--_k-space-inside);white-space:nowrap}
|
|
18206
|
+
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono)}
|
|
18207
|
+
|
|
18208
|
+
/* ——— a section: a PR or topic. Its kicker leads the meta line; its title outranks the page's ——— */
|
|
18209
|
+
.knobs-wt-section{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
18210
|
+
.knobs-wt-sintro{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0}
|
|
18211
|
+
.knobs-wt-shead{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0;scroll-margin-top:16px}
|
|
18212
|
+
.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}
|
|
18213
|
+
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18214
|
+
.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;
|
|
18215
|
+
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
18216
|
+
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
18217
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18218
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
18219
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18220
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
18221
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
18222
|
+
|
|
18223
|
+
/* ——— a step: on the page by default, a group's room between steps with a hairline in the middle;
|
|
18224
|
+
or (cards) one card each, the one surface its pieces sit on ——— */
|
|
18225
|
+
.knobs-walkthrough:not([data-cards]) .knobs-wt-step:not([data-full]){padding:0;border-radius:0;background:transparent;box-shadow:none}
|
|
18226
|
+
.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}
|
|
18227
|
+
.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);
|
|
18228
|
+
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
18229
|
+
.knobs-walkthrough[data-cards]{--kw-under:var(--kw-card)}
|
|
18230
|
+
.knobs-walkthrough[data-cards][data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
18231
|
+
.knobs-wt-step-head{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
18232
|
+
.knobs-wt-stepTitle{min-width:0;font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
18233
|
+
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18234
|
+
.knobs-wt-question{font-weight:var(--kw-strong)!important;max-width:var(--kw-measure)}
|
|
18235
|
+
.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}
|
|
18236
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
18237
|
+
|
|
18238
|
+
/* ——— the feed: updates and answers, newest first. Tight inside an item (4 / 8 / 4), a group's
|
|
18239
|
+
room between items with the hairline in the middle; no boxes ——— */
|
|
18240
|
+
.knobs-wt-feed{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0;scroll-margin-top:16px}
|
|
18241
|
+
.knobs-wt-feed-head{display:flex;align-items:baseline;gap:var(--_k-space-sibling)}
|
|
18242
|
+
.knobs-wt-feed-title{font-weight:var(--kw-strong)!important}
|
|
18243
|
+
.knobs-wt-feed-count{font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}
|
|
18244
|
+
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
18245
|
+
.knobs-wt-fi{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
18246
|
+
.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)}
|
|
18247
|
+
.knobs-wt-fi-q,.knobs-wt-fi-a{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
18248
|
+
.knobs-wt-fi-ask{max-width:var(--kw-measure);color:var(--_k-fg);font-weight:var(--kw-strong);text-wrap:pretty}
|
|
18249
|
+
.knobs-wt-fi-text{max-width:var(--kw-measure);color:var(--_k-fg);text-wrap:pretty}
|
|
18250
|
+
.knobs-wt-fi-answer{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18251
|
+
: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;
|
|
18252
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
18253
|
+
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18254
|
+
: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;
|
|
18255
|
+
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)}
|
|
18256
|
+
.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)}
|
|
18257
|
+
.knobs-wt-steplink svg{width:12px;height:12px}
|
|
18258
|
+
|
|
18259
|
+
/* ——— a disclosure: a small faint toggle with a caret, no fill. The body's height springs (in
|
|
18260
|
+
script) and its content fades in place, top-anchored, under a soft bottom mask ——— */
|
|
18261
|
+
.knobs-wt-disc{display:flex;flex-direction:column;min-width:0}
|
|
18262
|
+
.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;
|
|
18263
|
+
border-radius:calc(var(--_k-radius) / 2);transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
18264
|
+
.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)}
|
|
18265
|
+
.knobs-ui .knobs-wt-disc-toggle:focus-visible{box-shadow:0 0 0 2px var(--_k-focus)}
|
|
18266
|
+
.knobs-wt-disc-toggle svg{flex:none;width:12px;height:12px;transition:rotate var(--kw-state-ms) var(--kw-state)}
|
|
18267
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-toggle svg{rotate:90deg}
|
|
18268
|
+
.knobs-wt-disc-count{color:var(--_k-fg-3)}
|
|
18269
|
+
.knobs-wt-disc-body{overflow:hidden}
|
|
18270
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-body:not([data-moving]){overflow:visible}
|
|
18271
|
+
.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)}
|
|
18272
|
+
.knobs-wt-disc-content{padding-top:var(--_k-space-inside)}
|
|
18273
|
+
/* A trail sits on the toggle's label edge: faint lines, the time trailing. */
|
|
18274
|
+
.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}
|
|
18275
|
+
.knobs-wt-trail li{display:flex;align-items:baseline;gap:var(--_k-space-sibling);min-width:0;white-space:nowrap}
|
|
18276
|
+
.knobs-wt-trail-text{flex:0 1 auto;min-width:0;overflow:hidden;${fade2}}
|
|
18277
|
+
.knobs-wt-trail-at{flex:none}
|
|
18278
|
+
|
|
18279
|
+
/* ——— a step's sent notes ——— */
|
|
18280
|
+
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
18281
|
+
.knobs-wt-notes:empty{display:none}
|
|
18282
|
+
.knobs-wt-n{display:flex;align-items:flex-start;gap:var(--_k-space-sibling);padding:6px 0;overflow:hidden;
|
|
18283
|
+
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)}
|
|
18284
|
+
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
18285
|
+
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
18286
|
+
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
18287
|
+
.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)}
|
|
18288
|
+
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
18289
|
+
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
18290
|
+
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
18291
|
+
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
18292
|
+
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
|
|
18293
|
+
.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}
|
|
18294
|
+
|
|
18295
|
+
/* ——— the note bar, docked at the bottom of the column. It holds its own place at the page's end
|
|
18296
|
+
(so the last step stays clear of it), and script keeps its height as the scroller's
|
|
18297
|
+
scroll-padding-bottom ——— */
|
|
18298
|
+
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;display:grid;pointer-events:none}
|
|
18299
|
+
.knobs-wt-dock>*{pointer-events:auto}
|
|
18300
|
+
.knobs-wt-dock>:is(.knobs-wt-notebar,.knobs-wt-launch){grid-area:1/1}
|
|
18301
|
+
.knobs-wt-dock[data-mode="docked"]>.knobs-wt-launch{display:none}
|
|
18302
|
+
/* Collapsed: the launcher and the bar swap in place, a quick fade with a little scale and blur
|
|
18303
|
+
from the launcher's corner; the exit is the shorter. */
|
|
18304
|
+
: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);
|
|
18305
|
+
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%;
|
|
18306
|
+
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)}
|
|
18307
|
+
.knobs-ui .knobs-wt-launch:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
18308
|
+
.knobs-ui .knobs-wt-launch:focus-visible{box-shadow:var(--_k-focus-ring)}
|
|
18309
|
+
.knobs-wt-launch svg{width:16px;height:16px}
|
|
18310
|
+
.knobs-wt-launch kbd{font:inherit;font-weight:var(--_k-weight);color:var(--_k-fg-3)}
|
|
18311
|
+
.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)}
|
|
18312
|
+
.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;
|
|
18313
|
+
transition-duration:calc(var(--kw-quick-ms) * .8)}
|
|
18314
|
+
.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);
|
|
18315
|
+
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
18316
|
+
.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}}
|
|
18317
|
+
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
18318
|
+
: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;
|
|
18319
|
+
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
18320
|
+
.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)}
|
|
18321
|
+
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
18322
|
+
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
18323
|
+
.knobs-wt-attach:empty{display:none}
|
|
18324
|
+
.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}
|
|
18325
|
+
.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}
|
|
18326
|
+
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
18327
|
+
.knobs-wt-x svg{width:12px;height:12px}
|
|
18328
|
+
.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);
|
|
18329
|
+
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
18330
|
+
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
18331
|
+
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
18332
|
+
.knobs-wt-tool svg{width:16px;height:16px}
|
|
18333
|
+
.knobs-wt-rec{font-size:var(--_k-type-small)}
|
|
18334
|
+
.knobs-wt-rec:empty{display:none}
|
|
18335
|
+
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
18336
|
+
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
18337
|
+
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
18338
|
+
.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;
|
|
18339
|
+
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;
|
|
18340
|
+
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)}
|
|
18341
|
+
.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)}
|
|
18342
|
+
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
18343
|
+
.knobs-wt-back svg{flex:none;width:12px;height:12px}
|
|
18344
|
+
.knobs-wt-back-label{min-width:0;overflow:hidden;white-space:nowrap;${fade2}}
|
|
18345
|
+
|
|
18346
|
+
/* ——— ink over a step's media ——— */
|
|
18347
|
+
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
18348
|
+
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
18349
|
+
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
18350
|
+
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
18351
|
+
|
|
18352
|
+
/* ——— full-window: the step over the page above the note bar, its media filling it; its place held
|
|
18353
|
+
in the page. The one raised surface ——— */
|
|
18354
|
+
.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}
|
|
18355
|
+
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
18356
|
+
.knobs-wt-hold-card{flex:none}
|
|
18357
|
+
.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)}
|
|
18358
|
+
.knobs-wt-step[data-full]::before{content:none}
|
|
18359
|
+
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
18360
|
+
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
18361
|
+
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
18362
|
+
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
18363
|
+
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
18364
|
+
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
18365
|
+
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
18366
|
+
|
|
18367
|
+
/* ——— a taste test: the options side by side, Kit's pick checked and the rest stepping back. On
|
|
18368
|
+
the step's card, so no fill of their own ——— */
|
|
18369
|
+
.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)}
|
|
18370
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
18371
|
+
.knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
18372
|
+
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
18373
|
+
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
18374
|
+
.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;
|
|
18375
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
18376
|
+
.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)}
|
|
18377
|
+
.knobs-wt-letter{flex:none;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
18378
|
+
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
18379
|
+
.knobs-wt-suggested{flex:none;font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
18380
|
+
.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;
|
|
18381
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
18382
|
+
.knobs-wt-check svg{width:12px;height:12px}
|
|
18383
|
+
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
18384
|
+
.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);
|
|
18385
|
+
font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);opacity:.5;transition:opacity .15s}
|
|
18386
|
+
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
18387
|
+
.knobs-wt-ocap{color:var(--_k-fg-2);max-width:var(--kw-measure)}
|
|
18388
|
+
|
|
18389
|
+
/* ——— the rail: progress, contents, export ——— */
|
|
18390
|
+
.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)}
|
|
18391
|
+
.knobs-wt-progress{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
18392
|
+
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2)}
|
|
18393
|
+
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
18394
|
+
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
18395
|
+
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
18396
|
+
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
18397
|
+
/* The contents: rows centred on one spine, title rows (32 high, the control radius) and the
|
|
18398
|
+
steps under them (20 high, half of it), bled out so their text sits on the rail's edge; the
|
|
18399
|
+
selection pill slides to the current step, and base rows never brighten for being current. */
|
|
18400
|
+
.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}
|
|
18401
|
+
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
18402
|
+
.knobs-wt-toc-group{display:flex;flex-direction:column;min-width:0}
|
|
18403
|
+
.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;
|
|
18404
|
+
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;
|
|
18405
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
18406
|
+
.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)}
|
|
18407
|
+
.knobs-wt-toc[data-bare] .knobs-wt-toc-row{grid-template-columns:minmax(0,1fr) auto}
|
|
18408
|
+
.knobs-wt-toc[data-bare] .knobs-wt-toc-n{display:none}
|
|
18409
|
+
.knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18410
|
+
.knobs-ui .knobs-wt-toc-sub:is(:hover,:focus-visible){color:var(--_k-fg-2)}
|
|
18411
|
+
.knobs-ui .knobs-wt-toc-row:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
18412
|
+
.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)}
|
|
18413
|
+
.knobs-wt-toc-row[data-active] .knobs-wt-toc-n{color:var(--_k-fg-2)}
|
|
18414
|
+
.knobs-wt-toc-label{min-width:0;overflow:hidden;${fade2}}
|
|
18415
|
+
.knobs-pick-copy .knobs-wt-toc-n,.knobs-pick-copy .knobs-wt-toc-end{color:var(--_k-fg-2)}
|
|
18416
|
+
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
18417
|
+
.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);
|
|
18418
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
18419
|
+
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
18420
|
+
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
18421
|
+
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
18422
|
+
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
18423
|
+
.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;
|
|
18424
|
+
transition:background .15s,color .15s}
|
|
18425
|
+
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
18426
|
+
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
18427
|
+
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
18428
|
+
.knobs-wt-keys{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
18429
|
+
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
18430
|
+
/* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
|
|
18431
|
+
@container knobs-wt (max-width:940px){
|
|
18432
|
+
.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)}
|
|
18433
|
+
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
18434
|
+
.knobs-wt-step,.knobs-wt-shead,.knobs-wt-feed{scroll-margin-top:60px}
|
|
18435
|
+
}
|
|
18436
|
+
|
|
18437
|
+
/* ——— media slots. Only a picture's frame (a quiet fill while it loads or letterboxes) and a code
|
|
18438
|
+
block (a well) are bounded; a metric, a callout, a table, a stack and a history sit on the page,
|
|
18439
|
+
set apart by space, hairlines and their own colours. On a card (.knobs-surface) code drops its
|
|
18440
|
+
well for hairlines, so nothing draws a fill and a ring of its own there ——— */
|
|
18441
|
+
.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);
|
|
18442
|
+
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);
|
|
18443
|
+
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
18444
|
+
.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)}
|
|
18445
|
+
.knobs-wt-body{min-width:0}
|
|
18446
|
+
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
18447
|
+
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
18448
|
+
(92 px), and the frame strip with its gap (158 px). */
|
|
18449
|
+
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
18450
|
+
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
18451
|
+
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
18452
|
+
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
18453
|
+
.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)}
|
|
18454
|
+
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
18455
|
+
.knobs-wt-frame[data-natural]{aspect-ratio:auto;background:transparent}
|
|
18456
|
+
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
18457
|
+
.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);
|
|
18458
|
+
font:var(--_k-type-label)/var(--_k-leading-body) var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
18459
|
+
.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)}
|
|
18460
|
+
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
18461
|
+
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
18462
|
+
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
18463
|
+
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
18464
|
+
.knobs-wt-metric{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
18465
|
+
.knobs-wt-mlabel{color:var(--_k-fg-2)}
|
|
18466
|
+
.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"}
|
|
18467
|
+
.knobs-wt-mfrom{color:var(--_k-fg-3);font-size:var(--_k-type-title);line-height:var(--_k-leading-title)}
|
|
18468
|
+
.knobs-wt-mto{font-size:var(--_k-type-heading);line-height:var(--_k-leading-heading);font-weight:var(--_k-weight-label)}
|
|
18469
|
+
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
18470
|
+
.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)}
|
|
18471
|
+
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18472
|
+
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18473
|
+
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
18474
|
+
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
18475
|
+
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
18476
|
+
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
18477
|
+
.knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:var(--_k-space-sibling);max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
18478
|
+
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:7px;border-radius:50%;background:var(--kw-tone)}
|
|
18479
|
+
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18480
|
+
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
18481
|
+
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18482
|
+
.knobs-wt-text{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
18483
|
+
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
18484
|
+
.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)}
|
|
18485
|
+
|
|
18486
|
+
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
18487
|
+
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
18488
|
+
: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)}
|
|
18489
|
+
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18490
|
+
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
18491
|
+
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18492
|
+
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
18493
|
+
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
18494
|
+
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
18495
|
+
.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);
|
|
18496
|
+
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
18497
|
+
.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)}
|
|
18498
|
+
|
|
18499
|
+
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
18500
|
+
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
18501
|
+
.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)}
|
|
18502
|
+
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
18503
|
+
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
18504
|
+
.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)}
|
|
18505
|
+
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:var(--_k-type-small);font-variant-numeric:tabular-nums}
|
|
18506
|
+
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
18507
|
+
.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}
|
|
18508
|
+
.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)}
|
|
18509
|
+
.knobs-wt-hage{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
18510
|
+
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
18511
|
+
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
18512
|
+
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
18513
|
+
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
18514
|
+
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
18515
|
+
.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))}
|
|
18516
|
+
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
18517
|
+
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
18518
|
+
.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))}
|
|
18519
|
+
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
18520
|
+
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
18521
|
+
.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}
|
|
18522
|
+
.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}
|
|
18523
|
+
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
18524
|
+
@container knobs-wt-slot (max-width:520px){
|
|
18525
|
+
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
18526
|
+
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
18527
|
+
}
|
|
18528
|
+
|
|
18529
|
+
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
18530
|
+
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
18531
|
+
.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)}
|
|
18532
|
+
.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);
|
|
18533
|
+
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
18534
|
+
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
18535
|
+
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
18536
|
+
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18537
|
+
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
18538
|
+
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
18539
|
+
.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)}
|
|
18540
|
+
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
18541
|
+
.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}
|
|
18542
|
+
.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)}
|
|
18543
|
+
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
18544
|
+
.knobs-wt-trunk{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
18545
|
+
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
18546
|
+
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
18547
|
+
.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}
|
|
18548
|
+
.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}
|
|
18549
|
+
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
18550
|
+
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
18551
|
+
.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)}
|
|
18552
|
+
.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)}
|
|
18553
|
+
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
18554
|
+
.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)}
|
|
18555
|
+
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
18556
|
+
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
18557
|
+
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
18558
|
+
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
18559
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
18560
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
18561
|
+
@container knobs-wt-slot (max-width:520px){
|
|
18562
|
+
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
18563
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
18564
|
+
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
17669
18565
|
}
|
|
17670
|
-
|
|
17671
|
-
|
|
17672
|
-
|
|
17673
|
-
|
|
17674
|
-
|
|
17675
|
-
|
|
17676
|
-
|
|
17677
|
-
|
|
17678
|
-
|
|
17679
|
-
|
|
17680
|
-
|
|
17681
|
-
|
|
17682
|
-
|
|
17683
|
-
|
|
17684
|
-
|
|
17685
|
-
|
|
17686
|
-
|
|
17687
|
-
|
|
17688
|
-
|
|
17689
|
-
|
|
17690
|
-
|
|
17691
|
-
|
|
17692
|
-
|
|
17693
|
-
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
|
|
17697
|
-
|
|
17698
|
-
|
|
17699
|
-
|
|
17700
|
-
|
|
17701
|
-
|
|
17702
|
-
|
|
17703
|
-
|
|
17704
|
-
|
|
17705
|
-
|
|
17706
|
-
draw();
|
|
17707
|
-
return !x.resting || !y.resting || !w.resting;
|
|
17708
|
-
});
|
|
17709
|
-
let at = -2;
|
|
17710
|
-
let shown = false;
|
|
17711
|
-
const place = (snap) => {
|
|
17712
|
-
const p = pills[at];
|
|
17713
|
-
if (!p) {
|
|
17714
|
-
mark.removeAttribute("data-on");
|
|
17715
|
-
pills.forEach((b) => b.removeAttribute("aria-current"));
|
|
17716
|
-
shown = false;
|
|
17717
|
-
return;
|
|
17718
|
-
}
|
|
17719
|
-
pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
17720
|
-
const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
|
|
17721
|
-
if (snap || !shown || reducedMotion(win)) {
|
|
17722
|
-
x.snap(to[0]);
|
|
17723
|
-
y.snap(to[1]);
|
|
17724
|
-
w.snap(to[2]);
|
|
17725
|
-
draw();
|
|
17726
|
-
} else {
|
|
17727
|
-
x.set(to[0]);
|
|
17728
|
-
y.set(to[1]);
|
|
17729
|
-
w.set(to[2]);
|
|
17730
|
-
loop.wake();
|
|
17731
|
-
}
|
|
17732
|
-
mark.style.height = `${p.offsetHeight}px`;
|
|
17733
|
-
mark.dataset.on = "";
|
|
17734
|
-
shown = true;
|
|
17735
|
-
};
|
|
17736
|
-
const sync = () => {
|
|
17737
|
-
const next = chapterAt(chapters, io.now());
|
|
17738
|
-
if (next === at)
|
|
17739
|
-
return;
|
|
17740
|
-
at = next;
|
|
17741
|
-
place(false);
|
|
17742
|
-
};
|
|
17743
|
-
sync();
|
|
17744
|
-
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
|
|
17745
|
-
ro?.observe(bar);
|
|
17746
|
-
return {
|
|
17747
|
-
sync,
|
|
17748
|
-
get current() {
|
|
17749
|
-
return chapters[at] ?? null;
|
|
17750
|
-
},
|
|
17751
|
-
dispose() {
|
|
17752
|
-
loop.stop();
|
|
17753
|
-
ro?.disconnect();
|
|
17754
|
-
bar.remove();
|
|
17755
|
-
}
|
|
17756
|
-
};
|
|
18566
|
+
|
|
18567
|
+
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
18568
|
+
(the top one under the head), and thin bars show on hover. */
|
|
18569
|
+
/* Too narrow for its columns, each row becomes a block: its primary cell titling the rest as term
|
|
18570
|
+
and value, the blocks parted by hairlines. Scrolling sideways is the last resort (stack: never). */
|
|
18571
|
+
.knobs-wt-tablebox{min-width:0}
|
|
18572
|
+
.knobs-wt-tablebox[data-measure] table{width:min-content}
|
|
18573
|
+
.knobs-wt-tstack{display:none;flex-direction:column;min-width:0}
|
|
18574
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-table{display:none}
|
|
18575
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-tstack{display:flex}
|
|
18576
|
+
.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)}
|
|
18577
|
+
.knobs-wt-trow:first-child{padding-top:0}
|
|
18578
|
+
.knobs-wt-trow:last-of-type{padding-bottom:0;box-shadow:none}
|
|
18579
|
+
.knobs-wt-tline{display:flex;align-items:baseline;justify-content:space-between;gap:var(--_k-space-title);min-width:0}
|
|
18580
|
+
.knobs-wt-tbadges{flex:none;display:flex;align-items:center;gap:var(--_k-space-inside)}
|
|
18581
|
+
.knobs-wt-ttitle{flex:1 1 auto;min-width:0;color:var(--_k-fg);font-weight:var(--_k-weight-label);overflow-wrap:anywhere}
|
|
18582
|
+
.knobs-wt-ttitle[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label)}
|
|
18583
|
+
.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}
|
|
18584
|
+
.knobs-wt-tterms dt{color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
18585
|
+
.knobs-wt-tterms dd{min-width:0;color:var(--_k-fg-2);overflow-wrap:anywhere}
|
|
18586
|
+
.knobs-wt-tterms dd[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg)}
|
|
18587
|
+
.knobs-wt-tcaption{padding-top:var(--_k-space-sibling);color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
18588
|
+
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
18589
|
+
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
18590
|
+
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
18591
|
+
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
18592
|
+
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
18593
|
+
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
18594
|
+
.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)}
|
|
18595
|
+
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
18596
|
+
@supports (animation-timeline:scroll()){
|
|
18597
|
+
.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;
|
|
18598
|
+
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%;
|
|
18599
|
+
--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)));
|
|
18600
|
+
--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)));
|
|
18601
|
+
-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}
|
|
17757
18602
|
}
|
|
18603
|
+
.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)}
|
|
18604
|
+
.knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
18605
|
+
.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;
|
|
18606
|
+
background:var(--kw-under,var(--_k-pane-bg));box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
18607
|
+
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
18608
|
+
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
18609
|
+
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
18610
|
+
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
18611
|
+
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
18612
|
+
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
18613
|
+
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
18614
|
+
.knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg);white-space:nowrap}
|
|
18615
|
+
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
18616
|
+
.knobs-ui :is(.knobs-wt-table,.knobs-wt-tstack) a.knobs-wt-chip{text-decoration:none}
|
|
18617
|
+
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
18618
|
+
|
|
18619
|
+
/* Chapters: a readout list under a video or compare: number, label, start; the selection pill
|
|
18620
|
+
on the one playing, its rows bled out so their text sits on the media's edge. */
|
|
18621
|
+
.knobs-wt-body:has(>.knobs-wt-chapters){display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
18622
|
+
.knobs-wt-chapters{position:relative;display:flex;flex-direction:column;margin:0 calc(var(--_k-space-sibling) * -1)}
|
|
18623
|
+
.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);
|
|
18624
|
+
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)}
|
|
18625
|
+
.knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18626
|
+
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
18627
|
+
.knobs-wt-chapter-n{font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
18628
|
+
.knobs-wt-chapter-label{min-width:0;overflow:hidden;${fade2}}
|
|
18629
|
+
.knobs-wt-chapter-time{font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);color:var(--_k-fg-3)}
|
|
18630
|
+
.knobs-pick-copy :is(.knobs-wt-chapter-n,.knobs-wt-chapter-time){color:var(--_k-fg-2)}
|
|
18631
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
18632
|
+
@media(prefers-reduced-motion:reduce){.knobs-wt-disc-content{transition:opacity .15s}}
|
|
18633
|
+
`;
|
|
17758
18634
|
|
|
17759
18635
|
// src/ui/walkthrough-media.ts
|
|
17760
18636
|
function injectWalkthroughStyles(doc) {
|
|
@@ -18283,7 +19159,7 @@ function mediaSlot(container, options) {
|
|
|
18283
19159
|
}
|
|
18284
19160
|
};
|
|
18285
19161
|
}
|
|
18286
|
-
var CHECK3 =
|
|
19162
|
+
var CHECK3 = icon("check", { small: true });
|
|
18287
19163
|
|
|
18288
19164
|
// src/ui/walkthrough.ts
|
|
18289
19165
|
var el2 = (doc, tag, cls) => {
|
|
@@ -18303,14 +19179,18 @@ var lookOf2 = (o) => ({
|
|
|
18303
19179
|
});
|
|
18304
19180
|
var grid2 = (v) => Math.round(v * 64) / 64;
|
|
18305
19181
|
var ICON = {
|
|
18306
|
-
full:
|
|
18307
|
-
exit:
|
|
18308
|
-
pen:
|
|
18309
|
-
mic:
|
|
19182
|
+
full: icon("cornersOut"),
|
|
19183
|
+
exit: icon("cornersIn"),
|
|
19184
|
+
pen: icon("pencilSimple"),
|
|
19185
|
+
mic: icon("microphone"),
|
|
18310
19186
|
stop: svg('<rect x="4.5" y="4.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none"/>'),
|
|
18311
|
-
send:
|
|
18312
|
-
close:
|
|
19187
|
+
send: icon("paperPlaneRight"),
|
|
19188
|
+
close: icon("x", { small: true }),
|
|
19189
|
+
back: icon("arrowLeft", { small: true }),
|
|
19190
|
+
out: icon("arrowUpRight", { small: true })
|
|
18313
19191
|
};
|
|
19192
|
+
var DOCK_INSET = 12;
|
|
19193
|
+
var DOCK_GAP = 12;
|
|
18314
19194
|
var CALM2 = springMotion(SPRINGS.calm);
|
|
18315
19195
|
var SMOOTH = springMotion(SPRINGS.smooth);
|
|
18316
19196
|
var BACK_MS = 4500;
|
|
@@ -18443,8 +19323,12 @@ function walkthrough(container, options) {
|
|
|
18443
19323
|
let count = null;
|
|
18444
19324
|
let fill = null;
|
|
18445
19325
|
let tocEl = null;
|
|
18446
|
-
let
|
|
19326
|
+
let pill = null;
|
|
19327
|
+
let tocRows = [];
|
|
19328
|
+
let discs = [];
|
|
18447
19329
|
let full = null;
|
|
19330
|
+
const noteMode = options.noteBar ?? "collapsed";
|
|
19331
|
+
let reserve = noteBarReserve(52, DOCK_INSET, DOCK_GAP);
|
|
18448
19332
|
const viewOf = (key) => views.find((v) => v.step.key === key);
|
|
18449
19333
|
const feedback = () => collectFeedback(page, state);
|
|
18450
19334
|
const markdown = () => feedbackMarkdown(feedback(), page.verdicts);
|
|
@@ -18468,9 +19352,6 @@ function walkthrough(container, options) {
|
|
|
18468
19352
|
else
|
|
18469
19353
|
run();
|
|
18470
19354
|
};
|
|
18471
|
-
const pillY = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
18472
|
-
const pillH = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
18473
|
-
let pillPlaced = false;
|
|
18474
19355
|
const scroll = {
|
|
18475
19356
|
spring: new Spring(0, CALM2.omega, CALM2.zeta, 0.5),
|
|
18476
19357
|
to: null,
|
|
@@ -18478,13 +19359,6 @@ function walkthrough(container, options) {
|
|
|
18478
19359
|
};
|
|
18479
19360
|
const motion = frameLoop(win, (dt) => {
|
|
18480
19361
|
let more = false;
|
|
18481
|
-
if (mark) {
|
|
18482
|
-
pillY.step(dt);
|
|
18483
|
-
pillH.step(dt);
|
|
18484
|
-
mark.style.transform = `translateY(${grid2(pillY.x)}px)`;
|
|
18485
|
-
mark.style.height = `${grid2(pillY.x + pillH.x) - grid2(pillY.x)}px`;
|
|
18486
|
-
more ||= !pillY.resting || !pillH.resting;
|
|
18487
|
-
}
|
|
18488
19362
|
if (scroll.to && scroll.el) {
|
|
18489
19363
|
scroll.spring.set(scrollTarget(scroll.to, scroll.el));
|
|
18490
19364
|
scroll.spring.step(dt);
|
|
@@ -18548,21 +19422,12 @@ function walkthrough(container, options) {
|
|
|
18548
19422
|
v.glyph.dataset.tone = v.step.ask === "none" ? "none" : verdict ? verdictTone(verdict, page.verdicts.findIndex((x) => x.id === verdict)) : done ? "accent" : "dim";
|
|
18549
19423
|
};
|
|
18550
19424
|
const placeMark = () => {
|
|
18551
|
-
if (!
|
|
19425
|
+
if (!pill || !tocEl)
|
|
18552
19426
|
return;
|
|
19427
|
+
pill.update();
|
|
18553
19428
|
const row = viewOf(current)?.toc;
|
|
18554
19429
|
if (!row)
|
|
18555
|
-
return
|
|
18556
|
-
mark.dataset.on = "";
|
|
18557
|
-
if (!pillPlaced || reduced()) {
|
|
18558
|
-
pillY.snap(row.offsetTop);
|
|
18559
|
-
pillH.snap(row.offsetHeight);
|
|
18560
|
-
pillPlaced = true;
|
|
18561
|
-
} else {
|
|
18562
|
-
pillY.set(row.offsetTop);
|
|
18563
|
-
pillH.set(row.offsetHeight);
|
|
18564
|
-
}
|
|
18565
|
-
motion.wake();
|
|
19430
|
+
return;
|
|
18566
19431
|
const top = row.offsetTop;
|
|
18567
19432
|
const bottom = top + row.offsetHeight;
|
|
18568
19433
|
if (top < tocEl.scrollTop + 8)
|
|
@@ -18579,6 +19444,9 @@ function walkthrough(container, options) {
|
|
|
18579
19444
|
const v = viewOf(key);
|
|
18580
19445
|
v?.card.setAttribute("data-current", "");
|
|
18581
19446
|
v?.toc?.setAttribute("aria-current", "step");
|
|
19447
|
+
for (const r of tocRows)
|
|
19448
|
+
if (r.dataset.section)
|
|
19449
|
+
r.toggleAttribute("data-active", r.dataset.section === v?.step.section);
|
|
18582
19450
|
if (key)
|
|
18583
19451
|
record({ what: "step", step: key });
|
|
18584
19452
|
placeMark();
|
|
@@ -18595,6 +19463,16 @@ function walkthrough(container, options) {
|
|
|
18595
19463
|
else
|
|
18596
19464
|
break;
|
|
18597
19465
|
}
|
|
19466
|
+
const s = scrollerOf(root);
|
|
19467
|
+
if (s.scrollTop > 0 && s.scrollTop >= s.scrollHeight - s.clientHeight - 2) {
|
|
19468
|
+
const bottom = (s === doc.scrollingElement ? win.innerHeight : s.getBoundingClientRect().bottom) - reserve;
|
|
19469
|
+
for (let i = views.length - 1;i >= 0; i--) {
|
|
19470
|
+
if (views[i].card.getBoundingClientRect().top < bottom) {
|
|
19471
|
+
pick = views[i].step.key;
|
|
19472
|
+
break;
|
|
19473
|
+
}
|
|
19474
|
+
}
|
|
19475
|
+
}
|
|
18598
19476
|
setCurrent(pick);
|
|
18599
19477
|
};
|
|
18600
19478
|
let scrollRaf = 0;
|
|
@@ -18637,7 +19515,12 @@ function walkthrough(container, options) {
|
|
|
18637
19515
|
};
|
|
18638
19516
|
const scrim = el2(doc, "div", "knobs-wt-scrim");
|
|
18639
19517
|
scrim.addEventListener("click", () => setFull(false));
|
|
18640
|
-
const fullRect = () => ({
|
|
19518
|
+
const fullRect = () => ({
|
|
19519
|
+
x: DOCK_INSET,
|
|
19520
|
+
y: DOCK_INSET,
|
|
19521
|
+
w: win.innerWidth - DOCK_INSET * 2,
|
|
19522
|
+
h: win.innerHeight - DOCK_INSET - reserve
|
|
19523
|
+
});
|
|
18641
19524
|
const placeFull = (f) => {
|
|
18642
19525
|
const a = f.hold.getBoundingClientRect();
|
|
18643
19526
|
const b = fullRect();
|
|
@@ -18782,6 +19665,7 @@ function walkthrough(container, options) {
|
|
|
18782
19665
|
ink.on = true;
|
|
18783
19666
|
ink.layer.dataset.on = "";
|
|
18784
19667
|
root.dataset.inking = "";
|
|
19668
|
+
bar.setOpen(true);
|
|
18785
19669
|
bar.sync();
|
|
18786
19670
|
};
|
|
18787
19671
|
const voice = {
|
|
@@ -18821,6 +19705,7 @@ function walkthrough(container, options) {
|
|
|
18821
19705
|
});
|
|
18822
19706
|
voice.recorder = rec;
|
|
18823
19707
|
voice.started = performance.now();
|
|
19708
|
+
bar.setOpen(true);
|
|
18824
19709
|
rec.start();
|
|
18825
19710
|
voice.timer = win.setInterval(() => bar.sync(), 250);
|
|
18826
19711
|
bar.sync();
|
|
@@ -18847,7 +19732,10 @@ function walkthrough(container, options) {
|
|
|
18847
19732
|
if (!v)
|
|
18848
19733
|
return;
|
|
18849
19734
|
backTo = key;
|
|
18850
|
-
backPill.
|
|
19735
|
+
backPill.innerHTML = ICON.back;
|
|
19736
|
+
const words = el2(doc, "span", "knobs-wt-back-label");
|
|
19737
|
+
words.textContent = `Back to ${plainMarkdown(v.step.title)}`;
|
|
19738
|
+
backPill.append(words);
|
|
18851
19739
|
backPill.dataset.on = "";
|
|
18852
19740
|
win.clearTimeout(backTimer);
|
|
18853
19741
|
backTimer = win.setTimeout(hideBack, BACK_MS);
|
|
@@ -18879,7 +19767,41 @@ function walkthrough(container, options) {
|
|
|
18879
19767
|
sendBtn.dataset.send = "";
|
|
18880
19768
|
row.append(input, attach, fullBtn, penBtn, micBtn, sendBtn);
|
|
18881
19769
|
box.append(on, row);
|
|
18882
|
-
|
|
19770
|
+
const launch = el2(doc, "button", "knobs-wt-launch");
|
|
19771
|
+
launch.type = "button";
|
|
19772
|
+
launch.innerHTML = ICON.pen;
|
|
19773
|
+
launch.append("Note");
|
|
19774
|
+
const kbd = el2(doc, "kbd");
|
|
19775
|
+
kbd.textContent = "n";
|
|
19776
|
+
launch.append(kbd);
|
|
19777
|
+
launch.setAttribute("aria-label", "Write a note (n)");
|
|
19778
|
+
launch.addEventListener("click", () => setOpen(true, true));
|
|
19779
|
+
dock.dataset.mode = noteMode;
|
|
19780
|
+
dock.append(backPill, box, launch);
|
|
19781
|
+
let open = noteMode !== "collapsed";
|
|
19782
|
+
const setOpen = (on, focus = false) => {
|
|
19783
|
+
if (noteMode === "collapsed" && on !== open) {
|
|
19784
|
+
open = on;
|
|
19785
|
+
dock.toggleAttribute("data-open", on);
|
|
19786
|
+
box.inert = !on;
|
|
19787
|
+
launch.inert = on;
|
|
19788
|
+
syncReserve();
|
|
19789
|
+
}
|
|
19790
|
+
if (on && focus)
|
|
19791
|
+
input.focus({ preventScroll: true });
|
|
19792
|
+
};
|
|
19793
|
+
dock.toggleAttribute("data-open", open);
|
|
19794
|
+
box.inert = !open;
|
|
19795
|
+
launch.inert = open;
|
|
19796
|
+
const empty = () => !input.value.trim() && !voice.pending && !voice.recorder && !ink.on && !ink.paths.length;
|
|
19797
|
+
const onOutside = (e) => {
|
|
19798
|
+
if (open && noteMode === "collapsed" && !dock.contains(e.target) && empty())
|
|
19799
|
+
setOpen(false);
|
|
19800
|
+
};
|
|
19801
|
+
doc.addEventListener("pointerdown", onOutside, true);
|
|
19802
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => syncReserve()) : null;
|
|
19803
|
+
ro?.observe(box);
|
|
19804
|
+
ro?.observe(launch);
|
|
18883
19805
|
const fit = () => {
|
|
18884
19806
|
input.style.height = "auto";
|
|
18885
19807
|
input.style.height = `${Math.min(140, input.scrollHeight)}px`;
|
|
@@ -18895,6 +19817,8 @@ function walkthrough(container, options) {
|
|
|
18895
19817
|
} else if (e.key === "Escape") {
|
|
18896
19818
|
e.preventDefault();
|
|
18897
19819
|
input.blur();
|
|
19820
|
+
if (empty())
|
|
19821
|
+
setOpen(false);
|
|
18898
19822
|
viewOf(current)?.card.focus({ preventScroll: true });
|
|
18899
19823
|
}
|
|
18900
19824
|
});
|
|
@@ -18914,13 +19838,13 @@ function walkthrough(container, options) {
|
|
|
18914
19838
|
const sync = () => {
|
|
18915
19839
|
const v = viewOf(current);
|
|
18916
19840
|
const ctx = describeMedia(mediaContext(v));
|
|
18917
|
-
const where = v ?
|
|
19841
|
+
const where = v ? plainMarkdown(v.step.title) : "General note";
|
|
18918
19842
|
const text = ctx ? `${where} · ${ctx}` : where;
|
|
18919
19843
|
if (text !== lastOn) {
|
|
18920
19844
|
on.textContent = text;
|
|
18921
19845
|
lastOn = text;
|
|
18922
19846
|
}
|
|
18923
|
-
input.placeholder = v ?
|
|
19847
|
+
input.placeholder = v ? "A note on this step… (n)" : "A note on the whole page… (n)";
|
|
18924
19848
|
const attached = `${voice.pending?.url ?? ""}|${ink.paths.length}`;
|
|
18925
19849
|
if (attached !== lastAttached) {
|
|
18926
19850
|
lastAttached = attached;
|
|
@@ -18959,14 +19883,45 @@ function walkthrough(container, options) {
|
|
|
18959
19883
|
};
|
|
18960
19884
|
return {
|
|
18961
19885
|
dock,
|
|
19886
|
+
box,
|
|
19887
|
+
launch,
|
|
18962
19888
|
input,
|
|
18963
19889
|
sync,
|
|
19890
|
+
get open() {
|
|
19891
|
+
return open;
|
|
19892
|
+
},
|
|
19893
|
+
setOpen,
|
|
19894
|
+
empty,
|
|
19895
|
+
unobserve: () => {
|
|
19896
|
+
ro?.disconnect();
|
|
19897
|
+
doc.removeEventListener("pointerdown", onOutside, true);
|
|
19898
|
+
},
|
|
18964
19899
|
clear() {
|
|
18965
19900
|
input.value = "";
|
|
18966
19901
|
fit();
|
|
18967
19902
|
}
|
|
18968
19903
|
};
|
|
18969
19904
|
})();
|
|
19905
|
+
let padded = null;
|
|
19906
|
+
function syncReserve() {
|
|
19907
|
+
if (disposed)
|
|
19908
|
+
return;
|
|
19909
|
+
const h = (bar.open ? bar.box : bar.launch).offsetHeight;
|
|
19910
|
+
if (noteMode === "hidden")
|
|
19911
|
+
reserve = 0;
|
|
19912
|
+
else if (h)
|
|
19913
|
+
reserve = noteBarReserve(h, DOCK_INSET, DOCK_GAP);
|
|
19914
|
+
root.style.setProperty("--kw-reserve", `${reserve}px`);
|
|
19915
|
+
const s = scrollerOf(root);
|
|
19916
|
+
if (padded?.el !== s) {
|
|
19917
|
+
if (padded)
|
|
19918
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
19919
|
+
padded = { el: s, was: s.style.scrollPaddingBottom };
|
|
19920
|
+
}
|
|
19921
|
+
s.style.scrollPaddingBottom = `${reserve}px`;
|
|
19922
|
+
if (full)
|
|
19923
|
+
placeFull(full);
|
|
19924
|
+
}
|
|
18970
19925
|
const ticker = win.setInterval(() => !doc.hidden && bar.sync(), 500);
|
|
18971
19926
|
const send = (text = bar.input.value) => {
|
|
18972
19927
|
if (voice.recorder)
|
|
@@ -19002,6 +19957,10 @@ function walkthrough(container, options) {
|
|
|
19002
19957
|
syncProgress();
|
|
19003
19958
|
emit();
|
|
19004
19959
|
bar.sync();
|
|
19960
|
+
if (noteMode === "collapsed") {
|
|
19961
|
+
bar.input.blur();
|
|
19962
|
+
bar.setOpen(false);
|
|
19963
|
+
}
|
|
19005
19964
|
if (v && options.advance !== false) {
|
|
19006
19965
|
const to = adjacentStep(views.map((x) => x.step.key), v.step.key, 1);
|
|
19007
19966
|
if (to && to !== v.step.key) {
|
|
@@ -19009,7 +19968,8 @@ function walkthrough(container, options) {
|
|
|
19009
19968
|
setFull(false);
|
|
19010
19969
|
go(to);
|
|
19011
19970
|
showBack(v.step.key);
|
|
19012
|
-
|
|
19971
|
+
if (noteMode === "docked")
|
|
19972
|
+
bar.input.focus({ preventScroll: true });
|
|
19013
19973
|
}
|
|
19014
19974
|
}
|
|
19015
19975
|
};
|
|
@@ -19096,22 +20056,105 @@ function walkthrough(container, options) {
|
|
|
19096
20056
|
row.addEventListener("transitionend", done, { once: true });
|
|
19097
20057
|
win.setTimeout(done, 600);
|
|
19098
20058
|
};
|
|
20059
|
+
const metaLine = (cls) => el2(doc, "div", `knobs-wt-metaline ${cls}`);
|
|
20060
|
+
const metaText = (line, text, cls) => {
|
|
20061
|
+
const s = el2(doc, "span", cls);
|
|
20062
|
+
s.textContent = text;
|
|
20063
|
+
line.append(s);
|
|
20064
|
+
return s;
|
|
20065
|
+
};
|
|
20066
|
+
const metaLink = (line, text, href) => {
|
|
20067
|
+
const a = el2(doc, "a");
|
|
20068
|
+
a.href = href;
|
|
20069
|
+
a.target = "_blank";
|
|
20070
|
+
a.rel = "noreferrer";
|
|
20071
|
+
a.textContent = text;
|
|
20072
|
+
a.insertAdjacentHTML("beforeend", ICON.out);
|
|
20073
|
+
line.append(a);
|
|
20074
|
+
return a;
|
|
20075
|
+
};
|
|
20076
|
+
const feedItem = (f, now) => {
|
|
20077
|
+
const li = el2(doc, "li", "knobs-wt-fi");
|
|
20078
|
+
li.dataset.kind = f.kind;
|
|
20079
|
+
const q = el2(doc, "div", "knobs-wt-fi-q");
|
|
20080
|
+
const meta = metaLine("knobs-wt-fi-meta");
|
|
20081
|
+
if (f.at !== null) {
|
|
20082
|
+
const when = metaText(meta, ago(f.at, now));
|
|
20083
|
+
when.title = new Date(f.at).toLocaleString();
|
|
20084
|
+
} else
|
|
20085
|
+
metaText(meta, f.kind === "qa" ? "Answer" : "Update");
|
|
20086
|
+
const step = f.step ? page.steps.find((s) => s.key === f.step) : undefined;
|
|
20087
|
+
if (step) {
|
|
20088
|
+
const section = page.sections.find((s) => s.id === step.section);
|
|
20089
|
+
const b = el2(doc, "button", "knobs-wt-fi-step");
|
|
20090
|
+
b.type = "button";
|
|
20091
|
+
b.textContent = section?.link?.label ?? plainMarkdown(step.title);
|
|
20092
|
+
b.title = `Go to “${plainMarkdown(step.title)}”`;
|
|
20093
|
+
b.addEventListener("click", () => go(step.key));
|
|
20094
|
+
meta.append(b);
|
|
20095
|
+
}
|
|
20096
|
+
if (f.status) {
|
|
20097
|
+
const id = f.status.toLowerCase();
|
|
20098
|
+
const shipped = /^(ship|shipped|merged|done)$/.test(id);
|
|
20099
|
+
const changes = /^(changes?|changes queued)$/.test(id);
|
|
20100
|
+
const s = metaText(meta, shipped ? "Shipped" : changes ? "Changes queued" : f.status);
|
|
20101
|
+
s.dataset.status = shipped ? "on" : changes ? "warn" : "";
|
|
20102
|
+
}
|
|
20103
|
+
q.append(meta);
|
|
20104
|
+
if (f.q)
|
|
20105
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-ask", f.q));
|
|
20106
|
+
else
|
|
20107
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
20108
|
+
li.append(q);
|
|
20109
|
+
if (f.q || f.trail.length) {
|
|
20110
|
+
const a = el2(doc, "div", "knobs-wt-fi-a");
|
|
20111
|
+
if (f.q)
|
|
20112
|
+
a.append(prose2(doc, "div", "knobs-wt-fi-answer", f.text));
|
|
20113
|
+
if (f.trail.length) {
|
|
20114
|
+
const list = el2(doc, "ol", "knobs-wt-trail");
|
|
20115
|
+
for (const line of f.trail) {
|
|
20116
|
+
const i = line.indexOf(" · ");
|
|
20117
|
+
const row = el2(doc, "li");
|
|
20118
|
+
const words = el2(doc, "span", "knobs-wt-trail-text");
|
|
20119
|
+
words.textContent = i < 0 ? line : line.slice(i + 3);
|
|
20120
|
+
row.append(words);
|
|
20121
|
+
if (i >= 0) {
|
|
20122
|
+
const at = el2(doc, "span", "knobs-wt-trail-at");
|
|
20123
|
+
at.textContent = line.slice(0, i);
|
|
20124
|
+
row.append(at);
|
|
20125
|
+
}
|
|
20126
|
+
list.append(row);
|
|
20127
|
+
}
|
|
20128
|
+
discs.push(disclosure(a, { label: "Context", count: f.trail.length, content: list }));
|
|
20129
|
+
}
|
|
20130
|
+
li.append(a);
|
|
20131
|
+
}
|
|
20132
|
+
return li;
|
|
20133
|
+
};
|
|
19099
20134
|
const build = () => {
|
|
19100
20135
|
for (const v of views) {
|
|
19101
20136
|
v.slots.forEach((s) => s.dispose());
|
|
19102
20137
|
v.taste?.dispose();
|
|
19103
20138
|
}
|
|
20139
|
+
for (const d of discs)
|
|
20140
|
+
d.dispose();
|
|
20141
|
+
discs = [];
|
|
20142
|
+
pill?.dispose();
|
|
20143
|
+
pill = null;
|
|
20144
|
+
tocRows = [];
|
|
19104
20145
|
if (full) {
|
|
19105
20146
|
full.p.snap(0);
|
|
19106
20147
|
closeFull();
|
|
19107
20148
|
}
|
|
19108
20149
|
clearInk();
|
|
19109
20150
|
views = [];
|
|
19110
|
-
pillPlaced = false;
|
|
19111
20151
|
root.textContent = "";
|
|
19112
20152
|
root.removeAttribute("data-settled");
|
|
20153
|
+
root.dataset.rail = options.rail === false ? "none" : options.rail === "left" ? "left" : "right";
|
|
20154
|
+
root.toggleAttribute("data-cards", options.cards === true);
|
|
19113
20155
|
const layout = el2(doc, "div", "knobs-wt-layout");
|
|
19114
20156
|
const main = el2(doc, "div", "knobs-wt-main");
|
|
20157
|
+
const flow = el2(doc, "div", "knobs-wt-flow");
|
|
19115
20158
|
const head = el2(doc, "header", "knobs-wt-head");
|
|
19116
20159
|
const h1 = el2(doc, "h1", "knobs-wt-title");
|
|
19117
20160
|
h1.textContent = page.title;
|
|
@@ -19138,42 +20181,27 @@ function walkthrough(container, options) {
|
|
|
19138
20181
|
}
|
|
19139
20182
|
head.append(meta);
|
|
19140
20183
|
}
|
|
19141
|
-
|
|
20184
|
+
flow.append(head);
|
|
20185
|
+
let feedEl = null;
|
|
19142
20186
|
if (page.feed.length) {
|
|
19143
|
-
|
|
19144
|
-
|
|
19145
|
-
|
|
20187
|
+
feedEl = el2(doc, "section", "knobs-wt-feed");
|
|
20188
|
+
feedEl.id = "wt-latest";
|
|
20189
|
+
feedEl.setAttribute("aria-label", "Updates and answers");
|
|
20190
|
+
const fh = el2(doc, "header", "knobs-wt-feed-head");
|
|
20191
|
+
const h = el2(doc, "h2", "knobs-wt-feed-title");
|
|
20192
|
+
h.textContent = page.feed.some((f) => f.kind === "qa") ? "Updates & Q&A" : "Updates";
|
|
20193
|
+
const n = el2(doc, "span", "knobs-wt-feed-count");
|
|
20194
|
+
n.textContent = String(page.feed.length);
|
|
20195
|
+
fh.append(h, n);
|
|
20196
|
+
const list = el2(doc, "ol", "knobs-wt-feed-list");
|
|
19146
20197
|
const now = Date.now();
|
|
19147
|
-
for (const f of page.feed)
|
|
19148
|
-
|
|
19149
|
-
|
|
19150
|
-
|
|
19151
|
-
when.textContent = f.at === null ? "" : ago(f.at, now);
|
|
19152
|
-
if (f.at !== null)
|
|
19153
|
-
when.title = new Date(f.at).toLocaleString();
|
|
19154
|
-
const kind = el2(doc, "span", "knobs-wt-fi-kind");
|
|
19155
|
-
kind.textContent = f.kind === "qa" ? "Answer" : "Update";
|
|
19156
|
-
const body = el2(doc, "div", "knobs-wt-fi-body");
|
|
19157
|
-
if (f.q)
|
|
19158
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
|
|
19159
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
19160
|
-
li.append(when, kind, body);
|
|
19161
|
-
if (f.step) {
|
|
19162
|
-
const target = f.step;
|
|
19163
|
-
const link = el2(doc, "button", "knobs-wt-fi-step");
|
|
19164
|
-
link.type = "button";
|
|
19165
|
-
link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
|
|
19166
|
-
link.title = "Go to the step";
|
|
19167
|
-
link.addEventListener("click", () => go(target));
|
|
19168
|
-
li.append(link);
|
|
19169
|
-
}
|
|
19170
|
-
list.append(li);
|
|
19171
|
-
}
|
|
19172
|
-
feed.append(list);
|
|
19173
|
-
main.append(feed);
|
|
20198
|
+
for (const f of page.feed)
|
|
20199
|
+
list.append(feedItem(f, now));
|
|
20200
|
+
feedEl.append(fh, list);
|
|
20201
|
+
flow.append(feedEl);
|
|
19174
20202
|
}
|
|
19175
20203
|
let rail = null;
|
|
19176
|
-
count = fill = tocEl =
|
|
20204
|
+
count = fill = tocEl = null;
|
|
19177
20205
|
if (options.rail !== false) {
|
|
19178
20206
|
rail = el2(doc, "aside", "knobs-wt-rail");
|
|
19179
20207
|
rail.setAttribute("aria-label", "Progress");
|
|
@@ -19185,8 +20213,17 @@ function walkthrough(container, options) {
|
|
|
19185
20213
|
progress.append(count, meter);
|
|
19186
20214
|
tocEl = el2(doc, "nav", "knobs-wt-toc");
|
|
19187
20215
|
tocEl.setAttribute("aria-label", "Contents");
|
|
19188
|
-
|
|
19189
|
-
|
|
20216
|
+
const ns = page.sections.map((s) => s.kicker && s.link ? s.link.label : "");
|
|
20217
|
+
const nw = Math.max(0, ...ns.map((n) => n.length));
|
|
20218
|
+
tocEl.style.setProperty("--kw-toc-n", nw ? `${nw + 0.5}ch` : "0px");
|
|
20219
|
+
if (!nw)
|
|
20220
|
+
tocEl.dataset.bare = "";
|
|
20221
|
+
if (feedEl) {
|
|
20222
|
+
const group = el2(doc, "div", "knobs-wt-toc-group");
|
|
20223
|
+
const target = feedEl;
|
|
20224
|
+
group.append(tocRow("Latest", "", String(page.feed.length), false, () => target.scrollIntoView({ block: "start", behavior: reduced() ? "auto" : "smooth" })));
|
|
20225
|
+
tocEl.append(group);
|
|
20226
|
+
}
|
|
19190
20227
|
rail.append(progress, tocEl, actions(true));
|
|
19191
20228
|
if (options.keys !== false) {
|
|
19192
20229
|
const keys = el2(doc, "div", "knobs-wt-keys");
|
|
@@ -19198,45 +20235,44 @@ function walkthrough(container, options) {
|
|
|
19198
20235
|
const sec = el2(doc, "section", "knobs-wt-section");
|
|
19199
20236
|
sec.id = `wt-${section.id}`;
|
|
19200
20237
|
const sh = el2(doc, "header", "knobs-wt-shead");
|
|
19201
|
-
if (section.link || section.status) {
|
|
19202
|
-
const
|
|
19203
|
-
if (section.
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
a.rel = "noreferrer";
|
|
19208
|
-
a.textContent = `${section.link.label} ↗`;
|
|
19209
|
-
kicker.append(a);
|
|
19210
|
-
}
|
|
20238
|
+
if (section.kicker || section.link || section.status) {
|
|
20239
|
+
const meta = metaLine("knobs-wt-kicker");
|
|
20240
|
+
if (section.kicker)
|
|
20241
|
+
metaText(meta, section.kicker, "knobs-wt-kicker-lead");
|
|
20242
|
+
if (section.link)
|
|
20243
|
+
metaLink(meta, section.link.label, section.link.href);
|
|
19211
20244
|
if (section.status) {
|
|
19212
20245
|
const s = statusLook(section.status);
|
|
19213
|
-
|
|
19214
|
-
chip.dataset.tone = s.tone;
|
|
19215
|
-
chip.textContent = s.label;
|
|
19216
|
-
kicker.append(chip);
|
|
20246
|
+
metaText(meta, s.label, "knobs-wt-status").dataset.tone = s.tone;
|
|
19217
20247
|
}
|
|
19218
|
-
sh.append(
|
|
20248
|
+
sh.append(meta);
|
|
19219
20249
|
}
|
|
19220
|
-
const h2 = el2(doc, "h2", "knobs-wt-
|
|
19221
|
-
h2.
|
|
20250
|
+
const h2 = el2(doc, "h2", "knobs-wt-heading");
|
|
20251
|
+
h2.innerHTML = inlineMarkdown(section.title);
|
|
19222
20252
|
sh.append(h2);
|
|
20253
|
+
const intro = el2(doc, "div", "knobs-wt-sintro");
|
|
20254
|
+
intro.append(sh);
|
|
19223
20255
|
if (section.summary)
|
|
19224
|
-
|
|
19225
|
-
sec.append(
|
|
20256
|
+
intro.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
|
|
20257
|
+
sec.append(intro);
|
|
20258
|
+
let group = null;
|
|
19226
20259
|
if (tocEl) {
|
|
19227
|
-
|
|
19228
|
-
|
|
19229
|
-
|
|
19230
|
-
|
|
20260
|
+
group = el2(doc, "div", "knobs-wt-toc-group");
|
|
20261
|
+
const first = section.steps[0]?.key;
|
|
20262
|
+
const n = section.kicker && section.link ? section.link.label : "";
|
|
20263
|
+
group.append(tocRow(plainMarkdown(section.title), n, "", false, () => first ? go(first) : undefined, section.id));
|
|
20264
|
+
tocEl.append(group);
|
|
19231
20265
|
}
|
|
19232
20266
|
for (const step of section.steps) {
|
|
19233
|
-
const v = stepView(step);
|
|
20267
|
+
const v = stepView(step, group);
|
|
19234
20268
|
sec.append(v.card);
|
|
19235
20269
|
views.push(v);
|
|
19236
20270
|
}
|
|
19237
|
-
|
|
20271
|
+
flow.append(sec);
|
|
19238
20272
|
}
|
|
19239
|
-
main.append(
|
|
20273
|
+
main.append(flow);
|
|
20274
|
+
if (noteMode !== "hidden")
|
|
20275
|
+
main.append(bar.dock);
|
|
19240
20276
|
if (rail)
|
|
19241
20277
|
layout.append(rail);
|
|
19242
20278
|
layout.append(main);
|
|
@@ -19246,16 +20282,40 @@ function walkthrough(container, options) {
|
|
|
19246
20282
|
for (const n of notesOn(state, v.step.key))
|
|
19247
20283
|
renderNote(v, n);
|
|
19248
20284
|
}
|
|
20285
|
+
if (tocEl)
|
|
20286
|
+
pill = selectionPill(tocEl, {
|
|
20287
|
+
selected: () => viewOf(current)?.toc ?? null,
|
|
20288
|
+
rows: () => tocRows
|
|
20289
|
+
});
|
|
19249
20290
|
syncProgress();
|
|
19250
20291
|
current = null;
|
|
19251
20292
|
fromScroll();
|
|
19252
20293
|
placeMark();
|
|
19253
20294
|
bar.sync();
|
|
20295
|
+
syncReserve();
|
|
19254
20296
|
win.requestAnimationFrame(() => win.requestAnimationFrame(() => {
|
|
19255
20297
|
if (!disposed && !reduced())
|
|
19256
20298
|
root.dataset.settled = "";
|
|
19257
20299
|
}));
|
|
19258
20300
|
};
|
|
20301
|
+
const tocRow = (label, n, end, sub, run, section) => {
|
|
20302
|
+
const b = el2(doc, "button", sub ? "knobs-wt-toc-row knobs-wt-toc-sub" : "knobs-wt-toc-row");
|
|
20303
|
+
b.type = "button";
|
|
20304
|
+
if (section)
|
|
20305
|
+
b.dataset.section = section;
|
|
20306
|
+
const ncol = el2(doc, "span", "knobs-wt-toc-n");
|
|
20307
|
+
ncol.textContent = n;
|
|
20308
|
+
const t = el2(doc, "span", "knobs-wt-toc-label");
|
|
20309
|
+
t.textContent = label;
|
|
20310
|
+
const e = el2(doc, "span", "knobs-wt-toc-end");
|
|
20311
|
+
e.textContent = end;
|
|
20312
|
+
b.title = label;
|
|
20313
|
+
b.append(ncol, t, e);
|
|
20314
|
+
b.addEventListener("mousedown", (ev) => ev.preventDefault());
|
|
20315
|
+
b.addEventListener("click", run);
|
|
20316
|
+
tocRows.push(b);
|
|
20317
|
+
return b;
|
|
20318
|
+
};
|
|
19259
20319
|
const actions = (rail) => {
|
|
19260
20320
|
const row = el2(doc, "div", "knobs-wt-actions");
|
|
19261
20321
|
const btn = (text, run, primary = false) => {
|
|
@@ -19296,30 +20356,38 @@ function walkthrough(container, options) {
|
|
|
19296
20356
|
toast("Couldn't reach the clipboard", { tone: "warn", look, doc });
|
|
19297
20357
|
}
|
|
19298
20358
|
};
|
|
19299
|
-
const stepView = (step) => {
|
|
19300
|
-
const card = el2(doc, "article", "knobs-wt-step knobs-surface");
|
|
20359
|
+
const stepView = (step, group) => {
|
|
20360
|
+
const card = el2(doc, "article", options.cards ? "knobs-wt-step knobs-surface" : "knobs-wt-step");
|
|
19301
20361
|
card.id = `wt-${step.key.replace("/", "--")}`;
|
|
19302
20362
|
card.tabIndex = -1;
|
|
19303
20363
|
card.dataset.key = step.key;
|
|
19304
|
-
card.setAttribute("aria-label",
|
|
20364
|
+
card.setAttribute("aria-label", plainMarkdown(step.title));
|
|
19305
20365
|
const head = el2(doc, "header", "knobs-wt-step-head");
|
|
19306
|
-
const num = el2(doc, "span", "knobs-wt-num");
|
|
19307
|
-
num.textContent = step.number;
|
|
19308
20366
|
const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
|
|
19309
|
-
h3.
|
|
19310
|
-
head.append(
|
|
19311
|
-
card.append(head);
|
|
20367
|
+
h3.innerHTML = inlineMarkdown(step.title);
|
|
20368
|
+
head.append(h3);
|
|
19312
20369
|
if (step.caption)
|
|
19313
|
-
|
|
20370
|
+
head.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
|
|
20371
|
+
card.append(head);
|
|
19314
20372
|
const slots = [];
|
|
19315
20373
|
const onEvent = (e) => record({ ...e, step: step.key });
|
|
19316
20374
|
let media = null;
|
|
19317
20375
|
if (step.media.length) {
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
20376
|
+
const grid = (list) => {
|
|
20377
|
+
const g = el2(doc, "div", "knobs-wt-media");
|
|
20378
|
+
g.style.setProperty("--kw-n", String(Math.min(list.length, step.columns)));
|
|
20379
|
+
for (const m of list)
|
|
20380
|
+
slots.push(mediaSlot(g, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
20381
|
+
return g;
|
|
20382
|
+
};
|
|
20383
|
+
const [first, ...rest] = step.media;
|
|
20384
|
+
media = grid(step.more ? [first] : step.media);
|
|
19322
20385
|
card.append(media);
|
|
20386
|
+
if (step.more && rest.length) {
|
|
20387
|
+
const holder = el2(doc, "div", "knobs-wt-more");
|
|
20388
|
+
discs.push(disclosure(holder, { label: step.more, count: rest.length, content: grid(rest) }));
|
|
20389
|
+
card.append(holder);
|
|
20390
|
+
}
|
|
19323
20391
|
}
|
|
19324
20392
|
let taste = null;
|
|
19325
20393
|
if (step.question)
|
|
@@ -19344,16 +20412,11 @@ function walkthrough(container, options) {
|
|
|
19344
20412
|
});
|
|
19345
20413
|
let toc = null;
|
|
19346
20414
|
let glyph = null;
|
|
19347
|
-
if (
|
|
19348
|
-
toc =
|
|
19349
|
-
toc.type = "button";
|
|
20415
|
+
if (group) {
|
|
20416
|
+
toc = tocRow(plainMarkdown(step.title), "", "", true, () => go(step.key));
|
|
19350
20417
|
glyph = el2(doc, "span", "knobs-wt-toc-glyph");
|
|
19351
|
-
|
|
19352
|
-
|
|
19353
|
-
toc.title = `${step.number} ${step.title}`;
|
|
19354
|
-
toc.append(glyph, label);
|
|
19355
|
-
toc.addEventListener("click", () => go(step.key));
|
|
19356
|
-
tocEl.append(toc);
|
|
20418
|
+
toc.querySelector(".knobs-wt-toc-end").append(glyph);
|
|
20419
|
+
group.append(toc);
|
|
19357
20420
|
}
|
|
19358
20421
|
return { step, card, media, notes, toc, glyph, taste, slots };
|
|
19359
20422
|
};
|
|
@@ -19412,15 +20475,21 @@ function walkthrough(container, options) {
|
|
|
19412
20475
|
setFull(false);
|
|
19413
20476
|
return go(next);
|
|
19414
20477
|
}
|
|
20478
|
+
if ((key === "Home" || key === "End") && views.length) {
|
|
20479
|
+
claim();
|
|
20480
|
+
if (full)
|
|
20481
|
+
setFull(false);
|
|
20482
|
+
return go(views[key === "Home" ? 0 : views.length - 1].step.key);
|
|
20483
|
+
}
|
|
19415
20484
|
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
19416
20485
|
const d = (key === "ArrowLeft" ? -1 : 1) * (e.shiftKey ? 2 : 0.5);
|
|
19417
20486
|
if (seekBy(d))
|
|
19418
20487
|
claim();
|
|
19419
20488
|
return;
|
|
19420
20489
|
}
|
|
19421
|
-
if (key === "n") {
|
|
20490
|
+
if (key === "n" && noteMode !== "hidden") {
|
|
19422
20491
|
claim();
|
|
19423
|
-
bar.
|
|
20492
|
+
bar.setOpen(true, true);
|
|
19424
20493
|
return;
|
|
19425
20494
|
}
|
|
19426
20495
|
const v = viewOf(current);
|
|
@@ -19499,6 +20568,12 @@ function walkthrough(container, options) {
|
|
|
19499
20568
|
win.removeEventListener(type, stopScroll);
|
|
19500
20569
|
doc.removeEventListener("keydown", onKey);
|
|
19501
20570
|
unregisterHints();
|
|
20571
|
+
bar.unobserve();
|
|
20572
|
+
pill?.dispose();
|
|
20573
|
+
for (const d of discs)
|
|
20574
|
+
d.dispose();
|
|
20575
|
+
if (padded)
|
|
20576
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
19502
20577
|
for (const v of views) {
|
|
19503
20578
|
v.slots.forEach((s) => s.dispose());
|
|
19504
20579
|
v.taste?.dispose();
|