@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-solid.js
CHANGED
|
@@ -570,12 +570,20 @@ var compareCss = `
|
|
|
570
570
|
display:flex;flex-direction:column;gap:6px;width:100%;height:100%;min-height:160px;outline:none;user-select:none;-webkit-user-select:none;
|
|
571
571
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
572
572
|
:where(.knobs-ui) :is(.knobs-cmp-mode,.knobs-cmp-toggle){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;background:transparent;border:0;margin:0;padding:0;outline:none;box-shadow:none}
|
|
573
|
-
.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
.knobs-
|
|
578
|
-
.knobs-ui .knobs-cmp-mode
|
|
573
|
+
.knobs-cmp-bar{flex:none;display:flex;align-items:center;gap:var(--_k-gap);height:var(--_k-control-h)}
|
|
574
|
+
/* The modes: one fill, the selection pill on the one picked; a mode isn't brighter for being
|
|
575
|
+
picked: the pill's bright copy is. */
|
|
576
|
+
.knobs-cmp-modes{position:relative;display:inline-flex;height:var(--_k-control-h);border-radius:var(--_k-radius);background:var(--_k-fill)}
|
|
577
|
+
.knobs-cmp-modes[hidden]{display:none}
|
|
578
|
+
.knobs-ui .knobs-cmp-mode{display:inline-flex;align-items:center;height:100%;padding:0 8px;border-radius:var(--_k-radius);color:var(--_k-fg-2);cursor:pointer;white-space:nowrap;
|
|
579
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
580
|
+
.knobs-ui .knobs-cmp-mode:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
581
|
+
/* Toggles: icon buttons, the accent's wash when on. */
|
|
582
|
+
.knobs-ui .knobs-cmp-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--_k-control-h);height:var(--_k-control-h);border-radius:var(--_k-radius);color:var(--_k-fg-3);cursor:pointer;
|
|
583
|
+
transition:color calc(var(--_k-hover-out) * 1ms),background calc(var(--_k-hover-out) * 1ms)}
|
|
584
|
+
.knobs-ui .knobs-cmp-toggle:is(:hover,:focus-visible){color:var(--_k-fg);background:var(--_ku-wash)}
|
|
585
|
+
.knobs-ui .knobs-cmp-toggle[aria-pressed="true"]{color:var(--_k-accent-fg);background:var(--_k-accent-soft)}
|
|
586
|
+
.knobs-cmp-toggle svg{display:block}
|
|
579
587
|
.knobs-cmp-fill{flex:1}
|
|
580
588
|
.knobs-cmp-toggle[hidden]{display:none}
|
|
581
589
|
/* One surface: on a card (a walkthrough's step, a split's pane, anything .knobs-surface) or marked
|
|
@@ -590,7 +598,8 @@ var compareCss = `
|
|
|
590
598
|
/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */
|
|
591
599
|
.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}
|
|
592
600
|
.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}
|
|
593
|
-
.
|
|
601
|
+
/* Wiping, the grip stands in for the cursor. */
|
|
602
|
+
.knobs-compare[data-dragging],.knobs-compare[data-dragging] *{cursor:none!important}
|
|
594
603
|
.knobs-cmp-sizer{position:absolute;left:0;right:0;top:0;height:0;visibility:hidden;pointer-events:none}
|
|
595
604
|
.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}
|
|
596
605
|
.knobs-cmp-media{position:absolute;left:0;top:0;display:block;max-width:none;margin:0;padding:0;border:0;object-fit:fill;transform-origin:0 0;pointer-events:none;will-change:transform}
|
|
@@ -598,18 +607,26 @@ var compareCss = `
|
|
|
598
607
|
/* Glass: what's behind shows through, blurred, on the knobs tokens. */
|
|
599
608
|
.knobs-cmp-label,.knobs-cmp-zoom{background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);
|
|
600
609
|
box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim),0 2px 10px rgba(0,0,0,calc(.18 * var(--_k-shadow-k,1)))}
|
|
601
|
-
|
|
602
|
-
.knobs-cmp-label
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
610
|
+
/* ✗ Before · ✓ After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */
|
|
611
|
+
.knobs-cmp-label{position:absolute;left:0;top:0;display:flex;align-items:center;gap:4px;padding:1px 7px 1px 5px;border-radius:999px;font-size:var(--_k-text-meta);line-height:16px;font-weight:var(--_k-weight-label);
|
|
612
|
+
white-space:nowrap;pointer-events:none;will-change:transform}
|
|
613
|
+
.knobs-cmp-label[data-side="before"]{color:var(--_k-fg-3)}
|
|
614
|
+
.knobs-cmp-label[data-side="after"]{color:var(--_k-fg)}
|
|
615
|
+
.knobs-cmp-mark svg{display:block;width:12px;height:12px}
|
|
616
|
+
/* The wipe: a hairline down the line with a raised grip at the pointer's height; a wider strip
|
|
617
|
+
takes the hand and the keys (a slider). It fades with the mode; wiping, line and grip brighten. */
|
|
606
618
|
.knobs-cmp-handle{cursor:ew-resize;position:absolute;left:-12px;top:0;width:24px;height:0;opacity:0;pointer-events:none;outline:none;will-change:transform;transition:opacity .18s cubic-bezier(.4,0,1,1)}
|
|
607
619
|
.knobs-cmp-handle[data-on]{opacity:1;pointer-events:auto;transition:opacity .22s cubic-bezier(.2,.8,.2,1)}
|
|
608
|
-
.knobs-cmp-handle::before{content:"";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:var(--_ku-cmp-line);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}
|
|
609
|
-
.knobs-cmp-handle::
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
.knobs-cmp-
|
|
620
|
+
.knobs-cmp-handle::before{content:"";position:absolute;top:0;bottom:0;left:11.5px;width:1px;background:color-mix(in srgb,var(--_ku-cmp-line) 72%,transparent);box-shadow:0 0 0 .5px rgba(0,0,0,.28),0 0 6px rgba(0,0,0,.25)}
|
|
621
|
+
.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}
|
|
622
|
+
.knobs-cmp-grip{position:absolute;top:0;left:4px;width:16px;height:28px;border-radius:min(8px,calc(var(--_k-radius) * 999));background:var(--_k-bg-overlay);
|
|
623
|
+
box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border),inset 0 1px 0 var(--_k-rim);will-change:transform;transition:box-shadow calc(var(--_k-hover-out) * 1ms)}
|
|
624
|
+
.knobs-cmp-grip::before,.knobs-cmp-grip::after{content:"";position:absolute;top:10px;width:1px;height:8px;background:var(--_k-fg-3);transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
625
|
+
.knobs-cmp-grip::before{left:6px}
|
|
626
|
+
.knobs-cmp-grip::after{left:9px}
|
|
627
|
+
.knobs-compare[data-dragging] .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),inset 0 0 0 1px var(--_k-border-strong),inset 0 1px 0 var(--_k-rim)}
|
|
628
|
+
.knobs-compare[data-dragging] .knobs-cmp-grip::before,.knobs-compare[data-dragging] .knobs-cmp-grip::after{background:var(--_k-fg)}
|
|
629
|
+
.knobs-cmp-handle:focus-visible .knobs-cmp-grip,.knobs-compare[data-keyboard] .knobs-cmp-handle:focus .knobs-cmp-grip{box-shadow:var(--_k-shadow-overlay),0 0 0 2px var(--_k-accent)}
|
|
613
630
|
/* The split's hairline, down the middle side by side. */
|
|
614
631
|
.knobs-cmp-split{position:absolute;left:0;top:0;width:1px;height:0;margin-left:-.5px;background:color-mix(in srgb,var(--_k-bg) 72%,transparent);pointer-events:none;will-change:transform,opacity}
|
|
615
632
|
/* Zoomed: how far, and a way back, in the stage's corner; it fades in and out, nothing shifts. */
|
|
@@ -618,12 +635,12 @@ var compareCss = `
|
|
|
618
635
|
opacity:0;scale:.96;pointer-events:none;transition:opacity .16s cubic-bezier(.4,0,1,1),scale .16s cubic-bezier(.4,0,1,1)}
|
|
619
636
|
.knobs-cmp-zoom[data-on]{opacity:1;scale:1;pointer-events:auto;transition:opacity .2s cubic-bezier(.2,.8,.2,1),scale .2s cubic-bezier(.2,.8,.2,1)}
|
|
620
637
|
:where(.knobs-ui) .knobs-cmp-zoom-reset{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;
|
|
621
|
-
height:20px;padding:0
|
|
638
|
+
display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border-radius:999px;background:transparent;color:var(--_k-fg-2);cursor:pointer;transition:color .15s,background .15s}
|
|
622
639
|
:where(.knobs-ui) .knobs-cmp-zoom-reset:is(:hover,:focus-visible){color:var(--_k-fg);background:color-mix(in srgb,var(--_k-fg) 12%,transparent)}
|
|
623
640
|
.knobs-cmp-note{position:absolute;left:50%;top:50%;translate:-50% -50%;color:var(--_k-fg-3);font-size:var(--_k-text-meta);pointer-events:none}
|
|
624
641
|
.knobs-cmp-note:empty{display:none}
|
|
625
642
|
.knobs-cmp-strip-host{flex:none;height:60px;min-height:0}
|
|
626
|
-
.knobs-cmp-timeline-host{flex:none;
|
|
643
|
+
.knobs-cmp-timeline-host{flex:none;min-height:0}
|
|
627
644
|
/* The frame strip: Before over After per column, a difference bar under them, a dot where it peaks. */
|
|
628
645
|
.knobs-ui.knobs-cmp-strip{--_ku-cmp-diff:var(--k-compare-diff,var(--_k-ok));position:relative;width:100%;height:100%;min-height:40px;overflow:hidden;cursor:col-resize;touch-action:none;
|
|
629
646
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg)}
|
|
@@ -766,7 +783,7 @@ var init_picker_css = __esm(() => {
|
|
|
766
783
|
.knobs-picker-suggested{flex:none;color:var(--_k-fg-3);font-size:var(--_k-text-meta)}
|
|
767
784
|
.knobs-picker-check{flex:none;display:flex;width:14px;height:14px;color:var(--_k-accent);opacity:0;scale:.6;filter:blur(2px);
|
|
768
785
|
transition:opacity .11s ease-in,scale .11s ease-in,filter .11s ease-in}
|
|
769
|
-
.knobs-picker-check svg{display:block;width:
|
|
786
|
+
.knobs-picker-check svg{display:block;width:12px;height:12px}
|
|
770
787
|
.knobs-picker-option[data-chosen] .knobs-picker-check{opacity:1;scale:1;filter:none;transition:opacity .15s ease-out,scale var(--kp-snappy-ms) var(--kp-snappy),filter .15s ease-out}
|
|
771
788
|
.knobs-picker-body{position:relative;overflow:visible}
|
|
772
789
|
.knobs-picker-body[data-moving]{overflow:hidden}
|
|
@@ -870,6 +887,15 @@ var readoutCss = `
|
|
|
870
887
|
@media(prefers-reduced-motion:reduce){.knobs-rd :where(*){transition:none!important}}
|
|
871
888
|
`;
|
|
872
889
|
|
|
890
|
+
// src/ui/selection-pill-css.ts
|
|
891
|
+
var selectionPillCss = `
|
|
892
|
+
.knobs-pick-pill,.knobs-pick-copy{position:absolute;left:0;top:0;width:0;height:0;pointer-events:none;transition:opacity .1s linear}
|
|
893
|
+
.knobs-pick-pill{background:var(--_k-fill-selected);will-change:transform}
|
|
894
|
+
.knobs-pick-copy{overflow:hidden;will-change:transform}
|
|
895
|
+
.knobs-pick-copy-rows{position:absolute;left:0;top:0;width:0;height:0}
|
|
896
|
+
:is(.knobs-pick-pill,.knobs-pick-copy)[data-off]{opacity:0}
|
|
897
|
+
`;
|
|
898
|
+
|
|
873
899
|
// src/tokens/color.ts
|
|
874
900
|
function linearToOklch([r, g, b, a]) {
|
|
875
901
|
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
@@ -1310,6 +1336,22 @@ var init_schema = __esm(() => {
|
|
|
1310
1336
|
source: css("var(--k-warn)"),
|
|
1311
1337
|
doc: "Modified lines."
|
|
1312
1338
|
},
|
|
1339
|
+
{
|
|
1340
|
+
name: "before",
|
|
1341
|
+
tier: "semantic",
|
|
1342
|
+
type: "color",
|
|
1343
|
+
group: "Data",
|
|
1344
|
+
source: css("var(--k-fg-3)"),
|
|
1345
|
+
doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
name: "after",
|
|
1349
|
+
tier: "semantic",
|
|
1350
|
+
type: "color",
|
|
1351
|
+
group: "Data",
|
|
1352
|
+
source: css("var(--k-fg)"),
|
|
1353
|
+
doc: "After in a comparison, and only After."
|
|
1354
|
+
},
|
|
1313
1355
|
{
|
|
1314
1356
|
name: "series-1",
|
|
1315
1357
|
tier: "semantic",
|
|
@@ -1400,6 +1442,150 @@ var init_schema = __esm(() => {
|
|
|
1400
1442
|
source: value("288px"),
|
|
1401
1443
|
doc: "Panel width."
|
|
1402
1444
|
},
|
|
1445
|
+
{
|
|
1446
|
+
name: "space-inside",
|
|
1447
|
+
tier: "semantic",
|
|
1448
|
+
type: "length",
|
|
1449
|
+
group: "Space",
|
|
1450
|
+
source: css("var(--k-unit)"),
|
|
1451
|
+
doc: "Parts of one thing: an icon and its label, a meta line and its title."
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
name: "space-sibling",
|
|
1455
|
+
tier: "semantic",
|
|
1456
|
+
type: "length",
|
|
1457
|
+
group: "Space",
|
|
1458
|
+
source: css("calc(var(--k-unit) * 2)"),
|
|
1459
|
+
doc: "Siblings in a group: buttons in a row, a list item's lines."
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
name: "space-title",
|
|
1463
|
+
tier: "semantic",
|
|
1464
|
+
type: "length",
|
|
1465
|
+
group: "Space",
|
|
1466
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1467
|
+
doc: "A heading and what it heads."
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
name: "space-group",
|
|
1471
|
+
tier: "semantic",
|
|
1472
|
+
type: "length",
|
|
1473
|
+
group: "Space",
|
|
1474
|
+
source: css("calc(var(--k-unit) * 12)"),
|
|
1475
|
+
doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
name: "space-section",
|
|
1479
|
+
tier: "semantic",
|
|
1480
|
+
type: "length",
|
|
1481
|
+
group: "Space",
|
|
1482
|
+
source: css("calc(var(--k-unit) * 24)"),
|
|
1483
|
+
doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
name: "space-column",
|
|
1487
|
+
tier: "semantic",
|
|
1488
|
+
type: "length",
|
|
1489
|
+
group: "Space",
|
|
1490
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1491
|
+
doc: "Columns: a contents rail and the page, media side by side."
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
name: "pad-page",
|
|
1495
|
+
tier: "semantic",
|
|
1496
|
+
type: "length",
|
|
1497
|
+
group: "Space",
|
|
1498
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1499
|
+
doc: "A page's edge; 16px under 640px wide."
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
name: "pad-card",
|
|
1503
|
+
tier: "semantic",
|
|
1504
|
+
type: "length",
|
|
1505
|
+
group: "Space",
|
|
1506
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1507
|
+
doc: "Inside a card or popover."
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
name: "type-heading",
|
|
1511
|
+
tier: "semantic",
|
|
1512
|
+
type: "length",
|
|
1513
|
+
group: "Type",
|
|
1514
|
+
source: value("20px"),
|
|
1515
|
+
doc: "Section headings (a PR's title, under its kicker), weight 500."
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
name: "leading-heading",
|
|
1519
|
+
tier: "semantic",
|
|
1520
|
+
type: "length",
|
|
1521
|
+
group: "Type",
|
|
1522
|
+
source: value("28px"),
|
|
1523
|
+
doc: "Line height for type-heading."
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
name: "type-title",
|
|
1527
|
+
tier: "semantic",
|
|
1528
|
+
type: "length",
|
|
1529
|
+
group: "Type",
|
|
1530
|
+
source: value("16px"),
|
|
1531
|
+
doc: "A page's title, weight 500."
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
name: "leading-title",
|
|
1535
|
+
tier: "semantic",
|
|
1536
|
+
type: "length",
|
|
1537
|
+
group: "Type",
|
|
1538
|
+
source: value("24px"),
|
|
1539
|
+
doc: "Line height for type-title."
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
name: "type-body",
|
|
1543
|
+
tier: "semantic",
|
|
1544
|
+
type: "length",
|
|
1545
|
+
group: "Type",
|
|
1546
|
+
source: value("13px"),
|
|
1547
|
+
doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
name: "leading-body",
|
|
1551
|
+
tier: "semantic",
|
|
1552
|
+
type: "length",
|
|
1553
|
+
group: "Type",
|
|
1554
|
+
source: value("20px"),
|
|
1555
|
+
doc: "Line height for type-body."
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
name: "type-label",
|
|
1559
|
+
tier: "semantic",
|
|
1560
|
+
type: "length",
|
|
1561
|
+
group: "Type",
|
|
1562
|
+
source: value("12px"),
|
|
1563
|
+
doc: "Labels over media, weight 500; mono inside body text."
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
name: "leading-label",
|
|
1567
|
+
tier: "semantic",
|
|
1568
|
+
type: "length",
|
|
1569
|
+
group: "Type",
|
|
1570
|
+
source: value("16px"),
|
|
1571
|
+
doc: "Line height for type-label."
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
name: "type-small",
|
|
1575
|
+
tier: "semantic",
|
|
1576
|
+
type: "length",
|
|
1577
|
+
group: "Type",
|
|
1578
|
+
source: value("11px"),
|
|
1579
|
+
doc: "Meta, controls, keys, timestamps; mono inside labels."
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
name: "leading-small",
|
|
1583
|
+
tier: "semantic",
|
|
1584
|
+
type: "length",
|
|
1585
|
+
group: "Type",
|
|
1586
|
+
source: value("16px"),
|
|
1587
|
+
doc: "Line height for type-small."
|
|
1588
|
+
},
|
|
1403
1589
|
{
|
|
1404
1590
|
name: "font-size",
|
|
1405
1591
|
tier: "semantic",
|
|
@@ -2364,16 +2550,18 @@ function injectTokens(doc) {
|
|
|
2364
2550
|
style.textContent = rootCss;
|
|
2365
2551
|
doc.head.append(style);
|
|
2366
2552
|
}
|
|
2367
|
-
var ROOT_CLASS = "knobs-root", extras, spring, rootCss;
|
|
2553
|
+
var ROOT_CLASS = "knobs-root", extras, narrow, spring, rootCss;
|
|
2368
2554
|
var init_root = __esm(() => {
|
|
2369
2555
|
init_knobs();
|
|
2370
2556
|
init_css();
|
|
2371
2557
|
init_glide();
|
|
2372
2558
|
init_motion();
|
|
2373
2559
|
extras = `:where(.${ROOT_CLASS}){--_k-shadow-k:calc(var(--k-shadow-strength,calc(.48 - .32 * var(--_k-light,0))) / .48);--_k-glass-tone:var(--k-glass-tone,calc(.5 + .58 * var(--_k-light,0)));--_k-fill-base:var(--k-fill-base,var(--_k-fill-selected));--_k-fill-hover-mix:var(--k-fill-hover-mix,var(--k-fill-rest-mix,20%));--_k-reveal-ease:var(--k-ease,cubic-bezier(.2,.8,.2,1))}`;
|
|
2560
|
+
narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`;
|
|
2374
2561
|
spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`;
|
|
2375
2562
|
rootCss = `${tokensCss(knobs)}
|
|
2376
2563
|
${extras}
|
|
2564
|
+
${narrow}
|
|
2377
2565
|
${spring}
|
|
2378
2566
|
${DRIVERS}
|
|
2379
2567
|
${motionCss}`;
|
|
@@ -2584,6 +2772,12 @@ var css2 = `
|
|
|
2584
2772
|
--_ku-pane-bg and --_ku-pane-ring so this reaches them. */
|
|
2585
2773
|
: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;
|
|
2586
2774
|
--_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
|
|
2775
|
+
/* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
|
|
2776
|
+
ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
|
|
2777
|
+
card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
|
|
2778
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
|
|
2779
|
+
: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)}
|
|
2780
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
|
|
2587
2781
|
/* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
|
|
2588
2782
|
.knobs-ui{box-sizing:border-box}
|
|
2589
2783
|
: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}
|
|
@@ -2718,11 +2912,9 @@ var css2 = `
|
|
|
2718
2912
|
.knobs-tree:focus .knobs-tree-row[data-active][aria-selected="true"]::before{background:var(--_ku-select-focus)}
|
|
2719
2913
|
.knobs-tree-row[data-drop="into"]::before{opacity:1;background:color-mix(in srgb,var(--_k-accent) 30%,transparent)}
|
|
2720
2914
|
.knobs-tree-row[data-dragged]{opacity:.38}
|
|
2721
|
-
/* glide:
|
|
2722
|
-
.knobs-tree-
|
|
2723
|
-
|
|
2724
|
-
.knobs-tree-cursor[data-on]{opacity:1}
|
|
2725
|
-
.knobs-tree:focus .knobs-tree-cursor{background:var(--_ku-select-focus)}
|
|
2915
|
+
/* glide: the selection pill on the selected row, in the selection's colour (the row's own stays off). */
|
|
2916
|
+
.knobs-tree>.knobs-pick-pill{background:var(--_ku-select)}
|
|
2917
|
+
.knobs-tree:focus>.knobs-pick-pill{background:var(--_ku-select-focus)}
|
|
2726
2918
|
.knobs-tree[data-glide] .knobs-tree-row[aria-selected="true"]::before{opacity:0!important}
|
|
2727
2919
|
.knobs-tree-row>*{position:relative}
|
|
2728
2920
|
.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)}
|
|
@@ -2754,22 +2946,20 @@ var css2 = `
|
|
|
2754
2946
|
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)}
|
|
2755
2947
|
.knobs-tree-empty{padding:10px var(--_k-inset);color:var(--_k-fg-3)}
|
|
2756
2948
|
|
|
2757
|
-
/* Timeline:
|
|
2758
|
-
|
|
2949
|
+
/* Timeline: play beside a track: the ruler's canvas over a lane of markers, ranges as soft bands,
|
|
2950
|
+
and the playhead, a hairline in the accent with a cap. No clock: the time shows under the
|
|
2951
|
+
pointer on the track (the tag), in seconds, while hovering or scrubbing. */
|
|
2759
2952
|
:where(.knobs-timeline,.knobs-timeline *){box-sizing:border-box}
|
|
2760
2953
|
.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;
|
|
2761
2954
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
2762
2955
|
: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}
|
|
2763
|
-
.knobs-tl-transport{flex:none;display:flex;align-items:center
|
|
2956
|
+
.knobs-tl-transport{flex:none;display:flex;align-items:center}
|
|
2764
2957
|
.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);
|
|
2765
2958
|
background:var(--_k-fill-selected);color:var(--_k-fg);cursor:pointer;transition:background .15s,transform .15s var(--_ku-ease)}
|
|
2766
2959
|
.knobs-ui .knobs-tl-play:hover{background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
2767
2960
|
.knobs-ui .knobs-tl-play:active{transform:scale(.94)}
|
|
2768
2961
|
.knobs-tl-play svg{width:12px;height:12px}
|
|
2769
2962
|
.knobs-timeline[data-playing] .knobs-tl-play{background:var(--_k-accent);color:var(--_k-bg)}
|
|
2770
|
-
.knobs-tl-time{display:flex;flex-direction:column;line-height:1.2;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
2771
|
-
.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}
|
|
2772
|
-
.knobs-tl-sub{font-size:var(--_k-text-meta);color:var(--_k-fg-3);white-space:nowrap}
|
|
2773
2963
|
.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;
|
|
2774
2964
|
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
2775
2965
|
.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)}
|
|
@@ -2793,7 +2983,8 @@ var css2 = `
|
|
|
2793
2983
|
.knobs-tl-pin{position:absolute;top:13px;left:-5px;width:10px;height:10px;pointer-events:auto;cursor:grab}
|
|
2794
2984
|
.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)}
|
|
2795
2985
|
.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);
|
|
2796
|
-
font-size:var(--_k-text-meta);line-height:17px;white-space:nowrap;
|
|
2986
|
+
font-size:var(--_k-text-meta);line-height:17px;white-space:nowrap;pointer-events:auto;cursor:grab;transition:background .15s,color .15s}
|
|
2987
|
+
.knobs-tl-mtext{display:block;overflow:hidden;white-space:nowrap}
|
|
2797
2988
|
.knobs-tl-marker[data-selected]{--knobs-tl-c:var(--_k-accent)}
|
|
2798
2989
|
.knobs-tl-marker[data-selected] .knobs-tl-mlabel{background:color-mix(in srgb,var(--_k-accent) 24%,var(--_k-fill-selected))}
|
|
2799
2990
|
.knobs-tl-marker[data-selected] .knobs-tl-pin::after{scale:1.2}
|
|
@@ -2814,7 +3005,22 @@ var css2 = `
|
|
|
2814
3005
|
.knobs-timeline[data-scrubbing] .knobs-tl-hover{opacity:0}
|
|
2815
3006
|
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
2816
3007
|
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
2817
|
-
|
|
3008
|
+
.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}
|
|
3009
|
+
.knobs-tl-tag[data-on]{opacity:1}
|
|
3010
|
+
/* The lane (variant: "lane"): one slim track of ticks under a compare or a video; markers are
|
|
3011
|
+
faint chapter ticks, the current one in text colour; nothing to edit. */
|
|
3012
|
+
.knobs-ui.knobs-timeline[data-variant="lane"]{height:auto;min-height:0;padding:0;gap:var(--_k-gap)}
|
|
3013
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-track{height:var(--_k-control-h)}
|
|
3014
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-ruler{height:100%}
|
|
3015
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-lane{top:0}
|
|
3016
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker{top:0}
|
|
3017
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker::before{top:0;bottom:50%;left:-.75px;width:1.5px;background:var(--_k-fg-3)}
|
|
3018
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-marker[data-current]::before{background:var(--_k-fg)}
|
|
3019
|
+
.knobs-timeline[data-variant="lane"] :is(.knobs-tl-pin,.knobs-tl-mlabel,.knobs-tl-rlabel){display:none}
|
|
3020
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-head::before{top:0}
|
|
3021
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-head::after{content:none}
|
|
3022
|
+
.knobs-timeline[data-variant="lane"] .knobs-tl-tag{top:2px;bottom:auto}
|
|
3023
|
+
`, uiCss = () => aliased(css2 + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + compareCss + selectionPillCss) + rolling_css_default, lookDefaults, tune = (s, m) => {
|
|
2818
3024
|
s.omega = m.omega;
|
|
2819
3025
|
s.zeta = m.zeta;
|
|
2820
3026
|
return s;
|
|
@@ -2972,33 +3178,29 @@ var init_diff_css = __esm(() => {
|
|
|
2972
3178
|
.knobs-diff-fill{flex:1}
|
|
2973
3179
|
.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}
|
|
2974
3180
|
.knobs-diff-nav>span{min-width:3.6em;text-align:center}
|
|
2975
|
-
:where(.knobs-ui) :is(.knobs-diff-btn,.knobs-diff-
|
|
3181
|
+
: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;
|
|
2976
3182
|
margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
2977
|
-
.knobs-ui .knobs-diff-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;width:
|
|
3183
|
+
.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;
|
|
2978
3184
|
transition:background .15s,color .15s,opacity .15s}
|
|
2979
3185
|
.knobs-ui .knobs-diff-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
2980
3186
|
.knobs-ui .knobs-diff-btn[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
2981
3187
|
.knobs-ui .knobs-diff-btn:disabled{opacity:.35;cursor:default;background:transparent}
|
|
2982
|
-
.knobs-diff-btn svg{width:
|
|
3188
|
+
.knobs-diff-btn svg{width:16px;height:16px}
|
|
2983
3189
|
/* Viewed: a check with its word, as on GitHub; the path dims once it's ticked. */
|
|
2984
3190
|
.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);
|
|
2985
3191
|
font-size:var(--_k-text-meta);font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:background .15s,color .15s}
|
|
2986
3192
|
.knobs-ui .knobs-diff-viewed:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
2987
3193
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
2988
|
-
.knobs-diff-viewed svg{width:
|
|
3194
|
+
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
2989
3195
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
2990
3196
|
.knobs-diff-path{transition:opacity .2s}
|
|
2991
3197
|
.knobs-diff[data-viewed]>.knobs-diff-head .knobs-diff-path,.knobs-diff-part[data-viewed] .knobs-diff-path{opacity:.6}
|
|
2992
|
-
/* Split | Unified:
|
|
2993
|
-
|
|
2994
|
-
.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-
|
|
2995
|
-
.knobs-ui .knobs-diff-
|
|
2996
|
-
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:color
|
|
2997
|
-
.knobs-ui .knobs-diff-
|
|
2998
|
-
.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));
|
|
2999
|
-
box-shadow:0 1px 2px rgba(0,0,0,calc(.16 * var(--k-lift,1)));transition:transform var(--_ku-ease-ms) var(--_ku-ease)}
|
|
3000
|
-
.knobs-diff-seg[data-value="unified"]>.knobs-diff-pill{transform:translateX(100%)}
|
|
3001
|
-
.knobs-diff[data-frame="flat"] .knobs-diff-pill{box-shadow:none}
|
|
3198
|
+
/* Split | Unified: the selection pill on the one picked, its bright copy the picked one's text; a
|
|
3199
|
+
choice isn't brighter for being picked. Choices are styled by class, as the copy holds them too. */
|
|
3200
|
+
.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)}
|
|
3201
|
+
.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);
|
|
3202
|
+
font-weight:var(--_k-weight-label);white-space:nowrap;cursor:pointer;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
3203
|
+
.knobs-ui .knobs-diff-choice:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
3002
3204
|
/* The diff: one layer per file or layout on show, the old fading under the new. */
|
|
3003
3205
|
.knobs-diff-body{position:relative;flex:1;min-height:0}
|
|
3004
3206
|
.knobs-diff-probe{position:absolute;left:0;top:0;width:0;height:var(--kd-line);visibility:hidden;pointer-events:none}
|
|
@@ -3093,7 +3295,7 @@ var init_diff_css = __esm(() => {
|
|
|
3093
3295
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
3094
3296
|
.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}
|
|
3095
3297
|
.knobs-ui .knobs-diff-filter>button:hover{background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
3096
|
-
.knobs-diff-filter>button svg{width:
|
|
3298
|
+
.knobs-diff-filter>button svg{width:12px;height:12px}
|
|
3097
3299
|
.knobs-diff-list{position:relative;flex:1;min-height:0}
|
|
3098
3300
|
.knobs-diff-files .knobs-diff-counts{font-size:var(--_k-text-meta);align-items:center}
|
|
3099
3301
|
.knobs-diff-files .knobs-diff-counts{gap:5px}
|
|
@@ -3860,6 +4062,283 @@ var init_rgba = __esm(() => {
|
|
|
3860
4062
|
cache = new Map;
|
|
3861
4063
|
});
|
|
3862
4064
|
|
|
4065
|
+
// src/ui/icons.ts
|
|
4066
|
+
function icon(name, options = {}) {
|
|
4067
|
+
const size = options.small ? 12 : 16;
|
|
4068
|
+
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>`;
|
|
4069
|
+
}
|
|
4070
|
+
var PATHS, ICON_NAMES;
|
|
4071
|
+
var init_icons = __esm(() => {
|
|
4072
|
+
PATHS = {
|
|
4073
|
+
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",
|
|
4074
|
+
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",
|
|
4075
|
+
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",
|
|
4076
|
+
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",
|
|
4077
|
+
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",
|
|
4078
|
+
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",
|
|
4079
|
+
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",
|
|
4080
|
+
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",
|
|
4081
|
+
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",
|
|
4082
|
+
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",
|
|
4083
|
+
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",
|
|
4084
|
+
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",
|
|
4085
|
+
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",
|
|
4086
|
+
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",
|
|
4087
|
+
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",
|
|
4088
|
+
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",
|
|
4089
|
+
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",
|
|
4090
|
+
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",
|
|
4091
|
+
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",
|
|
4092
|
+
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",
|
|
4093
|
+
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",
|
|
4094
|
+
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",
|
|
4095
|
+
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",
|
|
4096
|
+
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",
|
|
4097
|
+
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",
|
|
4098
|
+
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",
|
|
4099
|
+
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"
|
|
4100
|
+
};
|
|
4101
|
+
ICON_NAMES = Object.keys(PATHS);
|
|
4102
|
+
});
|
|
4103
|
+
|
|
4104
|
+
// src/ui/selection-pill.ts
|
|
4105
|
+
function pillSpring(distance, base = SPRINGS.default) {
|
|
4106
|
+
return distance > 400 ? { duration: base.duration * 1.4, bounce: base.bounce } : base;
|
|
4107
|
+
}
|
|
4108
|
+
function pillBoxOf(row, container) {
|
|
4109
|
+
return {
|
|
4110
|
+
x: row.left - container.left - container.clientLeft + container.scrollLeft,
|
|
4111
|
+
y: row.top - container.top - container.clientTop + container.scrollTop,
|
|
4112
|
+
w: row.width,
|
|
4113
|
+
h: row.height
|
|
4114
|
+
};
|
|
4115
|
+
}
|
|
4116
|
+
function pillRadius(from, to, h, k) {
|
|
4117
|
+
const t = Math.abs(to.h - from.h) > 0.5 ? (h - from.h) / (to.h - from.h) : Number.isFinite(k) ? k : 1;
|
|
4118
|
+
return from.r + (to.r - from.r) * Math.min(1, Math.max(0, t));
|
|
4119
|
+
}
|
|
4120
|
+
function pillProgress(from, to, at) {
|
|
4121
|
+
const d = Math.hypot(to.x - from.x, to.y - from.y);
|
|
4122
|
+
if (d < 0.5)
|
|
4123
|
+
return 1;
|
|
4124
|
+
const p = ((at.x - from.x) * (to.x - from.x) + (at.y - from.y) * (to.y - from.y)) / (d * d);
|
|
4125
|
+
return Math.min(1, Math.max(0, p));
|
|
4126
|
+
}
|
|
4127
|
+
function planPill(state, next, flags = {}) {
|
|
4128
|
+
if (!next)
|
|
4129
|
+
return { kind: "hide" };
|
|
4130
|
+
if (!state.shown || !state.at || flags.first || flags.reduced || flags.snap)
|
|
4131
|
+
return { kind: "land", box: next };
|
|
4132
|
+
const t = state.target;
|
|
4133
|
+
if (t && t.x === next.x && t.y === next.y && t.w === next.w && t.h === next.h)
|
|
4134
|
+
return { kind: "stay" };
|
|
4135
|
+
const d = Math.hypot(next.x - state.at.x, next.y - state.at.y);
|
|
4136
|
+
return { kind: "travel", box: next, spring: pillSpring(d) };
|
|
4137
|
+
}
|
|
4138
|
+
function selectionPill(container, options) {
|
|
4139
|
+
const doc = container.ownerDocument;
|
|
4140
|
+
const win = doc.defaultView;
|
|
4141
|
+
injectUiStyles(doc);
|
|
4142
|
+
if (win.getComputedStyle(container).position === "static")
|
|
4143
|
+
container.style.position = "relative";
|
|
4144
|
+
const pill = doc.createElement("i");
|
|
4145
|
+
pill.className = "knobs-pick-pill";
|
|
4146
|
+
pill.setAttribute("aria-hidden", "true");
|
|
4147
|
+
pill.dataset.off = "";
|
|
4148
|
+
const copyOn = options.copy !== false;
|
|
4149
|
+
const copy = doc.createElement("div");
|
|
4150
|
+
copy.className = "knobs-pick-copy";
|
|
4151
|
+
copy.setAttribute("aria-hidden", "true");
|
|
4152
|
+
copy.inert = true;
|
|
4153
|
+
copy.dataset.off = "";
|
|
4154
|
+
const copyRows = doc.createElement("div");
|
|
4155
|
+
copyRows.className = "knobs-pick-copy-rows";
|
|
4156
|
+
copy.append(copyRows);
|
|
4157
|
+
container.prepend(pill);
|
|
4158
|
+
if (copyOn)
|
|
4159
|
+
container.append(copy);
|
|
4160
|
+
const { omega, zeta } = springMotion(SPRINGS.default);
|
|
4161
|
+
const springs = [0, 0, 0, 0].map(() => new Spring(0, omega, zeta, 0.01));
|
|
4162
|
+
const [sx, sy, sw, sh] = springs;
|
|
4163
|
+
let shown = false;
|
|
4164
|
+
let first = true;
|
|
4165
|
+
let target = null;
|
|
4166
|
+
let from = { x: 0, y: 0, w: 0, h: 0 };
|
|
4167
|
+
let fromR = 0;
|
|
4168
|
+
let toR = 0;
|
|
4169
|
+
let rowBoxes = [];
|
|
4170
|
+
const clones = new Map;
|
|
4171
|
+
let disposed = false;
|
|
4172
|
+
const radiusOf = (row) => options.radius?.(row) ?? (Number.parseFloat(win.getComputedStyle(row).borderTopLeftRadius) || 0);
|
|
4173
|
+
const rowsNow = () => options.rows ? [...options.rows()] : [...container.children].filter((n) => n !== pill && n !== copy);
|
|
4174
|
+
const measure = (row) => {
|
|
4175
|
+
const c = container.getBoundingClientRect();
|
|
4176
|
+
const r = row.getBoundingClientRect();
|
|
4177
|
+
return pillBoxOf(r, {
|
|
4178
|
+
left: c.left,
|
|
4179
|
+
top: c.top,
|
|
4180
|
+
scrollLeft: container.scrollLeft,
|
|
4181
|
+
scrollTop: container.scrollTop,
|
|
4182
|
+
clientLeft: container.clientLeft,
|
|
4183
|
+
clientTop: container.clientTop
|
|
4184
|
+
});
|
|
4185
|
+
};
|
|
4186
|
+
const at = () => ({ x: sx.x, y: sy.x, w: sw.x, h: sh.x });
|
|
4187
|
+
const syncCopy = (span) => {
|
|
4188
|
+
if (!copyOn)
|
|
4189
|
+
return;
|
|
4190
|
+
const keep = new Set;
|
|
4191
|
+
for (const { row, box } of rowBoxes) {
|
|
4192
|
+
if (!boxesMeet(box, span))
|
|
4193
|
+
continue;
|
|
4194
|
+
keep.add(row);
|
|
4195
|
+
let n = clones.get(row);
|
|
4196
|
+
if (!n) {
|
|
4197
|
+
n = row.cloneNode(true);
|
|
4198
|
+
n.removeAttribute("id");
|
|
4199
|
+
for (const d of n.querySelectorAll("[id]"))
|
|
4200
|
+
d.removeAttribute("id");
|
|
4201
|
+
clones.set(row, n);
|
|
4202
|
+
copyRows.append(n);
|
|
4203
|
+
}
|
|
4204
|
+
const s = n.style;
|
|
4205
|
+
s.position = "absolute";
|
|
4206
|
+
s.inset = "auto";
|
|
4207
|
+
s.left = `${box.x}px`;
|
|
4208
|
+
s.top = `${box.y}px`;
|
|
4209
|
+
s.width = `${box.w}px`;
|
|
4210
|
+
s.height = `${box.h}px`;
|
|
4211
|
+
s.margin = "0";
|
|
4212
|
+
s.transform = "none";
|
|
4213
|
+
s.clipPath = "";
|
|
4214
|
+
s.opacity = "";
|
|
4215
|
+
s.boxSizing = "border-box";
|
|
4216
|
+
s.color = options.color ?? "var(--_k-fg)";
|
|
4217
|
+
}
|
|
4218
|
+
for (const [row, n] of clones)
|
|
4219
|
+
if (!keep.has(row)) {
|
|
4220
|
+
n.remove();
|
|
4221
|
+
clones.delete(row);
|
|
4222
|
+
}
|
|
4223
|
+
};
|
|
4224
|
+
const paint = () => {
|
|
4225
|
+
const b = at();
|
|
4226
|
+
const x0 = grid(b.x);
|
|
4227
|
+
const y0 = grid(b.y);
|
|
4228
|
+
const w = grid(b.x + b.w) - x0;
|
|
4229
|
+
const h = grid(b.y + b.h) - y0;
|
|
4230
|
+
const r = target ? pillRadius({ h: from.h, r: fromR }, { h: target.h, r: toR }, b.h, pillProgress(from, target, b)) : toR;
|
|
4231
|
+
const radius = `${Math.max(0, Math.min(r, h / 2, w / 2)).toFixed(2)}px`;
|
|
4232
|
+
for (const n of copyOn ? [pill, copy] : [pill]) {
|
|
4233
|
+
n.style.transform = `translate3d(${x0}px,${y0}px,0)`;
|
|
4234
|
+
n.style.width = `${w}px`;
|
|
4235
|
+
n.style.height = `${h}px`;
|
|
4236
|
+
n.style.borderRadius = radius;
|
|
4237
|
+
}
|
|
4238
|
+
if (copyOn)
|
|
4239
|
+
copyRows.style.transform = `translate3d(${-x0}px,${-y0}px,0)`;
|
|
4240
|
+
};
|
|
4241
|
+
const loop = frameLoop(win, (dt) => {
|
|
4242
|
+
for (const s of springs)
|
|
4243
|
+
s.step(dt);
|
|
4244
|
+
paint();
|
|
4245
|
+
return springs.some((s) => !s.resting);
|
|
4246
|
+
});
|
|
4247
|
+
const show = (on) => {
|
|
4248
|
+
shown = on;
|
|
4249
|
+
pill.toggleAttribute("data-off", !on);
|
|
4250
|
+
copy.toggleAttribute("data-off", !on);
|
|
4251
|
+
container.toggleAttribute("data-pick-empty", !on);
|
|
4252
|
+
};
|
|
4253
|
+
const update = (o) => {
|
|
4254
|
+
if (disposed)
|
|
4255
|
+
return;
|
|
4256
|
+
const row = options.selected();
|
|
4257
|
+
const next = row?.isConnected ? measure(row) : null;
|
|
4258
|
+
const plan = planPill({ shown, at: shown ? at() : null, target }, next, {
|
|
4259
|
+
first,
|
|
4260
|
+
reduced: reducedMotion(win),
|
|
4261
|
+
...o?.snap ? { snap: true } : {}
|
|
4262
|
+
});
|
|
4263
|
+
first = false;
|
|
4264
|
+
for (const n of clones.values())
|
|
4265
|
+
n.remove();
|
|
4266
|
+
clones.clear();
|
|
4267
|
+
rowBoxes = copyOn ? rowsNow().filter((r) => r.isConnected).map((r) => ({ row: r, box: measure(r) })) : [];
|
|
4268
|
+
if (plan.kind === "hide") {
|
|
4269
|
+
if (shown)
|
|
4270
|
+
show(false);
|
|
4271
|
+
return;
|
|
4272
|
+
}
|
|
4273
|
+
if (plan.kind === "stay") {
|
|
4274
|
+
syncCopy(boxUnion(at(), target));
|
|
4275
|
+
return;
|
|
4276
|
+
}
|
|
4277
|
+
const r = radiusOf(row);
|
|
4278
|
+
if (plan.kind === "land") {
|
|
4279
|
+
sx.snap(plan.box.x);
|
|
4280
|
+
sy.snap(plan.box.y);
|
|
4281
|
+
sw.snap(plan.box.w);
|
|
4282
|
+
sh.snap(plan.box.h);
|
|
4283
|
+
from = plan.box;
|
|
4284
|
+
fromR = r;
|
|
4285
|
+
toR = r;
|
|
4286
|
+
target = plan.box;
|
|
4287
|
+
syncCopy(plan.box);
|
|
4288
|
+
paint();
|
|
4289
|
+
loop.stop();
|
|
4290
|
+
if (!shown)
|
|
4291
|
+
show(true);
|
|
4292
|
+
return;
|
|
4293
|
+
}
|
|
4294
|
+
const m = springMotion(plan.spring);
|
|
4295
|
+
for (const s of springs) {
|
|
4296
|
+
s.omega = m.omega;
|
|
4297
|
+
s.zeta = m.zeta;
|
|
4298
|
+
}
|
|
4299
|
+
const now = at();
|
|
4300
|
+
fromR = target ? pillRadius({ h: from.h, r: fromR }, { h: target.h, r: toR }, now.h, pillProgress(from, target, now)) : r;
|
|
4301
|
+
from = now;
|
|
4302
|
+
toR = r;
|
|
4303
|
+
target = plan.box;
|
|
4304
|
+
sx.set(plan.box.x);
|
|
4305
|
+
sy.set(plan.box.y);
|
|
4306
|
+
sw.set(plan.box.w);
|
|
4307
|
+
sh.set(plan.box.h);
|
|
4308
|
+
syncCopy(boxUnion(now, plan.box));
|
|
4309
|
+
loop.wake();
|
|
4310
|
+
};
|
|
4311
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => update({ snap: true })) : null;
|
|
4312
|
+
ro?.observe(container);
|
|
4313
|
+
update();
|
|
4314
|
+
return {
|
|
4315
|
+
element: pill,
|
|
4316
|
+
update,
|
|
4317
|
+
dispose() {
|
|
4318
|
+
disposed = true;
|
|
4319
|
+
loop.stop();
|
|
4320
|
+
ro?.disconnect();
|
|
4321
|
+
pill.remove();
|
|
4322
|
+
copy.remove();
|
|
4323
|
+
container.removeAttribute("data-pick-empty");
|
|
4324
|
+
}
|
|
4325
|
+
};
|
|
4326
|
+
}
|
|
4327
|
+
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) => {
|
|
4328
|
+
const x = Math.min(a.x, b.x);
|
|
4329
|
+
const y = Math.min(a.y, b.y);
|
|
4330
|
+
return {
|
|
4331
|
+
x,
|
|
4332
|
+
y,
|
|
4333
|
+
w: Math.max(a.x + a.w, b.x + b.w) - x,
|
|
4334
|
+
h: Math.max(a.y + a.h, b.y + b.h) - y
|
|
4335
|
+
};
|
|
4336
|
+
}, grid = (v) => Math.round(v * 64) / 64;
|
|
4337
|
+
var init_selection_pill = __esm(() => {
|
|
4338
|
+
init_motion();
|
|
4339
|
+
init_look();
|
|
4340
|
+
});
|
|
4341
|
+
|
|
3863
4342
|
// src/panel/hints.ts
|
|
3864
4343
|
function extractWords(text) {
|
|
3865
4344
|
return text.toLowerCase().match(/[a-z]+/g) ?? [];
|
|
@@ -4688,34 +5167,27 @@ function tree(container, options) {
|
|
|
4688
5167
|
const empty = doc.createElement("div");
|
|
4689
5168
|
empty.className = "knobs-tree-empty";
|
|
4690
5169
|
empty.hidden = true;
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
5170
|
+
root.append(space, line, empty);
|
|
5171
|
+
let pill = null;
|
|
5172
|
+
let picked = null;
|
|
5173
|
+
let travelUntil = 0;
|
|
5174
|
+
const pickedRow = () => {
|
|
5175
|
+
const id = sel.ids.length === 1 ? sel.ids[0] : null;
|
|
5176
|
+
const v = id === null ? undefined : views.get(id);
|
|
5177
|
+
return v && !v.leaving && rowIndex.has(v.id) ? v : null;
|
|
4698
5178
|
};
|
|
4699
5179
|
const placeCursor = (animate) => {
|
|
4700
|
-
if (!
|
|
5180
|
+
if (!pill)
|
|
4701
5181
|
return;
|
|
4702
5182
|
const id = sel.ids.length === 1 ? sel.ids[0] : null;
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
}
|
|
4710
|
-
|
|
4711
|
-
cursorY.set(i * h);
|
|
4712
|
-
else
|
|
4713
|
-
cursorY.snap(i * h);
|
|
4714
|
-
cursorOn = true;
|
|
4715
|
-
cursor.setAttribute("data-on", "");
|
|
4716
|
-
drawCursor();
|
|
4717
|
-
if (!cursorY.resting)
|
|
4718
|
-
loop.wake();
|
|
5183
|
+
root.toggleAttribute("data-glide", id !== null && rowIndex.has(id));
|
|
5184
|
+
const fresh = id !== picked;
|
|
5185
|
+
picked = id;
|
|
5186
|
+
if (animate && fresh) {
|
|
5187
|
+
travelUntil = performance.now() + 450;
|
|
5188
|
+
pill.update();
|
|
5189
|
+
} else if (performance.now() >= travelUntil)
|
|
5190
|
+
pill.update({ snap: true });
|
|
4719
5191
|
};
|
|
4720
5192
|
container.append(root);
|
|
4721
5193
|
const scrollbar = overlayScrollbar(root, space);
|
|
@@ -4744,6 +5216,12 @@ function tree(container, options) {
|
|
|
4744
5216
|
};
|
|
4745
5217
|
const views = new Map;
|
|
4746
5218
|
const pool = [];
|
|
5219
|
+
if (options.glide)
|
|
5220
|
+
pill = selectionPill(root, {
|
|
5221
|
+
rows: () => [...views.values()].filter((v) => !v.leaving).map((v) => v.el),
|
|
5222
|
+
selected: () => pickedRow()?.el ?? null,
|
|
5223
|
+
radius: (row) => Number.parseFloat(win.getComputedStyle(row, "::before").borderTopLeftRadius) || 0
|
|
5224
|
+
});
|
|
4747
5225
|
const makeView = (id) => {
|
|
4748
5226
|
const v = pool.pop() ?? createView();
|
|
4749
5227
|
v.id = id;
|
|
@@ -4924,12 +5402,6 @@ function tree(container, options) {
|
|
|
4924
5402
|
function frame(dt) {
|
|
4925
5403
|
let moving = false;
|
|
4926
5404
|
let bottom = rows.length * h;
|
|
4927
|
-
if (options.glide && !cursorY.resting) {
|
|
4928
|
-
cursorY.step(dt);
|
|
4929
|
-
drawCursor();
|
|
4930
|
-
if (!cursorY.resting)
|
|
4931
|
-
moving = true;
|
|
4932
|
-
}
|
|
4933
5405
|
for (const v of views.values()) {
|
|
4934
5406
|
v.y.step(dt);
|
|
4935
5407
|
if (!v.y.resting)
|
|
@@ -4949,6 +5421,8 @@ function tree(container, options) {
|
|
|
4949
5421
|
}
|
|
4950
5422
|
setSpace(moving ? bottom : rows.length * h);
|
|
4951
5423
|
trim();
|
|
5424
|
+
if (pill && moving && performance.now() >= travelUntil)
|
|
5425
|
+
pill.update({ snap: true });
|
|
4952
5426
|
return moving;
|
|
4953
5427
|
}
|
|
4954
5428
|
const trim = () => {
|
|
@@ -5577,6 +6051,7 @@ function tree(container, options) {
|
|
|
5577
6051
|
autoScroll.stop();
|
|
5578
6052
|
ro.disconnect();
|
|
5579
6053
|
scrollbar.dispose();
|
|
6054
|
+
pill?.dispose();
|
|
5580
6055
|
dragging?.ghost.remove();
|
|
5581
6056
|
root.remove();
|
|
5582
6057
|
}
|
|
@@ -5595,6 +6070,7 @@ var init_tree = __esm(() => {
|
|
|
5595
6070
|
init_motion();
|
|
5596
6071
|
init_page_hints();
|
|
5597
6072
|
init_look();
|
|
6073
|
+
init_selection_pill();
|
|
5598
6074
|
init_tree_model();
|
|
5599
6075
|
MOVE = springMotion(SPRINGS.default);
|
|
5600
6076
|
});
|
|
@@ -5731,7 +6207,7 @@ function codeDiff(container, options) {
|
|
|
5731
6207
|
};
|
|
5732
6208
|
const nav = make("span", "knobs-diff-nav");
|
|
5733
6209
|
const prev = button("Previous file", PREV);
|
|
5734
|
-
const next = button("Next file",
|
|
6210
|
+
const next = button("Next file", NEXT);
|
|
5735
6211
|
const place = make("span", "");
|
|
5736
6212
|
nav.append(prev, place, next);
|
|
5737
6213
|
const wrapButton = button("Wrap lines", WRAP);
|
|
@@ -5752,9 +6228,8 @@ function codeDiff(container, options) {
|
|
|
5752
6228
|
const seg = make("div", "knobs-diff-seg");
|
|
5753
6229
|
seg.setAttribute("role", "radiogroup");
|
|
5754
6230
|
seg.setAttribute("aria-label", "Layout");
|
|
5755
|
-
const pill = make("i", "knobs-diff-pill");
|
|
5756
6231
|
const choice = (value, label) => {
|
|
5757
|
-
const b = make("button", "");
|
|
6232
|
+
const b = make("button", "knobs-diff-choice");
|
|
5758
6233
|
b.type = "button";
|
|
5759
6234
|
b.setAttribute("role", "radio");
|
|
5760
6235
|
b.dataset.value = value;
|
|
@@ -5763,7 +6238,7 @@ function codeDiff(container, options) {
|
|
|
5763
6238
|
};
|
|
5764
6239
|
const splitButton = choice("split", "Split");
|
|
5765
6240
|
const unifiedButton = choice("unified", "Unified");
|
|
5766
|
-
seg.append(
|
|
6241
|
+
seg.append(splitButton, unifiedButton);
|
|
5767
6242
|
if (options.lead)
|
|
5768
6243
|
head.append(options.lead);
|
|
5769
6244
|
head.append(path, stat, make("span", "knobs-diff-fill"), nav, wrapButton, seg, viewedButton);
|
|
@@ -5774,6 +6249,11 @@ function codeDiff(container, options) {
|
|
|
5774
6249
|
body.append(note, probe);
|
|
5775
6250
|
root.append(head, body);
|
|
5776
6251
|
container.append(root);
|
|
6252
|
+
const segPill = selectionPill(seg, {
|
|
6253
|
+
rows: () => [splitButton, unifiedButton],
|
|
6254
|
+
selected: () => layout === "split" ? splitButton : unifiedButton
|
|
6255
|
+
});
|
|
6256
|
+
let pilled = layout;
|
|
5777
6257
|
const fileNow = () => files.find((f) => f.name === current) ?? null;
|
|
5778
6258
|
const paintHead = () => {
|
|
5779
6259
|
const file = fileNow();
|
|
@@ -5806,6 +6286,10 @@ function codeDiff(container, options) {
|
|
|
5806
6286
|
next.disabled = at >= files.length - 1;
|
|
5807
6287
|
wrapButton.setAttribute("aria-pressed", String(wrap));
|
|
5808
6288
|
seg.dataset.value = layout;
|
|
6289
|
+
if (pilled !== layout) {
|
|
6290
|
+
pilled = layout;
|
|
6291
|
+
segPill.update();
|
|
6292
|
+
}
|
|
5809
6293
|
splitButton.setAttribute("aria-checked", String(layout === "split"));
|
|
5810
6294
|
unifiedButton.setAttribute("aria-checked", String(layout === "unified"));
|
|
5811
6295
|
splitButton.tabIndex = layout === "split" ? 0 : -1;
|
|
@@ -6640,6 +7124,7 @@ function codeDiff(container, options) {
|
|
|
6640
7124
|
dispose() {
|
|
6641
7125
|
disposed = true;
|
|
6642
7126
|
loop.stop();
|
|
7127
|
+
segPill.dispose();
|
|
6643
7128
|
sizes.disconnect();
|
|
6644
7129
|
attaching.disconnect();
|
|
6645
7130
|
resized.disconnect();
|
|
@@ -6995,7 +7480,7 @@ function diffReview(container, options) {
|
|
|
6995
7480
|
}
|
|
6996
7481
|
};
|
|
6997
7482
|
}
|
|
6998
|
-
var lib, load = () => lib ??= import("@pierre/diffs"), SYNTAX, IN, OUT, FADE4, HEIGHT, DRAWER, BLUR = 3, WRAP, PREV, UNVIEWED, VIEWED, SEARCH, CLEAR2, SIDEBAR, SEPARATOR = 32;
|
|
7483
|
+
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;
|
|
6999
7484
|
var init_diff = __esm(() => {
|
|
7000
7485
|
init_glide();
|
|
7001
7486
|
init_motion();
|
|
@@ -7003,6 +7488,8 @@ var init_diff = __esm(() => {
|
|
|
7003
7488
|
init_diff_model();
|
|
7004
7489
|
init_look();
|
|
7005
7490
|
init_rgba();
|
|
7491
|
+
init_icons();
|
|
7492
|
+
init_selection_pill();
|
|
7006
7493
|
init_tree();
|
|
7007
7494
|
SYNTAX = { dark: "pierre-dark", light: "pierre-light" };
|
|
7008
7495
|
IN = springMotion(SPRINGS.default);
|
|
@@ -7010,13 +7497,14 @@ var init_diff = __esm(() => {
|
|
|
7010
7497
|
FADE4 = springMotion(FADE);
|
|
7011
7498
|
HEIGHT = springMotion(SPRINGS.calm);
|
|
7012
7499
|
DRAWER = springMotion(SPRINGS.calm);
|
|
7013
|
-
WRAP =
|
|
7014
|
-
PREV =
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7500
|
+
WRAP = icon("arrowUDownLeft");
|
|
7501
|
+
PREV = icon("caretLeft");
|
|
7502
|
+
NEXT = icon("caretRight");
|
|
7503
|
+
UNVIEWED = icon("circle");
|
|
7504
|
+
VIEWED = icon("checkCircle");
|
|
7505
|
+
SEARCH = icon("magnifyingGlass", { small: true });
|
|
7506
|
+
CLEAR2 = icon("x", { small: true });
|
|
7507
|
+
SIDEBAR = icon("sidebar");
|
|
7020
7508
|
});
|
|
7021
7509
|
|
|
7022
7510
|
// src/ui/layer.ts
|
|
@@ -7999,10 +8487,25 @@ function advance(t, dt, o) {
|
|
|
7999
8487
|
}
|
|
8000
8488
|
return { t: hi, ended: true, wrapped: false };
|
|
8001
8489
|
}
|
|
8002
|
-
|
|
8490
|
+
function moveHead(head, t, motion, catching, minGap = 0) {
|
|
8491
|
+
if (motion === "jump" && Math.abs(t - head.x) > minGap)
|
|
8492
|
+
return { x: head.x, target: t, catching: true };
|
|
8493
|
+
if (catching)
|
|
8494
|
+
return { x: head.x + (t - head.target), target: t, catching: true };
|
|
8495
|
+
return { x: t, target: t, catching: false };
|
|
8496
|
+
}
|
|
8497
|
+
function currentMarker(markers, t, fps) {
|
|
8498
|
+
let best = null;
|
|
8499
|
+
for (const m of markers)
|
|
8500
|
+
if (m.time <= t + 0.5 / fps && (!best || m.time >= best.time))
|
|
8501
|
+
best = m;
|
|
8502
|
+
return best;
|
|
8503
|
+
}
|
|
8504
|
+
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;
|
|
8003
8505
|
var init_timeline_model = __esm(() => {
|
|
8004
8506
|
SECOND_STEPS = [0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600];
|
|
8005
8507
|
FRAME_STEPS = [1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 9000, 18000];
|
|
8508
|
+
CATCH_UP = { duration: 0.15, bounce: 0 };
|
|
8006
8509
|
});
|
|
8007
8510
|
|
|
8008
8511
|
// src/ui/timeline.ts
|
|
@@ -8015,6 +8518,7 @@ function timeline(container, options) {
|
|
|
8015
8518
|
let speed = options.speed ?? 1;
|
|
8016
8519
|
let repeat = options.repeat ?? true;
|
|
8017
8520
|
const arrows = options.arrows ?? "frames";
|
|
8521
|
+
const lane = options.variant === "lane";
|
|
8018
8522
|
let time = Math.min(duration, Math.max(0, options.time ?? 0));
|
|
8019
8523
|
let playing = false;
|
|
8020
8524
|
let markers = [...options.markers ?? []];
|
|
@@ -8048,27 +8552,27 @@ function timeline(container, options) {
|
|
|
8048
8552
|
root.setAttribute("aria-label", options.label ?? "Timeline");
|
|
8049
8553
|
root.setAttribute("aria-keyshortcuts", "Space ArrowLeft ArrowRight , . Home End [ ] I O M");
|
|
8050
8554
|
applyLook2(root, options);
|
|
8555
|
+
if (lane)
|
|
8556
|
+
root.dataset.variant = "lane";
|
|
8051
8557
|
const transport = el("div", "knobs-tl-transport");
|
|
8052
8558
|
const playBtn = el("button", "knobs-tl-play");
|
|
8053
8559
|
playBtn.type = "button";
|
|
8054
8560
|
playBtn.tabIndex = -1;
|
|
8055
|
-
|
|
8056
|
-
const now = el("span", "knobs-tl-now");
|
|
8057
|
-
const sub = el("span", "knobs-tl-sub");
|
|
8058
|
-
readout.append(now, sub);
|
|
8059
|
-
transport.append(playBtn, readout);
|
|
8561
|
+
transport.append(playBtn);
|
|
8060
8562
|
const track = el("div", "knobs-tl-track");
|
|
8061
8563
|
const canvas = el("canvas", "knobs-tl-ruler");
|
|
8062
8564
|
canvas.setAttribute("aria-hidden", "true");
|
|
8063
|
-
const
|
|
8565
|
+
const markerLane = el("div", "knobs-tl-lane");
|
|
8064
8566
|
const hover = el("div", "knobs-tl-hover");
|
|
8567
|
+
const tag = el("span", "knobs-tl-tag");
|
|
8568
|
+
tag.setAttribute("aria-hidden", "true");
|
|
8065
8569
|
const head = el("div", "knobs-tl-head");
|
|
8066
8570
|
head.id = `${id}-head`;
|
|
8067
8571
|
head.setAttribute("role", "slider");
|
|
8068
8572
|
head.setAttribute("aria-label", "Playhead");
|
|
8069
8573
|
head.setAttribute("aria-valuemin", "0");
|
|
8070
8574
|
head.setAttribute("aria-valuemax", String(duration));
|
|
8071
|
-
track.append(canvas,
|
|
8575
|
+
track.append(canvas, markerLane, hover, head, tag);
|
|
8072
8576
|
root.append(transport, track);
|
|
8073
8577
|
container.append(root);
|
|
8074
8578
|
let width = 1;
|
|
@@ -8115,13 +8619,14 @@ function timeline(container, options) {
|
|
|
8115
8619
|
let drawn = "";
|
|
8116
8620
|
const drawRuler = () => {
|
|
8117
8621
|
const v = view();
|
|
8118
|
-
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${units}:${fps}`;
|
|
8622
|
+
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${height}:${units}:${fps}`;
|
|
8119
8623
|
if (key === drawn)
|
|
8120
8624
|
return;
|
|
8121
8625
|
drawn = key;
|
|
8122
8626
|
const dpr = win.devicePixelRatio || 1;
|
|
8123
8627
|
const w = Math.max(1, Math.round(width * dpr));
|
|
8124
|
-
const
|
|
8628
|
+
const rh = lane ? height : RULER;
|
|
8629
|
+
const h = Math.round(rh * dpr);
|
|
8125
8630
|
if (canvas.width !== w || canvas.height !== h) {
|
|
8126
8631
|
canvas.width = w;
|
|
8127
8632
|
canvas.height = h;
|
|
@@ -8130,8 +8635,19 @@ function timeline(container, options) {
|
|
|
8130
8635
|
if (!ctx)
|
|
8131
8636
|
return;
|
|
8132
8637
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
8133
|
-
ctx.clearRect(0, 0, width,
|
|
8638
|
+
ctx.clearRect(0, 0, width, rh);
|
|
8134
8639
|
const ticks = rulerTicks(v, width, { fps, units });
|
|
8640
|
+
if (lane) {
|
|
8641
|
+
ctx.fillStyle = colors.tick;
|
|
8642
|
+
for (const t of ticks.minor)
|
|
8643
|
+
if (t >= -0.000000001 && t <= duration + 0.000000001)
|
|
8644
|
+
ctx.fillRect(xOf(t) - 0.5, rh - 4, 1, 4);
|
|
8645
|
+
ctx.fillStyle = colors.major;
|
|
8646
|
+
for (const m of ticks.major)
|
|
8647
|
+
if (m.t >= -0.000000001 && m.t <= duration + 0.000000001)
|
|
8648
|
+
ctx.fillRect(xOf(m.t) - 0.5, rh - 7, 1, 7);
|
|
8649
|
+
return;
|
|
8650
|
+
}
|
|
8135
8651
|
const px = (t) => Math.round(xOf(t)) + 0.5;
|
|
8136
8652
|
ctx.fillStyle = colors.line;
|
|
8137
8653
|
ctx.fillRect(0, RULER - 1, width, 1);
|
|
@@ -8171,18 +8687,21 @@ function timeline(container, options) {
|
|
|
8171
8687
|
n.dataset.id = m.id;
|
|
8172
8688
|
const pin = el("span", "knobs-tl-pin");
|
|
8173
8689
|
const label = el("span", "knobs-tl-mlabel");
|
|
8690
|
+
label.append(el("span", "knobs-tl-mtext knobs-scroll-fade-x"));
|
|
8174
8691
|
n.append(pin, label);
|
|
8175
|
-
|
|
8692
|
+
markerLane.append(n);
|
|
8176
8693
|
markerEls.set(m.id, n);
|
|
8177
8694
|
if (built)
|
|
8178
8695
|
enter(n);
|
|
8179
8696
|
}
|
|
8180
8697
|
const label = n.querySelector(".knobs-tl-mlabel");
|
|
8181
|
-
|
|
8182
|
-
|
|
8698
|
+
const text = label.firstElementChild;
|
|
8699
|
+
if (text.textContent !== (m.label ?? ""))
|
|
8700
|
+
text.textContent = m.label ?? "";
|
|
8183
8701
|
label.hidden = !m.label;
|
|
8184
8702
|
n.style.setProperty("--knobs-tl-color", m.color ?? "");
|
|
8185
8703
|
n.toggleAttribute("data-selected", selected?.kind === "marker" && selected.id === m.id);
|
|
8704
|
+
n.toggleAttribute("data-current", m.id === currentId);
|
|
8186
8705
|
n.title = `${m.label ? `${m.label} · ` : ""}${clock(m.time)}`;
|
|
8187
8706
|
}
|
|
8188
8707
|
placeMarkers();
|
|
@@ -8210,7 +8729,7 @@ function timeline(container, options) {
|
|
|
8210
8729
|
b.dataset.edge = "end";
|
|
8211
8730
|
const label = el("span", "knobs-tl-rlabel");
|
|
8212
8731
|
n.append(label, a, b);
|
|
8213
|
-
track.insertBefore(n,
|
|
8732
|
+
track.insertBefore(n, markerLane);
|
|
8214
8733
|
rangeEls.set(r.id, n);
|
|
8215
8734
|
if (built)
|
|
8216
8735
|
enter(n);
|
|
@@ -8259,16 +8778,17 @@ function timeline(container, options) {
|
|
|
8259
8778
|
};
|
|
8260
8779
|
const clock = (t) => units === "frames" ? `f${toFrame(t, fps)}` : `${timeLabel(t, "seconds", fps, 0.01)}`;
|
|
8261
8780
|
let shownHead = time;
|
|
8781
|
+
let currentId = null;
|
|
8262
8782
|
const renderHead = () => {
|
|
8263
8783
|
head.style.transform = `translateX(${xOf(shownHead).toFixed(2)}px)`;
|
|
8264
|
-
const main = units === "frames" ? `f${toFrame(time, fps)}` : `${time.toFixed(2)}s`;
|
|
8265
|
-
const minor = units === "frames" ? `${time.toFixed(2)}s` : `f${toFrame(time, fps)}`;
|
|
8266
|
-
if (now.textContent !== main)
|
|
8267
|
-
now.textContent = main;
|
|
8268
|
-
if (sub.textContent !== minor)
|
|
8269
|
-
sub.textContent = minor;
|
|
8270
8784
|
head.setAttribute("aria-valuenow", time.toFixed(3));
|
|
8271
8785
|
head.setAttribute("aria-valuetext", `${time.toFixed(2)} seconds, frame ${toFrame(time, fps)}`);
|
|
8786
|
+
const cur = currentMarker(markers, time, fps)?.id ?? null;
|
|
8787
|
+
if (cur !== currentId) {
|
|
8788
|
+
markerEls.get(currentId ?? "")?.removeAttribute("data-current");
|
|
8789
|
+
currentId = cur;
|
|
8790
|
+
markerEls.get(cur ?? "")?.setAttribute("data-current", "");
|
|
8791
|
+
}
|
|
8272
8792
|
};
|
|
8273
8793
|
let viewSent = "";
|
|
8274
8794
|
const render = () => {
|
|
@@ -8294,18 +8814,27 @@ function timeline(container, options) {
|
|
|
8294
8814
|
};
|
|
8295
8815
|
const caret = new Spring(time, GLIDE.omega, GLIDE.zeta, 0.00001);
|
|
8296
8816
|
let gliding = false;
|
|
8297
|
-
const
|
|
8298
|
-
const
|
|
8299
|
-
|
|
8817
|
+
const headTo = (shown, motion) => {
|
|
8818
|
+
const from = gliding ? { x: caret.x, target: caret.target } : { x: shownHead, target: shownHead };
|
|
8819
|
+
const jump = motion === "jump" && !reducedMotion(win);
|
|
8820
|
+
const next = moveHead(from, shown, jump ? "jump" : "follow", gliding, 2 / pxPerSec());
|
|
8821
|
+
if (next.catching) {
|
|
8300
8822
|
if (!gliding)
|
|
8301
|
-
caret.snap(
|
|
8302
|
-
caret.
|
|
8823
|
+
caret.snap(from.x);
|
|
8824
|
+
caret.x = next.x;
|
|
8825
|
+
caret.target = next.target;
|
|
8303
8826
|
gliding = true;
|
|
8827
|
+
shownHead = caret.x;
|
|
8304
8828
|
loop.wake();
|
|
8305
8829
|
} else {
|
|
8306
8830
|
gliding = false;
|
|
8307
|
-
|
|
8831
|
+
caret.snap(next.x);
|
|
8832
|
+
shownHead = next.x;
|
|
8308
8833
|
}
|
|
8834
|
+
};
|
|
8835
|
+
const setTime = (t, source, shown = t, glide = false) => {
|
|
8836
|
+
const next = Math.min(duration, Math.max(0, t));
|
|
8837
|
+
headTo(Math.min(duration, Math.max(0, shown)), glide ? "jump" : "follow");
|
|
8309
8838
|
const moved = next !== time;
|
|
8310
8839
|
time = next;
|
|
8311
8840
|
renderHead();
|
|
@@ -8346,8 +8875,7 @@ function timeline(container, options) {
|
|
|
8346
8875
|
options.onCross?.(m);
|
|
8347
8876
|
}
|
|
8348
8877
|
time = step.t;
|
|
8349
|
-
|
|
8350
|
-
gliding = false;
|
|
8878
|
+
headTo(time, step.wrapped ? "jump" : "follow");
|
|
8351
8879
|
emitSeek(time, "play");
|
|
8352
8880
|
keepInView();
|
|
8353
8881
|
if (step.ended) {
|
|
@@ -8360,7 +8888,7 @@ function timeline(container, options) {
|
|
|
8360
8888
|
shownHead = caret.step(dt);
|
|
8361
8889
|
if (caret.resting) {
|
|
8362
8890
|
gliding = false;
|
|
8363
|
-
shownHead =
|
|
8891
|
+
shownHead = caret.target;
|
|
8364
8892
|
}
|
|
8365
8893
|
}
|
|
8366
8894
|
vStart.step(dt);
|
|
@@ -8373,9 +8901,9 @@ function timeline(container, options) {
|
|
|
8373
8901
|
return;
|
|
8374
8902
|
const r = loopRange();
|
|
8375
8903
|
if (r && (time < r.start || time >= r.end - 0.5 / fps))
|
|
8376
|
-
setTime(r.start, "code");
|
|
8904
|
+
setTime(r.start, "code", r.start, true);
|
|
8377
8905
|
else if (!r && time >= duration - 0.5 / fps)
|
|
8378
|
-
setTime(0, "code");
|
|
8906
|
+
setTime(0, "code", 0, true);
|
|
8379
8907
|
playing = true;
|
|
8380
8908
|
syncPlay();
|
|
8381
8909
|
emitPlay(true);
|
|
@@ -8504,24 +9032,35 @@ function timeline(container, options) {
|
|
|
8504
9032
|
};
|
|
8505
9033
|
const localX = (e) => e.clientX - track.getBoundingClientRect().left;
|
|
8506
9034
|
let drag = null;
|
|
8507
|
-
const scrubTo = (x) => {
|
|
9035
|
+
const scrubTo = (x, press = false) => {
|
|
8508
9036
|
const shownX = softClamp(x, xOf(0), xOf(duration), 10);
|
|
8509
9037
|
const s = scrubTime(tOf(shownX), {
|
|
8510
9038
|
duration,
|
|
8511
9039
|
fps,
|
|
8512
9040
|
pxPerSec: pxPerSec(),
|
|
8513
|
-
stops: snapMarkers ? markers.map((m) => m.time) : [],
|
|
9041
|
+
stops: snapMarkers && !lane ? markers.map((m) => m.time) : [],
|
|
8514
9042
|
frames: snapFrames
|
|
8515
9043
|
});
|
|
8516
|
-
setTime(s.t, "scrub", s.shown);
|
|
9044
|
+
setTime(s.t, "scrub", s.shown, press);
|
|
8517
9045
|
root.toggleAttribute("data-stuck", s.stop !== null);
|
|
8518
9046
|
};
|
|
9047
|
+
const showTag = (x) => {
|
|
9048
|
+
const at = Math.min(duration, Math.max(0, tOf(x)));
|
|
9049
|
+
const text = `${at.toFixed(2)} s`;
|
|
9050
|
+
if (tag.textContent !== text)
|
|
9051
|
+
tag.textContent = text;
|
|
9052
|
+
const cx = Math.min(width, Math.max(0, x));
|
|
9053
|
+
const flip = cx > width - tag.offsetWidth - 12;
|
|
9054
|
+
tag.style.transform = `translateX(${cx.toFixed(1)}px) translateX(${flip ? "calc(-100% - 4px)" : "4px"})`;
|
|
9055
|
+
tag.dataset.on = "";
|
|
9056
|
+
};
|
|
9057
|
+
const hideTag = () => delete tag.dataset.on;
|
|
8519
9058
|
track.addEventListener("pointerdown", (e) => {
|
|
8520
9059
|
if (e.button !== 0 || editing)
|
|
8521
9060
|
return;
|
|
8522
9061
|
root.focus({ preventScroll: true });
|
|
8523
9062
|
const t = e.target;
|
|
8524
|
-
const markerEl = t.closest(".knobs-tl-marker");
|
|
9063
|
+
const markerEl = lane ? null : t.closest(".knobs-tl-marker");
|
|
8525
9064
|
const edgeEl = t.closest(".knobs-tl-edge");
|
|
8526
9065
|
const rangeEl = t.closest(".knobs-tl-range");
|
|
8527
9066
|
track.setPointerCapture(e.pointerId);
|
|
@@ -8566,13 +9105,16 @@ function timeline(container, options) {
|
|
|
8566
9105
|
root.dataset.scrubbing = "";
|
|
8567
9106
|
for (const l of listeners)
|
|
8568
9107
|
l.onScrub?.(true);
|
|
8569
|
-
scrubTo(localX(e));
|
|
9108
|
+
scrubTo(localX(e), true);
|
|
9109
|
+
showTag(localX(e));
|
|
8570
9110
|
}
|
|
8571
9111
|
e.preventDefault();
|
|
8572
9112
|
});
|
|
8573
9113
|
track.addEventListener("pointermove", (e) => {
|
|
8574
9114
|
const x = localX(e);
|
|
8575
9115
|
hover.style.transform = `translateX(${x.toFixed(1)}px)`;
|
|
9116
|
+
if (!drag || drag.kind === "scrub")
|
|
9117
|
+
showTag(x);
|
|
8576
9118
|
if (!drag)
|
|
8577
9119
|
return;
|
|
8578
9120
|
if (drag.kind === "scrub")
|
|
@@ -8618,8 +9160,10 @@ function timeline(container, options) {
|
|
|
8618
9160
|
delete root.dataset.dragging;
|
|
8619
9161
|
root.removeAttribute("data-stuck");
|
|
8620
9162
|
if (d.kind === "scrub") {
|
|
8621
|
-
|
|
9163
|
+
headTo(time, "follow");
|
|
8622
9164
|
renderHead();
|
|
9165
|
+
if (!track.matches(":hover"))
|
|
9166
|
+
hideTag();
|
|
8623
9167
|
for (const l of listeners)
|
|
8624
9168
|
l.onScrub?.(false);
|
|
8625
9169
|
if (d.wasPlaying)
|
|
@@ -8632,7 +9176,7 @@ function timeline(container, options) {
|
|
|
8632
9176
|
} else {
|
|
8633
9177
|
const m = markers.find((x) => x.id === d.id);
|
|
8634
9178
|
if (m)
|
|
8635
|
-
setTime(m.time, "marker");
|
|
9179
|
+
setTime(m.time, "marker", m.time, true);
|
|
8636
9180
|
}
|
|
8637
9181
|
} else if (d.kind === "edge" || d.moved)
|
|
8638
9182
|
emitRanges();
|
|
@@ -8641,10 +9185,14 @@ function timeline(container, options) {
|
|
|
8641
9185
|
track.addEventListener("pointercancel", endDrag);
|
|
8642
9186
|
track.addEventListener("lostpointercapture", endDrag);
|
|
8643
9187
|
track.addEventListener("pointerleave", () => {
|
|
8644
|
-
if (
|
|
8645
|
-
|
|
9188
|
+
if (drag)
|
|
9189
|
+
return;
|
|
9190
|
+
hover.style.transform = "translateX(-100px)";
|
|
9191
|
+
hideTag();
|
|
8646
9192
|
});
|
|
8647
9193
|
track.addEventListener("dblclick", (e) => {
|
|
9194
|
+
if (lane)
|
|
9195
|
+
return;
|
|
8648
9196
|
const markerEl = e.target.closest(".knobs-tl-marker");
|
|
8649
9197
|
if (markerEl)
|
|
8650
9198
|
return rename(markerEl.dataset.id);
|
|
@@ -8655,6 +9203,8 @@ function timeline(container, options) {
|
|
|
8655
9203
|
rename(m.id);
|
|
8656
9204
|
});
|
|
8657
9205
|
track.addEventListener("wheel", (e) => {
|
|
9206
|
+
if (lane)
|
|
9207
|
+
return;
|
|
8658
9208
|
e.preventDefault();
|
|
8659
9209
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? height : 1;
|
|
8660
9210
|
if (e.ctrlKey || e.metaKey) {
|
|
@@ -8718,7 +9268,7 @@ function timeline(container, options) {
|
|
|
8718
9268
|
if (!m)
|
|
8719
9269
|
return;
|
|
8720
9270
|
select({ kind: "marker", id: m.id });
|
|
8721
|
-
return setTime(m.time, "marker");
|
|
9271
|
+
return setTime(m.time, "marker", m.time, true);
|
|
8722
9272
|
}
|
|
8723
9273
|
case "i":
|
|
8724
9274
|
case "I":
|
|
@@ -8730,11 +9280,13 @@ function timeline(container, options) {
|
|
|
8730
9280
|
return setEdge("end", time);
|
|
8731
9281
|
case "m":
|
|
8732
9282
|
case "M":
|
|
9283
|
+
if (lane)
|
|
9284
|
+
return;
|
|
8733
9285
|
claim();
|
|
8734
9286
|
addMarker(time);
|
|
8735
9287
|
return;
|
|
8736
9288
|
case "Enter":
|
|
8737
|
-
if (selected?.kind === "marker") {
|
|
9289
|
+
if (selected?.kind === "marker" && !lane) {
|
|
8738
9290
|
claim();
|
|
8739
9291
|
rename(selected.id);
|
|
8740
9292
|
}
|
|
@@ -8752,19 +9304,25 @@ function timeline(container, options) {
|
|
|
8752
9304
|
return;
|
|
8753
9305
|
case "=":
|
|
8754
9306
|
case "+":
|
|
9307
|
+
if (lane)
|
|
9308
|
+
return;
|
|
8755
9309
|
claim();
|
|
8756
9310
|
return zoom(1.5);
|
|
8757
9311
|
case "-":
|
|
9312
|
+
if (lane)
|
|
9313
|
+
return;
|
|
8758
9314
|
claim();
|
|
8759
9315
|
return zoom(1 / 1.5);
|
|
8760
9316
|
case "0":
|
|
9317
|
+
if (lane)
|
|
9318
|
+
return;
|
|
8761
9319
|
claim();
|
|
8762
9320
|
return fit();
|
|
8763
9321
|
}
|
|
8764
9322
|
});
|
|
8765
9323
|
const unregisterHints = options.hints === false ? undefined : hints.register(root, () => [
|
|
8766
9324
|
{ el: playBtn, label: playing ? "Pause" : "Play", activate: toggle },
|
|
8767
|
-
...markers.flatMap((m) => {
|
|
9325
|
+
...(lane ? [] : markers).flatMap((m) => {
|
|
8768
9326
|
const n = markerEls.get(m.id);
|
|
8769
9327
|
if (!n || n.dataset.leaving !== undefined)
|
|
8770
9328
|
return [];
|
|
@@ -8776,7 +9334,7 @@ function timeline(container, options) {
|
|
|
8776
9334
|
...label && !label.hidden ? { labelEl: label } : {},
|
|
8777
9335
|
activate: () => {
|
|
8778
9336
|
select({ kind: "marker", id: m.id });
|
|
8779
|
-
setTime(m.time, "marker");
|
|
9337
|
+
setTime(m.time, "marker", m.time, true);
|
|
8780
9338
|
root.focus({ preventScroll: true });
|
|
8781
9339
|
}
|
|
8782
9340
|
}
|
|
@@ -8788,7 +9346,7 @@ function timeline(container, options) {
|
|
|
8788
9346
|
activate: () => root.focus({ preventScroll: true })
|
|
8789
9347
|
}
|
|
8790
9348
|
], { listen: false, rank: 1 });
|
|
8791
|
-
const menu = contextMenu(track, (e) => {
|
|
9349
|
+
const menu = lane ? null : contextMenu(track, (e) => {
|
|
8792
9350
|
const t = e?.target ?? null;
|
|
8793
9351
|
const markerEl = t?.closest(".knobs-tl-marker");
|
|
8794
9352
|
const rangeEl = t?.closest(".knobs-tl-range");
|
|
@@ -8803,7 +9361,7 @@ function timeline(container, options) {
|
|
|
8803
9361
|
run: () => {
|
|
8804
9362
|
const m = markers.find((x) => x.id === mid);
|
|
8805
9363
|
if (m)
|
|
8806
|
-
setTime(m.time, "marker");
|
|
9364
|
+
setTime(m.time, "marker", m.time, true);
|
|
8807
9365
|
}
|
|
8808
9366
|
},
|
|
8809
9367
|
{ label: "Rename…", shortcut: "Enter", run: () => rename(mid) },
|
|
@@ -8967,7 +9525,7 @@ function timeline(container, options) {
|
|
|
8967
9525
|
listeners.clear();
|
|
8968
9526
|
loop.stop();
|
|
8969
9527
|
ro.disconnect();
|
|
8970
|
-
menu
|
|
9528
|
+
menu?.dispose();
|
|
8971
9529
|
root.remove();
|
|
8972
9530
|
}
|
|
8973
9531
|
};
|
|
@@ -8984,10 +9542,21 @@ var init_timeline = __esm(() => {
|
|
|
8984
9542
|
init_timeline_model();
|
|
8985
9543
|
INSTANT2 = springMotion(SPRINGS.instant);
|
|
8986
9544
|
CALM = springMotion(SPRINGS.calm);
|
|
8987
|
-
GLIDE = springMotion(
|
|
9545
|
+
GLIDE = springMotion(CATCH_UP);
|
|
8988
9546
|
});
|
|
8989
9547
|
|
|
8990
9548
|
// src/ui/compare-model.ts
|
|
9549
|
+
function compareModes(modes, mode) {
|
|
9550
|
+
const list = [...new Set((modes ?? ["side", "wipe"]).filter((m) => ALL_MODES.includes(m)))];
|
|
9551
|
+
const offered = list.length ? list : ["side", "wipe"];
|
|
9552
|
+
return { modes: offered, mode: mode && offered.includes(mode) ? mode : offered[0] };
|
|
9553
|
+
}
|
|
9554
|
+
function modeForKey(key, modes) {
|
|
9555
|
+
const k = key.toLowerCase();
|
|
9556
|
+
if (/^[1-9]$/.test(k))
|
|
9557
|
+
return modes[Number(k) - 1] ?? null;
|
|
9558
|
+
return modes.find((m) => MODE_KEYS[m] === k) ?? null;
|
|
9559
|
+
}
|
|
8991
9560
|
function mediaKind(src, kind) {
|
|
8992
9561
|
if (kind)
|
|
8993
9562
|
return kind;
|
|
@@ -9066,6 +9635,18 @@ function wipeGrab(x, rect, wipe, slop = 12) {
|
|
|
9066
9635
|
const onLine = Math.abs(x - line) <= slop;
|
|
9067
9636
|
return { onLine, offset: onLine ? x - line : 0 };
|
|
9068
9637
|
}
|
|
9638
|
+
function seamLabels(x, left, right, wb, wa, gap = 8) {
|
|
9639
|
+
const room = (space, w) => Math.min(1, Math.max(0, (space - w - 2 * gap) / gap));
|
|
9640
|
+
return {
|
|
9641
|
+
before: { x: x - gap - wb, opacity: room(x - left, wb) },
|
|
9642
|
+
after: { x: x + gap, opacity: room(right - x, wa) }
|
|
9643
|
+
};
|
|
9644
|
+
}
|
|
9645
|
+
function gripTop(y, rect, grip, margin = 8) {
|
|
9646
|
+
const lo = rect.y + margin;
|
|
9647
|
+
const hi = rect.y + rect.h - margin - grip;
|
|
9648
|
+
return hi < lo ? rect.y + (rect.h - grip) / 2 : Math.min(hi, Math.max(lo, y - grip / 2));
|
|
9649
|
+
}
|
|
9069
9650
|
function stripColumns(view, width, o) {
|
|
9070
9651
|
const { fps } = o;
|
|
9071
9652
|
const total = Math.max(1, Math.round(o.duration * fps));
|
|
@@ -9116,7 +9697,7 @@ function stripPeaks(diffs, o = {}) {
|
|
|
9116
9697
|
});
|
|
9117
9698
|
return out;
|
|
9118
9699
|
}
|
|
9119
|
-
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({
|
|
9700
|
+
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({
|
|
9120
9701
|
u: r.u - dx / Math.max(1, base.w) * r.w,
|
|
9121
9702
|
v: r.v - dy / Math.max(1, base.h) * r.h,
|
|
9122
9703
|
w: r.w
|
|
@@ -9135,6 +9716,8 @@ var VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), last
|
|
|
9135
9716
|
h: a.h + (b.h - a.h) * k
|
|
9136
9717
|
}), 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));
|
|
9137
9718
|
var init_compare_model = __esm(() => {
|
|
9719
|
+
ALL_MODES = ["side", "wipe", "difference"];
|
|
9720
|
+
MODE_KEYS = { side: "s", wipe: "w", difference: "d" };
|
|
9138
9721
|
VIDEO = /\.(mp4|m4v|mov|webm|ogv|mkv)$/i;
|
|
9139
9722
|
SEEK_IDLE = { seeking: false, pending: null };
|
|
9140
9723
|
ZOOM_FIT = { u: 0, v: 0, w: 1, h: 1 };
|
|
@@ -9934,8 +10517,8 @@ async function createCompareGpu(canvas, onLost) {
|
|
|
9934
10517
|
r(0, f.before);
|
|
9935
10518
|
r(4, f.after);
|
|
9936
10519
|
data.set([f.width, f.height, f.dpr, 0], 8);
|
|
9937
|
-
data.set([f.wipeX, f.soft, 0,
|
|
9938
|
-
data.set([f.from, f.to, f.mix,
|
|
10520
|
+
data.set([f.wipeX, f.soft, 0, 0], 12);
|
|
10521
|
+
data.set([f.from, f.to, f.mix, 0], 16);
|
|
9939
10522
|
data.set([f.threshold, f.gain, ready[0], ready[1]], 20);
|
|
9940
10523
|
data.set([f.accent[0], f.accent[1], f.accent[2], 1], 24);
|
|
9941
10524
|
const l = f.loupe;
|
|
@@ -9977,8 +10560,8 @@ var MODE_INDEX, WGSL = `
|
|
|
9977
10560
|
struct U {
|
|
9978
10561
|
ra: vec4f, rb: vec4f,
|
|
9979
10562
|
view: vec4f, // w, h, dpr, _
|
|
9980
|
-
wipe: vec4f, // x, soft, _,
|
|
9981
|
-
modes: vec4f, // from, to, mix,
|
|
10563
|
+
wipe: vec4f, // x, soft, _, _
|
|
10564
|
+
modes: vec4f, // from, to, mix, _
|
|
9982
10565
|
diff: vec4f, // threshold, gain, readyA, readyB
|
|
9983
10566
|
accent: vec4f,
|
|
9984
10567
|
loupe: vec4f, // x, y, r, zoom (0: none)
|
|
@@ -10029,21 +10612,14 @@ fn takeB(p: vec2f, r: vec4f, c0: vec4f, near: bool) -> vec4f {
|
|
|
10029
10612
|
|
|
10030
10613
|
fn pm(c: vec4f) -> vec4f { return vec4f(c.rgb * c.a, c.a); }
|
|
10031
10614
|
|
|
10032
|
-
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f
|
|
10033
|
-
let flick = u.modes.w > 0.5;
|
|
10615
|
+
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
10034
10616
|
switch mode {
|
|
10035
|
-
case 0u: {
|
|
10036
|
-
let bb = select(b, vec4f(a2.rgb, b.a), flick);
|
|
10037
|
-
return vec4f(a.rgb * a.a + bb.rgb * bb.a * (1.0 - a.a), a.a + bb.a * (1.0 - a.a));
|
|
10038
|
-
}
|
|
10039
10617
|
case 1u: {
|
|
10040
|
-
if (flick) { return pm(a); }
|
|
10041
10618
|
let s = max(u.wipe.y, 0.5);
|
|
10042
10619
|
let m = smoothstep(u.wipe.x - s, u.wipe.x + s, p.x);
|
|
10043
10620
|
return pm(vec4f(mix(a.rgb, b.rgb, m), mix(a.a, b.a, m)));
|
|
10044
10621
|
}
|
|
10045
10622
|
case 2u: {
|
|
10046
|
-
if (flick) { return pm(a); }
|
|
10047
10623
|
let d = abs(a.rgb - b.rgb);
|
|
10048
10624
|
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);
|
|
10049
10625
|
let c = mix(vec3f(luma(b.rgb) * 0.35), u.accent.rgb, h);
|
|
@@ -10051,8 +10627,8 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f, a2: vec4f) -> vec4f {
|
|
|
10051
10627
|
}
|
|
10052
10628
|
default: {}
|
|
10053
10629
|
}
|
|
10054
|
-
//
|
|
10055
|
-
return
|
|
10630
|
+
// Side by side: each side in its own place, Before over After where they meet.
|
|
10631
|
+
return vec4f(a.rgb * a.a + b.rgb * b.a * (1.0 - a.a), a.a + b.a * (1.0 - a.a));
|
|
10056
10632
|
}
|
|
10057
10633
|
|
|
10058
10634
|
@fragment fn fs(@builtin(position) q: vec4f) -> @location(0) vec4f {
|
|
@@ -10070,16 +10646,14 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f, a2: vec4f) -> vec4f {
|
|
|
10070
10646
|
}
|
|
10071
10647
|
let a = takeA(p, u.ra, u.ca, near);
|
|
10072
10648
|
let b = takeB(p, u.rb, u.cb, near);
|
|
10073
|
-
|
|
10074
|
-
let a2 = takeA(p, u.rb, u.cb, near);
|
|
10075
|
-
var o = mix(composite(u32(u.modes.x), p, a, b, a2), composite(u32(u.modes.y), p, a, b, a2), u.modes.z);
|
|
10649
|
+
var o = mix(composite(u32(u.modes.x), p, a, b), composite(u32(u.modes.y), p, a, b), u.modes.z);
|
|
10076
10650
|
if (near) { o = o + vec4f(0.05, 0.05, 0.06, 1.0) * (1.0 - o.a); }
|
|
10077
10651
|
o = mix(o, vec4f(0.92), ring * 0.9);
|
|
10078
10652
|
return o;
|
|
10079
10653
|
}
|
|
10080
10654
|
`, TEXTURE_BINDING = 4, COPY_DST = 2, RENDER_ATTACHMENT = 16, shared = null, lostListeners;
|
|
10081
10655
|
var init_compare_gpu = __esm(() => {
|
|
10082
|
-
MODE_INDEX = { side: 0, wipe: 1, difference: 2
|
|
10656
|
+
MODE_INDEX = { side: 0, wipe: 1, difference: 2 };
|
|
10083
10657
|
lostListeners = new Set;
|
|
10084
10658
|
});
|
|
10085
10659
|
|
|
@@ -10465,7 +11039,9 @@ function compare(container, options) {
|
|
|
10465
11039
|
...options.theme ? { theme: options.theme } : {},
|
|
10466
11040
|
...options.appearance ? { appearance: options.appearance } : {}
|
|
10467
11041
|
};
|
|
10468
|
-
|
|
11042
|
+
const offered = compareModes(options.modes, options.mode);
|
|
11043
|
+
const modeList = offered.modes;
|
|
11044
|
+
let mode = offered.mode;
|
|
10469
11045
|
let wipe = Math.min(1, Math.max(0, options.wipe ?? 0.5));
|
|
10470
11046
|
let loupeOn = options.loupe ?? false;
|
|
10471
11047
|
let threshold = options.threshold ?? 4 / 255;
|
|
@@ -10483,7 +11059,7 @@ function compare(container, options) {
|
|
|
10483
11059
|
root.setAttribute("role", "group");
|
|
10484
11060
|
root.setAttribute("aria-roledescription", "compare");
|
|
10485
11061
|
root.setAttribute("aria-label", options.label ?? "Compare");
|
|
10486
|
-
root.setAttribute("aria-keyshortcuts",
|
|
11062
|
+
root.setAttribute("aria-keyshortcuts", `Space ArrowLeft ArrowRight Shift+ArrowLeft Shift+ArrowRight , . ${modeList.map((m, i) => `${i + 1} ${modeKey(m)}`).join(" ")} Z L 0 = -`);
|
|
10487
11063
|
applyLook2(root, options);
|
|
10488
11064
|
root.dataset.mode = mode;
|
|
10489
11065
|
if (auto)
|
|
@@ -10492,35 +11068,37 @@ function compare(container, options) {
|
|
|
10492
11068
|
const modes = el("div", "knobs-cmp-modes");
|
|
10493
11069
|
modes.setAttribute("role", "radiogroup");
|
|
10494
11070
|
modes.setAttribute("aria-label", "Mode");
|
|
10495
|
-
|
|
11071
|
+
modes.hidden = modeList.length < 2;
|
|
11072
|
+
const modeBtns = modeList.map((m, i) => {
|
|
10496
11073
|
const b = el("button", "knobs-cmp-mode");
|
|
10497
11074
|
b.type = "button";
|
|
10498
11075
|
b.tabIndex = -1;
|
|
10499
|
-
b.textContent = m.
|
|
10500
|
-
b.title = `${m.
|
|
11076
|
+
b.textContent = MODE_LABEL[m].short;
|
|
11077
|
+
b.title = `${MODE_LABEL[m].long} · ${i + 1} or ${modeKey(m)}`;
|
|
10501
11078
|
b.setAttribute("role", "radio");
|
|
10502
|
-
b.setAttribute("aria-keyshortcuts",
|
|
11079
|
+
b.setAttribute("aria-keyshortcuts", `${i + 1} ${modeKey(m)}`);
|
|
10503
11080
|
b.addEventListener("click", () => {
|
|
10504
|
-
setMode(m
|
|
11081
|
+
setMode(m);
|
|
10505
11082
|
root.focus({ preventScroll: true });
|
|
10506
11083
|
});
|
|
10507
11084
|
modes.append(b);
|
|
10508
11085
|
return b;
|
|
10509
11086
|
});
|
|
10510
|
-
const
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
11087
|
+
const toggleBtn = (name, label, title) => {
|
|
11088
|
+
const b = el("button", "knobs-cmp-toggle");
|
|
11089
|
+
b.type = "button";
|
|
11090
|
+
b.tabIndex = -1;
|
|
11091
|
+
b.innerHTML = icon(name);
|
|
11092
|
+
b.setAttribute("aria-label", label);
|
|
11093
|
+
b.title = title;
|
|
11094
|
+
return b;
|
|
11095
|
+
};
|
|
11096
|
+
const loupeBtn = toggleBtn("magnifyingGlass", "Loupe", "Loupe · hold Z");
|
|
10515
11097
|
loupeBtn.addEventListener("click", () => {
|
|
10516
11098
|
setLoupe(!loupeOn);
|
|
10517
11099
|
root.focus({ preventScroll: true });
|
|
10518
11100
|
});
|
|
10519
|
-
const loopBtn =
|
|
10520
|
-
loopBtn.type = "button";
|
|
10521
|
-
loopBtn.tabIndex = -1;
|
|
10522
|
-
loopBtn.textContent = "Loop";
|
|
10523
|
-
loopBtn.title = "Loop · L (drag its ends on the timeline)";
|
|
11101
|
+
const loopBtn = toggleBtn("repeat", "Loop", "Loop · L (drag its ends on the timeline)");
|
|
10524
11102
|
loopBtn.setAttribute("aria-keyshortcuts", "L");
|
|
10525
11103
|
loopBtn.addEventListener("click", () => {
|
|
10526
11104
|
api.setLoop(!loopNow());
|
|
@@ -10537,7 +11115,8 @@ function compare(container, options) {
|
|
|
10537
11115
|
const zoomReset = el("button", "knobs-cmp-zoom-reset");
|
|
10538
11116
|
zoomReset.type = "button";
|
|
10539
11117
|
zoomReset.tabIndex = -1;
|
|
10540
|
-
zoomReset.
|
|
11118
|
+
zoomReset.innerHTML = icon("arrowCounterClockwise", { small: true });
|
|
11119
|
+
zoomReset.setAttribute("aria-label", "Reset zoom");
|
|
10541
11120
|
zoomReset.title = "Fit · 0 or double-click";
|
|
10542
11121
|
zoomReset.addEventListener("click", () => {
|
|
10543
11122
|
api.setZoom(null);
|
|
@@ -10547,11 +11126,25 @@ function compare(container, options) {
|
|
|
10547
11126
|
const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
|
|
10548
11127
|
labels[0].dataset.side = "before";
|
|
10549
11128
|
labels[1].dataset.side = "after";
|
|
11129
|
+
const setLabel = (index, text) => {
|
|
11130
|
+
const l = labels[index];
|
|
11131
|
+
if (!l.firstElementChild) {
|
|
11132
|
+
const mark = el("span", "knobs-cmp-mark");
|
|
11133
|
+
mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
|
|
11134
|
+
l.append(mark, el("span", "knobs-cmp-name"));
|
|
11135
|
+
}
|
|
11136
|
+
const name = l.lastElementChild;
|
|
11137
|
+
if (name.textContent !== text)
|
|
11138
|
+
name.textContent = text;
|
|
11139
|
+
};
|
|
10550
11140
|
const handle = el("div", "knobs-cmp-handle");
|
|
10551
11141
|
handle.setAttribute("role", "slider");
|
|
10552
11142
|
handle.setAttribute("aria-label", "Wipe");
|
|
10553
11143
|
handle.setAttribute("aria-valuemin", "0");
|
|
10554
11144
|
handle.setAttribute("aria-valuemax", "100");
|
|
11145
|
+
const grip = el("span", "knobs-cmp-grip");
|
|
11146
|
+
grip.setAttribute("aria-hidden", "true");
|
|
11147
|
+
handle.append(grip);
|
|
10555
11148
|
const note = el("div", "knobs-cmp-note");
|
|
10556
11149
|
stage.append(canvas, split, labels[0], labels[1], handle, zoomPill, note);
|
|
10557
11150
|
root.append(bar, stage);
|
|
@@ -10568,6 +11161,7 @@ function compare(container, options) {
|
|
|
10568
11161
|
root.append(host);
|
|
10569
11162
|
tl = timeline(host, {
|
|
10570
11163
|
...look,
|
|
11164
|
+
variant: "lane",
|
|
10571
11165
|
duration: 1,
|
|
10572
11166
|
fps: fps(),
|
|
10573
11167
|
arrows: { step: 0.5, shift: 2 },
|
|
@@ -10586,9 +11180,9 @@ function compare(container, options) {
|
|
|
10586
11180
|
const fade = new Spring(1, FADE6.omega, FADE6.zeta, 0.001);
|
|
10587
11181
|
let fromMode = mode;
|
|
10588
11182
|
let toMode = mode;
|
|
10589
|
-
|
|
10590
|
-
let
|
|
10591
|
-
let
|
|
11183
|
+
const wipeLine = new Spring(wipe, WIPE_CATCH.omega, WIPE_CATCH.zeta, 0.0001);
|
|
11184
|
+
let wipeCatching = false;
|
|
11185
|
+
let gripY = null;
|
|
10592
11186
|
let loupeHeld = false;
|
|
10593
11187
|
let pointer = null;
|
|
10594
11188
|
let drag = null;
|
|
@@ -10906,25 +11500,16 @@ function compare(container, options) {
|
|
|
10906
11500
|
gpu = g;
|
|
10907
11501
|
setRenderer("gpu");
|
|
10908
11502
|
};
|
|
10909
|
-
const syncFlicker = () => {
|
|
10910
|
-
win.clearInterval(flickerTimer);
|
|
10911
|
-
flickerTimer = 0;
|
|
10912
|
-
phase = false;
|
|
10913
|
-
if (mode === "flicker")
|
|
10914
|
-
flickerTimer = win.setInterval(() => {
|
|
10915
|
-
phase = !phase;
|
|
10916
|
-
requestDraw();
|
|
10917
|
-
}, FLICKER_MS);
|
|
10918
|
-
};
|
|
10919
11503
|
const syncModeUi = () => {
|
|
10920
11504
|
root.dataset.mode = mode;
|
|
10921
|
-
|
|
10922
|
-
modeBtns[i].setAttribute("aria-checked", String(m
|
|
11505
|
+
modeList.forEach((m, i) => {
|
|
11506
|
+
modeBtns[i].setAttribute("aria-checked", String(m === mode));
|
|
10923
11507
|
});
|
|
10924
11508
|
handle.tabIndex = mode === "wipe" ? 0 : -1;
|
|
11509
|
+
modePill?.update();
|
|
10925
11510
|
};
|
|
10926
11511
|
const setMode = (next, emit = true) => {
|
|
10927
|
-
if (next === mode)
|
|
11512
|
+
if (next === mode || !modeList.includes(next))
|
|
10928
11513
|
return;
|
|
10929
11514
|
mode = next;
|
|
10930
11515
|
const reduced = reducedMotion(win);
|
|
@@ -10940,19 +11525,29 @@ function compare(container, options) {
|
|
|
10940
11525
|
else
|
|
10941
11526
|
lay.set(next === "side" ? 0 : 1);
|
|
10942
11527
|
syncModeUi();
|
|
10943
|
-
syncFlicker();
|
|
10944
11528
|
if (emit)
|
|
10945
11529
|
options.onMode?.(next);
|
|
10946
11530
|
requestDraw();
|
|
10947
11531
|
};
|
|
10948
|
-
const setWipe = (next, emit = true) => {
|
|
11532
|
+
const setWipe = (next, emit = true, jump = false) => {
|
|
10949
11533
|
const w = Math.min(1, Math.max(0, next));
|
|
10950
|
-
if (w === wipe)
|
|
11534
|
+
if (w === wipe && !jump)
|
|
10951
11535
|
return;
|
|
10952
11536
|
wipe = w;
|
|
11537
|
+
const minGap = 2 / Math.max(1, wipeRect(layoutNow().L.overlay).w);
|
|
11538
|
+
const head = moveHead({ x: wipeLine.x, target: wipeLine.target }, w, jump && !reducedMotion(win) ? "jump" : "follow", wipeCatching, minGap);
|
|
11539
|
+
wipeCatching = head.catching;
|
|
11540
|
+
if (head.catching) {
|
|
11541
|
+
wipeLine.x = head.x;
|
|
11542
|
+
wipeLine.target = head.target;
|
|
11543
|
+
} else
|
|
11544
|
+
wipeLine.snap(head.x);
|
|
10953
11545
|
if (emit)
|
|
10954
11546
|
options.onWipe?.(w);
|
|
10955
|
-
|
|
11547
|
+
if (head.catching)
|
|
11548
|
+
requestDraw();
|
|
11549
|
+
else
|
|
11550
|
+
drawNow();
|
|
10956
11551
|
};
|
|
10957
11552
|
const setLoupe = (on) => {
|
|
10958
11553
|
loupeOn = on;
|
|
@@ -11105,28 +11700,44 @@ function compare(container, options) {
|
|
|
11105
11700
|
viewSent = key;
|
|
11106
11701
|
options.onView({ zoom: clampZoom(z), loop: l });
|
|
11107
11702
|
};
|
|
11703
|
+
const labelsIn = (m, r, wr, wx) => {
|
|
11704
|
+
if (m === "wipe") {
|
|
11705
|
+
const at = seamLabels(wx, wr.x, wr.x + wr.w, labelW[0], labelW[1], INSET);
|
|
11706
|
+
return [at.before, at.after];
|
|
11707
|
+
}
|
|
11708
|
+
const ax = r.after.x + INSET + (r.after.w - labelW[1] - INSET * 2) * lay.x;
|
|
11709
|
+
return [
|
|
11710
|
+
{ x: r.before.x + INSET, opacity: 1 },
|
|
11711
|
+
{ x: ax, opacity: 1 }
|
|
11712
|
+
];
|
|
11713
|
+
};
|
|
11714
|
+
const placeGrip = (wr) => {
|
|
11715
|
+
const gy = gripTop(gripY ?? wr.y + wr.h / 2, wr, GRIP.h) - wr.y;
|
|
11716
|
+
grip.style.transform = `translate3d(0,${gy.toFixed(2)}px,0)`;
|
|
11717
|
+
};
|
|
11108
11718
|
const draw = () => {
|
|
11109
11719
|
dirty = false;
|
|
11110
11720
|
const r = layoutNow();
|
|
11111
11721
|
const wr = wipeRect(r.L.overlay);
|
|
11112
|
-
const wx = wipeX(wr,
|
|
11722
|
+
const wx = wipeX(wr, wipeLine.x);
|
|
11113
11723
|
const k = lay.x;
|
|
11114
|
-
const
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
const
|
|
11118
|
-
const
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11724
|
+
const a = labelsIn(fromMode, r, wr, wx);
|
|
11725
|
+
const b = labelsIn(toMode, r, wr, wx);
|
|
11726
|
+
const f = Math.min(1, Math.max(0, fade.x));
|
|
11727
|
+
const ys = [r.before.y + INSET, r.after.y + INSET];
|
|
11728
|
+
for (const i of [0, 1]) {
|
|
11729
|
+
const x = a[i].x + (b[i].x - a[i].x) * f;
|
|
11730
|
+
labels[i].style.transform = `translate(${x.toFixed(2)}px,${ys[i].toFixed(2)}px)`;
|
|
11731
|
+
labels[i].style.opacity = (a[i].opacity + (b[i].opacity - a[i].opacity) * f).toFixed(3);
|
|
11732
|
+
}
|
|
11123
11733
|
const top = Math.min(r.L.side.before.y, r.L.side.after.y);
|
|
11124
11734
|
split.style.transform = `translate(${r.L.side.split.toFixed(2)}px,${top.toFixed(2)}px)`;
|
|
11125
11735
|
split.style.height = `${Math.max(0, r.L.side.after.h).toFixed(2)}px`;
|
|
11126
11736
|
split.style.opacity = String(Math.max(0, 1 - k * 2));
|
|
11127
|
-
handle.toggleAttribute("data-on", mode === "wipe"
|
|
11737
|
+
handle.toggleAttribute("data-on", mode === "wipe");
|
|
11128
11738
|
handle.style.transform = `translate(${wx.toFixed(2)}px,${wr.y.toFixed(2)}px)`;
|
|
11129
11739
|
handle.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
11740
|
+
placeGrip(wr);
|
|
11130
11741
|
handle.setAttribute("aria-valuenow", String(Math.round(wipe * 100)));
|
|
11131
11742
|
handle.setAttribute("aria-valuetext", `${Math.round(wipe * 100)}% Before`);
|
|
11132
11743
|
const pct = `${Math.round(100 / zw.x)}%`;
|
|
@@ -11149,7 +11760,7 @@ function compare(container, options) {
|
|
|
11149
11760
|
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w, cutAt));
|
|
11150
11761
|
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)` : "";
|
|
11151
11762
|
};
|
|
11152
|
-
const cut = mode === "wipe"
|
|
11763
|
+
const cut = mode === "wipe" ? wx : Number.POSITIVE_INFINITY;
|
|
11153
11764
|
for (const s of sides) {
|
|
11154
11765
|
const rect = s.index === 0 ? r.zBefore : r.zAfter;
|
|
11155
11766
|
const clip = s.index === 0 ? r.before : r.after;
|
|
@@ -11158,10 +11769,8 @@ function compare(container, options) {
|
|
|
11158
11769
|
place(s.preview, rect, clip, at);
|
|
11159
11770
|
if (s.index !== 0)
|
|
11160
11771
|
continue;
|
|
11161
|
-
for (const n of [s.el, s.preview])
|
|
11162
|
-
n.style.mixBlendMode = mode === "difference"
|
|
11163
|
-
n.style.opacity = mode === "flicker" && !showsBefore ? "0" : "";
|
|
11164
|
-
}
|
|
11772
|
+
for (const n of [s.el, s.preview])
|
|
11773
|
+
n.style.mixBlendMode = mode === "difference" ? "difference" : "";
|
|
11165
11774
|
}
|
|
11166
11775
|
return;
|
|
11167
11776
|
}
|
|
@@ -11182,8 +11791,6 @@ function compare(container, options) {
|
|
|
11182
11791
|
from: MODE_INDEX[fromMode],
|
|
11183
11792
|
to: MODE_INDEX[toMode],
|
|
11184
11793
|
mix: Math.min(1, Math.max(0, fade.x)),
|
|
11185
|
-
flick: flickHeld,
|
|
11186
|
-
phase,
|
|
11187
11794
|
threshold,
|
|
11188
11795
|
gain: 1,
|
|
11189
11796
|
accent,
|
|
@@ -11199,6 +11806,11 @@ function compare(container, options) {
|
|
|
11199
11806
|
const loop = frameLoop(win, (dt) => {
|
|
11200
11807
|
lay.step(dt);
|
|
11201
11808
|
fade.step(dt);
|
|
11809
|
+
if (wipeCatching) {
|
|
11810
|
+
wipeLine.step(dt);
|
|
11811
|
+
if (wipeLine.resting)
|
|
11812
|
+
wipeCatching = false;
|
|
11813
|
+
}
|
|
11202
11814
|
zu.step(dt);
|
|
11203
11815
|
zv.step(dt);
|
|
11204
11816
|
zw.step(dt);
|
|
@@ -11232,7 +11844,7 @@ function compare(container, options) {
|
|
|
11232
11844
|
pushFrame(s);
|
|
11233
11845
|
}
|
|
11234
11846
|
}
|
|
11235
|
-
const moving = !lay.resting || !fade.resting || !zoomResting();
|
|
11847
|
+
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching;
|
|
11236
11848
|
if (moving)
|
|
11237
11849
|
dirty = true;
|
|
11238
11850
|
if (auto && !lay.resting)
|
|
@@ -11375,16 +11987,19 @@ function compare(container, options) {
|
|
|
11375
11987
|
e.preventDefault();
|
|
11376
11988
|
return startPinch();
|
|
11377
11989
|
}
|
|
11378
|
-
if (mode === "wipe"
|
|
11990
|
+
if (mode === "wipe") {
|
|
11379
11991
|
const wr = wipeRect(layoutNow().L.overlay);
|
|
11380
11992
|
const inside = p.x >= wr.x - SLOP && p.x <= wr.x + wr.w + SLOP && p.y >= wr.y && p.y <= wr.y + wr.h;
|
|
11381
|
-
const grab = wipeGrab(p.x, wr,
|
|
11993
|
+
const grab = wipeGrab(p.x, wr, wipeLine.x, SLOP);
|
|
11382
11994
|
if (inside && (grab.onLine || !zoomed())) {
|
|
11383
11995
|
drag = { kind: "wipe", offset: grab.offset };
|
|
11384
11996
|
root.dataset.dragging = "";
|
|
11997
|
+
gripY = p.y;
|
|
11385
11998
|
e.preventDefault();
|
|
11386
11999
|
if (!grab.onLine)
|
|
11387
|
-
setWipe(wipeAt(p.x, wr));
|
|
12000
|
+
setWipe(wipeAt(p.x, wr), true, true);
|
|
12001
|
+
else
|
|
12002
|
+
drawNow();
|
|
11388
12003
|
return;
|
|
11389
12004
|
}
|
|
11390
12005
|
}
|
|
@@ -11410,6 +12025,11 @@ function compare(container, options) {
|
|
|
11410
12025
|
pinch = { d, x: mid.x, y: mid.y };
|
|
11411
12026
|
return handZoom(zoomAbout(panned, k, q.pu, q.pv));
|
|
11412
12027
|
}
|
|
12028
|
+
if (mode === "wipe" && drag?.kind !== "pan") {
|
|
12029
|
+
gripY = p.y;
|
|
12030
|
+
if (!drag)
|
|
12031
|
+
placeGrip(wipeRect(layoutNow().L.overlay));
|
|
12032
|
+
}
|
|
11413
12033
|
if (drag?.kind === "wipe")
|
|
11414
12034
|
setWipe(wipeAt(p.x, wipeRect(layoutNow().L.overlay), drag.offset));
|
|
11415
12035
|
else if (drag?.kind === "pan") {
|
|
@@ -11482,12 +12102,6 @@ function compare(container, options) {
|
|
|
11482
12102
|
const z = { u: zu.target, v: zv.target, w: zw.target, h: zw.target };
|
|
11483
12103
|
glideZoom(zoomAbout(z, factor, 0.5, 0.5));
|
|
11484
12104
|
};
|
|
11485
|
-
const holdFlick = (on) => {
|
|
11486
|
-
if (flickHeld === on)
|
|
11487
|
-
return;
|
|
11488
|
-
flickHeld = on;
|
|
11489
|
-
drawNow();
|
|
11490
|
-
};
|
|
11491
12105
|
const holdLoupe = (on) => {
|
|
11492
12106
|
if (loupeHeld === on)
|
|
11493
12107
|
return;
|
|
@@ -11533,25 +12147,17 @@ function compare(container, options) {
|
|
|
11533
12147
|
case "s":
|
|
11534
12148
|
case "w":
|
|
11535
12149
|
case "d":
|
|
11536
|
-
if (e.altKey || e.shiftKey || key === "s" && claimsHintKey(doc, key))
|
|
11537
|
-
return;
|
|
11538
|
-
claim();
|
|
11539
|
-
return setMode(KEY_MODE[key]);
|
|
11540
12150
|
case "1":
|
|
11541
12151
|
case "2":
|
|
11542
|
-
case "3":
|
|
11543
|
-
|
|
11544
|
-
if (e.altKey || e.shiftKey)
|
|
12152
|
+
case "3": {
|
|
12153
|
+
if (e.altKey || e.shiftKey || key === "s" && claimsHintKey(doc, key))
|
|
11545
12154
|
return;
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
case "x":
|
|
11549
|
-
if (e.altKey)
|
|
12155
|
+
const m = modeForKey(key, modeList);
|
|
12156
|
+
if (!m)
|
|
11550
12157
|
return;
|
|
11551
12158
|
claim();
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
return;
|
|
12159
|
+
return setMode(m);
|
|
12160
|
+
}
|
|
11555
12161
|
case "z":
|
|
11556
12162
|
if (e.altKey)
|
|
11557
12163
|
return;
|
|
@@ -11592,7 +12198,7 @@ function compare(container, options) {
|
|
|
11592
12198
|
old.preview.replaceWith(s.preview);
|
|
11593
12199
|
sides[index] = s;
|
|
11594
12200
|
note.textContent = "";
|
|
11595
|
-
|
|
12201
|
+
setLabel(index, labelOf(index));
|
|
11596
12202
|
if (near)
|
|
11597
12203
|
loadSide(s);
|
|
11598
12204
|
readColors();
|
|
@@ -11603,12 +12209,15 @@ function compare(container, options) {
|
|
|
11603
12209
|
stage.insertBefore(sides[1].preview, labels[0]);
|
|
11604
12210
|
stage.insertBefore(sides[0].el, labels[0]);
|
|
11605
12211
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
11606
|
-
|
|
11607
|
-
|
|
12212
|
+
setLabel(0, labelOf(0));
|
|
12213
|
+
setLabel(1, labelOf(1));
|
|
11608
12214
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
11609
12215
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
12216
|
+
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
12217
|
+
rows: () => modeBtns,
|
|
12218
|
+
selected: () => modeBtns[modeList.indexOf(mode)] ?? null
|
|
12219
|
+
}) : null;
|
|
11610
12220
|
syncModeUi();
|
|
11611
|
-
syncFlicker();
|
|
11612
12221
|
const unlisten = tl?.listen({
|
|
11613
12222
|
onSeek: (t, source) => {
|
|
11614
12223
|
if (source === "play") {
|
|
@@ -11666,24 +12275,20 @@ function compare(container, options) {
|
|
|
11666
12275
|
});
|
|
11667
12276
|
root.addEventListener("keydown", onKey);
|
|
11668
12277
|
root.addEventListener("keyup", (e) => {
|
|
11669
|
-
|
|
11670
|
-
if (key === "x")
|
|
11671
|
-
holdFlick(false);
|
|
11672
|
-
else if (key === "z")
|
|
12278
|
+
if (e.key.toLowerCase() === "z")
|
|
11673
12279
|
holdLoupe(false);
|
|
11674
12280
|
});
|
|
11675
12281
|
root.addEventListener("focusout", (e) => {
|
|
11676
12282
|
if (root.contains(e.relatedTarget))
|
|
11677
12283
|
return;
|
|
11678
|
-
holdFlick(false);
|
|
11679
12284
|
holdLoupe(false);
|
|
11680
12285
|
});
|
|
11681
12286
|
const unregisterHints = options.hints === false ? undefined : hints.register(root, () => [
|
|
11682
|
-
...
|
|
12287
|
+
...modeList.length > 1 ? modeList.map((m, i) => ({
|
|
11683
12288
|
el: modeBtns[i],
|
|
11684
|
-
label: m.
|
|
11685
|
-
activate: () => setMode(m
|
|
11686
|
-
})),
|
|
12289
|
+
label: MODE_LABEL[m].long,
|
|
12290
|
+
activate: () => setMode(m)
|
|
12291
|
+
})) : [],
|
|
11687
12292
|
{ el: loopBtn, label: "Loop", activate: () => api.setLoop(!loopNow()) },
|
|
11688
12293
|
...loupeBtn.hidden ? [] : [{ el: loupeBtn, label: "Loupe", activate: () => setLoupe(!loupeOn) }],
|
|
11689
12294
|
...zoomed() ? [{ el: zoomReset, label: "Reset zoom", activate: () => api.setZoom(null) }] : [],
|
|
@@ -11708,6 +12313,7 @@ function compare(container, options) {
|
|
|
11708
12313
|
get mode() {
|
|
11709
12314
|
return mode;
|
|
11710
12315
|
},
|
|
12316
|
+
modes: modeList,
|
|
11711
12317
|
get wipe() {
|
|
11712
12318
|
return wipe;
|
|
11713
12319
|
},
|
|
@@ -11744,11 +12350,11 @@ function compare(container, options) {
|
|
|
11744
12350
|
if (before)
|
|
11745
12351
|
replace(0, before);
|
|
11746
12352
|
else if (next.before)
|
|
11747
|
-
|
|
12353
|
+
setLabel(0, next.before.label ?? "Before");
|
|
11748
12354
|
if (after)
|
|
11749
12355
|
replace(1, after);
|
|
11750
12356
|
else if (next.after)
|
|
11751
|
-
|
|
12357
|
+
setLabel(1, next.after.label ?? "After");
|
|
11752
12358
|
if (before || after)
|
|
11753
12359
|
strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
|
|
11754
12360
|
if (next.before || next.after)
|
|
@@ -11763,7 +12369,7 @@ function compare(container, options) {
|
|
|
11763
12369
|
tl?.update({ fps: next.fps });
|
|
11764
12370
|
requestDraw();
|
|
11765
12371
|
},
|
|
11766
|
-
seek: (t) => tl ? tl.seek(t) : ownSeek(t),
|
|
12372
|
+
seek: (t, o) => tl ? tl.seek(t, o?.glide ? { glide: true } : undefined) : ownSeek(t),
|
|
11767
12373
|
seekBy(d) {
|
|
11768
12374
|
const total = duration || tl?.duration || 0;
|
|
11769
12375
|
const t = Math.min(total, Math.max(0, now() + d));
|
|
@@ -11804,7 +12410,7 @@ function compare(container, options) {
|
|
|
11804
12410
|
dispose() {
|
|
11805
12411
|
disposed = true;
|
|
11806
12412
|
loop.stop();
|
|
11807
|
-
|
|
12413
|
+
modePill?.dispose();
|
|
11808
12414
|
win.clearTimeout(releaseTimer);
|
|
11809
12415
|
ro.disconnect();
|
|
11810
12416
|
nearIo?.disconnect();
|
|
@@ -11834,7 +12440,7 @@ function compare(container, options) {
|
|
|
11834
12440
|
wake();
|
|
11835
12441
|
return api;
|
|
11836
12442
|
}
|
|
11837
|
-
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM,
|
|
12443
|
+
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
11838
12444
|
var init_compare = __esm(() => {
|
|
11839
12445
|
init_motion();
|
|
11840
12446
|
init_page_hints();
|
|
@@ -11842,21 +12448,24 @@ var init_compare = __esm(() => {
|
|
|
11842
12448
|
init_compare_gpu();
|
|
11843
12449
|
init_compare_model();
|
|
11844
12450
|
init_compare_strip();
|
|
12451
|
+
init_icons();
|
|
11845
12452
|
init_look();
|
|
11846
12453
|
init_rgba();
|
|
12454
|
+
init_selection_pill();
|
|
11847
12455
|
init_timeline();
|
|
12456
|
+
init_timeline_model();
|
|
11848
12457
|
LAYOUT2 = springMotion({ duration: 0.35, bounce: 0 });
|
|
11849
12458
|
FADE6 = springMotion(SPRINGS.snappy);
|
|
11850
12459
|
FADE_REDUCED = springMotion(FADE);
|
|
11851
12460
|
ZOOM = springMotion({ duration: 0.35, bounce: 0 });
|
|
12461
|
+
WIPE_CATCH = springMotion(CATCH_UP);
|
|
12462
|
+
GRIP = { w: 16, h: 28 };
|
|
11852
12463
|
LOUPE = { r: 88, zoom: 4 };
|
|
11853
|
-
|
|
11854
|
-
{
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
];
|
|
11859
|
-
KEY_MODE = { s: "side", w: "wipe", d: "difference" };
|
|
12464
|
+
MODE_LABEL = {
|
|
12465
|
+
side: { short: "Side", long: "Side by side" },
|
|
12466
|
+
wipe: { short: "Wipe", long: "Wipe" },
|
|
12467
|
+
difference: { short: "Difference", long: "Difference" }
|
|
12468
|
+
};
|
|
11860
12469
|
});
|
|
11861
12470
|
|
|
11862
12471
|
// src/ui/solid.ts
|
|
@@ -14757,6 +15366,7 @@ init_diff();
|
|
|
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();
|