@kitlangton/knobs 0.4.0-next.3 → 0.4.0-next.5
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 +65 -11
- package/dist/dev/{chunk-8mabjeyk.js → chunk-dyq4m24m.js} +162 -1
- package/dist/dev/{chunk-zwj6yngd.js → chunk-qc6szek7.js} +69 -9
- package/dist/dev/{chunk-j6zmtens.js → chunk-y2axkmz3.js} +2 -2
- package/dist/dev/index.js +3 -3
- package/dist/panel.js +231 -9
- 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 +4 -1
- package/dist/types/ui/compare-model.d.ts +36 -1
- package/dist/types/ui/compare.d.ts +3 -2
- package/dist/types/ui/diff.d.ts +4 -5
- package/dist/types/ui/history-css.d.ts +1 -0
- package/dist/types/ui/history-model.d.ts +249 -0
- package/dist/types/ui/history.d.ts +38 -0
- package/dist/types/ui/index.d.ts +2 -1
- package/dist/types/ui/player-css.d.ts +1 -0
- package/dist/types/ui/player.d.ts +60 -0
- package/dist/types/ui/timeline-model.d.ts +4 -0
- package/dist/types/ui/timeline.d.ts +10 -3
- package/dist/types/ui/walkthrough-blocks.d.ts +38 -1
- package/dist/types/ui/walkthrough-model.d.ts +90 -1
- package/dist/types/ui/walkthrough.d.ts +22 -2
- package/dist/ui-react.js +1858 -832
- package/dist/ui-solid.js +1858 -832
- package/dist/ui.js +2028 -832
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -595,6 +595,8 @@ var compareCss = `
|
|
|
595
595
|
.knobs-cmp-stage{position:relative;flex:1;min-height:96px;overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_ku-cmp-stage);touch-action:pan-y;outline:none}
|
|
596
596
|
.knobs-compare[data-frame="flat"] .knobs-cmp-stage{border-radius:0}
|
|
597
597
|
.knobs-compare[data-mode="wipe"] .knobs-cmp-stage{cursor:ew-resize}
|
|
598
|
+
/* Videos: a click on the stage plays and pauses. */
|
|
599
|
+
.knobs-compare[data-video]:not([data-mode="wipe"],[data-zoomed]) .knobs-cmp-stage{cursor:pointer}
|
|
598
600
|
/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */
|
|
599
601
|
.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}
|
|
600
602
|
.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}
|
|
@@ -604,14 +606,28 @@ var compareCss = `
|
|
|
604
606
|
.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}
|
|
605
607
|
.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}
|
|
606
608
|
.knobs-compare[data-renderer="gpu"] .knobs-cmp-media{opacity:0}
|
|
609
|
+
/* The media comes in with its first frames: a fade and a 4px blur on the default spring. */
|
|
610
|
+
.knobs-cmp-canvas,.knobs-compare[data-renderer="dom"] .knobs-cmp-media{transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}
|
|
611
|
+
.knobs-compare:not([data-ready]) :is(.knobs-cmp-canvas,.knobs-cmp-media){opacity:0;filter:blur(4px)}
|
|
607
612
|
/* Glass: what's behind shows through, blurred, on the knobs tokens. */
|
|
608
613
|
.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);
|
|
609
614
|
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)))}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
.knobs-cmp-
|
|
614
|
-
.knobs-cmp-
|
|
615
|
+
/* ✗ Before · ✓ After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */
|
|
616
|
+
.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);
|
|
617
|
+
white-space:nowrap;pointer-events:none;will-change:transform}
|
|
618
|
+
.knobs-cmp-label[data-side="before"]{color:var(--_k-fg-3)}
|
|
619
|
+
.knobs-cmp-label[data-side="after"]{color:var(--_k-fg)}
|
|
620
|
+
/* Fusing, the mark folds away and the label is its name. */
|
|
621
|
+
.knobs-cmp-mark{flex:none;display:flex;justify-content:flex-end;overflow:hidden}
|
|
622
|
+
.knobs-cmp-mark svg{display:block;flex:none;width:12px;height:12px}
|
|
623
|
+
/* The fuse's seam: a blurred strip over where the sides meet, soft at both sides. */
|
|
624
|
+
.knobs-cmp-seam{position:absolute;left:0;top:0;width:8px;height:0;opacity:0;pointer-events:none;will-change:transform,opacity;
|
|
625
|
+
-webkit-mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent);mask-image:linear-gradient(to right,transparent,#000 35%,#000 65%,transparent)}
|
|
626
|
+
/* The wipe: a hairline down the line with a raised grip in its middle (at the pointer's height
|
|
627
|
+
while dragged); a wider strip takes the hand and the keys (a slider). It fades in with the
|
|
628
|
+
fuse; wiping, line and grip brighten. */
|
|
629
|
+
.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,opacity}
|
|
630
|
+
.knobs-cmp-handle[data-on]{pointer-events:auto}
|
|
615
631
|
.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)}
|
|
616
632
|
.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}
|
|
617
633
|
.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);
|
|
@@ -643,6 +659,27 @@ var compareCss = `
|
|
|
643
659
|
@media(prefers-reduced-motion:reduce){:is(.knobs-compare,.knobs-cmp-strip) :where(*,::before,::after){transition-duration:.12s!important}}
|
|
644
660
|
`;
|
|
645
661
|
|
|
662
|
+
// src/ui/player-css.ts
|
|
663
|
+
var playerCss = `
|
|
664
|
+
:where(.knobs-player,.knobs-player *){box-sizing:border-box}
|
|
665
|
+
.knobs-ui.knobs-player{--_kp-stage:var(--_k-compare-stage);display:flex;flex-direction:column;gap:6px;width:100%;outline:none;
|
|
666
|
+
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
667
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-ui.knobs-player,.knobs-ui.knobs-player[data-nested]{--_kp-stage:var(--k-compare-stage,transparent)}
|
|
668
|
+
.knobs-player-frame{position:relative;width:100%;aspect-ratio:var(--kp-aspect,16/9);overflow:hidden;border-radius:var(--_k-radius-panel);background:var(--_kp-stage);cursor:pointer}
|
|
669
|
+
.knobs-player[data-frame="flat"] .knobs-player-frame{border-radius:0}
|
|
670
|
+
.knobs-player-media{position:absolute;inset:0;display:block;width:100%;height:100%;margin:0;padding:0;border:0;object-fit:contain;
|
|
671
|
+
opacity:0;filter:blur(4px);transition:opacity calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default),filter calc(var(--_k-motion-default-ms) * 1ms) var(--_k-motion-default)}
|
|
672
|
+
.knobs-player[data-ready] .knobs-player-media{opacity:1;filter:none}
|
|
673
|
+
.knobs-player-glyph{position:absolute;left:50%;top:50%;display:grid;place-items:center;width:44px;height:44px;margin:-22px 0 0 -22px;border-radius:50%;color:var(--_k-fg);pointer-events:none;
|
|
674
|
+
opacity:0;filter:blur(4px);scale:.96;
|
|
675
|
+
background:color-mix(in srgb,var(--_k-bg) 52%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.6);backdrop-filter:blur(14px) saturate(1.6);
|
|
676
|
+
box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim);
|
|
677
|
+
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy),filter calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy),scale calc(var(--_k-motion-snappy-ms) * 1ms) var(--_k-motion-snappy)}
|
|
678
|
+
.knobs-player-glyph svg{width:16px;height:16px}
|
|
679
|
+
.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}
|
|
680
|
+
.knobs-player-line{flex:none;min-height:0}
|
|
681
|
+
`;
|
|
682
|
+
|
|
646
683
|
// src/ui/overlay-css.ts
|
|
647
684
|
var overlayCss = `
|
|
648
685
|
.knobs-layers{position:fixed;inset:0;z-index:2147480005;pointer-events:none}
|
|
@@ -1331,6 +1368,22 @@ var init_schema = __esm(() => {
|
|
|
1331
1368
|
source: css("var(--k-warn)"),
|
|
1332
1369
|
doc: "Modified lines."
|
|
1333
1370
|
},
|
|
1371
|
+
{
|
|
1372
|
+
name: "before",
|
|
1373
|
+
tier: "semantic",
|
|
1374
|
+
type: "color",
|
|
1375
|
+
group: "Data",
|
|
1376
|
+
source: css("var(--k-fg-3)"),
|
|
1377
|
+
doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
name: "after",
|
|
1381
|
+
tier: "semantic",
|
|
1382
|
+
type: "color",
|
|
1383
|
+
group: "Data",
|
|
1384
|
+
source: css("var(--k-fg)"),
|
|
1385
|
+
doc: "After in a comparison, and only After."
|
|
1386
|
+
},
|
|
1334
1387
|
{
|
|
1335
1388
|
name: "series-1",
|
|
1336
1389
|
tier: "semantic",
|
|
@@ -1421,6 +1474,150 @@ var init_schema = __esm(() => {
|
|
|
1421
1474
|
source: value("288px"),
|
|
1422
1475
|
doc: "Panel width."
|
|
1423
1476
|
},
|
|
1477
|
+
{
|
|
1478
|
+
name: "space-inside",
|
|
1479
|
+
tier: "semantic",
|
|
1480
|
+
type: "length",
|
|
1481
|
+
group: "Space",
|
|
1482
|
+
source: css("var(--k-unit)"),
|
|
1483
|
+
doc: "Parts of one thing: an icon and its label, a meta line and its title."
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
name: "space-sibling",
|
|
1487
|
+
tier: "semantic",
|
|
1488
|
+
type: "length",
|
|
1489
|
+
group: "Space",
|
|
1490
|
+
source: css("calc(var(--k-unit) * 2)"),
|
|
1491
|
+
doc: "Siblings in a group: buttons in a row, a list item's lines."
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
name: "space-title",
|
|
1495
|
+
tier: "semantic",
|
|
1496
|
+
type: "length",
|
|
1497
|
+
group: "Space",
|
|
1498
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1499
|
+
doc: "A heading and what it heads."
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
name: "space-group",
|
|
1503
|
+
tier: "semantic",
|
|
1504
|
+
type: "length",
|
|
1505
|
+
group: "Space",
|
|
1506
|
+
source: css("calc(var(--k-unit) * 12)"),
|
|
1507
|
+
doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
name: "space-section",
|
|
1511
|
+
tier: "semantic",
|
|
1512
|
+
type: "length",
|
|
1513
|
+
group: "Space",
|
|
1514
|
+
source: css("calc(var(--k-unit) * 24)"),
|
|
1515
|
+
doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
name: "space-column",
|
|
1519
|
+
tier: "semantic",
|
|
1520
|
+
type: "length",
|
|
1521
|
+
group: "Space",
|
|
1522
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1523
|
+
doc: "Columns: a contents rail and the page, media side by side."
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
name: "pad-page",
|
|
1527
|
+
tier: "semantic",
|
|
1528
|
+
type: "length",
|
|
1529
|
+
group: "Space",
|
|
1530
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1531
|
+
doc: "A page's edge; 16px under 640px wide."
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
name: "pad-card",
|
|
1535
|
+
tier: "semantic",
|
|
1536
|
+
type: "length",
|
|
1537
|
+
group: "Space",
|
|
1538
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1539
|
+
doc: "Inside a card or popover."
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
name: "type-heading",
|
|
1543
|
+
tier: "semantic",
|
|
1544
|
+
type: "length",
|
|
1545
|
+
group: "Type",
|
|
1546
|
+
source: value("20px"),
|
|
1547
|
+
doc: "A page's title, weight 500."
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
name: "leading-heading",
|
|
1551
|
+
tier: "semantic",
|
|
1552
|
+
type: "length",
|
|
1553
|
+
group: "Type",
|
|
1554
|
+
source: value("28px"),
|
|
1555
|
+
doc: "Line height for type-heading."
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
name: "type-title",
|
|
1559
|
+
tier: "semantic",
|
|
1560
|
+
type: "length",
|
|
1561
|
+
group: "Type",
|
|
1562
|
+
source: value("16px"),
|
|
1563
|
+
doc: "Section titles (under their kicker), weight 500."
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
name: "leading-title",
|
|
1567
|
+
tier: "semantic",
|
|
1568
|
+
type: "length",
|
|
1569
|
+
group: "Type",
|
|
1570
|
+
source: value("24px"),
|
|
1571
|
+
doc: "Line height for type-title."
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
name: "type-body",
|
|
1575
|
+
tier: "semantic",
|
|
1576
|
+
type: "length",
|
|
1577
|
+
group: "Type",
|
|
1578
|
+
source: value("13px"),
|
|
1579
|
+
doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
name: "leading-body",
|
|
1583
|
+
tier: "semantic",
|
|
1584
|
+
type: "length",
|
|
1585
|
+
group: "Type",
|
|
1586
|
+
source: value("20px"),
|
|
1587
|
+
doc: "Line height for type-body."
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
name: "type-label",
|
|
1591
|
+
tier: "semantic",
|
|
1592
|
+
type: "length",
|
|
1593
|
+
group: "Type",
|
|
1594
|
+
source: value("12px"),
|
|
1595
|
+
doc: "Mono inside body text: code and paths."
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
name: "leading-label",
|
|
1599
|
+
tier: "semantic",
|
|
1600
|
+
type: "length",
|
|
1601
|
+
group: "Type",
|
|
1602
|
+
source: value("16px"),
|
|
1603
|
+
doc: "Line height for type-label."
|
|
1604
|
+
},
|
|
1605
|
+
{
|
|
1606
|
+
name: "type-small",
|
|
1607
|
+
tier: "semantic",
|
|
1608
|
+
type: "length",
|
|
1609
|
+
group: "Type",
|
|
1610
|
+
source: value("11px"),
|
|
1611
|
+
doc: "Meta, controls, keys, timestamps; mono inside labels."
|
|
1612
|
+
},
|
|
1613
|
+
{
|
|
1614
|
+
name: "leading-small",
|
|
1615
|
+
tier: "semantic",
|
|
1616
|
+
type: "length",
|
|
1617
|
+
group: "Type",
|
|
1618
|
+
source: value("16px"),
|
|
1619
|
+
doc: "Line height for type-small."
|
|
1620
|
+
},
|
|
1424
1621
|
{
|
|
1425
1622
|
name: "font-size",
|
|
1426
1623
|
tier: "semantic",
|
|
@@ -2385,16 +2582,18 @@ function injectTokens(doc) {
|
|
|
2385
2582
|
style.textContent = rootCss;
|
|
2386
2583
|
doc.head.append(style);
|
|
2387
2584
|
}
|
|
2388
|
-
var ROOT_CLASS = "knobs-root", extras, spring, rootCss;
|
|
2585
|
+
var ROOT_CLASS = "knobs-root", extras, narrow, spring, rootCss;
|
|
2389
2586
|
var init_root = __esm(() => {
|
|
2390
2587
|
init_knobs();
|
|
2391
2588
|
init_css();
|
|
2392
2589
|
init_glide();
|
|
2393
2590
|
init_motion();
|
|
2394
2591
|
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))}`;
|
|
2592
|
+
narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`;
|
|
2395
2593
|
spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`;
|
|
2396
2594
|
rootCss = `${tokensCss(knobs)}
|
|
2397
2595
|
${extras}
|
|
2596
|
+
${narrow}
|
|
2398
2597
|
${spring}
|
|
2399
2598
|
${DRIVERS}
|
|
2400
2599
|
${motionCss}`;
|
|
@@ -2684,6 +2883,12 @@ var css2 = `
|
|
|
2684
2883
|
--_ku-pane-bg and --_ku-pane-ring so this reaches them. */
|
|
2685
2884
|
: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;
|
|
2686
2885
|
--_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
|
|
2886
|
+
/* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
|
|
2887
|
+
ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
|
|
2888
|
+
card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
|
|
2889
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
|
|
2890
|
+
: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)}
|
|
2891
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
|
|
2687
2892
|
/* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
|
|
2688
2893
|
.knobs-ui{box-sizing:border-box}
|
|
2689
2894
|
: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}
|
|
@@ -2909,8 +3114,6 @@ var css2 = `
|
|
|
2909
3114
|
.knobs-tl-hover{position:absolute;left:0;top:0;bottom:0;width:1px;margin-left:-.5px;background:var(--_k-border-strong);transform:translateX(-100px);pointer-events:none;opacity:0;transition:opacity .15s}
|
|
2910
3115
|
.knobs-tl-track:hover .knobs-tl-hover{opacity:1}
|
|
2911
3116
|
.knobs-timeline[data-scrubbing] .knobs-tl-hover{opacity:0}
|
|
2912
|
-
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
2913
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
2914
3117
|
.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}
|
|
2915
3118
|
.knobs-tl-tag[data-on]{opacity:1}
|
|
2916
3119
|
/* The lane (variant: "lane"): one slim track of ticks under a compare or a video; markers are
|
|
@@ -2926,7 +3129,26 @@ var css2 = `
|
|
|
2926
3129
|
.knobs-timeline[data-variant="lane"] .knobs-tl-head::before{top:0}
|
|
2927
3130
|
.knobs-timeline[data-variant="lane"] .knobs-tl-head::after{content:none}
|
|
2928
3131
|
.knobs-timeline[data-variant="lane"] .knobs-tl-tag{top:2px;bottom:auto}
|
|
2929
|
-
|
|
3132
|
+
/* The line (variant: "line"): a player's progress under its media. One 2px line, fg-3 with fg
|
|
3133
|
+
filling it, a segment per chapter; it thickens under the pointer and while scrubbing. The
|
|
3134
|
+
chapter and time under the pointer float over it; nothing else shows. */
|
|
3135
|
+
.knobs-ui.knobs-timeline[data-variant="line"]{height:auto;min-height:0;padding:0;gap:0}
|
|
3136
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-transport{display:none}
|
|
3137
|
+
.knobs-ui.knobs-timeline[data-variant="line"] .knobs-tl-track{height:16px;overflow:visible;border-radius:var(--_k-radius);background:transparent;box-shadow:none;cursor:pointer}
|
|
3138
|
+
.knobs-timeline[data-variant="line"] :is(.knobs-tl-ruler,.knobs-tl-lane,.knobs-tl-hover,.knobs-tl-head,.knobs-tl-rlabel){display:none}
|
|
3139
|
+
.knobs-tl-segs{position:absolute;left:0;right:0;top:50%;height:2px;margin-top:-1px;pointer-events:none;transition:scale calc(var(--_k-hover-out) * 1ms) var(--_ku-ease)}
|
|
3140
|
+
.knobs-tl-seg{position:absolute;left:0;top:0;height:100%;overflow:hidden;border-radius:1px;background:var(--_k-fg-3);will-change:transform}
|
|
3141
|
+
.knobs-tl-seg-fill{position:absolute;inset:0;background:var(--_k-fg);transform-origin:0 0;will-change:transform}
|
|
3142
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-track:hover .knobs-tl-segs,.knobs-timeline[data-variant="line"][data-scrubbing] .knobs-tl-segs{scale:1 2}
|
|
3143
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-range{top:3px;bottom:3px;border-radius:3px}
|
|
3144
|
+
.knobs-timeline[data-variant="line"]:focus-visible .knobs-tl-track,.knobs-timeline[data-variant="line"][data-keyboard]:focus .knobs-tl-track{background:transparent;box-shadow:0 0 0 2px color-mix(in srgb,var(--_k-accent) 60%,transparent)}
|
|
3145
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-tag{top:auto;bottom:calc(100% + 2px);display:flex;gap:6px;padding:0 6px;border-radius:calc(var(--_k-radius) * 999);background:color-mix(in srgb,var(--_k-bg) 72%,transparent);
|
|
3146
|
+
-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:inset 0 0 0 .5px var(--_k-border)}
|
|
3147
|
+
.knobs-tl-tag-label{color:var(--_k-fg-2)}
|
|
3148
|
+
.knobs-tl-tag-label:empty{display:none}
|
|
3149
|
+
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
3150
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
3151
|
+
`, uiCss = () => aliased(css2 + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + compareCss + playerCss + selectionPillCss) + rolling_css_default, RESTYLED = ".knobs-ui,.knobs-panel,.knobs-chip,.knobs-notice", lookDefaults, tune = (s, m) => {
|
|
2930
3152
|
s.omega = m.omega;
|
|
2931
3153
|
s.zeta = m.zeta;
|
|
2932
3154
|
return s;
|
|
@@ -5305,6 +5527,17 @@ function currentMarker(markers, t, fps) {
|
|
|
5305
5527
|
best = m;
|
|
5306
5528
|
return best;
|
|
5307
5529
|
}
|
|
5530
|
+
function minutes(t) {
|
|
5531
|
+
const s = Math.max(0, Math.floor(t + 0.000001));
|
|
5532
|
+
const h = Math.floor(s / 3600);
|
|
5533
|
+
const m = Math.floor(s % 3600 / 60);
|
|
5534
|
+
const ss = String(s % 60).padStart(2, "0");
|
|
5535
|
+
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
5536
|
+
}
|
|
5537
|
+
function chapterBounds(times, duration) {
|
|
5538
|
+
const inside = times.filter((t) => t > 0.000001 && t < duration - 0.000001);
|
|
5539
|
+
return [0, ...[...new Set(inside)].sort((a, b) => a - b), duration];
|
|
5540
|
+
}
|
|
5308
5541
|
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;
|
|
5309
5542
|
var init_timeline_model = __esm(() => {
|
|
5310
5543
|
SECOND_STEPS = [0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600];
|
|
@@ -5322,7 +5555,8 @@ function timeline(container, options) {
|
|
|
5322
5555
|
let speed = options.speed ?? 1;
|
|
5323
5556
|
let repeat = options.repeat ?? true;
|
|
5324
5557
|
const arrows = options.arrows ?? "frames";
|
|
5325
|
-
const
|
|
5558
|
+
const line = options.variant === "line";
|
|
5559
|
+
const lane = line || options.variant === "lane";
|
|
5326
5560
|
let time = Math.min(duration, Math.max(0, options.time ?? 0));
|
|
5327
5561
|
let playing = false;
|
|
5328
5562
|
let markers = [...options.markers ?? []];
|
|
@@ -5357,7 +5591,7 @@ function timeline(container, options) {
|
|
|
5357
5591
|
root.setAttribute("aria-keyshortcuts", "Space ArrowLeft ArrowRight , . Home End [ ] I O M");
|
|
5358
5592
|
applyLook2(root, options);
|
|
5359
5593
|
if (lane)
|
|
5360
|
-
root.dataset.variant = "lane";
|
|
5594
|
+
root.dataset.variant = line ? "line" : "lane";
|
|
5361
5595
|
const transport = el("div", "knobs-tl-transport");
|
|
5362
5596
|
const playBtn = el("button", "knobs-tl-play");
|
|
5363
5597
|
playBtn.type = "button";
|
|
@@ -5370,6 +5604,10 @@ function timeline(container, options) {
|
|
|
5370
5604
|
const hover = el("div", "knobs-tl-hover");
|
|
5371
5605
|
const tag = el("span", "knobs-tl-tag");
|
|
5372
5606
|
tag.setAttribute("aria-hidden", "true");
|
|
5607
|
+
const tagLabel = el("span", "knobs-tl-tag-label");
|
|
5608
|
+
const tagTime = el("span", "knobs-tl-tag-time");
|
|
5609
|
+
tag.append(tagLabel, tagTime);
|
|
5610
|
+
const segs = el("div", "knobs-tl-segs");
|
|
5373
5611
|
const head = el("div", "knobs-tl-head");
|
|
5374
5612
|
head.id = `${id}-head`;
|
|
5375
5613
|
head.setAttribute("role", "slider");
|
|
@@ -5377,11 +5615,13 @@ function timeline(container, options) {
|
|
|
5377
5615
|
head.setAttribute("aria-valuemin", "0");
|
|
5378
5616
|
head.setAttribute("aria-valuemax", String(duration));
|
|
5379
5617
|
track.append(canvas, markerLane, hover, head, tag);
|
|
5618
|
+
if (line)
|
|
5619
|
+
track.insertBefore(segs, markerLane);
|
|
5380
5620
|
root.append(transport, track);
|
|
5381
5621
|
container.append(root);
|
|
5382
5622
|
let width = 1;
|
|
5383
5623
|
let height = 1;
|
|
5384
|
-
const fitView = () => clampView({ start: 0, span: duration }, duration, { pad: 0.02 });
|
|
5624
|
+
const fitView = () => clampView({ start: 0, span: duration }, duration, { pad: line ? 0 : 0.02 });
|
|
5385
5625
|
let target = fitView();
|
|
5386
5626
|
const vStart = new Spring(target.start, INSTANT.omega, 1, 0.00001);
|
|
5387
5627
|
const vSpan = new Spring(target.span, INSTANT.omega, 1, 0.00001);
|
|
@@ -5390,13 +5630,13 @@ function timeline(container, options) {
|
|
|
5390
5630
|
const xOf = (t) => (t - vStart.x) * pxPerSec();
|
|
5391
5631
|
const tOf = (x) => vStart.x + x / pxPerSec();
|
|
5392
5632
|
const minSpan = () => Math.max(4 / fps, 0.05);
|
|
5393
|
-
const retarget = (next, motion = INSTANT) => {
|
|
5394
|
-
target = clampView(next, duration, { pad: 0.04, minSpan: minSpan() });
|
|
5633
|
+
const retarget = (next, motion = INSTANT, hand = false) => {
|
|
5634
|
+
target = clampView(next, duration, { pad: line ? 0 : 0.04, minSpan: minSpan() });
|
|
5395
5635
|
for (const s of [vStart, vSpan]) {
|
|
5396
5636
|
s.omega = motion.omega;
|
|
5397
5637
|
s.zeta = motion.zeta;
|
|
5398
5638
|
}
|
|
5399
|
-
if (reducedMotion(win) && motion === CALM) {
|
|
5639
|
+
if (hand || reducedMotion(win) && motion === CALM) {
|
|
5400
5640
|
vStart.snap(target.start);
|
|
5401
5641
|
vSpan.snap(target.span);
|
|
5402
5642
|
} else {
|
|
@@ -5422,6 +5662,8 @@ function timeline(container, options) {
|
|
|
5422
5662
|
};
|
|
5423
5663
|
let drawn = "";
|
|
5424
5664
|
const drawRuler = () => {
|
|
5665
|
+
if (line)
|
|
5666
|
+
return;
|
|
5425
5667
|
const v = view();
|
|
5426
5668
|
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${height}:${units}:${fps}`;
|
|
5427
5669
|
if (key === drawn)
|
|
@@ -5509,6 +5751,8 @@ function timeline(container, options) {
|
|
|
5509
5751
|
n.title = `${m.label ? `${m.label} · ` : ""}${clock(m.time)}`;
|
|
5510
5752
|
}
|
|
5511
5753
|
placeMarkers();
|
|
5754
|
+
if (line)
|
|
5755
|
+
syncSegments();
|
|
5512
5756
|
};
|
|
5513
5757
|
const placeMarkers = () => {
|
|
5514
5758
|
for (const m of markers) {
|
|
@@ -5517,6 +5761,36 @@ function timeline(container, options) {
|
|
|
5517
5761
|
n.style.transform = `translateX(${xOf(m.time).toFixed(2)}px)`;
|
|
5518
5762
|
}
|
|
5519
5763
|
};
|
|
5764
|
+
let bounds = [];
|
|
5765
|
+
const segEls = [];
|
|
5766
|
+
const syncSegments = () => {
|
|
5767
|
+
bounds = chapterBounds(markers.map((m) => m.time), duration);
|
|
5768
|
+
while (segEls.length > bounds.length - 1)
|
|
5769
|
+
segEls.pop().el.remove();
|
|
5770
|
+
while (segEls.length < bounds.length - 1) {
|
|
5771
|
+
const n = el("i", "knobs-tl-seg");
|
|
5772
|
+
const fill = el("b", "knobs-tl-seg-fill");
|
|
5773
|
+
n.append(fill);
|
|
5774
|
+
segs.append(n);
|
|
5775
|
+
segEls.push({ el: n, fill });
|
|
5776
|
+
}
|
|
5777
|
+
placeSegments();
|
|
5778
|
+
};
|
|
5779
|
+
const placeSegments = () => {
|
|
5780
|
+
if (!line)
|
|
5781
|
+
return;
|
|
5782
|
+
const last = segEls.length - 1;
|
|
5783
|
+
segEls.forEach((s, i) => {
|
|
5784
|
+
const a = bounds[i];
|
|
5785
|
+
const b = bounds[i + 1];
|
|
5786
|
+
const x0 = xOf(a) + (i > 0 ? SEG_GAP / 2 : 0);
|
|
5787
|
+
const x1 = xOf(b) - (i < last ? SEG_GAP / 2 : 0);
|
|
5788
|
+
s.el.style.transform = `translateX(${x0.toFixed(2)}px)`;
|
|
5789
|
+
s.el.style.width = `${Math.max(0, x1 - x0).toFixed(2)}px`;
|
|
5790
|
+
const k = Math.min(1, Math.max(0, (shownHead - a) / Math.max(0.000000001, b - a)));
|
|
5791
|
+
s.fill.style.transform = `scaleX(${k.toFixed(4)})`;
|
|
5792
|
+
});
|
|
5793
|
+
};
|
|
5520
5794
|
const syncRanges = () => {
|
|
5521
5795
|
const keep = new Set(ranges.map((r) => r.id));
|
|
5522
5796
|
for (const [k, n] of rangeEls)
|
|
@@ -5533,7 +5807,7 @@ function timeline(container, options) {
|
|
|
5533
5807
|
b.dataset.edge = "end";
|
|
5534
5808
|
const label = el("span", "knobs-tl-rlabel");
|
|
5535
5809
|
n.append(label, a, b);
|
|
5536
|
-
track.insertBefore(n, markerLane);
|
|
5810
|
+
track.insertBefore(n, line ? segs : markerLane);
|
|
5537
5811
|
rangeEls.set(r.id, n);
|
|
5538
5812
|
if (built)
|
|
5539
5813
|
enter(n);
|
|
@@ -5585,6 +5859,7 @@ function timeline(container, options) {
|
|
|
5585
5859
|
let currentId = null;
|
|
5586
5860
|
const renderHead = () => {
|
|
5587
5861
|
head.style.transform = `translateX(${xOf(shownHead).toFixed(2)}px)`;
|
|
5862
|
+
placeSegments();
|
|
5588
5863
|
head.setAttribute("aria-valuenow", time.toFixed(3));
|
|
5589
5864
|
head.setAttribute("aria-valuetext", `${time.toFixed(2)} seconds, frame ${toFrame(time, fps)}`);
|
|
5590
5865
|
const cur = currentMarker(markers, time, fps)?.id ?? null;
|
|
@@ -5848,14 +6123,25 @@ function timeline(container, options) {
|
|
|
5848
6123
|
setTime(s.t, "scrub", s.shown, press);
|
|
5849
6124
|
root.toggleAttribute("data-stuck", s.stop !== null);
|
|
5850
6125
|
};
|
|
6126
|
+
let pointerX = null;
|
|
6127
|
+
const zoomAtHand = (factor) => zoom(factor, pointerX === null ? time : target.start + pointerX / width * target.span);
|
|
5851
6128
|
const showTag = (x) => {
|
|
5852
6129
|
const at = Math.min(duration, Math.max(0, tOf(x)));
|
|
5853
|
-
const text = `${at.toFixed(2)} s`;
|
|
5854
|
-
if (
|
|
5855
|
-
|
|
6130
|
+
const text = line ? minutes(at) : `${at.toFixed(2)} s`;
|
|
6131
|
+
if (tagTime.textContent !== text)
|
|
6132
|
+
tagTime.textContent = text;
|
|
6133
|
+
const label = line ? currentMarker(markers, at, fps)?.label ?? "" : "";
|
|
6134
|
+
if (tagLabel.textContent !== label)
|
|
6135
|
+
tagLabel.textContent = label;
|
|
5856
6136
|
const cx = Math.min(width, Math.max(0, x));
|
|
5857
|
-
|
|
5858
|
-
|
|
6137
|
+
if (line) {
|
|
6138
|
+
const w = tag.offsetWidth;
|
|
6139
|
+
const left = Math.min(Math.max(0, width - w), Math.max(0, cx - w / 2));
|
|
6140
|
+
tag.style.transform = `translateX(${left.toFixed(1)}px)`;
|
|
6141
|
+
} else {
|
|
6142
|
+
const flip = cx > width - tag.offsetWidth - 12;
|
|
6143
|
+
tag.style.transform = `translateX(${cx.toFixed(1)}px) translateX(${flip ? "calc(-100% - 4px)" : "4px"})`;
|
|
6144
|
+
}
|
|
5859
6145
|
tag.dataset.on = "";
|
|
5860
6146
|
};
|
|
5861
6147
|
const hideTag = () => delete tag.dataset.on;
|
|
@@ -5916,6 +6202,7 @@ function timeline(container, options) {
|
|
|
5916
6202
|
});
|
|
5917
6203
|
track.addEventListener("pointermove", (e) => {
|
|
5918
6204
|
const x = localX(e);
|
|
6205
|
+
pointerX = x;
|
|
5919
6206
|
hover.style.transform = `translateX(${x.toFixed(1)}px)`;
|
|
5920
6207
|
if (!drag || drag.kind === "scrub")
|
|
5921
6208
|
showTag(x);
|
|
@@ -5989,6 +6276,7 @@ function timeline(container, options) {
|
|
|
5989
6276
|
track.addEventListener("pointercancel", endDrag);
|
|
5990
6277
|
track.addEventListener("lostpointercapture", endDrag);
|
|
5991
6278
|
track.addEventListener("pointerleave", () => {
|
|
6279
|
+
pointerX = null;
|
|
5992
6280
|
if (drag)
|
|
5993
6281
|
return;
|
|
5994
6282
|
hover.style.transform = "translateX(-100px)";
|
|
@@ -5996,7 +6284,7 @@ function timeline(container, options) {
|
|
|
5996
6284
|
});
|
|
5997
6285
|
track.addEventListener("dblclick", (e) => {
|
|
5998
6286
|
if (lane)
|
|
5999
|
-
return;
|
|
6287
|
+
return fit();
|
|
6000
6288
|
const markerEl = e.target.closest(".knobs-tl-marker");
|
|
6001
6289
|
if (markerEl)
|
|
6002
6290
|
return rename(markerEl.dataset.id);
|
|
@@ -6007,18 +6295,40 @@ function timeline(container, options) {
|
|
|
6007
6295
|
rename(m.id);
|
|
6008
6296
|
});
|
|
6009
6297
|
track.addEventListener("wheel", (e) => {
|
|
6010
|
-
|
|
6298
|
+
const zooming = e.ctrlKey || e.metaKey;
|
|
6299
|
+
if (zooming && pinching)
|
|
6300
|
+
return e.preventDefault();
|
|
6301
|
+
const sideways = Math.abs(e.deltaX) > Math.abs(e.deltaY);
|
|
6302
|
+
if (lane && !zooming && !sideways)
|
|
6011
6303
|
return;
|
|
6012
6304
|
e.preventDefault();
|
|
6013
6305
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? height : 1;
|
|
6014
|
-
if (
|
|
6306
|
+
if (zooming) {
|
|
6015
6307
|
const at = target.start + localX(e) / width * target.span;
|
|
6016
|
-
|
|
6308
|
+
const k = Math.exp(-e.deltaY * scale * (e.ctrlKey ? 0.01 : 0.002));
|
|
6309
|
+
retarget(zoomView(target, k, at), INSTANT, lane);
|
|
6017
6310
|
} else {
|
|
6018
|
-
const d = (
|
|
6019
|
-
retarget({ ...target, start: target.start + d / width * target.span });
|
|
6311
|
+
const d = (sideways ? e.deltaX : e.deltaY) * scale;
|
|
6312
|
+
retarget({ ...target, start: target.start + d / width * target.span }, INSTANT, lane);
|
|
6020
6313
|
}
|
|
6021
6314
|
}, { passive: false });
|
|
6315
|
+
let pinchScale = 1;
|
|
6316
|
+
let pinching = false;
|
|
6317
|
+
const onGesture = (e) => {
|
|
6318
|
+
const g = e;
|
|
6319
|
+
e.preventDefault();
|
|
6320
|
+
if (e.type === "gesturestart")
|
|
6321
|
+
pinchScale = 1;
|
|
6322
|
+
pinching = e.type !== "gestureend";
|
|
6323
|
+
if (e.type !== "gesturechange")
|
|
6324
|
+
return;
|
|
6325
|
+
const s = g.scale ?? 1;
|
|
6326
|
+
const x = g.clientX !== undefined ? localX({ clientX: g.clientX }) : width / 2;
|
|
6327
|
+
retarget(zoomView(target, s / pinchScale, target.start + x / width * target.span), INSTANT, true);
|
|
6328
|
+
pinchScale = s;
|
|
6329
|
+
};
|
|
6330
|
+
for (const type of ["gesturestart", "gesturechange", "gestureend"])
|
|
6331
|
+
track.addEventListener(type, onGesture);
|
|
6022
6332
|
root.addEventListener("keydown", (e) => {
|
|
6023
6333
|
if (e.target !== root || e.metaKey || e.ctrlKey) {
|
|
6024
6334
|
if ((e.metaKey || e.ctrlKey) && (e.key === "=" || e.key === "-" || e.key === "0") && e.target === root) {
|
|
@@ -6026,7 +6336,7 @@ function timeline(container, options) {
|
|
|
6026
6336
|
if (e.key === "0")
|
|
6027
6337
|
fit();
|
|
6028
6338
|
else
|
|
6029
|
-
|
|
6339
|
+
zoomAtHand(e.key === "=" ? 1.5 : 1 / 1.5);
|
|
6030
6340
|
}
|
|
6031
6341
|
return;
|
|
6032
6342
|
}
|
|
@@ -6108,18 +6418,12 @@ function timeline(container, options) {
|
|
|
6108
6418
|
return;
|
|
6109
6419
|
case "=":
|
|
6110
6420
|
case "+":
|
|
6111
|
-
if (lane)
|
|
6112
|
-
return;
|
|
6113
6421
|
claim();
|
|
6114
|
-
return
|
|
6422
|
+
return zoomAtHand(1.5);
|
|
6115
6423
|
case "-":
|
|
6116
|
-
if (lane)
|
|
6117
|
-
return;
|
|
6118
6424
|
claim();
|
|
6119
|
-
return
|
|
6425
|
+
return zoomAtHand(1 / 1.5);
|
|
6120
6426
|
case "0":
|
|
6121
|
-
if (lane)
|
|
6122
|
-
return;
|
|
6123
6427
|
claim();
|
|
6124
6428
|
return fit();
|
|
6125
6429
|
}
|
|
@@ -6335,7 +6639,7 @@ function timeline(container, options) {
|
|
|
6335
6639
|
};
|
|
6336
6640
|
return api;
|
|
6337
6641
|
}
|
|
6338
|
-
var RULER = 22, INSTANT, CALM, GLIDE, uid2 = 0, PLAY = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M5 3.6v8.8c0 .5.5.8.9.5l6.6-4.4c.4-.3.4-.8 0-1L5.9 3.1c-.4-.3-.9 0-.9.5Z" fill="currentColor"/></svg>', PAUSE = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="4" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/><rect x="9.2" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/></svg>';
|
|
6642
|
+
var RULER = 22, SEG_GAP = 3, INSTANT, CALM, GLIDE, uid2 = 0, PLAY = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M5 3.6v8.8c0 .5.5.8.9.5l6.6-4.4c.4-.3.4-.8 0-1L5.9 3.1c-.4-.3-.9 0-.9.5Z" fill="currentColor"/></svg>', PAUSE = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="4" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/><rect x="9.2" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/></svg>';
|
|
6339
6643
|
var init_timeline = __esm(() => {
|
|
6340
6644
|
init_rgba();
|
|
6341
6645
|
init_motion();
|
|
@@ -6407,15 +6711,28 @@ function compareLayout(box, before, after) {
|
|
|
6407
6711
|
const shape = after.w > 0 && after.h > 0 ? after : before;
|
|
6408
6712
|
const pair = letterbox({ w: shape.w * 2, h: shape.h }, box);
|
|
6409
6713
|
const half = pair.w / 2;
|
|
6714
|
+
const fused = { x: pair.x + half / 2, y: pair.y, w: half, h: pair.h };
|
|
6410
6715
|
return {
|
|
6411
6716
|
side: {
|
|
6412
6717
|
before: letterbox(before, { x: pair.x, y: pair.y, w: half, h: pair.h }),
|
|
6413
6718
|
after: letterbox(after, { x: pair.x + half, y: pair.y, w: half, h: pair.h }),
|
|
6414
6719
|
split: pair.x + half
|
|
6415
6720
|
},
|
|
6416
|
-
overlay: { before: letterbox(before,
|
|
6721
|
+
overlay: { before: letterbox(before, fused), after: letterbox(after, fused) }
|
|
6417
6722
|
};
|
|
6418
6723
|
}
|
|
6724
|
+
function fuseFrame(L, before, after, k, wipe) {
|
|
6725
|
+
const t = Math.min(1, Math.max(0, k));
|
|
6726
|
+
const o = L.overlay;
|
|
6727
|
+
const left = Math.min(o.before.x, o.after.x);
|
|
6728
|
+
const line = wipeX({ x: left, y: 0, w: Math.max(o.before.x + o.before.w, o.after.x + o.after.w) - left, h: 0 }, wipe);
|
|
6729
|
+
const cut = L.side.split + (line - L.side.split) * t;
|
|
6730
|
+
const contact = Math.max(0, Math.min(cut - after.x, before.x + before.w - cut));
|
|
6731
|
+
const feather = Math.min(contact, 1 + FUSE.feather * Math.sin(Math.PI * t));
|
|
6732
|
+
const overlap = before.x + before.w - after.x;
|
|
6733
|
+
const seam = t > 0.001 && overlap >= 0 ? Math.min(1, Math.max(0, overlap / FUSE.seamFade)) * Math.min(1, t * 4) : 0;
|
|
6734
|
+
return { cut, feather, seam, blur: t < 0.995 ? FUSE.blur * (1 - t) : 0 };
|
|
6735
|
+
}
|
|
6419
6736
|
function clampZoom(r) {
|
|
6420
6737
|
const w = Math.min(1, Math.max(1 / ZOOM_MAX, r.w));
|
|
6421
6738
|
const u = Math.min(1 - w, Math.max(0, r.u));
|
|
@@ -6501,7 +6818,15 @@ function stripPeaks(diffs, o = {}) {
|
|
|
6501
6818
|
});
|
|
6502
6819
|
return out;
|
|
6503
6820
|
}
|
|
6504
|
-
var ALL_MODES, MODE_KEYS, modeKey = (mode) => MODE_KEYS[mode].toUpperCase(), VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), lastFrame = (duration, fps) => Math.max(0, Math.ceil(duration * fps - 0.0001) - 1), seekTime = (t, fps, duration) => frameMidpoint(frameOf(t, fps), fps, duration), sameFrame = (a, b, fps) => frameOf(a, fps) === frameOf(b, fps), SEEK_IDLE,
|
|
6821
|
+
var ALL_MODES, MODE_KEYS, modeKey = (mode) => MODE_KEYS[mode].toUpperCase(), VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), lastFrame = (duration, fps) => Math.max(0, Math.ceil(duration * fps - 0.0001) - 1), seekTime = (t, fps, duration) => frameMidpoint(frameOf(t, fps), fps, duration), sameFrame = (a, b, fps) => frameOf(a, fps) === frameOf(b, fps), SEEK_IDLE, FUSE, labelFold = (fold, mark, blur = 3) => {
|
|
6822
|
+
const f = Math.min(1, Math.max(0, fold));
|
|
6823
|
+
const open = 1 - f;
|
|
6824
|
+
return {
|
|
6825
|
+
width: mark * open,
|
|
6826
|
+
opacity: Math.min(1, Math.max(0, (open - 0.2) / 0.8)),
|
|
6827
|
+
blur: blur * Math.min(1, Math.max(0, (f - 0.25) / 0.75))
|
|
6828
|
+
};
|
|
6829
|
+
}, 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({
|
|
6505
6830
|
u: r.u - dx / Math.max(1, base.w) * r.w,
|
|
6506
6831
|
v: r.v - dy / Math.max(1, base.h) * r.h,
|
|
6507
6832
|
w: r.w
|
|
@@ -6524,6 +6849,7 @@ var init_compare_model = __esm(() => {
|
|
|
6524
6849
|
MODE_KEYS = { side: "s", wipe: "w", difference: "d" };
|
|
6525
6850
|
VIDEO = /\.(mp4|m4v|mov|webm|ogv|mkv)$/i;
|
|
6526
6851
|
SEEK_IDLE = { seeking: false, pending: null };
|
|
6852
|
+
FUSE = { feather: 24, blur: 4, seamFade: 48 };
|
|
6527
6853
|
ZOOM_FIT = { u: 0, v: 0, w: 1, h: 1 };
|
|
6528
6854
|
});
|
|
6529
6855
|
|
|
@@ -7418,11 +7744,6 @@ fn pm(c: vec4f) -> vec4f { return vec4f(c.rgb * c.a, c.a); }
|
|
|
7418
7744
|
|
|
7419
7745
|
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
7420
7746
|
switch mode {
|
|
7421
|
-
case 1u: {
|
|
7422
|
-
let s = max(u.wipe.y, 0.5);
|
|
7423
|
-
let m = smoothstep(u.wipe.x - s, u.wipe.x + s, p.x);
|
|
7424
|
-
return pm(vec4f(mix(a.rgb, b.rgb, m), mix(a.a, b.a, m)));
|
|
7425
|
-
}
|
|
7426
7747
|
case 2u: {
|
|
7427
7748
|
let d = abs(a.rgb - b.rgb);
|
|
7428
7749
|
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);
|
|
@@ -7431,8 +7752,10 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
|
7431
7752
|
}
|
|
7432
7753
|
default: {}
|
|
7433
7754
|
}
|
|
7434
|
-
// Side by side
|
|
7435
|
-
|
|
7755
|
+
// Side by side, fusing and wiping: Before over After, cut at the seam with its feather.
|
|
7756
|
+
let s = max(u.wipe.y, 0.5);
|
|
7757
|
+
let ka = a.a * (1.0 - smoothstep(u.wipe.x - s, u.wipe.x + s, p.x));
|
|
7758
|
+
return vec4f(a.rgb * ka + b.rgb * b.a * (1.0 - ka), ka + b.a * (1.0 - ka));
|
|
7436
7759
|
}
|
|
7437
7760
|
|
|
7438
7761
|
@fragment fn fs(@builtin(position) q: vec4f) -> @location(0) vec4f {
|
|
@@ -7834,6 +8157,196 @@ var init_compare_strip = __esm(() => {
|
|
|
7834
8157
|
DIFF = { w: 32, h: 18 };
|
|
7835
8158
|
});
|
|
7836
8159
|
|
|
8160
|
+
// src/ui/player.ts
|
|
8161
|
+
function player(container, options) {
|
|
8162
|
+
const doc = container.ownerDocument;
|
|
8163
|
+
const el = (tag, cls) => {
|
|
8164
|
+
const n = doc.createElement(tag);
|
|
8165
|
+
n.className = cls;
|
|
8166
|
+
return n;
|
|
8167
|
+
};
|
|
8168
|
+
const look = {
|
|
8169
|
+
...options.preset ? { preset: options.preset } : {},
|
|
8170
|
+
...options.theme ? { theme: options.theme } : {},
|
|
8171
|
+
...options.appearance ? { appearance: options.appearance } : {}
|
|
8172
|
+
};
|
|
8173
|
+
const root = el("div", "knobs-player");
|
|
8174
|
+
root.setAttribute("role", "group");
|
|
8175
|
+
root.setAttribute("aria-label", options.label ?? "Video");
|
|
8176
|
+
applyLook2(root, options);
|
|
8177
|
+
const frame = el("div", "knobs-player-frame");
|
|
8178
|
+
frame.style.setProperty("--kp-aspect", String(options.aspect ?? 16 / 9));
|
|
8179
|
+
const v = el("video", "knobs-player-media");
|
|
8180
|
+
v.muted = options.muted ?? true;
|
|
8181
|
+
v.defaultMuted = v.muted;
|
|
8182
|
+
v.playsInline = true;
|
|
8183
|
+
v.preload = "metadata";
|
|
8184
|
+
v.setAttribute("playsinline", "");
|
|
8185
|
+
if (options.poster)
|
|
8186
|
+
v.poster = options.poster;
|
|
8187
|
+
if (options.captions) {
|
|
8188
|
+
const track = doc.createElement("track");
|
|
8189
|
+
track.kind = "captions";
|
|
8190
|
+
track.label = "Captions";
|
|
8191
|
+
track.srclang = doc.documentElement.lang || "en";
|
|
8192
|
+
track.default = true;
|
|
8193
|
+
track.src = options.captions;
|
|
8194
|
+
v.append(track);
|
|
8195
|
+
}
|
|
8196
|
+
const glyph = playGlyph(doc);
|
|
8197
|
+
frame.append(v, glyph.element);
|
|
8198
|
+
const host = el("div", "knobs-player-line");
|
|
8199
|
+
root.append(frame, host);
|
|
8200
|
+
container.append(root);
|
|
8201
|
+
const markers = (options.chapters ?? []).map((c, i) => ({
|
|
8202
|
+
id: c.id ?? `c${i}`,
|
|
8203
|
+
time: c.start,
|
|
8204
|
+
label: c.label
|
|
8205
|
+
}));
|
|
8206
|
+
const tl = timeline(host, {
|
|
8207
|
+
...look,
|
|
8208
|
+
variant: "line",
|
|
8209
|
+
duration: 1,
|
|
8210
|
+
fps: options.fps ?? 30,
|
|
8211
|
+
markers,
|
|
8212
|
+
repeat: options.loop ?? true,
|
|
8213
|
+
arrows: { step: 5, shift: 10 },
|
|
8214
|
+
label: options.label ? `${options.label} time` : "Video time",
|
|
8215
|
+
...options.hints === false ? { hints: false } : {}
|
|
8216
|
+
});
|
|
8217
|
+
const onFrame = () => root.setAttribute("data-ready", "");
|
|
8218
|
+
let pending = null;
|
|
8219
|
+
const seekVideo = (t) => {
|
|
8220
|
+
if (v.readyState < 1)
|
|
8221
|
+
return;
|
|
8222
|
+
if (v.seeking)
|
|
8223
|
+
pending = t;
|
|
8224
|
+
else
|
|
8225
|
+
v.currentTime = t;
|
|
8226
|
+
};
|
|
8227
|
+
let reported = 0;
|
|
8228
|
+
const onSeeked = () => {
|
|
8229
|
+
if (pending !== null) {
|
|
8230
|
+
const t = pending;
|
|
8231
|
+
pending = null;
|
|
8232
|
+
v.currentTime = t;
|
|
8233
|
+
return;
|
|
8234
|
+
}
|
|
8235
|
+
if (!v.paused || tl.playing || Math.abs(v.currentTime - reported) < 0.1)
|
|
8236
|
+
return;
|
|
8237
|
+
reported = v.currentTime;
|
|
8238
|
+
options.onSeek?.(reported);
|
|
8239
|
+
};
|
|
8240
|
+
const onMeta = () => {
|
|
8241
|
+
onFrame();
|
|
8242
|
+
if (v.videoWidth)
|
|
8243
|
+
frame.style.setProperty("--kp-aspect", String(v.videoWidth / v.videoHeight));
|
|
8244
|
+
if (Number.isFinite(v.duration))
|
|
8245
|
+
tl.update({ duration: v.duration });
|
|
8246
|
+
};
|
|
8247
|
+
v.addEventListener("loadedmetadata", onMeta);
|
|
8248
|
+
v.addEventListener("loadeddata", onFrame);
|
|
8249
|
+
v.addEventListener("seeked", onSeeked);
|
|
8250
|
+
const unlisten = tl.listen({
|
|
8251
|
+
onSeek(t, source) {
|
|
8252
|
+
if (source === "play") {
|
|
8253
|
+
if (Math.abs(v.currentTime - t) > 0.25)
|
|
8254
|
+
v.currentTime = t;
|
|
8255
|
+
return;
|
|
8256
|
+
}
|
|
8257
|
+
if (Math.abs(v.currentTime - t) < 1 / (options.fps ?? 30))
|
|
8258
|
+
return;
|
|
8259
|
+
seekVideo(t);
|
|
8260
|
+
},
|
|
8261
|
+
onPlay(on) {
|
|
8262
|
+
if (on)
|
|
8263
|
+
v.play().catch(() => tl.pause());
|
|
8264
|
+
else {
|
|
8265
|
+
v.pause();
|
|
8266
|
+
reported = tl.time;
|
|
8267
|
+
}
|
|
8268
|
+
root.toggleAttribute("data-playing", on);
|
|
8269
|
+
options.onPlay?.(on, tl.time);
|
|
8270
|
+
},
|
|
8271
|
+
onScrub(on) {
|
|
8272
|
+
if (on)
|
|
8273
|
+
v.pause();
|
|
8274
|
+
}
|
|
8275
|
+
});
|
|
8276
|
+
tl.drive(() => {
|
|
8277
|
+
if (v.readyState < 1)
|
|
8278
|
+
return Number.NaN;
|
|
8279
|
+
if (v.seeking)
|
|
8280
|
+
return tl.time;
|
|
8281
|
+
return v.ended ? Number.POSITIVE_INFINITY : v.currentTime;
|
|
8282
|
+
});
|
|
8283
|
+
const onClick = (e) => {
|
|
8284
|
+
if (e.button !== 0)
|
|
8285
|
+
return;
|
|
8286
|
+
tl.toggle();
|
|
8287
|
+
glyph.flash(tl.playing);
|
|
8288
|
+
tl.focus();
|
|
8289
|
+
};
|
|
8290
|
+
frame.addEventListener("click", onClick);
|
|
8291
|
+
v.src = options.src;
|
|
8292
|
+
const api = {
|
|
8293
|
+
element: root,
|
|
8294
|
+
video: v,
|
|
8295
|
+
timeline: tl,
|
|
8296
|
+
get time() {
|
|
8297
|
+
return tl.time;
|
|
8298
|
+
},
|
|
8299
|
+
get playing() {
|
|
8300
|
+
return tl.playing;
|
|
8301
|
+
},
|
|
8302
|
+
get duration() {
|
|
8303
|
+
return Number.isFinite(v.duration) ? v.duration : 0;
|
|
8304
|
+
},
|
|
8305
|
+
play: () => tl.play(),
|
|
8306
|
+
pause: () => tl.pause(),
|
|
8307
|
+
toggle: () => tl.toggle(),
|
|
8308
|
+
seek: (t, o) => tl.seek(t, o?.glide ? { glide: true } : undefined),
|
|
8309
|
+
seekBy: (d) => tl.seek(Math.min(tl.duration, Math.max(0, tl.time + d)), { glide: true }),
|
|
8310
|
+
focus: () => tl.focus(),
|
|
8311
|
+
dispose() {
|
|
8312
|
+
unlisten();
|
|
8313
|
+
glyph.dispose();
|
|
8314
|
+
tl.drive(null);
|
|
8315
|
+
tl.dispose();
|
|
8316
|
+
v.pause();
|
|
8317
|
+
v.removeEventListener("loadedmetadata", onMeta);
|
|
8318
|
+
v.removeEventListener("loadeddata", onFrame);
|
|
8319
|
+
v.removeEventListener("seeked", onSeeked);
|
|
8320
|
+
v.removeAttribute("src");
|
|
8321
|
+
v.load();
|
|
8322
|
+
root.remove();
|
|
8323
|
+
}
|
|
8324
|
+
};
|
|
8325
|
+
return api;
|
|
8326
|
+
}
|
|
8327
|
+
function playGlyph(doc) {
|
|
8328
|
+
const element = doc.createElement("span");
|
|
8329
|
+
element.className = "knobs-player-glyph";
|
|
8330
|
+
element.setAttribute("aria-hidden", "true");
|
|
8331
|
+
let timer = 0;
|
|
8332
|
+
const win = doc.defaultView;
|
|
8333
|
+
return {
|
|
8334
|
+
element,
|
|
8335
|
+
flash(playing) {
|
|
8336
|
+
element.innerHTML = playing ? PLAY : PAUSE;
|
|
8337
|
+
element.setAttribute("data-flash", "");
|
|
8338
|
+
win.clearTimeout(timer);
|
|
8339
|
+
timer = win.setTimeout(() => element.removeAttribute("data-flash"), FLASH_MS);
|
|
8340
|
+
},
|
|
8341
|
+
dispose: () => win.clearTimeout(timer)
|
|
8342
|
+
};
|
|
8343
|
+
}
|
|
8344
|
+
var FLASH_MS = 450;
|
|
8345
|
+
var init_player = __esm(() => {
|
|
8346
|
+
init_look();
|
|
8347
|
+
init_timeline();
|
|
8348
|
+
});
|
|
8349
|
+
|
|
7837
8350
|
// src/ui/compare.ts
|
|
7838
8351
|
function compare(container, options) {
|
|
7839
8352
|
const doc = container.ownerDocument;
|
|
@@ -7930,6 +8443,19 @@ function compare(container, options) {
|
|
|
7930
8443
|
const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
|
|
7931
8444
|
labels[0].dataset.side = "before";
|
|
7932
8445
|
labels[1].dataset.side = "after";
|
|
8446
|
+
const setLabel = (index, text) => {
|
|
8447
|
+
const l = labels[index];
|
|
8448
|
+
if (!l.firstElementChild) {
|
|
8449
|
+
const mark = el("span", "knobs-cmp-mark");
|
|
8450
|
+
mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
|
|
8451
|
+
l.append(mark, el("span", "knobs-cmp-name"));
|
|
8452
|
+
}
|
|
8453
|
+
const name = l.lastElementChild;
|
|
8454
|
+
if (name.textContent !== text)
|
|
8455
|
+
name.textContent = text;
|
|
8456
|
+
};
|
|
8457
|
+
const seam = el("div", "knobs-cmp-seam");
|
|
8458
|
+
seam.setAttribute("aria-hidden", "true");
|
|
7933
8459
|
const handle = el("div", "knobs-cmp-handle");
|
|
7934
8460
|
handle.setAttribute("role", "slider");
|
|
7935
8461
|
handle.setAttribute("aria-label", "Wipe");
|
|
@@ -7939,7 +8465,8 @@ function compare(container, options) {
|
|
|
7939
8465
|
grip.setAttribute("aria-hidden", "true");
|
|
7940
8466
|
handle.append(grip);
|
|
7941
8467
|
const note = el("div", "knobs-cmp-note");
|
|
7942
|
-
|
|
8468
|
+
const glyph = playGlyph(doc);
|
|
8469
|
+
stage.append(canvas, split, seam, labels[0], labels[1], handle, zoomPill, note, glyph.element);
|
|
7943
8470
|
root.append(bar, stage);
|
|
7944
8471
|
const wantsStrip = options.strip === true;
|
|
7945
8472
|
let tl = bound;
|
|
@@ -7954,7 +8481,7 @@ function compare(container, options) {
|
|
|
7954
8481
|
root.append(host);
|
|
7955
8482
|
tl = timeline(host, {
|
|
7956
8483
|
...look,
|
|
7957
|
-
variant: "
|
|
8484
|
+
variant: "line",
|
|
7958
8485
|
duration: 1,
|
|
7959
8486
|
fps: fps(),
|
|
7960
8487
|
arrows: { step: 0.5, shift: 2 },
|
|
@@ -7975,12 +8502,13 @@ function compare(container, options) {
|
|
|
7975
8502
|
let toMode = mode;
|
|
7976
8503
|
const wipeLine = new Spring(wipe, WIPE_CATCH.omega, WIPE_CATCH.zeta, 0.0001);
|
|
7977
8504
|
let wipeCatching = false;
|
|
7978
|
-
|
|
8505
|
+
const gripAt = new Spring(0.5, LAYOUT.omega, LAYOUT.zeta, 0.0001);
|
|
7979
8506
|
let loupeHeld = false;
|
|
7980
8507
|
let pointer = null;
|
|
7981
8508
|
let drag = null;
|
|
7982
8509
|
const touches = new Map;
|
|
7983
8510
|
let pinch = null;
|
|
8511
|
+
let press = null;
|
|
7984
8512
|
const zu = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
7985
8513
|
const zv = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
7986
8514
|
const zw = new Spring(1, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
@@ -8267,6 +8795,8 @@ function compare(container, options) {
|
|
|
8267
8795
|
for (const s of sides) {
|
|
8268
8796
|
const st = s.el.style;
|
|
8269
8797
|
st.clipPath = "";
|
|
8798
|
+
st.maskImage = "";
|
|
8799
|
+
st.setProperty("-webkit-mask-image", "");
|
|
8270
8800
|
st.mixBlendMode = "";
|
|
8271
8801
|
st.opacity = "";
|
|
8272
8802
|
s.shown = null;
|
|
@@ -8493,43 +9023,65 @@ function compare(container, options) {
|
|
|
8493
9023
|
viewSent = key;
|
|
8494
9024
|
options.onView({ zoom: clampZoom(z), loop: l });
|
|
8495
9025
|
};
|
|
8496
|
-
const
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
return [at.before, at.after];
|
|
8500
|
-
}
|
|
8501
|
-
const ax = r.after.x + INSET + (r.after.w - labelW[1] - INSET * 2) * lay.x;
|
|
8502
|
-
return [
|
|
8503
|
-
{ x: r.before.x + INSET, opacity: 1 },
|
|
8504
|
-
{ x: ax, opacity: 1 }
|
|
8505
|
-
];
|
|
9026
|
+
const differenceWeight = () => {
|
|
9027
|
+
const f = Math.min(1, Math.max(0, fade.x));
|
|
9028
|
+
return (fromMode === "difference" ? 1 - f : 0) + (toMode === "difference" ? f : 0);
|
|
8506
9029
|
};
|
|
8507
9030
|
const placeGrip = (wr) => {
|
|
8508
|
-
const gy = gripTop(
|
|
9031
|
+
const gy = gripTop(wr.y + gripAt.x * wr.h, wr, GRIP.h) - wr.y;
|
|
8509
9032
|
grip.style.transform = `translate3d(0,${gy.toFixed(2)}px,0)`;
|
|
8510
9033
|
};
|
|
9034
|
+
let folded = 0;
|
|
8511
9035
|
const draw = () => {
|
|
8512
9036
|
dirty = false;
|
|
9037
|
+
if (!root.hasAttribute("data-ready") && sides.every((x) => x.shown || x.failed))
|
|
9038
|
+
root.setAttribute("data-ready", "");
|
|
8513
9039
|
const r = layoutNow();
|
|
8514
9040
|
const wr = wipeRect(r.L.overlay);
|
|
8515
|
-
const
|
|
8516
|
-
const
|
|
8517
|
-
const
|
|
8518
|
-
const
|
|
8519
|
-
|
|
9041
|
+
const k = Math.min(1, Math.max(0, lay.x));
|
|
9042
|
+
const fu = fuseFrame(r.L, r.before, r.after, k, wipeLine.x);
|
|
9043
|
+
const dw = differenceWeight();
|
|
9044
|
+
const fusing = 1 - dw;
|
|
9045
|
+
folded = k * fusing;
|
|
9046
|
+
const fold = labelFold(folded, MARK.w);
|
|
9047
|
+
const w = labelW.map((x) => x - (MARK.w - fold.width) - MARK.gap * folded);
|
|
9048
|
+
const ride = seamLabels(fu.cut, r.before.x, r.after.x + r.after.w, w[0], w[1], INSET);
|
|
9049
|
+
const apart = [r.before.x + INSET, r.after.x + INSET];
|
|
9050
|
+
const corner = [r.before.x + INSET, r.after.x + r.after.w - labelW[1] - INSET];
|
|
9051
|
+
const rides = [ride.before, ride.after];
|
|
8520
9052
|
const ys = [r.before.y + INSET, r.after.y + INSET];
|
|
8521
9053
|
for (const i of [0, 1]) {
|
|
8522
|
-
const
|
|
8523
|
-
|
|
8524
|
-
|
|
9054
|
+
const fused = apart[i] + (rides[i].x - apart[i]) * k;
|
|
9055
|
+
const x = fused + (corner[i] - fused) * dw;
|
|
9056
|
+
const opacity = (1 - k + k * rides[i].opacity) * fusing + dw;
|
|
9057
|
+
const l = labels[i];
|
|
9058
|
+
l.style.transform = `translate(${x.toFixed(2)}px,${ys[i].toFixed(2)}px)`;
|
|
9059
|
+
l.style.opacity = opacity.toFixed(3);
|
|
9060
|
+
const mark = l.firstElementChild;
|
|
9061
|
+
if (mark) {
|
|
9062
|
+
mark.style.width = `${fold.width.toFixed(2)}px`;
|
|
9063
|
+
mark.style.marginRight = `${(-MARK.gap * folded).toFixed(2)}px`;
|
|
9064
|
+
mark.style.opacity = fold.opacity.toFixed(3);
|
|
9065
|
+
mark.style.filter = fold.blur > 0.05 ? `blur(${fold.blur.toFixed(2)}px)` : "";
|
|
9066
|
+
}
|
|
8525
9067
|
}
|
|
8526
9068
|
const top = Math.min(r.L.side.before.y, r.L.side.after.y);
|
|
8527
9069
|
split.style.transform = `translate(${r.L.side.split.toFixed(2)}px,${top.toFixed(2)}px)`;
|
|
8528
9070
|
split.style.height = `${Math.max(0, r.L.side.after.h).toFixed(2)}px`;
|
|
8529
9071
|
split.style.opacity = String(Math.max(0, 1 - k * 2));
|
|
9072
|
+
const seamOn = fu.seam * fusing;
|
|
9073
|
+
const blur = fu.blur > 0.01 ? `blur(${fu.blur.toFixed(2)}px)` : "none";
|
|
9074
|
+
seam.style.transform = `translate(${fu.cut.toFixed(2)}px,${wr.y.toFixed(2)}px) translateX(-50%)`;
|
|
9075
|
+
seam.style.width = `${(8 + 2 * fu.feather).toFixed(2)}px`;
|
|
9076
|
+
seam.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
9077
|
+
seam.style.opacity = (blur === "none" ? 0 : seamOn).toFixed(3);
|
|
9078
|
+
seam.style.backdropFilter = blur;
|
|
9079
|
+
seam.style.setProperty("-webkit-backdrop-filter", blur);
|
|
8530
9080
|
handle.toggleAttribute("data-on", mode === "wipe");
|
|
8531
|
-
handle.style.transform = `translate(${
|
|
9081
|
+
handle.style.transform = `translate(${fu.cut.toFixed(2)}px,${wr.y.toFixed(2)}px)`;
|
|
8532
9082
|
handle.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
9083
|
+
handle.style.opacity = seamOn.toFixed(3);
|
|
9084
|
+
handle.style.filter = blur;
|
|
8533
9085
|
placeGrip(wr);
|
|
8534
9086
|
handle.setAttribute("aria-valuenow", String(Math.round(wipe * 100)));
|
|
8535
9087
|
handle.setAttribute("aria-valuetext", `${Math.round(wipe * 100)}% Before`);
|
|
@@ -8542,24 +9094,27 @@ function compare(container, options) {
|
|
|
8542
9094
|
if (pending)
|
|
8543
9095
|
return;
|
|
8544
9096
|
if (renderer === "dom") {
|
|
8545
|
-
const
|
|
9097
|
+
const cut = mode === "difference" ? null : fu;
|
|
9098
|
+
const place = (n, rect, clip, before) => {
|
|
8546
9099
|
const st = n.style;
|
|
8547
9100
|
st.transform = `translate(${rect.x.toFixed(2)}px,${rect.y.toFixed(2)}px)`;
|
|
8548
9101
|
st.width = `${rect.w.toFixed(2)}px`;
|
|
8549
9102
|
st.height = `${rect.h.toFixed(2)}px`;
|
|
9103
|
+
const edge = before && cut ? cut.cut + cut.feather : Number.POSITIVE_INFINITY;
|
|
8550
9104
|
const t = Math.max(0, clip.y - rect.y);
|
|
8551
9105
|
const l = Math.max(0, clip.x - rect.x);
|
|
8552
9106
|
const b = Math.max(0, rect.y + rect.h - (clip.y + clip.h));
|
|
8553
|
-
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w,
|
|
9107
|
+
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w, edge));
|
|
8554
9108
|
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)` : "";
|
|
9109
|
+
const mask = before && cut && cut.feather > 0.5 ? `linear-gradient(to right,#000 ${(cut.cut - cut.feather - rect.x).toFixed(2)}px,transparent ${(edge - rect.x).toFixed(2)}px)` : "";
|
|
9110
|
+
st.maskImage = mask;
|
|
9111
|
+
st.setProperty("-webkit-mask-image", mask);
|
|
8555
9112
|
};
|
|
8556
|
-
const cut = mode === "wipe" ? wx : Number.POSITIVE_INFINITY;
|
|
8557
9113
|
for (const s of sides) {
|
|
8558
9114
|
const rect = s.index === 0 ? r.zBefore : r.zAfter;
|
|
8559
9115
|
const clip = s.index === 0 ? r.before : r.after;
|
|
8560
|
-
|
|
8561
|
-
place(s.
|
|
8562
|
-
place(s.preview, rect, clip, at);
|
|
9116
|
+
place(s.el, rect, clip, s.index === 0);
|
|
9117
|
+
place(s.preview, rect, clip, s.index === 0);
|
|
8563
9118
|
if (s.index !== 0)
|
|
8564
9119
|
continue;
|
|
8565
9120
|
for (const n of [s.el, s.preview])
|
|
@@ -8579,8 +9134,8 @@ function compare(container, options) {
|
|
|
8579
9134
|
width: Math.max(1, Math.round(stageW * dpr)),
|
|
8580
9135
|
height: Math.max(1, Math.round(stageH * dpr)),
|
|
8581
9136
|
dpr,
|
|
8582
|
-
wipeX:
|
|
8583
|
-
soft: 0.75 * dpr,
|
|
9137
|
+
wipeX: fu.cut * dpr,
|
|
9138
|
+
soft: Math.max(0.75, fu.feather) * dpr,
|
|
8584
9139
|
from: MODE_INDEX[fromMode],
|
|
8585
9140
|
to: MODE_INDEX[toMode],
|
|
8586
9141
|
mix: Math.min(1, Math.max(0, fade.x)),
|
|
@@ -8607,6 +9162,7 @@ function compare(container, options) {
|
|
|
8607
9162
|
zu.step(dt);
|
|
8608
9163
|
zv.step(dt);
|
|
8609
9164
|
zw.step(dt);
|
|
9165
|
+
gripAt.step(dt);
|
|
8610
9166
|
const playing = isPlaying();
|
|
8611
9167
|
if (playing) {
|
|
8612
9168
|
const m = master();
|
|
@@ -8637,11 +9193,9 @@ function compare(container, options) {
|
|
|
8637
9193
|
pushFrame(s);
|
|
8638
9194
|
}
|
|
8639
9195
|
}
|
|
8640
|
-
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching;
|
|
9196
|
+
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching || !gripAt.resting;
|
|
8641
9197
|
if (moving)
|
|
8642
9198
|
dirty = true;
|
|
8643
|
-
if (auto && !lay.resting)
|
|
8644
|
-
fitHeight();
|
|
8645
9199
|
if (dirty)
|
|
8646
9200
|
draw();
|
|
8647
9201
|
return playing || moving;
|
|
@@ -8667,13 +9221,7 @@ function compare(container, options) {
|
|
|
8667
9221
|
zw.set(c.w);
|
|
8668
9222
|
requestDraw();
|
|
8669
9223
|
};
|
|
8670
|
-
const autoHeight = (w) =>
|
|
8671
|
-
const shape = sizeOf(sides[1]);
|
|
8672
|
-
const side = splitHeight(w, shape);
|
|
8673
|
-
const over = w * shape.h / shape.w;
|
|
8674
|
-
const h = side + (over - side) * lay.x;
|
|
8675
|
-
return Math.max(60, Math.min(win.innerHeight * 0.8, h));
|
|
8676
|
-
};
|
|
9224
|
+
const autoHeight = (w) => Math.max(60, Math.min(win.innerHeight * 0.8, splitHeight(w, sizeOf(sides[1]))));
|
|
8677
9225
|
const fitHeight = () => {
|
|
8678
9226
|
const h = autoHeight(stageW);
|
|
8679
9227
|
if (Math.abs(h - stageH) < 0.25)
|
|
@@ -8685,7 +9233,8 @@ function compare(container, options) {
|
|
|
8685
9233
|
const readColors = () => {
|
|
8686
9234
|
const c = tokenColor(win.getComputedStyle(root), "--_ku-cmp-diff", [0.49, 0.81, 0.61, 1]);
|
|
8687
9235
|
accent = [c[0], c[1], c[2]];
|
|
8688
|
-
|
|
9236
|
+
const unfold = MARK.w - labelFold(folded, MARK.w).width + MARK.gap * folded;
|
|
9237
|
+
labelW = [labels[0].offsetWidth + unfold, labels[1].offsetWidth + unfold];
|
|
8689
9238
|
requestDraw();
|
|
8690
9239
|
};
|
|
8691
9240
|
const measure = () => {
|
|
@@ -8776,8 +9325,10 @@ function compare(container, options) {
|
|
|
8776
9325
|
root.focus({ preventScroll: true });
|
|
8777
9326
|
touches.set(e.pointerId, p);
|
|
8778
9327
|
stage.setPointerCapture(e.pointerId);
|
|
9328
|
+
press = touches.size === 1 && mode !== "wipe" && master() ? p : null;
|
|
8779
9329
|
if (touches.size >= 2) {
|
|
8780
9330
|
e.preventDefault();
|
|
9331
|
+
press = null;
|
|
8781
9332
|
return startPinch();
|
|
8782
9333
|
}
|
|
8783
9334
|
if (mode === "wipe") {
|
|
@@ -8787,7 +9338,7 @@ function compare(container, options) {
|
|
|
8787
9338
|
if (inside && (grab.onLine || !zoomed())) {
|
|
8788
9339
|
drag = { kind: "wipe", offset: grab.offset };
|
|
8789
9340
|
root.dataset.dragging = "";
|
|
8790
|
-
|
|
9341
|
+
gripAt.snap(wr.h > 0 ? (p.y - wr.y) / wr.h : 0.5);
|
|
8791
9342
|
e.preventDefault();
|
|
8792
9343
|
if (!grab.onLine)
|
|
8793
9344
|
setWipe(wipeAt(p.x, wr), true, true);
|
|
@@ -8805,6 +9356,8 @@ function compare(container, options) {
|
|
|
8805
9356
|
const onMove = (e) => {
|
|
8806
9357
|
const p = local(e);
|
|
8807
9358
|
pointer = p;
|
|
9359
|
+
if (press && Math.hypot(p.x - press.x, p.y - press.y) > 4)
|
|
9360
|
+
press = null;
|
|
8808
9361
|
if (touches.has(e.pointerId))
|
|
8809
9362
|
touches.set(e.pointerId, p);
|
|
8810
9363
|
if (pinch && touches.size >= 2) {
|
|
@@ -8818,14 +9371,12 @@ function compare(container, options) {
|
|
|
8818
9371
|
pinch = { d, x: mid.x, y: mid.y };
|
|
8819
9372
|
return handZoom(zoomAbout(panned, k, q.pu, q.pv));
|
|
8820
9373
|
}
|
|
8821
|
-
if (
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
if (drag?.kind === "
|
|
8827
|
-
setWipe(wipeAt(p.x, wipeRect(layoutNow().L.overlay), drag.offset));
|
|
8828
|
-
else if (drag?.kind === "pan") {
|
|
9374
|
+
if (drag?.kind === "wipe") {
|
|
9375
|
+
const wr = wipeRect(layoutNow().L.overlay);
|
|
9376
|
+
gripAt.snap(wr.h > 0 ? (p.y - wr.y) / wr.h : 0.5);
|
|
9377
|
+
setWipe(wipeAt(p.x, wr, drag.offset));
|
|
9378
|
+
placeGrip(wr);
|
|
9379
|
+
} else if (drag?.kind === "pan") {
|
|
8829
9380
|
const dx = p.x - drag.x;
|
|
8830
9381
|
const dy = p.y - drag.y;
|
|
8831
9382
|
drag.x = p.x;
|
|
@@ -8836,11 +9387,23 @@ function compare(container, options) {
|
|
|
8836
9387
|
drawNow();
|
|
8837
9388
|
};
|
|
8838
9389
|
const endDrag = (e) => {
|
|
9390
|
+
if (press && e.type === "pointerup") {
|
|
9391
|
+
api.toggle();
|
|
9392
|
+
glyph.flash(isPlaying());
|
|
9393
|
+
}
|
|
9394
|
+
press = null;
|
|
8839
9395
|
touches.delete(e.pointerId);
|
|
8840
9396
|
if (touches.size < 2)
|
|
8841
9397
|
pinch = null;
|
|
8842
9398
|
if (!drag)
|
|
8843
9399
|
return;
|
|
9400
|
+
if (drag.kind === "wipe") {
|
|
9401
|
+
if (reducedMotion(win))
|
|
9402
|
+
gripAt.snap(0.5);
|
|
9403
|
+
else
|
|
9404
|
+
gripAt.set(0.5);
|
|
9405
|
+
requestDraw();
|
|
9406
|
+
}
|
|
8844
9407
|
drag = null;
|
|
8845
9408
|
delete root.dataset.dragging;
|
|
8846
9409
|
delete root.dataset.panning;
|
|
@@ -8990,8 +9553,9 @@ function compare(container, options) {
|
|
|
8990
9553
|
old.el.replaceWith(s.el);
|
|
8991
9554
|
old.preview.replaceWith(s.preview);
|
|
8992
9555
|
sides[index] = s;
|
|
9556
|
+
root.toggleAttribute("data-video", sides.some((x) => x.kind === "video"));
|
|
8993
9557
|
note.textContent = "";
|
|
8994
|
-
|
|
9558
|
+
setLabel(index, labelOf(index));
|
|
8995
9559
|
if (near)
|
|
8996
9560
|
loadSide(s);
|
|
8997
9561
|
readColors();
|
|
@@ -9002,8 +9566,9 @@ function compare(container, options) {
|
|
|
9002
9566
|
stage.insertBefore(sides[1].preview, labels[0]);
|
|
9003
9567
|
stage.insertBefore(sides[0].el, labels[0]);
|
|
9004
9568
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
9005
|
-
|
|
9006
|
-
|
|
9569
|
+
setLabel(0, labelOf(0));
|
|
9570
|
+
setLabel(1, labelOf(1));
|
|
9571
|
+
root.toggleAttribute("data-video", sides.some((s) => s.kind === "video"));
|
|
9007
9572
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
9008
9573
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
9009
9574
|
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
@@ -9143,11 +9708,11 @@ function compare(container, options) {
|
|
|
9143
9708
|
if (before)
|
|
9144
9709
|
replace(0, before);
|
|
9145
9710
|
else if (next.before)
|
|
9146
|
-
|
|
9711
|
+
setLabel(0, next.before.label ?? "Before");
|
|
9147
9712
|
if (after)
|
|
9148
9713
|
replace(1, after);
|
|
9149
9714
|
else if (next.after)
|
|
9150
|
-
|
|
9715
|
+
setLabel(1, next.after.label ?? "After");
|
|
9151
9716
|
if (before || after)
|
|
9152
9717
|
strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
|
|
9153
9718
|
if (next.before || next.after)
|
|
@@ -9204,6 +9769,7 @@ function compare(container, options) {
|
|
|
9204
9769
|
disposed = true;
|
|
9205
9770
|
loop.stop();
|
|
9206
9771
|
modePill?.dispose();
|
|
9772
|
+
glyph.dispose();
|
|
9207
9773
|
win.clearTimeout(releaseTimer);
|
|
9208
9774
|
ro.disconnect();
|
|
9209
9775
|
nearIo?.disconnect();
|
|
@@ -9233,7 +9799,7 @@ function compare(container, options) {
|
|
|
9233
9799
|
wake();
|
|
9234
9800
|
return api;
|
|
9235
9801
|
}
|
|
9236
|
-
var COMPARE_FFMPEG = "ffmpeg -i in.mov -vf fps=30 -fps_mode cfr -c:v libx264 -preset slow -crf 18 -g 15 -keyint_min 15 -pix_fmt yuv420p -movflags +faststart -an out.mp4", LAYOUT, FADE2, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
9802
|
+
var COMPARE_FFMPEG = "ffmpeg -i in.mov -vf fps=30 -fps_mode cfr -c:v libx264 -preset slow -crf 18 -g 15 -keyint_min 15 -pix_fmt yuv420p -movflags +faststart -an out.mp4", LAYOUT, FADE2, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, MARK, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
9237
9803
|
var init_compare = __esm(() => {
|
|
9238
9804
|
init_motion();
|
|
9239
9805
|
init_page_hints();
|
|
@@ -9244,15 +9810,17 @@ var init_compare = __esm(() => {
|
|
|
9244
9810
|
init_icons();
|
|
9245
9811
|
init_look();
|
|
9246
9812
|
init_rgba();
|
|
9813
|
+
init_player();
|
|
9247
9814
|
init_selection_pill();
|
|
9248
9815
|
init_timeline();
|
|
9249
9816
|
init_timeline_model();
|
|
9250
|
-
LAYOUT = springMotion(
|
|
9817
|
+
LAYOUT = springMotion(SPRINGS.default);
|
|
9251
9818
|
FADE2 = springMotion(SPRINGS.snappy);
|
|
9252
9819
|
FADE_REDUCED = springMotion(FADE);
|
|
9253
9820
|
ZOOM = springMotion({ duration: 0.35, bounce: 0 });
|
|
9254
9821
|
WIPE_CATCH = springMotion(CATCH_UP);
|
|
9255
9822
|
GRIP = { w: 16, h: 28 };
|
|
9823
|
+
MARK = { w: 12, gap: 4 };
|
|
9256
9824
|
LOUPE = { r: 88, zoom: 4 };
|
|
9257
9825
|
MODE_LABEL = {
|
|
9258
9826
|
side: { short: "Side", long: "Side by side" },
|
|
@@ -10298,19 +10866,19 @@ var init_diff_css = __esm(() => {
|
|
|
10298
10866
|
@property --kd-fb{syntax:"<length>";inherits:false;initial-value:0px}
|
|
10299
10867
|
:where(.knobs-ui){--kd-add:var(--_k-diff-add);--kd-del:var(--_k-diff-del);--kd-mod:var(--_k-diff-mod);--kd-move:var(--k-diff-move,var(--_k-info))}
|
|
10300
10868
|
:where(.knobs-diff,.knobs-diff *,.knobs-diff-files,.knobs-diff-files *){box-sizing:border-box}
|
|
10301
|
-
.knobs-ui.knobs-diff{--kd-bg:var(--k-diff-bg,var(--_kd-bg,
|
|
10869
|
+
.knobs-ui.knobs-diff{--kd-bg:var(--k-diff-bg,var(--_kd-bg,transparent));--kd-solid:var(--kd-fill,var(--kd-bg));--kd-line:calc(var(--_k-font-size) * 1.5);
|
|
10302
10870
|
--kd-i:var(--k-diff-inset,8px);--kd-x:var(--kd-i);--kd-inner:max(3px,calc(var(--_ku-pane-radius) - var(--kd-i)));--kd-ctl:var(--kd-inner);
|
|
10303
10871
|
--kd-head:calc(var(--_k-control-h) + 2 * var(--kd-i));--kd-fade:var(--k-diff-fade,20px);--kd-stick:0px;position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
10304
10872
|
background:var(--kd-bg);border-radius:var(--_ku-pane-radius);font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);text-align:left;
|
|
10305
10873
|
letter-spacing:normal;word-spacing:normal;text-transform:none;-webkit-font-smoothing:antialiased}
|
|
10306
10874
|
.knobs-ui.knobs-diff[data-height="auto"]{height:auto}
|
|
10307
|
-
.knobs-diff::after{content:"";position:absolute;inset:0;z-index:3;
|
|
10875
|
+
.knobs-ui.knobs-diff:not([data-on="pane"])::after{content:"";position:absolute;inset:0;z-index:3;box-shadow:inset 0 -1px 0 var(--_k-border-subtle);pointer-events:none}
|
|
10308
10876
|
.knobs-diff [hidden],.knobs-diff-files [hidden]{display:none!important}
|
|
10309
10877
|
.knobs-diff svg{display:block;flex:none}
|
|
10310
|
-
.knobs-ui.knobs-diff[data-on="
|
|
10311
|
-
/*
|
|
10878
|
+
.knobs-ui.knobs-diff:not([data-on="pane"]){--kd-x:0px;--kd-head:calc(var(--_k-control-h) + var(--kd-i));--kd-ctl:var(--_k-radius)}
|
|
10879
|
+
/* A hairline under the header, firmer once the code has scrolled under it. */
|
|
10312
10880
|
.knobs-diff-head{position:relative;z-index:1;flex:none;display:flex;align-items:center;gap:8px;height:var(--kd-head);padding:0 var(--kd-x);
|
|
10313
|
-
box-shadow:inset 0 -1px
|
|
10881
|
+
box-shadow:inset 0 -1px var(--_k-border-subtle);transition:box-shadow .15s;user-select:none;-webkit-user-select:none}
|
|
10314
10882
|
.knobs-diff[data-scrolled]>.knobs-diff-head{box-shadow:inset 0 -1px var(--_k-border)}
|
|
10315
10883
|
.knobs-diff-path{flex:0 1 auto;min-width:0;overflow:hidden;white-space:nowrap}
|
|
10316
10884
|
.knobs-diff-dir,.knobs-diff-from{color:var(--_k-fg-3)}
|
|
@@ -10348,6 +10916,15 @@ var init_diff_css = __esm(() => {
|
|
|
10348
10916
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
10349
10917
|
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
10350
10918
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
10919
|
+
/* Narrow, the header gives up words before anything is cut off at its end: Viewed keeps its
|
|
10920
|
+
check, then the counts' bar goes, then the counts; the path fades at its end throughout. */
|
|
10921
|
+
.knobs-diff-head,.knobs-diff-part-head{container-type:inline-size}
|
|
10922
|
+
@container (max-width:520px){
|
|
10923
|
+
.knobs-diff-viewed-label{display:none}
|
|
10924
|
+
.knobs-ui .knobs-diff-viewed{width:var(--_k-control-h);padding:0;justify-content:center}
|
|
10925
|
+
.knobs-diff-counts .knobs-diff-bar{display:none}
|
|
10926
|
+
}
|
|
10927
|
+
@container (max-width:400px){.knobs-diff-counts{display:none}.knobs-diff-nav>span{min-width:2.6em}}
|
|
10351
10928
|
.knobs-diff-path{transition:opacity .2s}
|
|
10352
10929
|
.knobs-diff[data-viewed]>.knobs-diff-head .knobs-diff-path,.knobs-diff-part[data-viewed] .knobs-diff-path{opacity:.6}
|
|
10353
10930
|
/* Split | Unified: the selection pill on the one picked, its bright copy the picked one's text; a
|
|
@@ -10412,24 +10989,26 @@ var init_diff_css = __esm(() => {
|
|
|
10412
10989
|
--diffs-bg-deletion-number-override:color-mix(in srgb,var(--kd-del) 55%,var(--kd-solid));
|
|
10413
10990
|
--diffs-bg-addition-emphasis-override:color-mix(in srgb,var(--kd-add) 22%,transparent);
|
|
10414
10991
|
--diffs-bg-deletion-emphasis-override:color-mix(in srgb,var(--kd-del) 22%,transparent);
|
|
10415
|
-
|
|
10416
|
-
|
|
10417
|
-
--diffs-bg-
|
|
10992
|
+
/* Unchanged lines and the folds between hunks sit on the void; only a split's missing lines
|
|
10993
|
+
are faintly filled. */
|
|
10994
|
+
--diffs-bg-separator-override:var(--kd-solid);
|
|
10995
|
+
--diffs-bg-context-override:var(--kd-solid);
|
|
10996
|
+
--diffs-bg-buffer-override:color-mix(in srgb,var(--_k-fg) 2.5%,var(--kd-solid));
|
|
10418
10997
|
--diffs-bg-selection-override:var(--_k-accent);
|
|
10419
10998
|
--diffs-fg-number-override:var(--_k-fg-3);
|
|
10420
10999
|
}
|
|
10421
|
-
/* diffReview
|
|
10422
|
-
is pinned to its right edge, so it slides out from under the diff), parted
|
|
10423
|
-
|
|
10424
|
-
.knobs-ui.knobs-diff-review{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
11000
|
+
/* diffReview, on the void as the diff is: the file list a drawer at its left (its width springs;
|
|
11001
|
+
the list inside is pinned to its right edge, so it slides out from under the diff), parted
|
|
11002
|
+
from the diff by a hairline; one hairline runs under both headers and one under it all. */
|
|
11003
|
+
.knobs-ui.knobs-diff-review{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
10425
11004
|
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);text-align:left;letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
10426
|
-
.knobs-diff-review::after{content:"";position:absolute;inset:0;z-index:5;
|
|
11005
|
+
.knobs-diff-review::after{content:"";position:absolute;inset:0;z-index:5;box-shadow:inset 0 -1px 0 var(--_k-border-subtle);pointer-events:none}
|
|
10427
11006
|
:where(.knobs-diff-review,.knobs-diff-review *){box-sizing:border-box}
|
|
10428
|
-
.knobs-diff-drawer{position:relative;flex:none;width:0;height:100%;overflow:hidden;box-shadow:inset -1px 0 var(--_k-border)}
|
|
11007
|
+
.knobs-diff-drawer{position:relative;flex:none;width:0;height:100%;overflow:hidden;box-shadow:inset -1px 0 var(--_k-border-subtle)}
|
|
10429
11008
|
.knobs-diff-drawer[data-shut]{visibility:hidden}
|
|
10430
11009
|
.knobs-diff-drawer-in{position:absolute;top:0;bottom:0;right:0;display:flex;flex-direction:column}
|
|
10431
11010
|
.knobs-diff-drawer-head{flex:none;display:flex;align-items:center;gap:6px;height:calc(var(--_k-control-h) + 2 * var(--k-diff-inset,8px));padding:0 var(--k-diff-inset,8px) 0 calc(var(--_ku-row-x) + 8px);
|
|
10432
|
-
user-select:none;-webkit-user-select:none}
|
|
11011
|
+
box-shadow:inset 0 -1px var(--_k-border-subtle);user-select:none;-webkit-user-select:none}
|
|
10433
11012
|
.knobs-diff-drawer-title{font-weight:var(--_k-weight-title)}
|
|
10434
11013
|
.knobs-diff-drawer-count{color:var(--_k-fg-3);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums}
|
|
10435
11014
|
.knobs-diff-drawer-in>.knobs-diff-files{flex:1;min-height:0;height:auto}
|
|
@@ -10441,10 +11020,11 @@ var init_diff_css = __esm(() => {
|
|
|
10441
11020
|
.knobs-ui .knobs-diff-toggle[aria-pressed]:not(:hover,:focus-visible){background:transparent}
|
|
10442
11021
|
/* diffReview's file list: a filter over a compact tree, a status letter, the counts and their
|
|
10443
11022
|
bar on each file; one highlight glides to the file on show. Viewed files dim, with a tick. */
|
|
10444
|
-
.knobs-diff-files{--k-row:var(--k-diff-row,28px);display:flex;flex-direction:column;height:100%;min-height:0;padding-top:
|
|
11023
|
+
.knobs-diff-files{--k-row:var(--k-diff-row,28px);display:flex;flex-direction:column;height:100%;min-height:0;padding-top:4px}
|
|
10445
11024
|
.knobs-diff-filter{position:relative;flex:none;display:flex;align-items:center;gap:6px;height:26px;margin:0 var(--_ku-row-x) 4px;padding:0 4px 0 8px;
|
|
10446
|
-
border-radius:max(6px,var(--_ku-row-radius));
|
|
10447
|
-
|
|
11025
|
+
border-radius:max(6px,var(--_ku-row-radius));color:var(--_k-fg-3);box-shadow:inset 0 0 0 1px transparent;transition:box-shadow .15s}
|
|
11026
|
+
/* The filter is a line of text, no box; focused, a hairline ring. */
|
|
11027
|
+
.knobs-diff-filter:focus-within{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_k-accent) 45%,transparent)}
|
|
10448
11028
|
.knobs-diff-filter svg{width:12px;height:12px;flex:none}
|
|
10449
11029
|
.knobs-ui .knobs-diff-filter>input{flex:1;min-width:0;height:100%;font:var(--_k-weight) var(--_k-font-size)/1 var(--_k-font);color:var(--_k-fg);caret-color:var(--_k-accent);background:transparent}
|
|
10450
11030
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
@@ -11263,7 +11843,10 @@ function codeDiff(container, options) {
|
|
|
11263
11843
|
const viewedToggle = () => {
|
|
11264
11844
|
const b = make("button", "knobs-diff-viewed");
|
|
11265
11845
|
b.type = "button";
|
|
11266
|
-
|
|
11846
|
+
const label = make("span", "knobs-diff-viewed-label");
|
|
11847
|
+
label.textContent = "Viewed";
|
|
11848
|
+
b.append(make("span", ""), label);
|
|
11849
|
+
b.setAttribute("aria-label", "Viewed");
|
|
11267
11850
|
return b;
|
|
11268
11851
|
};
|
|
11269
11852
|
const paintViewed = (b, on) => {
|
|
@@ -15962,6 +16545,7 @@ init_timeline();
|
|
|
15962
16545
|
init_timeline_model();
|
|
15963
16546
|
init_compare();
|
|
15964
16547
|
init_compare_strip();
|
|
16548
|
+
init_player();
|
|
15965
16549
|
init_compare_model();
|
|
15966
16550
|
init_tree();
|
|
15967
16551
|
init_tree_model();
|
|
@@ -19378,401 +19962,15 @@ function optionPicker(container, options) {
|
|
|
19378
19962
|
// src/ui/walkthrough.ts
|
|
19379
19963
|
init_motion();
|
|
19380
19964
|
init_page_hints();
|
|
19965
|
+
init_icons();
|
|
19381
19966
|
init_look();
|
|
19967
|
+
init_selection_pill();
|
|
19382
19968
|
|
|
19383
|
-
// src/ui/walkthrough-
|
|
19384
|
-
init_compare_model();
|
|
19385
|
-
init_glide();
|
|
19386
|
-
init_look();
|
|
19387
|
-
|
|
19388
|
-
// src/ui/walkthrough-css.ts
|
|
19969
|
+
// src/ui/walkthrough-blocks.ts
|
|
19389
19970
|
init_motion();
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
19394
|
-
.knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;
|
|
19395
|
-
--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));
|
|
19396
|
-
--kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-pad:16px;--kw-ink:var(--k-walkthrough-ink,#ff375f);
|
|
19397
|
-
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;
|
|
19398
|
-
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
19399
|
-
.knobs-walkthrough [hidden]{display:none!important}
|
|
19400
|
-
.knobs-walkthrough :is(h1,h2,h3,p){margin:0;font:inherit;letter-spacing:inherit}
|
|
19401
|
-
.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}
|
|
19402
|
-
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
19403
|
-
.knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
|
|
19404
|
-
: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;
|
|
19405
|
-
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
19406
|
-
|
|
19407
|
-
/* ——— layout: the rail beside the column; one column where it's narrow ——— */
|
|
19408
|
-
.knobs-wt-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;align-items:start}
|
|
19409
|
-
.knobs-wt-main{display:flex;flex-direction:column;gap:56px;min-width:0;max-width:1120px;padding-bottom:40vh}
|
|
19410
|
-
@container knobs-wt (max-width:880px){.knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:0}.knobs-wt-main{gap:44px}}
|
|
19411
|
-
|
|
19412
|
-
/* ——— the page's head ——— */
|
|
19413
|
-
.knobs-wt-head{display:flex;flex-direction:column;gap:10px}
|
|
19414
|
-
.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}
|
|
19415
|
-
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
19416
|
-
.knobs-wt-meta{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2px)}
|
|
19417
|
-
.knobs-wt-meta>span{display:inline-flex;gap:6px;white-space:nowrap}
|
|
19418
|
-
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono);font-size:calc(1em - .5px)}
|
|
19419
|
-
|
|
19420
|
-
/* ——— a section: a PR or topic ——— */
|
|
19421
|
-
.knobs-wt-section{display:flex;flex-direction:column;gap:14px;min-width:0}
|
|
19422
|
-
.knobs-wt-shead{display:flex;flex-direction:column;gap:6px;scroll-margin-top:16px}
|
|
19423
|
-
.knobs-wt-kicker{display:flex;align-items:center;gap:10px;font-size:calc(var(--kw-text) - 2px);color:var(--_k-fg-3)}
|
|
19424
|
-
.knobs-wt-kicker a{font-family:var(--_k-mono);color:var(--_k-fg-2);text-decoration:none}
|
|
19425
|
-
.knobs-wt-kicker a:hover{color:var(--_k-fg)}
|
|
19426
|
-
.knobs-wt-stitle{font-size:calc(var(--kw-text) + 4px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.3}
|
|
19427
|
-
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
19428
|
-
.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;
|
|
19429
|
-
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
19430
|
-
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
19431
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19432
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19433
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19434
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
19435
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
19436
|
-
|
|
19437
|
-
/* ——— a step: one card ——— */
|
|
19438
|
-
.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);
|
|
19439
|
-
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
19440
|
-
.knobs-walkthrough[data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
19441
|
-
.knobs-wt-step-head{display:flex;align-items:baseline;gap:10px;min-width:0}
|
|
19442
|
-
.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}
|
|
19443
|
-
.knobs-wt-stepTitle{flex:1;min-width:0;font-weight:var(--_k-weight-title)!important}
|
|
19444
|
-
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);margin-top:-6px!important}
|
|
19445
|
-
.knobs-wt-question{font-weight:var(--_k-weight-label)!important}
|
|
19446
|
-
/* The step Kit is on: its number lights, and its choices show their keys. */
|
|
19447
|
-
.knobs-wt-step[data-current] .knobs-wt-num{color:var(--_k-fg)}
|
|
19448
|
-
.knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:12px;min-width:0}
|
|
19449
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
19450
|
-
|
|
19451
|
-
/* ——— the feed: the agent's updates and answers, newest first, compact ——— */
|
|
19452
|
-
.knobs-wt-feed{margin-top:-24px}
|
|
19453
|
-
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;max-height:260px;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column}
|
|
19454
|
-
.knobs-wt-feed-list::-webkit-scrollbar{display:none}
|
|
19455
|
-
.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)}
|
|
19456
|
-
.knobs-wt-fi+.knobs-wt-fi{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19457
|
-
.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}
|
|
19458
|
-
.knobs-wt-fi-kind{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 2.5px);font-weight:var(--_k-weight-label)}
|
|
19459
|
-
.knobs-wt-fi[data-kind="qa"] .knobs-wt-fi-kind{color:var(--kw-info)}
|
|
19460
|
-
.knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
19461
|
-
.knobs-wt-fi-q{color:var(--_k-fg-2)}
|
|
19462
|
-
.knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
|
|
19463
|
-
: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;
|
|
19464
|
-
padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
|
|
19465
|
-
.knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19466
|
-
|
|
19467
|
-
/* ——— a step's sent notes ——— */
|
|
19468
|
-
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
19469
|
-
.knobs-wt-notes:empty{display:none}
|
|
19470
|
-
.knobs-wt-n{display:flex;align-items:flex-start;gap:10px;padding:6px 0;overflow:hidden;
|
|
19471
|
-
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)}
|
|
19472
|
-
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
19473
|
-
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
19474
|
-
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19475
|
-
.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}
|
|
19476
|
-
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
19477
|
-
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
19478
|
-
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;font-size:calc(var(--kw-text) - 1px)}
|
|
19479
|
-
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
19480
|
-
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:6px;background:var(--_k-fill)}
|
|
19481
|
-
.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}
|
|
19482
|
-
|
|
19483
|
-
/* ——— the note bar, docked at the bottom of the column ——— */
|
|
19484
|
-
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;margin-top:-24px}
|
|
19485
|
-
.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);
|
|
19486
|
-
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
19487
|
-
.knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap;overflow:hidden;
|
|
19488
|
-
-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)}
|
|
19489
|
-
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
19490
|
-
: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;
|
|
19491
|
-
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
19492
|
-
.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)}
|
|
19493
|
-
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
19494
|
-
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
19495
|
-
.knobs-wt-attach:empty{display:none}
|
|
19496
|
-
.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}
|
|
19497
|
-
.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}
|
|
19498
|
-
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19499
|
-
.knobs-wt-x svg{width:10px;height:10px}
|
|
19500
|
-
.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);
|
|
19501
|
-
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
19502
|
-
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19503
|
-
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
19504
|
-
.knobs-wt-tool svg{width:15px;height:15px}
|
|
19505
|
-
.knobs-wt-rec{font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums}
|
|
19506
|
-
.knobs-wt-rec:empty{display:none}
|
|
19507
|
-
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
19508
|
-
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
19509
|
-
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
19510
|
-
.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);
|
|
19511
|
-
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;
|
|
19512
|
-
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)}
|
|
19513
|
-
.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)}
|
|
19514
|
-
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
19515
|
-
|
|
19516
|
-
/* ——— ink over a step's media ——— */
|
|
19517
|
-
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
19518
|
-
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
19519
|
-
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
19520
|
-
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
19521
|
-
|
|
19522
|
-
/* ——— full-window: the step over the page, its media filling it; its place held in the page ——— */
|
|
19523
|
-
.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}
|
|
19524
|
-
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
19525
|
-
.knobs-wt-hold-card{flex:none}
|
|
19526
|
-
.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)}
|
|
19527
|
-
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
19528
|
-
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
19529
|
-
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
19530
|
-
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
19531
|
-
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
19532
|
-
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
19533
|
-
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
19534
|
-
|
|
19535
|
-
/* ——— a taste test: the options side by side, Kit's pick lit and the rest stepping back ——— */
|
|
19536
|
-
.knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:10px}
|
|
19537
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
19538
|
-
.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);
|
|
19539
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19540
|
-
.knobs-wt-option[data-picked]{background:color-mix(in srgb,var(--_k-accent) 12%,var(--_ku-wash))}
|
|
19541
|
-
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19542
|
-
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
19543
|
-
.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}
|
|
19544
|
-
.knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
19545
|
-
.knobs-wt-letter{flex:none;font:var(--_k-weight-title) calc(var(--kw-text) - 1px)/1 var(--_k-font);color:var(--_k-fg)}
|
|
19546
|
-
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
19547
|
-
.knobs-wt-suggested{flex:none;font-size:calc(var(--kw-text) - 3px);color:var(--_k-fg-3)}
|
|
19548
|
-
.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;
|
|
19549
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19550
|
-
.knobs-wt-check svg{width:12px;height:12px}
|
|
19551
|
-
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
19552
|
-
.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);
|
|
19553
|
-
font:var(--_k-weight-label) calc(var(--kw-text) - 4px)/1 var(--_k-font);font-variant-numeric:tabular-nums;opacity:.5;transition:opacity .15s}
|
|
19554
|
-
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
19555
|
-
.knobs-wt-ocap{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 1px);padding:0 4px}
|
|
19556
|
-
|
|
19557
|
-
/* ——— the rail: progress, contents, export ——— */
|
|
19558
|
-
.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)}
|
|
19559
|
-
.knobs-wt-progress{display:flex;flex-direction:column;gap:7px}
|
|
19560
|
-
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2);font-variant-numeric:tabular-nums}
|
|
19561
|
-
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
19562
|
-
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
19563
|
-
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
19564
|
-
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
19565
|
-
/* The contents: no box, one text spine for sections and steps (the steps' dots hang in the
|
|
19566
|
-
gutter left of it), and one pill behind the current step that springs between rows. */
|
|
19567
|
-
.knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;margin:0 -8px;padding:0 0 8px}
|
|
19568
|
-
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
19569
|
-
.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;
|
|
19570
|
-
-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)}
|
|
19571
|
-
.knobs-wt-toc-section:first-of-type{padding-top:2px}
|
|
19572
|
-
.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}
|
|
19573
|
-
.knobs-wt-toc-mark[data-on]{opacity:1}
|
|
19574
|
-
.knobs-walkthrough[data-settled] .knobs-wt-toc-mark{transition:opacity .15s}
|
|
19575
|
-
.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}
|
|
19576
|
-
.knobs-ui .knobs-wt-toc-step:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
19577
|
-
.knobs-wt-toc-step[aria-current="step"]{color:var(--_k-fg)}
|
|
19578
|
-
.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)}
|
|
19579
|
-
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
19580
|
-
.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);
|
|
19581
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
19582
|
-
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
19583
|
-
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
19584
|
-
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
19585
|
-
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
19586
|
-
.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;
|
|
19587
|
-
transition:background .15s,color .15s}
|
|
19588
|
-
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19589
|
-
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
19590
|
-
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
19591
|
-
.knobs-wt-keys{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);line-height:1.6}
|
|
19592
|
-
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
19593
|
-
/* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
|
|
19594
|
-
@container knobs-wt (max-width:880px){
|
|
19595
|
-
.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)}
|
|
19596
|
-
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
19597
|
-
.knobs-wt-step,.knobs-wt-shead{scroll-margin-top:60px}
|
|
19598
|
-
}
|
|
19599
|
-
|
|
19600
|
-
/* ——— media slots ——— */
|
|
19601
|
-
.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);
|
|
19602
|
-
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
19603
|
-
.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}
|
|
19604
|
-
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
19605
|
-
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
19606
|
-
(92 px), and the frame strip with its gap (158 px). */
|
|
19607
|
-
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
19608
|
-
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
19609
|
-
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
19610
|
-
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
19611
|
-
.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)}
|
|
19612
|
-
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
19613
|
-
.knobs-wt-frame[data-natural]{aspect-ratio:auto}
|
|
19614
|
-
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
19615
|
-
.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);
|
|
19616
|
-
font:calc(var(--k-walkthrough-text,14px) - 2px)/1.55 var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
19617
|
-
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
19618
|
-
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
19619
|
-
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
19620
|
-
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
19621
|
-
.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)}
|
|
19622
|
-
.knobs-wt-mlabel{color:var(--_k-fg-2);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
|
|
19623
|
-
.knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
19624
|
-
.knobs-wt-mfrom{color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) + 2px)}
|
|
19625
|
-
.knobs-wt-mto{font-size:calc(var(--k-walkthrough-text,14px) + 12px);font-weight:var(--_k-weight-title);line-height:1}
|
|
19626
|
-
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
19627
|
-
.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)}
|
|
19628
|
-
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19629
|
-
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19630
|
-
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
19631
|
-
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
19632
|
-
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
19633
|
-
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
19634
|
-
.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)}
|
|
19635
|
-
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:.62em;border-radius:50%;background:var(--kw-tone)}
|
|
19636
|
-
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19637
|
-
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19638
|
-
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19639
|
-
.knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19640
|
-
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
19641
|
-
.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)}
|
|
19642
|
-
|
|
19643
|
-
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
19644
|
-
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
19645
|
-
: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)}
|
|
19646
|
-
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19647
|
-
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19648
|
-
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19649
|
-
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
19650
|
-
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
19651
|
-
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
19652
|
-
.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);
|
|
19653
|
-
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
19654
|
-
.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)}
|
|
19655
|
-
|
|
19656
|
-
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
19657
|
-
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
19658
|
-
.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)}
|
|
19659
|
-
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
19660
|
-
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
19661
|
-
.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)}
|
|
19662
|
-
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
|
|
19663
|
-
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
19664
|
-
.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}
|
|
19665
|
-
.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)}
|
|
19666
|
-
.knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
|
|
19667
|
-
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
19668
|
-
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
19669
|
-
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
19670
|
-
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
19671
|
-
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
19672
|
-
.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))}
|
|
19673
|
-
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
19674
|
-
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
19675
|
-
.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))}
|
|
19676
|
-
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
19677
|
-
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
19678
|
-
.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}
|
|
19679
|
-
.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}
|
|
19680
|
-
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19681
|
-
@container knobs-wt-slot (max-width:520px){
|
|
19682
|
-
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
19683
|
-
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
19684
|
-
}
|
|
19685
|
-
|
|
19686
|
-
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
19687
|
-
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
19688
|
-
.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)}
|
|
19689
|
-
.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);
|
|
19690
|
-
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
19691
|
-
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
19692
|
-
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
19693
|
-
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19694
|
-
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
19695
|
-
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
19696
|
-
.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)}
|
|
19697
|
-
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
19698
|
-
.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}
|
|
19699
|
-
.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)}
|
|
19700
|
-
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
19701
|
-
.knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
19702
|
-
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
19703
|
-
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
19704
|
-
.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}
|
|
19705
|
-
.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}
|
|
19706
|
-
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
19707
|
-
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
19708
|
-
.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)}
|
|
19709
|
-
.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)}
|
|
19710
|
-
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19711
|
-
.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)}
|
|
19712
|
-
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
19713
|
-
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
19714
|
-
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
19715
|
-
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
19716
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
19717
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19718
|
-
@container knobs-wt-slot (max-width:520px){
|
|
19719
|
-
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
19720
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
19721
|
-
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
19722
|
-
}
|
|
19723
|
-
|
|
19724
|
-
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
19725
|
-
(the top one under the head), and thin bars show on hover. */
|
|
19726
|
-
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
19727
|
-
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
19728
|
-
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
19729
|
-
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
19730
|
-
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
19731
|
-
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
19732
|
-
.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)}
|
|
19733
|
-
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
19734
|
-
@supports (animation-timeline:scroll()){
|
|
19735
|
-
.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;
|
|
19736
|
-
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%;
|
|
19737
|
-
--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)));
|
|
19738
|
-
--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)));
|
|
19739
|
-
-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}
|
|
19740
|
-
}
|
|
19741
|
-
.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)}
|
|
19742
|
-
.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)}
|
|
19743
|
-
.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;
|
|
19744
|
-
background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
19745
|
-
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
19746
|
-
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
19747
|
-
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
19748
|
-
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
19749
|
-
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
19750
|
-
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
19751
|
-
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
19752
|
-
.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}
|
|
19753
|
-
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
19754
|
-
.knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
|
|
19755
|
-
.knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
|
|
19756
|
-
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
19757
|
-
|
|
19758
|
-
/* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
|
|
19759
|
-
.knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
|
|
19760
|
-
.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;
|
|
19761
|
-
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
|
|
19762
|
-
.knobs-wt-chapter-mark[data-on]{opacity:1}
|
|
19763
|
-
.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);
|
|
19764
|
-
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)}
|
|
19765
|
-
.knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19766
|
-
.knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
|
|
19767
|
-
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
|
|
19768
|
-
.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)}
|
|
19769
|
-
.knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
|
|
19770
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
19771
|
-
`;
|
|
19772
|
-
|
|
19773
|
-
// src/ui/walkthrough-blocks.ts
|
|
19774
|
-
init_motion();
|
|
19775
|
-
init_look();
|
|
19971
|
+
init_icons();
|
|
19972
|
+
init_look();
|
|
19973
|
+
init_selection_pill();
|
|
19776
19974
|
|
|
19777
19975
|
// src/ui/walkthrough-model.ts
|
|
19778
19976
|
var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
|
|
@@ -19979,7 +20177,15 @@ function fillTable(m) {
|
|
|
19979
20177
|
out[k] = fillCell(v);
|
|
19980
20178
|
return out;
|
|
19981
20179
|
});
|
|
19982
|
-
|
|
20180
|
+
const primary = columns.find((c) => c.key === m.primary)?.key ?? columns[0]?.key ?? "";
|
|
20181
|
+
return {
|
|
20182
|
+
kind: "table",
|
|
20183
|
+
columns,
|
|
20184
|
+
rows,
|
|
20185
|
+
...m.caption ? { caption: m.caption } : {},
|
|
20186
|
+
stack: m.stack ?? "auto",
|
|
20187
|
+
primary
|
|
20188
|
+
};
|
|
19983
20189
|
}
|
|
19984
20190
|
function fillChapters(chapters) {
|
|
19985
20191
|
const id = uniqueIds();
|
|
@@ -20052,6 +20258,8 @@ function normalizeWalkthrough(doc) {
|
|
|
20052
20258
|
...step.caption ? { caption: step.caption } : {},
|
|
20053
20259
|
...step.question ? { question: step.question } : {},
|
|
20054
20260
|
media: list.map((m) => fillMedia(m, doc.base)),
|
|
20261
|
+
columns: Math.max(1, Math.min(3, Math.round(step.columns ?? 1))),
|
|
20262
|
+
...step.more?.trim() ? { more: step.more.trim() } : {},
|
|
20055
20263
|
options,
|
|
20056
20264
|
ask
|
|
20057
20265
|
};
|
|
@@ -20063,8 +20271,10 @@ function normalizeWalkthrough(doc) {
|
|
|
20063
20271
|
id,
|
|
20064
20272
|
title: s.title,
|
|
20065
20273
|
...link ? { link } : {},
|
|
20274
|
+
...typeof s.kicker === "string" && s.kicker.trim() ? { kicker: s.kicker.trim() } : {},
|
|
20066
20275
|
...s.status ? { status: s.status } : {},
|
|
20067
20276
|
...s.summary ? { summary: s.summary } : {},
|
|
20277
|
+
...s.more?.trim() ? { more: s.more.trim() } : {},
|
|
20068
20278
|
steps: own
|
|
20069
20279
|
};
|
|
20070
20280
|
});
|
|
@@ -20073,30 +20283,95 @@ function normalizeWalkthrough(doc) {
|
|
|
20073
20283
|
value
|
|
20074
20284
|
}));
|
|
20075
20285
|
const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
|
|
20286
|
+
const extra = (x) => ({
|
|
20287
|
+
...x.status?.trim() ? { status: x.status.trim() } : {},
|
|
20288
|
+
trail: (x.trail ?? []).filter((t) => typeof t === "string" && t.trim())
|
|
20289
|
+
});
|
|
20076
20290
|
const feed = sortFeed([
|
|
20077
|
-
...(doc.updates ?? []).map((u) => ({
|
|
20291
|
+
...(doc.updates ?? []).map((u) => ({
|
|
20292
|
+
kind: "update",
|
|
20293
|
+
at: parseAt(u.at),
|
|
20294
|
+
text: u.text,
|
|
20295
|
+
step: stepRef(u.step),
|
|
20296
|
+
...extra(u)
|
|
20297
|
+
})),
|
|
20078
20298
|
...(doc.qa ?? []).map((x) => ({
|
|
20079
20299
|
kind: "qa",
|
|
20080
20300
|
at: parseAt(x.at),
|
|
20081
20301
|
text: x.a,
|
|
20082
20302
|
q: x.q,
|
|
20083
|
-
step: stepRef(x.step)
|
|
20303
|
+
step: stepRef(x.step),
|
|
20304
|
+
...extra(x)
|
|
20084
20305
|
}))
|
|
20085
20306
|
]);
|
|
20086
20307
|
return {
|
|
20087
20308
|
id: doc.id,
|
|
20088
20309
|
title: doc.title,
|
|
20089
20310
|
...doc.summary ? { summary: doc.summary } : {},
|
|
20311
|
+
...doc.more?.trim() ? { more: doc.more.trim() } : {},
|
|
20090
20312
|
meta,
|
|
20091
20313
|
feed,
|
|
20092
20314
|
verdicts: ((doc.verdicts?.length) ? doc.verdicts : DEFAULT_VERDICTS).map((v) => ({
|
|
20093
20315
|
id: slug(v),
|
|
20094
20316
|
label: label(v)
|
|
20095
20317
|
})),
|
|
20096
|
-
sections,
|
|
20097
|
-
steps
|
|
20318
|
+
sections: withKickers(sections, doc.sections, doc.kickers),
|
|
20319
|
+
steps,
|
|
20320
|
+
prs: knownPRs(doc, sections),
|
|
20321
|
+
...repoOf(doc) ? { repo: repoOf(doc) } : {}
|
|
20098
20322
|
};
|
|
20099
20323
|
}
|
|
20324
|
+
var prNumber = (href) => /\/(?:pull|merge_requests)\/(\d+)(?:[/?#]|$)/.exec(href)?.[1] ?? null;
|
|
20325
|
+
var repoOf = (doc) => doc.repo?.trim().replace(/^https?:\/\/github\.com\//, "").replace(/\/+$/, "") || undefined;
|
|
20326
|
+
function knownPRs(doc, sections) {
|
|
20327
|
+
const out = {};
|
|
20328
|
+
const repo = repoOf(doc);
|
|
20329
|
+
for (const s of sections) {
|
|
20330
|
+
const n = s.link && prNumber(s.link.href);
|
|
20331
|
+
if (n)
|
|
20332
|
+
out[n] = { href: s.link.href.replace(/(\/pull\/\d+).*$/, "$1") };
|
|
20333
|
+
}
|
|
20334
|
+
for (const [k, pr] of Object.entries(doc.prs ?? {})) {
|
|
20335
|
+
const n = k.replace(/^#/, "");
|
|
20336
|
+
if (!/^\d+$/.test(n))
|
|
20337
|
+
continue;
|
|
20338
|
+
out[n] = { ...out[n], ...pr };
|
|
20339
|
+
}
|
|
20340
|
+
if (repo) {
|
|
20341
|
+
for (const n of Object.keys(out))
|
|
20342
|
+
if (!out[n].href)
|
|
20343
|
+
out[n] = { ...out[n], href: `https://github.com/${repo}/pull/${n}` };
|
|
20344
|
+
}
|
|
20345
|
+
return out;
|
|
20346
|
+
}
|
|
20347
|
+
function findPR(prs, n, repo) {
|
|
20348
|
+
const known = prs[n];
|
|
20349
|
+
if (known)
|
|
20350
|
+
return known;
|
|
20351
|
+
return repo ? { href: `https://github.com/${repo}/pull/${n}` } : null;
|
|
20352
|
+
}
|
|
20353
|
+
var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
|
|
20354
|
+
function withKickers(sections, source, kickers = "pr") {
|
|
20355
|
+
if (kickers === false)
|
|
20356
|
+
return [...sections];
|
|
20357
|
+
const noun = typeof kickers === "object" ? kickers.noun.trim() : "PR";
|
|
20358
|
+
const counted = typeof kickers === "object" ? sections : sections.filter((s) => s.link && isPullRequest(s.link.href));
|
|
20359
|
+
return sections.map((s, i) => {
|
|
20360
|
+
const own = source[i]?.kicker;
|
|
20361
|
+
if (own !== undefined || s.kicker)
|
|
20362
|
+
return s;
|
|
20363
|
+
const at = counted.indexOf(s);
|
|
20364
|
+
return at < 0 ? s : { ...s, kicker: `${noun} ${at + 1} of ${counted.length}`.trim() };
|
|
20365
|
+
});
|
|
20366
|
+
}
|
|
20367
|
+
function tableStacks(stack, room, natural) {
|
|
20368
|
+
if (stack !== "auto")
|
|
20369
|
+
return stack === "always";
|
|
20370
|
+
return room > 0 && natural > room + 1;
|
|
20371
|
+
}
|
|
20372
|
+
function noteBarReserve(bar, inset, gap) {
|
|
20373
|
+
return Math.max(0, Math.ceil(bar)) + inset + gap;
|
|
20374
|
+
}
|
|
20100
20375
|
function parseAt(at) {
|
|
20101
20376
|
if (!at)
|
|
20102
20377
|
return null;
|
|
@@ -20381,6 +20656,9 @@ function feedbackMarkdown(fb, verdicts) {
|
|
|
20381
20656
|
`;
|
|
20382
20657
|
}
|
|
20383
20658
|
var escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
20659
|
+
function plainMarkdown(text) {
|
|
20660
|
+
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();
|
|
20661
|
+
}
|
|
20384
20662
|
function inlineMarkdown(text) {
|
|
20385
20663
|
const codes = [];
|
|
20386
20664
|
let s = text.replace(/`([^`\n]+)`/g, (_, c) => {
|
|
@@ -20401,6 +20679,10 @@ function inlineMarkdown(text) {
|
|
|
20401
20679
|
}
|
|
20402
20680
|
|
|
20403
20681
|
// src/ui/walkthrough-blocks.ts
|
|
20682
|
+
var GLYPH = {
|
|
20683
|
+
go: icon("caretRight", { small: true }),
|
|
20684
|
+
caret: icon("caretRight", { small: true })
|
|
20685
|
+
};
|
|
20404
20686
|
var el = (doc, tag, cls) => {
|
|
20405
20687
|
const n = doc.createElement(tag);
|
|
20406
20688
|
if (cls)
|
|
@@ -20430,9 +20712,10 @@ function stepButton(doc, ref, steps) {
|
|
|
20430
20712
|
const s = ref && steps?.find(ref);
|
|
20431
20713
|
if (!s || !steps)
|
|
20432
20714
|
return null;
|
|
20433
|
-
const b =
|
|
20715
|
+
const b = el(doc, "button", "knobs-wt-steplink");
|
|
20716
|
+
b.innerHTML = GLYPH.go;
|
|
20434
20717
|
b.type = "button";
|
|
20435
|
-
b.title = `Go to
|
|
20718
|
+
b.title = `Go to “${s.title}”`;
|
|
20436
20719
|
b.setAttribute("aria-label", b.title);
|
|
20437
20720
|
b.addEventListener("click", (e) => {
|
|
20438
20721
|
e.stopPropagation();
|
|
@@ -20557,7 +20840,7 @@ function mountStack(host, m, steps) {
|
|
|
20557
20840
|
if (target && steps) {
|
|
20558
20841
|
const title = text(doc, "button", "knobs-wt-stitle", it.title);
|
|
20559
20842
|
title.type = "button";
|
|
20560
|
-
title.title = `Go to
|
|
20843
|
+
title.title = `Go to “${target.title}”`;
|
|
20561
20844
|
title.addEventListener("click", (e) => {
|
|
20562
20845
|
e.stopPropagation();
|
|
20563
20846
|
steps.go(target.key);
|
|
@@ -20612,175 +20895,861 @@ function delta(doc, d) {
|
|
|
20612
20895
|
s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
|
|
20613
20896
|
return s;
|
|
20614
20897
|
}
|
|
20615
|
-
function
|
|
20616
|
-
|
|
20617
|
-
|
|
20618
|
-
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
|
|
20622
|
-
|
|
20623
|
-
|
|
20624
|
-
|
|
20625
|
-
|
|
20626
|
-
|
|
20627
|
-
|
|
20628
|
-
|
|
20629
|
-
|
|
20630
|
-
|
|
20631
|
-
|
|
20632
|
-
|
|
20633
|
-
|
|
20634
|
-
|
|
20635
|
-
|
|
20636
|
-
|
|
20637
|
-
|
|
20638
|
-
|
|
20639
|
-
|
|
20640
|
-
|
|
20641
|
-
|
|
20642
|
-
|
|
20643
|
-
|
|
20644
|
-
|
|
20645
|
-
|
|
20646
|
-
|
|
20647
|
-
|
|
20648
|
-
|
|
20649
|
-
|
|
20650
|
-
|
|
20651
|
-
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
|
|
20669
|
-
|
|
20670
|
-
|
|
20671
|
-
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
|
|
20678
|
-
|
|
20679
|
-
|
|
20680
|
-
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
|
|
20686
|
-
|
|
20687
|
-
|
|
20688
|
-
|
|
20689
|
-
|
|
20690
|
-
|
|
20691
|
-
|
|
20692
|
-
}
|
|
20693
|
-
|
|
20694
|
-
|
|
20898
|
+
function cellContent(doc, into, cell, steps) {
|
|
20899
|
+
let content;
|
|
20900
|
+
if (cell.badge) {
|
|
20901
|
+
content = link(doc, "knobs-wt-chip", cell.text, cell.href);
|
|
20902
|
+
content.dataset.tone = cell.badge;
|
|
20903
|
+
} else {
|
|
20904
|
+
const inner = cell.code ? text(doc, "code", "", cell.text) : null;
|
|
20905
|
+
if (cell.href) {
|
|
20906
|
+
content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
|
|
20907
|
+
if (inner)
|
|
20908
|
+
content.append(inner);
|
|
20909
|
+
} else
|
|
20910
|
+
content = inner ?? text(doc, "span", "", cell.text);
|
|
20911
|
+
if (cell.tone) {
|
|
20912
|
+
content.classList.add("knobs-wt-ctone");
|
|
20913
|
+
content.dataset.tone = cell.tone;
|
|
20914
|
+
}
|
|
20915
|
+
}
|
|
20916
|
+
into.append(content);
|
|
20917
|
+
const go = stepButton(doc, cell.step, steps);
|
|
20918
|
+
if (go)
|
|
20919
|
+
into.append(go);
|
|
20920
|
+
}
|
|
20921
|
+
var cellAttrs = (td, c) => {
|
|
20922
|
+
td.dataset.align = c.align;
|
|
20923
|
+
if (c.mono)
|
|
20924
|
+
td.dataset.mono = "";
|
|
20925
|
+
};
|
|
20926
|
+
function mountTable(host, m, steps) {
|
|
20927
|
+
const doc = host.ownerDocument;
|
|
20928
|
+
const win = doc.defaultView;
|
|
20929
|
+
const box = el(doc, "div", "knobs-wt-tablebox");
|
|
20930
|
+
const scroller = el(doc, "div", "knobs-wt-table");
|
|
20931
|
+
const table = el(doc, "table");
|
|
20932
|
+
if (m.caption)
|
|
20933
|
+
table.append(text(doc, "caption", "", m.caption));
|
|
20934
|
+
const head = el(doc, "thead");
|
|
20935
|
+
const hr = el(doc, "tr");
|
|
20936
|
+
for (const c of m.columns) {
|
|
20937
|
+
const th = text(doc, "th", "", c.label);
|
|
20938
|
+
th.scope = "col";
|
|
20939
|
+
th.dataset.align = c.align;
|
|
20940
|
+
hr.append(th);
|
|
20941
|
+
}
|
|
20942
|
+
head.append(hr);
|
|
20943
|
+
const body = el(doc, "tbody");
|
|
20944
|
+
for (const r of m.rows) {
|
|
20945
|
+
const tr = el(doc, "tr");
|
|
20946
|
+
for (const c of m.columns) {
|
|
20947
|
+
const td = el(doc, "td");
|
|
20948
|
+
cellAttrs(td, c);
|
|
20949
|
+
const cell = r[c.key];
|
|
20950
|
+
if (cell) {
|
|
20951
|
+
if (cell.text.length > 40 && !c.mono && !cell.code)
|
|
20952
|
+
td.dataset.long = "";
|
|
20953
|
+
cellContent(doc, td, cell, steps);
|
|
20954
|
+
}
|
|
20955
|
+
tr.append(td);
|
|
20956
|
+
}
|
|
20957
|
+
body.append(tr);
|
|
20958
|
+
}
|
|
20959
|
+
table.append(head, body);
|
|
20960
|
+
scroller.append(table);
|
|
20961
|
+
const stack = el(doc, "div", "knobs-wt-tstack");
|
|
20962
|
+
stack.setAttribute("role", "list");
|
|
20963
|
+
if (m.caption)
|
|
20964
|
+
stack.setAttribute("aria-label", m.caption);
|
|
20965
|
+
const primary = m.columns.find((c) => c.key === m.primary) ?? m.columns[0];
|
|
20966
|
+
for (const r of m.rows) {
|
|
20967
|
+
const item = el(doc, "div", "knobs-wt-trow");
|
|
20968
|
+
item.setAttribute("role", "listitem");
|
|
20969
|
+
const title = el(doc, "div", "knobs-wt-ttitle");
|
|
20970
|
+
if (primary) {
|
|
20971
|
+
cellAttrs(title, primary);
|
|
20972
|
+
const cell = r[primary.key];
|
|
20973
|
+
if (cell)
|
|
20974
|
+
cellContent(doc, title, cell, steps);
|
|
20975
|
+
}
|
|
20976
|
+
const line = el(doc, "div", "knobs-wt-tline");
|
|
20977
|
+
line.append(title);
|
|
20978
|
+
const badges = el(doc, "div", "knobs-wt-tbadges");
|
|
20979
|
+
for (const c of m.columns) {
|
|
20980
|
+
const cell = r[c.key];
|
|
20981
|
+
if (c !== primary && cell?.badge)
|
|
20982
|
+
cellContent(doc, badges, cell, steps);
|
|
20983
|
+
}
|
|
20984
|
+
if (badges.childNodes.length)
|
|
20985
|
+
line.append(badges);
|
|
20986
|
+
item.append(line);
|
|
20987
|
+
const terms = el(doc, "dl", "knobs-wt-tterms");
|
|
20988
|
+
for (const c of m.columns) {
|
|
20989
|
+
if (c === primary)
|
|
20990
|
+
continue;
|
|
20991
|
+
const cell = r[c.key];
|
|
20992
|
+
if (!cell || cell.text === "" || cell.badge)
|
|
20993
|
+
continue;
|
|
20994
|
+
const dd = el(doc, "dd");
|
|
20995
|
+
cellAttrs(dd, c);
|
|
20996
|
+
dd.removeAttribute("data-align");
|
|
20997
|
+
cellContent(doc, dd, cell, steps);
|
|
20998
|
+
terms.append(text(doc, "dt", "", c.label), dd);
|
|
20999
|
+
}
|
|
21000
|
+
if (terms.childNodes.length)
|
|
21001
|
+
item.append(terms);
|
|
21002
|
+
stack.append(item);
|
|
21003
|
+
}
|
|
21004
|
+
if (m.caption)
|
|
21005
|
+
stack.append(text(doc, "p", "knobs-wt-tcaption", m.caption));
|
|
21006
|
+
box.append(scroller, stack);
|
|
21007
|
+
host.append(box);
|
|
21008
|
+
let natural = 0;
|
|
21009
|
+
const measureNatural = () => {
|
|
21010
|
+
if (!box.isConnected)
|
|
21011
|
+
return 0;
|
|
21012
|
+
const was = box.dataset.stacked;
|
|
21013
|
+
delete box.dataset.stacked;
|
|
21014
|
+
box.dataset.measure = "";
|
|
21015
|
+
const w = table.getBoundingClientRect().width;
|
|
21016
|
+
delete box.dataset.measure;
|
|
21017
|
+
if (was !== undefined)
|
|
21018
|
+
box.dataset.stacked = was;
|
|
21019
|
+
return w;
|
|
21020
|
+
};
|
|
21021
|
+
const measure = () => {
|
|
21022
|
+
if (!natural)
|
|
21023
|
+
natural = measureNatural();
|
|
21024
|
+
const stacked = tableStacks(m.stack, box.clientWidth, natural);
|
|
21025
|
+
box.toggleAttribute("data-stacked", stacked);
|
|
21026
|
+
scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
|
|
21027
|
+
const scrolls = !stacked && (scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1);
|
|
21028
|
+
if (scrolls) {
|
|
21029
|
+
scroller.tabIndex = 0;
|
|
21030
|
+
scroller.setAttribute("role", "region");
|
|
21031
|
+
scroller.setAttribute("aria-label", m.caption ?? "Table");
|
|
21032
|
+
} else {
|
|
21033
|
+
scroller.removeAttribute("tabindex");
|
|
21034
|
+
scroller.removeAttribute("role");
|
|
21035
|
+
scroller.removeAttribute("aria-label");
|
|
21036
|
+
}
|
|
21037
|
+
};
|
|
21038
|
+
if (m.stack === "always")
|
|
21039
|
+
box.dataset.stacked = "";
|
|
21040
|
+
const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
|
|
21041
|
+
ro?.observe(box);
|
|
21042
|
+
measure();
|
|
21043
|
+
doc.fonts?.ready.then(() => {
|
|
21044
|
+
if (!box.isConnected)
|
|
21045
|
+
return;
|
|
21046
|
+
natural = 0;
|
|
21047
|
+
measure();
|
|
21048
|
+
});
|
|
21049
|
+
return {
|
|
21050
|
+
dispose: () => {
|
|
21051
|
+
ro?.disconnect();
|
|
21052
|
+
box.remove();
|
|
21053
|
+
},
|
|
21054
|
+
context: () => ({ kind: "table" })
|
|
21055
|
+
};
|
|
21056
|
+
}
|
|
21057
|
+
function chapterPills(host, chapters, io) {
|
|
21058
|
+
const doc = host.ownerDocument;
|
|
21059
|
+
const list = el(doc, "div", "knobs-wt-chapters");
|
|
21060
|
+
list.setAttribute("role", "group");
|
|
21061
|
+
list.setAttribute("aria-label", "Chapters");
|
|
21062
|
+
let at = -2;
|
|
21063
|
+
const rows = chapters.map((c, i) => {
|
|
21064
|
+
const b = el(doc, "button", "knobs-wt-chapter");
|
|
21065
|
+
b.type = "button";
|
|
21066
|
+
b.append(text(doc, "span", "knobs-wt-chapter-n", String(i + 1)));
|
|
21067
|
+
b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
|
|
21068
|
+
b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
|
|
21069
|
+
b.addEventListener("click", () => {
|
|
21070
|
+
io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
|
|
21071
|
+
io.seek(c.start);
|
|
21072
|
+
select(i);
|
|
21073
|
+
});
|
|
21074
|
+
list.append(b);
|
|
21075
|
+
return b;
|
|
21076
|
+
});
|
|
21077
|
+
host.append(list);
|
|
21078
|
+
const pill = selectionPill(list, {
|
|
21079
|
+
selected: () => rows[at] ?? null,
|
|
21080
|
+
rows: () => rows
|
|
21081
|
+
});
|
|
21082
|
+
const select = (i) => {
|
|
21083
|
+
if (i === at)
|
|
21084
|
+
return;
|
|
21085
|
+
at = i;
|
|
21086
|
+
rows.forEach((b, k) => k === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
21087
|
+
pill.update();
|
|
21088
|
+
};
|
|
21089
|
+
const sync = () => select(chapterAt(chapters, io.now()));
|
|
21090
|
+
sync();
|
|
21091
|
+
return {
|
|
21092
|
+
sync,
|
|
21093
|
+
get current() {
|
|
21094
|
+
return chapters[at] ?? null;
|
|
21095
|
+
},
|
|
21096
|
+
dispose() {
|
|
21097
|
+
pill.dispose();
|
|
21098
|
+
list.remove();
|
|
21099
|
+
}
|
|
21100
|
+
};
|
|
21101
|
+
}
|
|
21102
|
+
function disclosure(host, options) {
|
|
21103
|
+
const doc = host.ownerDocument;
|
|
21104
|
+
const win = doc.defaultView;
|
|
21105
|
+
let open = options.open === true;
|
|
21106
|
+
const root = el(doc, "div", "knobs-wt-disc");
|
|
21107
|
+
const toggle = el(doc, "button", "knobs-wt-disc-toggle");
|
|
21108
|
+
toggle.type = "button";
|
|
21109
|
+
toggle.innerHTML = GLYPH.caret;
|
|
21110
|
+
toggle.append(text(doc, "span", "", options.label));
|
|
21111
|
+
if (options.count !== undefined)
|
|
21112
|
+
toggle.append(text(doc, "span", "knobs-wt-disc-count", String(options.count)));
|
|
21113
|
+
const viewport = el(doc, "div", "knobs-wt-disc-body");
|
|
21114
|
+
const content = el(doc, "div", "knobs-wt-disc-content");
|
|
21115
|
+
content.append(options.content);
|
|
21116
|
+
viewport.append(content);
|
|
21117
|
+
root.append(toggle, viewport);
|
|
21118
|
+
host.append(root);
|
|
21119
|
+
const STATE = springMotion(SPRINGS.default);
|
|
21120
|
+
const h = new Spring(0, STATE.omega, STATE.zeta, 0.25);
|
|
21121
|
+
let full = 0;
|
|
21122
|
+
const paint = (moving) => {
|
|
21123
|
+
const k = full > 0 ? Math.max(0, Math.min(1, h.x / full)) : open ? 1 : 0;
|
|
21124
|
+
viewport.style.height = !moving && open ? "" : `${Math.max(0, h.x).toFixed(2)}px`;
|
|
21125
|
+
viewport.toggleAttribute("data-moving", moving);
|
|
21126
|
+
content.style.opacity = (open ? Math.min(1, k * 1.25) : Math.max(0, k * 1.5 - 0.5)).toFixed(3);
|
|
21127
|
+
};
|
|
21128
|
+
const loop = frameLoop(win, (dt) => {
|
|
21129
|
+
h.step(dt);
|
|
21130
|
+
const moving = !h.resting;
|
|
21131
|
+
paint(moving);
|
|
21132
|
+
return moving;
|
|
21133
|
+
});
|
|
21134
|
+
const sync = () => {
|
|
21135
|
+
root.toggleAttribute("data-open", open);
|
|
21136
|
+
toggle.setAttribute("aria-expanded", String(open));
|
|
21137
|
+
viewport.inert = !open;
|
|
21138
|
+
};
|
|
21139
|
+
sync();
|
|
21140
|
+
h.snap(0);
|
|
21141
|
+
paint(false);
|
|
21142
|
+
if (open) {
|
|
21143
|
+
viewport.style.height = "";
|
|
21144
|
+
content.style.opacity = "1";
|
|
21145
|
+
}
|
|
21146
|
+
const api = {
|
|
21147
|
+
element: root,
|
|
21148
|
+
get open() {
|
|
21149
|
+
return open;
|
|
21150
|
+
},
|
|
21151
|
+
toggle(next = !open) {
|
|
21152
|
+
if (next === open)
|
|
21153
|
+
return;
|
|
21154
|
+
open = next;
|
|
21155
|
+
sync();
|
|
21156
|
+
full = content.offsetHeight;
|
|
21157
|
+
if (reducedMotion(win)) {
|
|
21158
|
+
loop.stop();
|
|
21159
|
+
h.snap(open ? full : 0);
|
|
21160
|
+
viewport.style.height = open ? "" : "0px";
|
|
21161
|
+
content.style.opacity = open ? "1" : "0";
|
|
21162
|
+
return;
|
|
21163
|
+
}
|
|
21164
|
+
if (h.resting)
|
|
21165
|
+
h.snap(open ? 0 : full);
|
|
21166
|
+
h.set(open ? full : 0);
|
|
21167
|
+
paint(true);
|
|
21168
|
+
loop.wake();
|
|
21169
|
+
},
|
|
21170
|
+
dispose() {
|
|
21171
|
+
loop.stop();
|
|
21172
|
+
root.remove();
|
|
21173
|
+
}
|
|
21174
|
+
};
|
|
21175
|
+
toggle.addEventListener("click", () => api.toggle());
|
|
21176
|
+
return api;
|
|
21177
|
+
}
|
|
21178
|
+
var PR_PATHS = {
|
|
21179
|
+
pull: "M104,64A32,32,0,1,0,64,95v66a32,32,0,1,0,16,0V95A32.06,32.06,0,0,0,104,64ZM56,64A16,16,0,1,1,72,80,16,16,0,0,1,56,64ZM88,192a16,16,0,1,1-16-16A16,16,0,0,1,88,192Zm120-31V110.63a23.85,23.85,0,0,0-7-17L163.31,56H192a8,8,0,0,0,0-16H144a8,8,0,0,0-8,8V96a8,8,0,0,0,16,0V67.31L189.66,105a8,8,0,0,1,2.34,5.66V161a32,32,0,1,0,16,0Zm-8,47a16,16,0,1,1,16-16A16,16,0,0,1,200,208Z",
|
|
21180
|
+
merge: "M208,112a32.05,32.05,0,0,0-30.69,23l-42.21-6a8,8,0,0,1-4.95-2.71L94.43,84.55A32,32,0,1,0,72,87v82a32,32,0,1,0,16,0V101.63l30,35a24,24,0,0,0,14.83,8.14l44,6.28A32,32,0,1,0,208,112ZM64,56A16,16,0,1,1,80,72,16,16,0,0,1,64,56ZM96,200a16,16,0,1,1-16-16A16,16,0,0,1,96,200Zm112-40a16,16,0,1,1,16-16A16,16,0,0,1,208,160Z"
|
|
21181
|
+
};
|
|
21182
|
+
var prGlyph = (merged) => `<svg class="knobs-icon" viewBox="0 0 256 256" width="12" height="12" fill="currentColor" aria-hidden="true" focusable="false"><path d="${merged ? PR_PATHS.merge : PR_PATHS.pull}"/></svg>`;
|
|
21183
|
+
var PR_STATE = { merged: "Merged", open: "Open", draft: "Draft", closed: "Closed" };
|
|
21184
|
+
function prChip(doc, n, pr) {
|
|
21185
|
+
const chip = el(doc, pr.href ? "a" : "span", "knobs-wt-pr");
|
|
21186
|
+
if (pr.href) {
|
|
21187
|
+
chip.setAttribute("href", pr.href);
|
|
21188
|
+
chip.setAttribute("target", "_blank");
|
|
21189
|
+
chip.setAttribute("rel", "noreferrer");
|
|
21190
|
+
}
|
|
21191
|
+
if (pr.state)
|
|
21192
|
+
chip.dataset.state = pr.state;
|
|
21193
|
+
chip.innerHTML = prGlyph(pr.state === "merged");
|
|
21194
|
+
chip.append(text(doc, "span", "", `#${n}`));
|
|
21195
|
+
const tip = [`#${n}`, pr.title, pr.state ? PR_STATE[pr.state] : ""].filter(Boolean).join(" · ");
|
|
21196
|
+
chip.title = tip;
|
|
21197
|
+
chip.setAttribute("aria-label", `Pull request ${tip}`);
|
|
21198
|
+
return chip;
|
|
21199
|
+
}
|
|
21200
|
+
var PR_URL = /^https?:\/\/[^/]+\/.+\/(?:pull|merge_requests)\/(\d+)\/?(?:[?#].*)?$/;
|
|
21201
|
+
var PR_REF = /(^|[^\w&/#])#(\d{3,7})\b/g;
|
|
21202
|
+
function linkPRs(root, find) {
|
|
21203
|
+
const doc = root.ownerDocument;
|
|
21204
|
+
for (const a of Array.from(root.querySelectorAll("a[href]"))) {
|
|
21205
|
+
if (a.classList.contains("knobs-wt-pr") || a.closest(".knobs-wt-slot,button"))
|
|
21206
|
+
continue;
|
|
21207
|
+
const n = PR_URL.exec(a.getAttribute("href") ?? "")?.[1];
|
|
21208
|
+
const words = a.textContent?.trim() ?? "";
|
|
21209
|
+
if (!n || !(words === `#${n}` || words === n || words === a.getAttribute("href")))
|
|
21210
|
+
continue;
|
|
21211
|
+
a.replaceWith(prChip(doc, n, { href: a.href, ...find(n) }));
|
|
21212
|
+
}
|
|
21213
|
+
const walker = doc.createTreeWalker(root, 5);
|
|
21214
|
+
const hits = [];
|
|
21215
|
+
for (let t = walker.nextNode();t; t = walker.nextNode()) {
|
|
21216
|
+
if (t.nodeType !== 3)
|
|
21217
|
+
continue;
|
|
21218
|
+
const p = t.parentElement;
|
|
21219
|
+
if (!p || p.closest("a,code,pre,button,.knobs-wt-slot,.knobs-wt-pr"))
|
|
21220
|
+
continue;
|
|
21221
|
+
PR_REF.lastIndex = 0;
|
|
21222
|
+
if (PR_REF.test(t.nodeValue ?? ""))
|
|
21223
|
+
hits.push(t);
|
|
21224
|
+
}
|
|
21225
|
+
for (const t of hits) {
|
|
21226
|
+
const value = t.nodeValue ?? "";
|
|
21227
|
+
const frag = doc.createDocumentFragment();
|
|
21228
|
+
let last = 0;
|
|
21229
|
+
let changed = false;
|
|
21230
|
+
PR_REF.lastIndex = 0;
|
|
21231
|
+
for (let m = PR_REF.exec(value);m; m = PR_REF.exec(value)) {
|
|
21232
|
+
const pr = find(m[2]);
|
|
21233
|
+
if (!pr)
|
|
21234
|
+
continue;
|
|
21235
|
+
const at = m.index + m[1].length;
|
|
21236
|
+
frag.append(value.slice(last, at), prChip(doc, m[2], pr));
|
|
21237
|
+
last = at + m[2].length + 1;
|
|
21238
|
+
changed = true;
|
|
21239
|
+
}
|
|
21240
|
+
if (!changed)
|
|
21241
|
+
continue;
|
|
21242
|
+
frag.append(value.slice(last));
|
|
21243
|
+
t.replaceWith(frag);
|
|
21244
|
+
}
|
|
21245
|
+
}
|
|
21246
|
+
|
|
21247
|
+
// src/ui/walkthrough-media.ts
|
|
21248
|
+
init_compare_model();
|
|
21249
|
+
init_glide();
|
|
21250
|
+
init_icons();
|
|
21251
|
+
init_look();
|
|
21252
|
+
|
|
21253
|
+
// src/ui/walkthrough-css.ts
|
|
21254
|
+
init_motion();
|
|
21255
|
+
var snappy3 = springCss(SPRINGS.snappy);
|
|
21256
|
+
var calm = springCss(SPRINGS.calm);
|
|
21257
|
+
var state = springCss(SPRINGS.default);
|
|
21258
|
+
var quick = springCss(FADE);
|
|
21259
|
+
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)";
|
|
21260
|
+
var walkthroughCss = `
|
|
21261
|
+
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
21262
|
+
.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;
|
|
21263
|
+
--kw-measure:var(--k-walkthrough-measure,68ch);--kw-width:var(--k-walkthrough-width,960px);--kw-rail-w:220px;--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info));
|
|
21264
|
+
--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);
|
|
21265
|
+
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;
|
|
21266
|
+
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
21267
|
+
.knobs-walkthrough [hidden]{display:none!important}
|
|
21268
|
+
/* (0,0,1): a host's element rules stop here, and every class rule below wins over it. */
|
|
21269
|
+
:where(.knobs-walkthrough) :is(h1,h2,h3,p,ol,ul,dl,dd){margin:0;font:inherit;letter-spacing:inherit}
|
|
21270
|
+
.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}
|
|
21271
|
+
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
21272
|
+
.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)}
|
|
21273
|
+
: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;
|
|
21274
|
+
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
21275
|
+
|
|
21276
|
+
/* ——— layout: the contents rail sticky at the left edge (right if asked), and the column centred
|
|
21277
|
+
in the room beside it, up to --kw-width: media take the column, prose stops at the measure.
|
|
21278
|
+
One column where it's narrow ——— */
|
|
21279
|
+
.knobs-wt-layout{display:grid;grid-template-columns:var(--kw-rail-w) minmax(0,1fr);gap:var(--_k-space-column);align-items:start}
|
|
21280
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-layout{grid-template-columns:minmax(0,1fr) var(--kw-rail-w)}
|
|
21281
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-main{grid-column:1;grid-row:1}
|
|
21282
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-rail{grid-column:2;grid-row:1}
|
|
21283
|
+
.knobs-walkthrough[data-rail="none"] .knobs-wt-layout{grid-template-columns:minmax(0,1fr)}
|
|
21284
|
+
.knobs-wt-main{justify-self:center;width:100%;max-width:var(--kw-width);display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0;padding-bottom:12px}
|
|
21285
|
+
/* The intro, the updates and each section: a section's room apart, the hairline in the middle. */
|
|
21286
|
+
.knobs-wt-flow{display:flex;flex-direction:column;gap:calc(var(--_k-space-section) / 2);min-width:0}
|
|
21287
|
+
.knobs-wt-flow>*+*{padding-top:calc(var(--_k-space-section) / 2);box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
21288
|
+
@container knobs-wt (max-width:960px){.knobs-walkthrough[data-rail] .knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:var(--_k-space-title)}
|
|
21289
|
+
.knobs-walkthrough[data-rail] .knobs-wt-layout>*{grid-column:auto;grid-row:auto}}
|
|
21290
|
+
|
|
21291
|
+
/* ——— one line of facts: small, faint, joined by ·, its trailing edge fading ——— */
|
|
21292
|
+
.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}}
|
|
21293
|
+
.knobs-wt-metaline>*{flex:none}
|
|
21294
|
+
.knobs-wt-metaline>*+*::before{content:"·";margin-right:var(--_k-space-inside);color:var(--_k-fg-3)}
|
|
21295
|
+
.knobs-walkthrough .knobs-wt-metaline a:not(.knobs-wt-pr){display:inline-flex;align-items:baseline;color:inherit;text-decoration:none;transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21296
|
+
.knobs-walkthrough .knobs-wt-metaline a:not(.knobs-wt-pr):hover{color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21297
|
+
.knobs-wt-metaline svg{align-self:center;width:12px;height:12px;margin-left:2px}
|
|
21298
|
+
/* A pull request: a small chip, its state's icon and number in a quiet tint of the state (open
|
|
21299
|
+
the success hue, merged the violet series, draft and closed neutral), its title on hover. */
|
|
21300
|
+
.knobs-ui .knobs-wt-pr{--kw-pr:var(--_k-fg-2);display:inline-flex;align-items:center;gap:3px;height:18px;padding:0 5px 0 4px;margin:0 1px;border-radius:calc(var(--_k-radius) / 2);vertical-align:1px;
|
|
21301
|
+
background:color-mix(in oklch,var(--kw-pr) 12%,transparent);color:var(--kw-pr);font:var(--_k-weight-label) var(--_k-type-small)/1 var(--_k-font);font-variant-numeric:tabular-nums;white-space:nowrap;text-decoration:none;
|
|
21302
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
21303
|
+
.knobs-ui .knobs-wt-pr[data-state="open"]{--kw-pr:color-mix(in oklch,var(--_k-ok) 60%,var(--_k-fg-2))}
|
|
21304
|
+
.knobs-ui .knobs-wt-pr[data-state="merged"]{--kw-pr:color-mix(in oklch,var(--_k-series-5) 60%,var(--_k-fg-2))}
|
|
21305
|
+
.knobs-ui .knobs-wt-pr:is([data-state="draft"],[data-state="closed"]){--kw-pr:var(--_k-fg-3)}
|
|
21306
|
+
.knobs-ui a.knobs-wt-pr:is(:hover,:focus-visible){background:color-mix(in oklch,var(--kw-pr) 22%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21307
|
+
.knobs-wt-pr svg{flex:none}
|
|
21308
|
+
.knobs-wt-metaline .knobs-wt-pr{align-self:center;margin:0}
|
|
21309
|
+
.knobs-wt-kicker-lead{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
21310
|
+
.knobs-wt-metaline [data-status="on"]{color:var(--_k-fg)}
|
|
21311
|
+
.knobs-wt-metaline [data-status="warn"]{color:var(--_k-warn)}
|
|
21312
|
+
|
|
21313
|
+
/* ——— the page's head ——— */
|
|
21314
|
+
.knobs-wt-head{display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
21315
|
+
.knobs-wt-title{font-size:var(--_k-type-heading)!important;line-height:var(--_k-leading-heading);font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
21316
|
+
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
21317
|
+
.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)}
|
|
21318
|
+
.knobs-wt-meta>span{display:inline-flex;gap:var(--_k-space-inside);white-space:nowrap}
|
|
21319
|
+
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono)}
|
|
21320
|
+
|
|
21321
|
+
/* ——— a section: a PR or topic. Its kicker leads the meta line, its title under it (16/24, under
|
|
21322
|
+
the page's 20/28), both on the column's edge ——— */
|
|
21323
|
+
.knobs-wt-section{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
21324
|
+
.knobs-wt-sintro{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0}
|
|
21325
|
+
.knobs-wt-shead{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0;scroll-margin-top:16px}
|
|
21326
|
+
.knobs-wt-heading{font-size:var(--_k-type-title)!important;line-height:var(--_k-leading-title);font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
21327
|
+
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
21328
|
+
.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;
|
|
21329
|
+
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
21330
|
+
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
21331
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21332
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
21333
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21334
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
21335
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
21336
|
+
|
|
21337
|
+
/* ——— a step: on the page by default, a group's room between steps with a hairline in the middle;
|
|
21338
|
+
or (cards) one card each, the one surface its pieces sit on ——— */
|
|
21339
|
+
.knobs-walkthrough:not([data-cards]) .knobs-wt-step:not([data-full]){padding:0;border-radius:0;background:transparent;box-shadow:none}
|
|
21340
|
+
.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}
|
|
21341
|
+
.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);
|
|
21342
|
+
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
21343
|
+
.knobs-walkthrough[data-cards]{--kw-under:var(--kw-card)}
|
|
21344
|
+
.knobs-walkthrough[data-cards][data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
21345
|
+
.knobs-wt-step-head{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
21346
|
+
.knobs-wt-stepTitle{min-width:0;font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
21347
|
+
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
21348
|
+
.knobs-wt-question{font-weight:var(--kw-strong)!important;max-width:var(--kw-measure)}
|
|
21349
|
+
.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}
|
|
21350
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
21351
|
+
|
|
21352
|
+
/* ——— the feed: updates and answers, newest first. Tight inside an item (4 / 8 / 4), a group's
|
|
21353
|
+
room between items with the hairline in the middle; no boxes ——— */
|
|
21354
|
+
.knobs-wt-feed{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0;scroll-margin-top:16px}
|
|
21355
|
+
.knobs-wt-feed-head{display:flex;align-items:baseline;gap:var(--_k-space-sibling)}
|
|
21356
|
+
.knobs-wt-feed-title{font-weight:var(--kw-strong)!important}
|
|
21357
|
+
.knobs-wt-feed-count{font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}
|
|
21358
|
+
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
21359
|
+
.knobs-wt-fi{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
21360
|
+
.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)}
|
|
21361
|
+
.knobs-wt-fi-q,.knobs-wt-fi-a{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
21362
|
+
.knobs-wt-fi-ask{max-width:var(--kw-measure);color:var(--_k-fg);font-weight:var(--kw-strong);text-wrap:pretty}
|
|
21363
|
+
.knobs-wt-fi-text{max-width:var(--kw-measure);color:var(--_k-fg);text-wrap:pretty}
|
|
21364
|
+
.knobs-wt-fi-answer{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
21365
|
+
: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;
|
|
21366
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21367
|
+
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21368
|
+
: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;
|
|
21369
|
+
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)}
|
|
21370
|
+
.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)}
|
|
21371
|
+
.knobs-wt-steplink svg{width:12px;height:12px}
|
|
21372
|
+
|
|
21373
|
+
/* ——— a disclosure: a small faint toggle with a caret, no fill. The body's height springs (in
|
|
21374
|
+
script) and its content fades in place, top-anchored, under a soft bottom mask ——— */
|
|
21375
|
+
.knobs-wt-disc{display:flex;flex-direction:column;min-width:0}
|
|
21376
|
+
.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;
|
|
21377
|
+
border-radius:calc(var(--_k-radius) / 2);transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21378
|
+
.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)}
|
|
21379
|
+
.knobs-ui .knobs-wt-disc-toggle:focus-visible{box-shadow:0 0 0 2px var(--_k-focus)}
|
|
21380
|
+
.knobs-wt-disc-toggle svg{flex:none;width:12px;height:12px;transition:rotate var(--kw-state-ms) var(--kw-state)}
|
|
21381
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-toggle svg{rotate:90deg}
|
|
21382
|
+
.knobs-wt-disc-count{color:var(--_k-fg-3)}
|
|
21383
|
+
.knobs-wt-disc-body{overflow:hidden}
|
|
21384
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-body:not([data-moving]){overflow:visible}
|
|
21385
|
+
.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)}
|
|
21386
|
+
.knobs-wt-disc-content{padding-top:var(--_k-space-inside)}
|
|
21387
|
+
/* "More" under a caption or summary: the rest of its words, in the same voice. */
|
|
21388
|
+
.knobs-wt-more-text{display:flex;flex-direction:column;gap:var(--_k-space-sibling);max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
21389
|
+
/* A trail sits on the toggle's label edge: faint lines, the time trailing. */
|
|
21390
|
+
.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}
|
|
21391
|
+
.knobs-wt-trail li{display:flex;align-items:baseline;gap:var(--_k-space-sibling);min-width:0;white-space:nowrap}
|
|
21392
|
+
.knobs-wt-trail-text{flex:0 1 auto;min-width:0;overflow:hidden;${fade2}}
|
|
21393
|
+
.knobs-wt-trail-at{flex:none}
|
|
21394
|
+
|
|
21395
|
+
/* ——— a step's sent notes ——— */
|
|
21396
|
+
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
21397
|
+
.knobs-wt-notes:empty{display:none}
|
|
21398
|
+
.knobs-wt-n{display:flex;align-items:flex-start;gap:var(--_k-space-sibling);padding:6px 0;overflow:hidden;
|
|
21399
|
+
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)}
|
|
21400
|
+
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
21401
|
+
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
21402
|
+
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
21403
|
+
.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)}
|
|
21404
|
+
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
21405
|
+
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
21406
|
+
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
21407
|
+
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
21408
|
+
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
|
|
21409
|
+
.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}
|
|
21410
|
+
|
|
21411
|
+
/* ——— the note bar, docked at the bottom of the column. It holds its own place at the page's end
|
|
21412
|
+
(so the last step stays clear of it), and script keeps its height as the scroller's
|
|
21413
|
+
scroll-padding-bottom ——— */
|
|
21414
|
+
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;display:grid;pointer-events:none}
|
|
21415
|
+
.knobs-wt-dock>*{pointer-events:auto}
|
|
21416
|
+
.knobs-wt-dock>:is(.knobs-wt-notebar,.knobs-wt-launch){grid-area:1/1}
|
|
21417
|
+
.knobs-wt-dock[data-mode="docked"]>.knobs-wt-launch{display:none}
|
|
21418
|
+
/* Collapsed: the launcher and the bar swap in place, a quick fade with a little scale and blur
|
|
21419
|
+
from the launcher's corner; the exit is the shorter. */
|
|
21420
|
+
: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);
|
|
21421
|
+
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%;
|
|
21422
|
+
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)}
|
|
21423
|
+
.knobs-ui .knobs-wt-launch:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
21424
|
+
.knobs-ui .knobs-wt-launch:focus-visible{box-shadow:var(--_k-focus-ring)}
|
|
21425
|
+
.knobs-wt-launch svg{width:16px;height:16px}
|
|
21426
|
+
.knobs-wt-launch kbd{font:inherit;font-weight:var(--_k-weight);color:var(--_k-fg-3)}
|
|
21427
|
+
.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)}
|
|
21428
|
+
.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;
|
|
21429
|
+
transition-duration:calc(var(--kw-quick-ms) * .8)}
|
|
21430
|
+
.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);
|
|
21431
|
+
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
21432
|
+
.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}}
|
|
21433
|
+
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
21434
|
+
: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;
|
|
21435
|
+
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
21436
|
+
.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)}
|
|
21437
|
+
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
21438
|
+
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
21439
|
+
.knobs-wt-attach:empty{display:none}
|
|
21440
|
+
.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}
|
|
21441
|
+
.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}
|
|
21442
|
+
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
21443
|
+
.knobs-wt-x svg{width:12px;height:12px}
|
|
21444
|
+
.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);
|
|
21445
|
+
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
21446
|
+
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
21447
|
+
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
21448
|
+
.knobs-wt-tool svg{width:16px;height:16px}
|
|
21449
|
+
.knobs-wt-rec{font-size:var(--_k-type-small)}
|
|
21450
|
+
.knobs-wt-rec:empty{display:none}
|
|
21451
|
+
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
21452
|
+
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
21453
|
+
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
21454
|
+
.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;
|
|
21455
|
+
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;
|
|
21456
|
+
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)}
|
|
21457
|
+
.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)}
|
|
21458
|
+
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
21459
|
+
.knobs-wt-back svg{flex:none;width:12px;height:12px}
|
|
21460
|
+
.knobs-wt-back-label{min-width:0;overflow:hidden;white-space:nowrap;${fade2}}
|
|
21461
|
+
|
|
21462
|
+
/* ——— ink over a step's media ——— */
|
|
21463
|
+
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
21464
|
+
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
21465
|
+
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
21466
|
+
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
21467
|
+
|
|
21468
|
+
/* ——— full-window: the step over the page above the note bar, its media filling it; its place held
|
|
21469
|
+
in the page. The one raised surface ——— */
|
|
21470
|
+
.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}
|
|
21471
|
+
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
21472
|
+
.knobs-wt-hold-card{flex:none}
|
|
21473
|
+
.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)}
|
|
21474
|
+
.knobs-wt-step[data-full]::before{content:none}
|
|
21475
|
+
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
21476
|
+
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
21477
|
+
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
21478
|
+
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
21479
|
+
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
21480
|
+
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
21481
|
+
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
21482
|
+
|
|
21483
|
+
/* ——— a taste test: the options side by side, Kit's pick checked and the rest stepping back. On
|
|
21484
|
+
the step's card, so no fill of their own ——— */
|
|
21485
|
+
.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)}
|
|
21486
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
21487
|
+
.knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
21488
|
+
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
21489
|
+
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
21490
|
+
.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;
|
|
21491
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
21492
|
+
.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)}
|
|
21493
|
+
.knobs-wt-letter{flex:none;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
21494
|
+
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
21495
|
+
.knobs-wt-suggested{flex:none;font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
21496
|
+
.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;
|
|
21497
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
21498
|
+
.knobs-wt-check svg{width:12px;height:12px}
|
|
21499
|
+
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
21500
|
+
.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);
|
|
21501
|
+
font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);opacity:.5;transition:opacity .15s}
|
|
21502
|
+
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
21503
|
+
.knobs-wt-ocap{color:var(--_k-fg-2);max-width:var(--kw-measure)}
|
|
21504
|
+
|
|
21505
|
+
/* ——— the rail: progress, contents, export ——— */
|
|
21506
|
+
.knobs-wt-rail{position:sticky;top:var(--_k-pad-page);display:flex;flex-direction:column;gap:var(--_k-space-title);max-height:calc(100vh - var(--_k-pad-page) * 2);min-height:0;font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
21507
|
+
.knobs-wt-progress{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
21508
|
+
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2)}
|
|
21509
|
+
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
21510
|
+
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
21511
|
+
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
21512
|
+
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
21513
|
+
/* The contents: every row on one text edge and in one colour, title rows (32 high, the control
|
|
21514
|
+
radius) and the steps under them (20 high, half of it), bled out so their text sits on the
|
|
21515
|
+
rail's edge; the selection pill slides to the current step, and base rows never brighten. */
|
|
21516
|
+
.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}
|
|
21517
|
+
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
21518
|
+
.knobs-wt-toc-group{display:flex;flex-direction:column;min-width:0}
|
|
21519
|
+
.knobs-ui .knobs-wt-toc-row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--_k-space-sibling);align-items:center;flex:none;width:100%;height:32px;
|
|
21520
|
+
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(--_k-weight);text-align:left;white-space:nowrap;cursor:pointer;
|
|
21521
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
21522
|
+
.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)}
|
|
21523
|
+
.knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21524
|
+
.knobs-ui .knobs-wt-toc-row:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
21525
|
+
.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)}
|
|
21526
|
+
.knobs-wt-toc-label{min-width:0;overflow:hidden;${fade2}}
|
|
21527
|
+
.knobs-pick-copy .knobs-wt-toc-end{color:var(--_k-fg-2)}
|
|
21528
|
+
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
21529
|
+
.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);
|
|
21530
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
21531
|
+
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
21532
|
+
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
21533
|
+
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
21534
|
+
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
21535
|
+
.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;
|
|
21536
|
+
transition:background .15s,color .15s}
|
|
21537
|
+
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
21538
|
+
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
21539
|
+
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
21540
|
+
.knobs-wt-keys{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
21541
|
+
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
21542
|
+
/* Narrow: the contents go; with review on, the rail becomes a bar along the top with the
|
|
21543
|
+
progress and the export. */
|
|
21544
|
+
@container knobs-wt (max-width:960px){
|
|
21545
|
+
.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)}
|
|
21546
|
+
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
21547
|
+
.knobs-walkthrough:not([data-review]) .knobs-wt-rail{display:none}
|
|
21548
|
+
.knobs-wt-step,.knobs-wt-shead,.knobs-wt-feed{scroll-margin-top:60px}
|
|
21549
|
+
}
|
|
21550
|
+
|
|
21551
|
+
/* ——— media slots. Only a picture's frame (a quiet fill while it loads or letterboxes) and a code
|
|
21552
|
+
block (a well) are bounded; a metric, a callout, a table, a stack and a history sit on the page,
|
|
21553
|
+
set apart by space, hairlines and their own colours. On a card (.knobs-surface) code drops its
|
|
21554
|
+
well for hairlines, so nothing draws a fill and a ring of its own there ——— */
|
|
21555
|
+
.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);
|
|
21556
|
+
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);
|
|
21557
|
+
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info));--kw-frame-r:var(--_k-radius-panel)}
|
|
21558
|
+
.knobs-surface .knobs-wt-slot{--kw-frame-r:calc(var(--_k-radius-panel) - 4px)}
|
|
21559
|
+
/* A slot's label: sentence case as written, small and faint, never a heading. */
|
|
21560
|
+
.knobs-wt-slot-label{display:block;min-width:0;overflow:hidden;white-space:nowrap;font:var(--_k-weight) var(--_k-type-small)/var(--_k-leading-small) var(--_k-font);letter-spacing:normal;text-transform:none;color:var(--_k-fg-3);${fade2}}
|
|
21561
|
+
.knobs-wt-body{min-width:0}
|
|
21562
|
+
/* One frame for every slot that has one (a picture, a video, a code block, a compare's stage, a
|
|
21563
|
+
slot still loading): the panel radius and a quiet fill, no ring; concentric on a card. */
|
|
21564
|
+
.knobs-wt-slot .knobs-cmp-stage{border-radius:var(--kw-frame-r)}
|
|
21565
|
+
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
21566
|
+
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
21567
|
+
(92 px), and the frame strip with its gap (158 px). */
|
|
21568
|
+
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
21569
|
+
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
21570
|
+
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
21571
|
+
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
21572
|
+
.knobs-wt-frame{position:relative;width:100%;overflow:hidden;border-radius:var(--kw-frame-r);background:var(--_k-fill);aspect-ratio:var(--kw-aspect,16/9)}
|
|
21573
|
+
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
21574
|
+
.knobs-wt-frame[data-natural]{aspect-ratio:auto;background:transparent}
|
|
21575
|
+
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
21576
|
+
.knobs-wt-code{margin:0;padding:var(--_k-pad-card);max-height:420px;overflow:auto;border-radius:var(--kw-frame-r);background:var(--_k-fill);color:var(--_k-fg);
|
|
21577
|
+
font:var(--_k-type-label)/var(--_k-leading-body) var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
21578
|
+
.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)}
|
|
21579
|
+
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
21580
|
+
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
21581
|
+
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
21582
|
+
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
21583
|
+
.knobs-wt-metric{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
21584
|
+
.knobs-wt-mlabel{color:var(--_k-fg-2)}
|
|
21585
|
+
.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"}
|
|
21586
|
+
.knobs-wt-mfrom{color:var(--_k-fg-3)}
|
|
21587
|
+
.knobs-wt-mto{font-size:var(--_k-type-title);line-height:var(--_k-leading-title);font-weight:var(--_k-weight-label)}
|
|
21588
|
+
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
21589
|
+
.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)}
|
|
21590
|
+
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21591
|
+
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21592
|
+
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
21593
|
+
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
21594
|
+
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
21595
|
+
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
21596
|
+
.knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:var(--_k-space-sibling);max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
21597
|
+
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:7px;border-radius:50%;background:var(--kw-tone)}
|
|
21598
|
+
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21599
|
+
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
21600
|
+
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21601
|
+
.knobs-wt-text{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
21602
|
+
.knobs-wt-hold{border-radius:var(--kw-frame-r);background:var(--_k-fill)}
|
|
21603
|
+
.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)}
|
|
21604
|
+
|
|
21605
|
+
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
21606
|
+
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
21607
|
+
: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)}
|
|
21608
|
+
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
21609
|
+
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
21610
|
+
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
21611
|
+
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
21612
|
+
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
21613
|
+
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
21614
|
+
.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);
|
|
21615
|
+
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
21616
|
+
.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)}
|
|
21617
|
+
|
|
21618
|
+
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
21619
|
+
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
21620
|
+
.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)}
|
|
21621
|
+
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
21622
|
+
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
21623
|
+
.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)}
|
|
21624
|
+
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:var(--_k-type-small);font-variant-numeric:tabular-nums}
|
|
21625
|
+
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
21626
|
+
.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}
|
|
21627
|
+
.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)}
|
|
21628
|
+
.knobs-wt-hage{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
21629
|
+
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
21630
|
+
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
21631
|
+
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
21632
|
+
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
21633
|
+
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
21634
|
+
.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))}
|
|
21635
|
+
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
21636
|
+
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
21637
|
+
.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))}
|
|
21638
|
+
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
21639
|
+
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
21640
|
+
.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}
|
|
21641
|
+
.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}
|
|
21642
|
+
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
21643
|
+
@container knobs-wt-slot (max-width:520px){
|
|
21644
|
+
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
21645
|
+
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
21646
|
+
}
|
|
21647
|
+
|
|
21648
|
+
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
21649
|
+
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
21650
|
+
.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)}
|
|
21651
|
+
.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);
|
|
21652
|
+
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
21653
|
+
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
21654
|
+
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
21655
|
+
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21656
|
+
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
21657
|
+
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
21658
|
+
.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)}
|
|
21659
|
+
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
21660
|
+
.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}
|
|
21661
|
+
.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)}
|
|
21662
|
+
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
21663
|
+
.knobs-wt-trunk{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
21664
|
+
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
21665
|
+
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
21666
|
+
.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}
|
|
21667
|
+
.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}
|
|
21668
|
+
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
21669
|
+
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
21670
|
+
.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)}
|
|
21671
|
+
.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)}
|
|
21672
|
+
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
21673
|
+
.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)}
|
|
21674
|
+
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
21675
|
+
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
21676
|
+
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
21677
|
+
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
21678
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
21679
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
21680
|
+
@container knobs-wt-slot (max-width:520px){
|
|
21681
|
+
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
21682
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
21683
|
+
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
20695
21684
|
}
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
20701
|
-
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
draw();
|
|
20733
|
-
return !x.resting || !y.resting || !w.resting;
|
|
20734
|
-
});
|
|
20735
|
-
let at = -2;
|
|
20736
|
-
let shown = false;
|
|
20737
|
-
const place = (snap) => {
|
|
20738
|
-
const p = pills[at];
|
|
20739
|
-
if (!p) {
|
|
20740
|
-
mark.removeAttribute("data-on");
|
|
20741
|
-
pills.forEach((b) => b.removeAttribute("aria-current"));
|
|
20742
|
-
shown = false;
|
|
20743
|
-
return;
|
|
20744
|
-
}
|
|
20745
|
-
pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
20746
|
-
const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
|
|
20747
|
-
if (snap || !shown || reducedMotion(win)) {
|
|
20748
|
-
x.snap(to[0]);
|
|
20749
|
-
y.snap(to[1]);
|
|
20750
|
-
w.snap(to[2]);
|
|
20751
|
-
draw();
|
|
20752
|
-
} else {
|
|
20753
|
-
x.set(to[0]);
|
|
20754
|
-
y.set(to[1]);
|
|
20755
|
-
w.set(to[2]);
|
|
20756
|
-
loop.wake();
|
|
20757
|
-
}
|
|
20758
|
-
mark.style.height = `${p.offsetHeight}px`;
|
|
20759
|
-
mark.dataset.on = "";
|
|
20760
|
-
shown = true;
|
|
20761
|
-
};
|
|
20762
|
-
const sync = () => {
|
|
20763
|
-
const next = chapterAt(chapters, io.now());
|
|
20764
|
-
if (next === at)
|
|
20765
|
-
return;
|
|
20766
|
-
at = next;
|
|
20767
|
-
place(false);
|
|
20768
|
-
};
|
|
20769
|
-
sync();
|
|
20770
|
-
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
|
|
20771
|
-
ro?.observe(bar);
|
|
20772
|
-
return {
|
|
20773
|
-
sync,
|
|
20774
|
-
get current() {
|
|
20775
|
-
return chapters[at] ?? null;
|
|
20776
|
-
},
|
|
20777
|
-
dispose() {
|
|
20778
|
-
loop.stop();
|
|
20779
|
-
ro?.disconnect();
|
|
20780
|
-
bar.remove();
|
|
20781
|
-
}
|
|
20782
|
-
};
|
|
21685
|
+
|
|
21686
|
+
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
21687
|
+
(the top one under the head), and thin bars show on hover. */
|
|
21688
|
+
/* Too narrow for its columns, each row becomes a block: its primary cell titling the rest as term
|
|
21689
|
+
and value, the blocks parted by hairlines. Scrolling sideways is the last resort (stack: never). */
|
|
21690
|
+
.knobs-wt-tablebox{min-width:0}
|
|
21691
|
+
.knobs-wt-tablebox[data-measure] table{width:min-content}
|
|
21692
|
+
.knobs-wt-tstack{display:none;flex-direction:column;min-width:0}
|
|
21693
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-table{display:none}
|
|
21694
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-tstack{display:flex}
|
|
21695
|
+
.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)}
|
|
21696
|
+
.knobs-wt-trow:first-child{padding-top:0}
|
|
21697
|
+
.knobs-wt-trow:last-of-type{padding-bottom:0;box-shadow:none}
|
|
21698
|
+
.knobs-wt-tline{display:flex;align-items:baseline;justify-content:space-between;gap:var(--_k-space-title);min-width:0}
|
|
21699
|
+
.knobs-wt-tbadges{flex:none;display:flex;align-items:center;gap:var(--_k-space-inside)}
|
|
21700
|
+
.knobs-wt-ttitle{flex:1 1 auto;min-width:0;color:var(--_k-fg);font-weight:var(--_k-weight-label);overflow-wrap:anywhere}
|
|
21701
|
+
.knobs-wt-ttitle[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label)}
|
|
21702
|
+
.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}
|
|
21703
|
+
.knobs-wt-tterms dt{color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21704
|
+
.knobs-wt-tterms dd{min-width:0;color:var(--_k-fg-2);overflow-wrap:anywhere}
|
|
21705
|
+
.knobs-wt-tterms dd[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg)}
|
|
21706
|
+
.knobs-wt-tcaption{padding-top:var(--_k-space-sibling);color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21707
|
+
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
21708
|
+
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
21709
|
+
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
21710
|
+
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
21711
|
+
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
21712
|
+
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
21713
|
+
.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)}
|
|
21714
|
+
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:var(--kw-frame-r)}
|
|
21715
|
+
@supports (animation-timeline:scroll()){
|
|
21716
|
+
.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;
|
|
21717
|
+
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%;
|
|
21718
|
+
--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)));
|
|
21719
|
+
--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)));
|
|
21720
|
+
-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}
|
|
20783
21721
|
}
|
|
21722
|
+
.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)}
|
|
21723
|
+
.knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
21724
|
+
.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;
|
|
21725
|
+
background:var(--kw-under,var(--_k-pane-bg));box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
21726
|
+
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
21727
|
+
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
21728
|
+
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
21729
|
+
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
21730
|
+
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
21731
|
+
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
21732
|
+
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
21733
|
+
.knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg);white-space:nowrap}
|
|
21734
|
+
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
21735
|
+
.knobs-ui :is(.knobs-wt-table,.knobs-wt-tstack) a.knobs-wt-chip{text-decoration:none}
|
|
21736
|
+
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
21737
|
+
|
|
21738
|
+
/* Chapters: a readout list under a video or compare: number, label, start; the selection pill
|
|
21739
|
+
on the one playing, its rows bled out so their text sits on the media's edge. */
|
|
21740
|
+
.knobs-wt-body:has(>.knobs-wt-chapters){display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
21741
|
+
.knobs-wt-chapters{position:relative;display:flex;flex-direction:column;margin:0 calc(var(--_k-space-sibling) * -1)}
|
|
21742
|
+
.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);
|
|
21743
|
+
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)}
|
|
21744
|
+
.knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
21745
|
+
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
21746
|
+
.knobs-wt-chapter-n{font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
21747
|
+
.knobs-wt-chapter-label{min-width:0;overflow:hidden;${fade2}}
|
|
21748
|
+
.knobs-wt-chapter-time{font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);color:var(--_k-fg-3)}
|
|
21749
|
+
.knobs-pick-copy :is(.knobs-wt-chapter-n,.knobs-wt-chapter-time){color:var(--_k-fg-2)}
|
|
21750
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
21751
|
+
@media(prefers-reduced-motion:reduce){.knobs-wt-disc-content{transition:opacity .15s}}
|
|
21752
|
+
`;
|
|
20784
21753
|
|
|
20785
21754
|
// src/ui/walkthrough-media.ts
|
|
20786
21755
|
function injectWalkthroughStyles(doc) {
|
|
@@ -21309,7 +22278,7 @@ function mediaSlot(container, options) {
|
|
|
21309
22278
|
}
|
|
21310
22279
|
};
|
|
21311
22280
|
}
|
|
21312
|
-
var CHECK3 =
|
|
22281
|
+
var CHECK3 = icon("check", { small: true });
|
|
21313
22282
|
|
|
21314
22283
|
// src/ui/walkthrough.ts
|
|
21315
22284
|
var el2 = (doc, tag, cls) => {
|
|
@@ -21327,16 +22296,20 @@ var lookOf2 = (o) => ({
|
|
|
21327
22296
|
...o.preset ? { preset: o.preset } : {},
|
|
21328
22297
|
...o.theme ? { theme: o.theme } : {}
|
|
21329
22298
|
});
|
|
21330
|
-
var
|
|
22299
|
+
var grid2 = (v) => Math.round(v * 64) / 64;
|
|
21331
22300
|
var ICON = {
|
|
21332
|
-
full:
|
|
21333
|
-
exit:
|
|
21334
|
-
pen:
|
|
21335
|
-
mic:
|
|
22301
|
+
full: icon("cornersOut"),
|
|
22302
|
+
exit: icon("cornersIn"),
|
|
22303
|
+
pen: icon("pencilSimple"),
|
|
22304
|
+
mic: icon("microphone"),
|
|
21336
22305
|
stop: svg('<rect x="4.5" y="4.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none"/>'),
|
|
21337
|
-
send:
|
|
21338
|
-
close:
|
|
22306
|
+
send: icon("paperPlaneRight"),
|
|
22307
|
+
close: icon("x", { small: true }),
|
|
22308
|
+
back: icon("arrowLeft", { small: true }),
|
|
22309
|
+
out: icon("arrowUpRight", { small: true })
|
|
21339
22310
|
};
|
|
22311
|
+
var DOCK_INSET = 12;
|
|
22312
|
+
var DOCK_GAP = 12;
|
|
21340
22313
|
var CALM2 = springMotion(SPRINGS.calm);
|
|
21341
22314
|
var SMOOTH = springMotion(SPRINGS.smooth);
|
|
21342
22315
|
var BACK_MS = 4500;
|
|
@@ -21352,16 +22325,25 @@ function tasteTest(container, options) {
|
|
|
21352
22325
|
...o.media !== undefined ? { media: fillMedia(o.media) } : {},
|
|
21353
22326
|
suggested: o.suggested === true
|
|
21354
22327
|
});
|
|
21355
|
-
|
|
22328
|
+
const pickable = options.pickable !== false;
|
|
22329
|
+
let picked = pickable ? options.picked ?? null : null;
|
|
21356
22330
|
const root = el2(doc, "div", "knobs-wt-options");
|
|
21357
|
-
|
|
21358
|
-
|
|
22331
|
+
if (pickable) {
|
|
22332
|
+
root.setAttribute("role", "radiogroup");
|
|
22333
|
+
root.setAttribute("aria-label", "Options");
|
|
22334
|
+
} else
|
|
22335
|
+
root.dataset.static = "";
|
|
21359
22336
|
root.style.setProperty("--kw-n", String(Math.min(list.length, 3)));
|
|
21360
22337
|
if (!container.closest(".knobs-ui"))
|
|
21361
22338
|
applyLook2(root, options);
|
|
21362
22339
|
const slots = [];
|
|
21363
22340
|
const tiles = list.map((o, i) => {
|
|
21364
22341
|
const tile = el2(doc, "div", "knobs-wt-option");
|
|
22342
|
+
if (!pickable) {
|
|
22343
|
+
const name = el2(doc, "span", "knobs-wt-slot-label");
|
|
22344
|
+
name.textContent = o.label;
|
|
22345
|
+
tile.append(name);
|
|
22346
|
+
}
|
|
21365
22347
|
const pick = el2(doc, "button", "knobs-wt-pick");
|
|
21366
22348
|
pick.type = "button";
|
|
21367
22349
|
pick.setAttribute("role", "radio");
|
|
@@ -21390,7 +22372,8 @@ function tasteTest(container, options) {
|
|
|
21390
22372
|
api.pick(next);
|
|
21391
22373
|
options.onPick?.(next);
|
|
21392
22374
|
});
|
|
21393
|
-
|
|
22375
|
+
if (pickable)
|
|
22376
|
+
tile.append(pick);
|
|
21394
22377
|
if (o.media)
|
|
21395
22378
|
slots.push(mediaSlot(tile, {
|
|
21396
22379
|
...look,
|
|
@@ -21469,8 +22452,13 @@ function walkthrough(container, options) {
|
|
|
21469
22452
|
let count = null;
|
|
21470
22453
|
let fill = null;
|
|
21471
22454
|
let tocEl = null;
|
|
21472
|
-
let
|
|
22455
|
+
let pill = null;
|
|
22456
|
+
let tocRows = [];
|
|
22457
|
+
let discs = [];
|
|
21473
22458
|
let full = null;
|
|
22459
|
+
const review = options.review === true;
|
|
22460
|
+
const noteMode = review ? options.noteBar ?? "collapsed" : "hidden";
|
|
22461
|
+
let reserve = noteBarReserve(52, DOCK_INSET, DOCK_GAP);
|
|
21474
22462
|
const viewOf = (key) => views.find((v) => v.step.key === key);
|
|
21475
22463
|
const feedback = () => collectFeedback(page, state);
|
|
21476
22464
|
const markdown = () => feedbackMarkdown(feedback(), page.verdicts);
|
|
@@ -21494,9 +22482,6 @@ function walkthrough(container, options) {
|
|
|
21494
22482
|
else
|
|
21495
22483
|
run();
|
|
21496
22484
|
};
|
|
21497
|
-
const pillY = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
21498
|
-
const pillH = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
21499
|
-
let pillPlaced = false;
|
|
21500
22485
|
const scroll = {
|
|
21501
22486
|
spring: new Spring(0, CALM2.omega, CALM2.zeta, 0.5),
|
|
21502
22487
|
to: null,
|
|
@@ -21504,13 +22489,6 @@ function walkthrough(container, options) {
|
|
|
21504
22489
|
};
|
|
21505
22490
|
const motion = frameLoop(win, (dt) => {
|
|
21506
22491
|
let more = false;
|
|
21507
|
-
if (mark) {
|
|
21508
|
-
pillY.step(dt);
|
|
21509
|
-
pillH.step(dt);
|
|
21510
|
-
mark.style.transform = `translateY(${grid3(pillY.x)}px)`;
|
|
21511
|
-
mark.style.height = `${grid3(pillY.x + pillH.x) - grid3(pillY.x)}px`;
|
|
21512
|
-
more ||= !pillY.resting || !pillH.resting;
|
|
21513
|
-
}
|
|
21514
22492
|
if (scroll.to && scroll.el) {
|
|
21515
22493
|
scroll.spring.set(scrollTarget(scroll.to, scroll.el));
|
|
21516
22494
|
scroll.spring.step(dt);
|
|
@@ -21574,21 +22552,12 @@ function walkthrough(container, options) {
|
|
|
21574
22552
|
v.glyph.dataset.tone = v.step.ask === "none" ? "none" : verdict ? verdictTone(verdict, page.verdicts.findIndex((x) => x.id === verdict)) : done ? "accent" : "dim";
|
|
21575
22553
|
};
|
|
21576
22554
|
const placeMark = () => {
|
|
21577
|
-
if (!
|
|
22555
|
+
if (!pill || !tocEl)
|
|
21578
22556
|
return;
|
|
22557
|
+
pill.update();
|
|
21579
22558
|
const row = viewOf(current)?.toc;
|
|
21580
22559
|
if (!row)
|
|
21581
|
-
return
|
|
21582
|
-
mark.dataset.on = "";
|
|
21583
|
-
if (!pillPlaced || reduced()) {
|
|
21584
|
-
pillY.snap(row.offsetTop);
|
|
21585
|
-
pillH.snap(row.offsetHeight);
|
|
21586
|
-
pillPlaced = true;
|
|
21587
|
-
} else {
|
|
21588
|
-
pillY.set(row.offsetTop);
|
|
21589
|
-
pillH.set(row.offsetHeight);
|
|
21590
|
-
}
|
|
21591
|
-
motion.wake();
|
|
22560
|
+
return;
|
|
21592
22561
|
const top = row.offsetTop;
|
|
21593
22562
|
const bottom = top + row.offsetHeight;
|
|
21594
22563
|
if (top < tocEl.scrollTop + 8)
|
|
@@ -21605,6 +22574,9 @@ function walkthrough(container, options) {
|
|
|
21605
22574
|
const v = viewOf(key);
|
|
21606
22575
|
v?.card.setAttribute("data-current", "");
|
|
21607
22576
|
v?.toc?.setAttribute("aria-current", "step");
|
|
22577
|
+
for (const r of tocRows)
|
|
22578
|
+
if (r.dataset.section)
|
|
22579
|
+
r.toggleAttribute("data-active", r.dataset.section === v?.step.section);
|
|
21608
22580
|
if (key)
|
|
21609
22581
|
record({ what: "step", step: key });
|
|
21610
22582
|
placeMark();
|
|
@@ -21621,6 +22593,16 @@ function walkthrough(container, options) {
|
|
|
21621
22593
|
else
|
|
21622
22594
|
break;
|
|
21623
22595
|
}
|
|
22596
|
+
const s = scrollerOf(root);
|
|
22597
|
+
if (s.scrollTop > 0 && s.scrollTop >= s.scrollHeight - s.clientHeight - 2) {
|
|
22598
|
+
const bottom = (s === doc.scrollingElement ? win.innerHeight : s.getBoundingClientRect().bottom) - reserve;
|
|
22599
|
+
for (let i = views.length - 1;i >= 0; i--) {
|
|
22600
|
+
if (views[i].card.getBoundingClientRect().top < bottom) {
|
|
22601
|
+
pick = views[i].step.key;
|
|
22602
|
+
break;
|
|
22603
|
+
}
|
|
22604
|
+
}
|
|
22605
|
+
}
|
|
21624
22606
|
setCurrent(pick);
|
|
21625
22607
|
};
|
|
21626
22608
|
let scrollRaf = 0;
|
|
@@ -21663,15 +22645,20 @@ function walkthrough(container, options) {
|
|
|
21663
22645
|
};
|
|
21664
22646
|
const scrim = el2(doc, "div", "knobs-wt-scrim");
|
|
21665
22647
|
scrim.addEventListener("click", () => setFull(false));
|
|
21666
|
-
const fullRect = () => ({
|
|
22648
|
+
const fullRect = () => ({
|
|
22649
|
+
x: DOCK_INSET,
|
|
22650
|
+
y: DOCK_INSET,
|
|
22651
|
+
w: win.innerWidth - DOCK_INSET * 2,
|
|
22652
|
+
h: win.innerHeight - DOCK_INSET - reserve
|
|
22653
|
+
});
|
|
21667
22654
|
const placeFull = (f) => {
|
|
21668
22655
|
const a = f.hold.getBoundingClientRect();
|
|
21669
22656
|
const b = fullRect();
|
|
21670
22657
|
const k = reduced() ? Math.round(f.p.target) : f.p.x;
|
|
21671
|
-
const left =
|
|
21672
|
-
const top =
|
|
21673
|
-
const right =
|
|
21674
|
-
const bottom =
|
|
22658
|
+
const left = grid2(a.left + (b.x - a.left) * k);
|
|
22659
|
+
const top = grid2(a.top + (b.y - a.top) * k);
|
|
22660
|
+
const right = grid2(a.right + (b.x + b.w - a.right) * k);
|
|
22661
|
+
const bottom = grid2(a.bottom + (b.y + b.h - a.bottom) * k);
|
|
21675
22662
|
const s = f.v.card.style;
|
|
21676
22663
|
s.left = `${left}px`;
|
|
21677
22664
|
s.top = `${top}px`;
|
|
@@ -21808,6 +22795,7 @@ function walkthrough(container, options) {
|
|
|
21808
22795
|
ink.on = true;
|
|
21809
22796
|
ink.layer.dataset.on = "";
|
|
21810
22797
|
root.dataset.inking = "";
|
|
22798
|
+
bar.setOpen(true);
|
|
21811
22799
|
bar.sync();
|
|
21812
22800
|
};
|
|
21813
22801
|
const voice = {
|
|
@@ -21847,6 +22835,7 @@ function walkthrough(container, options) {
|
|
|
21847
22835
|
});
|
|
21848
22836
|
voice.recorder = rec;
|
|
21849
22837
|
voice.started = performance.now();
|
|
22838
|
+
bar.setOpen(true);
|
|
21850
22839
|
rec.start();
|
|
21851
22840
|
voice.timer = win.setInterval(() => bar.sync(), 250);
|
|
21852
22841
|
bar.sync();
|
|
@@ -21873,7 +22862,10 @@ function walkthrough(container, options) {
|
|
|
21873
22862
|
if (!v)
|
|
21874
22863
|
return;
|
|
21875
22864
|
backTo = key;
|
|
21876
|
-
backPill.
|
|
22865
|
+
backPill.innerHTML = ICON.back;
|
|
22866
|
+
const words = el2(doc, "span", "knobs-wt-back-label");
|
|
22867
|
+
words.textContent = `Back to ${plainMarkdown(v.step.title)}`;
|
|
22868
|
+
backPill.append(words);
|
|
21877
22869
|
backPill.dataset.on = "";
|
|
21878
22870
|
win.clearTimeout(backTimer);
|
|
21879
22871
|
backTimer = win.setTimeout(hideBack, BACK_MS);
|
|
@@ -21905,7 +22897,41 @@ function walkthrough(container, options) {
|
|
|
21905
22897
|
sendBtn.dataset.send = "";
|
|
21906
22898
|
row.append(input, attach, fullBtn, penBtn, micBtn, sendBtn);
|
|
21907
22899
|
box.append(on, row);
|
|
21908
|
-
|
|
22900
|
+
const launch = el2(doc, "button", "knobs-wt-launch");
|
|
22901
|
+
launch.type = "button";
|
|
22902
|
+
launch.innerHTML = ICON.pen;
|
|
22903
|
+
launch.append("Note");
|
|
22904
|
+
const kbd = el2(doc, "kbd");
|
|
22905
|
+
kbd.textContent = "n";
|
|
22906
|
+
launch.append(kbd);
|
|
22907
|
+
launch.setAttribute("aria-label", "Write a note (n)");
|
|
22908
|
+
launch.addEventListener("click", () => setOpen(true, true));
|
|
22909
|
+
dock.dataset.mode = noteMode;
|
|
22910
|
+
dock.append(backPill, box, launch);
|
|
22911
|
+
let open = noteMode !== "collapsed";
|
|
22912
|
+
const setOpen = (on, focus = false) => {
|
|
22913
|
+
if (noteMode === "collapsed" && on !== open) {
|
|
22914
|
+
open = on;
|
|
22915
|
+
dock.toggleAttribute("data-open", on);
|
|
22916
|
+
box.inert = !on;
|
|
22917
|
+
launch.inert = on;
|
|
22918
|
+
syncReserve();
|
|
22919
|
+
}
|
|
22920
|
+
if (on && focus)
|
|
22921
|
+
input.focus({ preventScroll: true });
|
|
22922
|
+
};
|
|
22923
|
+
dock.toggleAttribute("data-open", open);
|
|
22924
|
+
box.inert = !open;
|
|
22925
|
+
launch.inert = open;
|
|
22926
|
+
const empty = () => !input.value.trim() && !voice.pending && !voice.recorder && !ink.on && !ink.paths.length;
|
|
22927
|
+
const onOutside = (e) => {
|
|
22928
|
+
if (open && noteMode === "collapsed" && !dock.contains(e.target) && empty())
|
|
22929
|
+
setOpen(false);
|
|
22930
|
+
};
|
|
22931
|
+
doc.addEventListener("pointerdown", onOutside, true);
|
|
22932
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => syncReserve()) : null;
|
|
22933
|
+
ro?.observe(box);
|
|
22934
|
+
ro?.observe(launch);
|
|
21909
22935
|
const fit = () => {
|
|
21910
22936
|
input.style.height = "auto";
|
|
21911
22937
|
input.style.height = `${Math.min(140, input.scrollHeight)}px`;
|
|
@@ -21921,6 +22947,8 @@ function walkthrough(container, options) {
|
|
|
21921
22947
|
} else if (e.key === "Escape") {
|
|
21922
22948
|
e.preventDefault();
|
|
21923
22949
|
input.blur();
|
|
22950
|
+
if (empty())
|
|
22951
|
+
setOpen(false);
|
|
21924
22952
|
viewOf(current)?.card.focus({ preventScroll: true });
|
|
21925
22953
|
}
|
|
21926
22954
|
});
|
|
@@ -21940,13 +22968,13 @@ function walkthrough(container, options) {
|
|
|
21940
22968
|
const sync = () => {
|
|
21941
22969
|
const v = viewOf(current);
|
|
21942
22970
|
const ctx = describeMedia(mediaContext(v));
|
|
21943
|
-
const where = v ?
|
|
22971
|
+
const where = v ? plainMarkdown(v.step.title) : "General note";
|
|
21944
22972
|
const text = ctx ? `${where} · ${ctx}` : where;
|
|
21945
22973
|
if (text !== lastOn) {
|
|
21946
22974
|
on.textContent = text;
|
|
21947
22975
|
lastOn = text;
|
|
21948
22976
|
}
|
|
21949
|
-
input.placeholder = v ?
|
|
22977
|
+
input.placeholder = v ? "A note on this step… (n)" : "A note on the whole page… (n)";
|
|
21950
22978
|
const attached = `${voice.pending?.url ?? ""}|${ink.paths.length}`;
|
|
21951
22979
|
if (attached !== lastAttached) {
|
|
21952
22980
|
lastAttached = attached;
|
|
@@ -21985,14 +23013,45 @@ function walkthrough(container, options) {
|
|
|
21985
23013
|
};
|
|
21986
23014
|
return {
|
|
21987
23015
|
dock,
|
|
23016
|
+
box,
|
|
23017
|
+
launch,
|
|
21988
23018
|
input,
|
|
21989
23019
|
sync,
|
|
23020
|
+
get open() {
|
|
23021
|
+
return open;
|
|
23022
|
+
},
|
|
23023
|
+
setOpen,
|
|
23024
|
+
empty,
|
|
23025
|
+
unobserve: () => {
|
|
23026
|
+
ro?.disconnect();
|
|
23027
|
+
doc.removeEventListener("pointerdown", onOutside, true);
|
|
23028
|
+
},
|
|
21990
23029
|
clear() {
|
|
21991
23030
|
input.value = "";
|
|
21992
23031
|
fit();
|
|
21993
23032
|
}
|
|
21994
23033
|
};
|
|
21995
23034
|
})();
|
|
23035
|
+
let padded = null;
|
|
23036
|
+
function syncReserve() {
|
|
23037
|
+
if (disposed)
|
|
23038
|
+
return;
|
|
23039
|
+
const h = (bar.open ? bar.box : bar.launch).offsetHeight;
|
|
23040
|
+
if (noteMode === "hidden")
|
|
23041
|
+
reserve = 0;
|
|
23042
|
+
else if (h)
|
|
23043
|
+
reserve = noteBarReserve(h, DOCK_INSET, DOCK_GAP);
|
|
23044
|
+
root.style.setProperty("--kw-reserve", `${reserve}px`);
|
|
23045
|
+
const s = scrollerOf(root);
|
|
23046
|
+
if (padded?.el !== s) {
|
|
23047
|
+
if (padded)
|
|
23048
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
23049
|
+
padded = { el: s, was: s.style.scrollPaddingBottom };
|
|
23050
|
+
}
|
|
23051
|
+
s.style.scrollPaddingBottom = `${reserve}px`;
|
|
23052
|
+
if (full)
|
|
23053
|
+
placeFull(full);
|
|
23054
|
+
}
|
|
21996
23055
|
const ticker = win.setInterval(() => !doc.hidden && bar.sync(), 500);
|
|
21997
23056
|
const send = (text = bar.input.value) => {
|
|
21998
23057
|
if (voice.recorder)
|
|
@@ -22028,6 +23087,10 @@ function walkthrough(container, options) {
|
|
|
22028
23087
|
syncProgress();
|
|
22029
23088
|
emit();
|
|
22030
23089
|
bar.sync();
|
|
23090
|
+
if (noteMode === "collapsed") {
|
|
23091
|
+
bar.input.blur();
|
|
23092
|
+
bar.setOpen(false);
|
|
23093
|
+
}
|
|
22031
23094
|
if (v && options.advance !== false) {
|
|
22032
23095
|
const to = adjacentStep(views.map((x) => x.step.key), v.step.key, 1);
|
|
22033
23096
|
if (to && to !== v.step.key) {
|
|
@@ -22035,7 +23098,8 @@ function walkthrough(container, options) {
|
|
|
22035
23098
|
setFull(false);
|
|
22036
23099
|
go(to);
|
|
22037
23100
|
showBack(v.step.key);
|
|
22038
|
-
|
|
23101
|
+
if (noteMode === "docked")
|
|
23102
|
+
bar.input.focus({ preventScroll: true });
|
|
22039
23103
|
}
|
|
22040
23104
|
}
|
|
22041
23105
|
};
|
|
@@ -22122,28 +23186,121 @@ function walkthrough(container, options) {
|
|
|
22122
23186
|
row.addEventListener("transitionend", done, { once: true });
|
|
22123
23187
|
win.setTimeout(done, 600);
|
|
22124
23188
|
};
|
|
23189
|
+
const metaLine = (cls) => el2(doc, "div", `knobs-wt-metaline ${cls}`);
|
|
23190
|
+
const metaText = (line, text, cls) => {
|
|
23191
|
+
const s = el2(doc, "span", cls);
|
|
23192
|
+
s.textContent = text;
|
|
23193
|
+
line.append(s);
|
|
23194
|
+
return s;
|
|
23195
|
+
};
|
|
23196
|
+
const findPRIn = (n) => findPR(page.prs, n, page.repo);
|
|
23197
|
+
const metaLink = (line, text, href) => {
|
|
23198
|
+
const n = prNumber(href);
|
|
23199
|
+
if (n) {
|
|
23200
|
+
const chip = prChip(doc, n, { href, ...findPRIn(n) });
|
|
23201
|
+
line.append(chip);
|
|
23202
|
+
return chip;
|
|
23203
|
+
}
|
|
23204
|
+
const a = el2(doc, "a");
|
|
23205
|
+
a.href = href;
|
|
23206
|
+
a.target = "_blank";
|
|
23207
|
+
a.rel = "noreferrer";
|
|
23208
|
+
a.textContent = text;
|
|
23209
|
+
a.insertAdjacentHTML("beforeend", ICON.out);
|
|
23210
|
+
line.append(a);
|
|
23211
|
+
return a;
|
|
23212
|
+
};
|
|
23213
|
+
const feedItem = (f, now) => {
|
|
23214
|
+
const li = el2(doc, "li", "knobs-wt-fi");
|
|
23215
|
+
li.dataset.kind = f.kind;
|
|
23216
|
+
const q = el2(doc, "div", "knobs-wt-fi-q");
|
|
23217
|
+
const meta = metaLine("knobs-wt-fi-meta");
|
|
23218
|
+
if (f.at !== null) {
|
|
23219
|
+
const when = metaText(meta, ago(f.at, now));
|
|
23220
|
+
when.title = new Date(f.at).toLocaleString();
|
|
23221
|
+
} else
|
|
23222
|
+
metaText(meta, f.kind === "qa" ? "Answer" : "Update");
|
|
23223
|
+
const step = f.step ? page.steps.find((s) => s.key === f.step) : undefined;
|
|
23224
|
+
if (step) {
|
|
23225
|
+
const section = page.sections.find((s) => s.id === step.section);
|
|
23226
|
+
const b = el2(doc, "button", "knobs-wt-fi-step");
|
|
23227
|
+
b.type = "button";
|
|
23228
|
+
b.textContent = section?.link?.label ?? plainMarkdown(step.title);
|
|
23229
|
+
b.title = `Go to “${plainMarkdown(step.title)}”`;
|
|
23230
|
+
b.addEventListener("click", () => go(step.key));
|
|
23231
|
+
meta.append(b);
|
|
23232
|
+
}
|
|
23233
|
+
if (f.status) {
|
|
23234
|
+
const id = f.status.toLowerCase();
|
|
23235
|
+
const shipped = /^(ship|shipped|merged|done)$/.test(id);
|
|
23236
|
+
const changes = /^(changes?|changes queued)$/.test(id);
|
|
23237
|
+
const s = metaText(meta, shipped ? "Shipped" : changes ? "Changes queued" : f.status);
|
|
23238
|
+
s.dataset.status = shipped ? "on" : changes ? "warn" : "";
|
|
23239
|
+
}
|
|
23240
|
+
q.append(meta);
|
|
23241
|
+
if (f.q)
|
|
23242
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-ask", f.q));
|
|
23243
|
+
else
|
|
23244
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
23245
|
+
li.append(q);
|
|
23246
|
+
if (f.q || f.trail.length) {
|
|
23247
|
+
const a = el2(doc, "div", "knobs-wt-fi-a");
|
|
23248
|
+
if (f.q)
|
|
23249
|
+
a.append(prose2(doc, "div", "knobs-wt-fi-answer", f.text));
|
|
23250
|
+
if (f.trail.length) {
|
|
23251
|
+
const list = el2(doc, "ol", "knobs-wt-trail");
|
|
23252
|
+
for (const line of f.trail) {
|
|
23253
|
+
const i = line.indexOf(" · ");
|
|
23254
|
+
const row = el2(doc, "li");
|
|
23255
|
+
const words = el2(doc, "span", "knobs-wt-trail-text");
|
|
23256
|
+
words.textContent = i < 0 ? line : line.slice(i + 3);
|
|
23257
|
+
row.append(words);
|
|
23258
|
+
if (i >= 0) {
|
|
23259
|
+
const at = el2(doc, "span", "knobs-wt-trail-at");
|
|
23260
|
+
at.textContent = line.slice(0, i);
|
|
23261
|
+
row.append(at);
|
|
23262
|
+
}
|
|
23263
|
+
list.append(row);
|
|
23264
|
+
}
|
|
23265
|
+
discs.push(disclosure(a, { label: "Context", count: f.trail.length, content: list }));
|
|
23266
|
+
}
|
|
23267
|
+
li.append(a);
|
|
23268
|
+
}
|
|
23269
|
+
return li;
|
|
23270
|
+
};
|
|
22125
23271
|
const build = () => {
|
|
22126
23272
|
for (const v of views) {
|
|
22127
23273
|
v.slots.forEach((s) => s.dispose());
|
|
22128
23274
|
v.taste?.dispose();
|
|
22129
23275
|
}
|
|
23276
|
+
for (const d of discs)
|
|
23277
|
+
d.dispose();
|
|
23278
|
+
discs = [];
|
|
23279
|
+
pill?.dispose();
|
|
23280
|
+
pill = null;
|
|
23281
|
+
tocRows = [];
|
|
22130
23282
|
if (full) {
|
|
22131
23283
|
full.p.snap(0);
|
|
22132
23284
|
closeFull();
|
|
22133
23285
|
}
|
|
22134
23286
|
clearInk();
|
|
22135
23287
|
views = [];
|
|
22136
|
-
pillPlaced = false;
|
|
22137
23288
|
root.textContent = "";
|
|
22138
23289
|
root.removeAttribute("data-settled");
|
|
23290
|
+
root.dataset.rail = options.rail === false ? "none" : options.rail === "right" ? "right" : "left";
|
|
23291
|
+
root.toggleAttribute("data-cards", options.cards === true);
|
|
23292
|
+
root.toggleAttribute("data-review", review);
|
|
22139
23293
|
const layout = el2(doc, "div", "knobs-wt-layout");
|
|
22140
23294
|
const main = el2(doc, "div", "knobs-wt-main");
|
|
23295
|
+
const flow = el2(doc, "div", "knobs-wt-flow");
|
|
22141
23296
|
const head = el2(doc, "header", "knobs-wt-head");
|
|
22142
23297
|
const h1 = el2(doc, "h1", "knobs-wt-title");
|
|
22143
23298
|
h1.textContent = page.title;
|
|
22144
23299
|
head.append(h1);
|
|
22145
23300
|
if (page.summary)
|
|
22146
23301
|
head.append(prose2(doc, "p", "knobs-wt-summary", page.summary));
|
|
23302
|
+
if (page.more)
|
|
23303
|
+
head.append(more(page.more));
|
|
22147
23304
|
if (page.meta.length) {
|
|
22148
23305
|
const meta = el2(doc, "div", "knobs-wt-meta");
|
|
22149
23306
|
for (const m of page.meta) {
|
|
@@ -22164,57 +23321,51 @@ function walkthrough(container, options) {
|
|
|
22164
23321
|
}
|
|
22165
23322
|
head.append(meta);
|
|
22166
23323
|
}
|
|
22167
|
-
|
|
23324
|
+
flow.append(head);
|
|
23325
|
+
let feedEl = null;
|
|
22168
23326
|
if (page.feed.length) {
|
|
22169
|
-
|
|
22170
|
-
|
|
22171
|
-
|
|
23327
|
+
feedEl = el2(doc, "section", "knobs-wt-feed");
|
|
23328
|
+
feedEl.id = "wt-latest";
|
|
23329
|
+
feedEl.setAttribute("aria-label", "Updates and answers");
|
|
23330
|
+
const fh = el2(doc, "header", "knobs-wt-feed-head");
|
|
23331
|
+
const h = el2(doc, "h2", "knobs-wt-feed-title");
|
|
23332
|
+
h.textContent = page.feed.some((f) => f.kind === "qa") ? "Updates & Q&A" : "Updates";
|
|
23333
|
+
const n = el2(doc, "span", "knobs-wt-feed-count");
|
|
23334
|
+
n.textContent = String(page.feed.length);
|
|
23335
|
+
fh.append(h, n);
|
|
23336
|
+
const list = el2(doc, "ol", "knobs-wt-feed-list");
|
|
22172
23337
|
const now = Date.now();
|
|
22173
|
-
for (const f of page.feed)
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22177
|
-
when.textContent = f.at === null ? "" : ago(f.at, now);
|
|
22178
|
-
if (f.at !== null)
|
|
22179
|
-
when.title = new Date(f.at).toLocaleString();
|
|
22180
|
-
const kind = el2(doc, "span", "knobs-wt-fi-kind");
|
|
22181
|
-
kind.textContent = f.kind === "qa" ? "Answer" : "Update";
|
|
22182
|
-
const body = el2(doc, "div", "knobs-wt-fi-body");
|
|
22183
|
-
if (f.q)
|
|
22184
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
|
|
22185
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
22186
|
-
li.append(when, kind, body);
|
|
22187
|
-
if (f.step) {
|
|
22188
|
-
const target = f.step;
|
|
22189
|
-
const link = el2(doc, "button", "knobs-wt-fi-step");
|
|
22190
|
-
link.type = "button";
|
|
22191
|
-
link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
|
|
22192
|
-
link.title = "Go to the step";
|
|
22193
|
-
link.addEventListener("click", () => go(target));
|
|
22194
|
-
li.append(link);
|
|
22195
|
-
}
|
|
22196
|
-
list.append(li);
|
|
22197
|
-
}
|
|
22198
|
-
feed.append(list);
|
|
22199
|
-
main.append(feed);
|
|
23338
|
+
for (const f of page.feed)
|
|
23339
|
+
list.append(feedItem(f, now));
|
|
23340
|
+
feedEl.append(fh, list);
|
|
23341
|
+
flow.append(feedEl);
|
|
22200
23342
|
}
|
|
22201
23343
|
let rail = null;
|
|
22202
|
-
count = fill = tocEl =
|
|
23344
|
+
count = fill = tocEl = null;
|
|
22203
23345
|
if (options.rail !== false) {
|
|
22204
23346
|
rail = el2(doc, "aside", "knobs-wt-rail");
|
|
22205
|
-
rail.setAttribute("aria-label", "
|
|
22206
|
-
const progress = el2(doc, "div", "knobs-wt-progress");
|
|
22207
|
-
count = el2(doc, "div", "knobs-wt-count");
|
|
22208
|
-
const meter = el2(doc, "div", "knobs-wt-bar");
|
|
22209
|
-
fill = el2(doc, "div", "knobs-wt-fill");
|
|
22210
|
-
meter.append(fill);
|
|
22211
|
-
progress.append(count, meter);
|
|
23347
|
+
rail.setAttribute("aria-label", "Contents");
|
|
22212
23348
|
tocEl = el2(doc, "nav", "knobs-wt-toc");
|
|
22213
23349
|
tocEl.setAttribute("aria-label", "Contents");
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22217
|
-
|
|
23350
|
+
if (feedEl) {
|
|
23351
|
+
const group = el2(doc, "div", "knobs-wt-toc-group");
|
|
23352
|
+
const target = feedEl;
|
|
23353
|
+
group.append(tocRow("Latest", false, () => target.scrollIntoView({ block: "start", behavior: reduced() ? "auto" : "smooth" })));
|
|
23354
|
+
tocEl.append(group);
|
|
23355
|
+
}
|
|
23356
|
+
if (review) {
|
|
23357
|
+
const progress = el2(doc, "div", "knobs-wt-progress");
|
|
23358
|
+
count = el2(doc, "div", "knobs-wt-count");
|
|
23359
|
+
const meter = el2(doc, "div", "knobs-wt-bar");
|
|
23360
|
+
fill = el2(doc, "div", "knobs-wt-fill");
|
|
23361
|
+
meter.append(fill);
|
|
23362
|
+
progress.append(count, meter);
|
|
23363
|
+
rail.append(progress);
|
|
23364
|
+
}
|
|
23365
|
+
rail.append(tocEl);
|
|
23366
|
+
if (review)
|
|
23367
|
+
rail.append(actions(true));
|
|
23368
|
+
if (review && options.keys !== false) {
|
|
22218
23369
|
const keys = el2(doc, "div", "knobs-wt-keys");
|
|
22219
23370
|
keys.innerHTML = "<kbd>j</kbd> <kbd>k</kbd> steps · <kbd>←</kbd> <kbd>→</kbd> seek · <kbd>f</kbd> full · <kbd>n</kbd> note" + (page.steps.some((s) => s.ask === "pick") ? " · <kbd>1</kbd>–<kbd>9</kbd> pick" : "");
|
|
22220
23371
|
rail.append(keys);
|
|
@@ -22224,45 +23375,47 @@ function walkthrough(container, options) {
|
|
|
22224
23375
|
const sec = el2(doc, "section", "knobs-wt-section");
|
|
22225
23376
|
sec.id = `wt-${section.id}`;
|
|
22226
23377
|
const sh = el2(doc, "header", "knobs-wt-shead");
|
|
22227
|
-
|
|
22228
|
-
|
|
22229
|
-
|
|
22230
|
-
|
|
22231
|
-
|
|
22232
|
-
|
|
22233
|
-
|
|
22234
|
-
|
|
22235
|
-
|
|
22236
|
-
|
|
22237
|
-
if (section.status) {
|
|
22238
|
-
const s = statusLook(section.status);
|
|
22239
|
-
const chip = el2(doc, "span", "knobs-wt-chip");
|
|
22240
|
-
chip.dataset.tone = s.tone;
|
|
22241
|
-
chip.textContent = s.label;
|
|
22242
|
-
kicker.append(chip);
|
|
23378
|
+
const status = review ? section.status : undefined;
|
|
23379
|
+
if (section.kicker || section.link || status) {
|
|
23380
|
+
const meta = metaLine("knobs-wt-kicker");
|
|
23381
|
+
if (section.kicker)
|
|
23382
|
+
metaText(meta, section.kicker, "knobs-wt-kicker-lead");
|
|
23383
|
+
if (section.link)
|
|
23384
|
+
metaLink(meta, section.link.label, section.link.href);
|
|
23385
|
+
if (status) {
|
|
23386
|
+
const s = statusLook(status);
|
|
23387
|
+
metaText(meta, s.label, "knobs-wt-status").dataset.tone = s.tone;
|
|
22243
23388
|
}
|
|
22244
|
-
sh.append(
|
|
23389
|
+
sh.append(meta);
|
|
22245
23390
|
}
|
|
22246
|
-
const h2 = el2(doc, "h2", "knobs-wt-
|
|
22247
|
-
h2.
|
|
23391
|
+
const h2 = el2(doc, "h2", "knobs-wt-heading");
|
|
23392
|
+
h2.innerHTML = inlineMarkdown(section.title);
|
|
22248
23393
|
sh.append(h2);
|
|
23394
|
+
const intro = el2(doc, "div", "knobs-wt-sintro");
|
|
23395
|
+
intro.append(sh);
|
|
22249
23396
|
if (section.summary)
|
|
22250
|
-
|
|
22251
|
-
|
|
23397
|
+
intro.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
|
|
23398
|
+
if (section.more)
|
|
23399
|
+
intro.append(more(section.more));
|
|
23400
|
+
sec.append(intro);
|
|
23401
|
+
let group = null;
|
|
22252
23402
|
if (tocEl) {
|
|
22253
|
-
|
|
22254
|
-
|
|
22255
|
-
|
|
22256
|
-
tocEl.append(
|
|
23403
|
+
group = el2(doc, "div", "knobs-wt-toc-group");
|
|
23404
|
+
const first = section.steps[0]?.key;
|
|
23405
|
+
group.append(tocRow(plainMarkdown(section.title), false, () => first ? go(first) : undefined, section.id));
|
|
23406
|
+
tocEl.append(group);
|
|
22257
23407
|
}
|
|
22258
23408
|
for (const step of section.steps) {
|
|
22259
|
-
const v = stepView(step);
|
|
23409
|
+
const v = stepView(step, group);
|
|
22260
23410
|
sec.append(v.card);
|
|
22261
23411
|
views.push(v);
|
|
22262
23412
|
}
|
|
22263
|
-
|
|
23413
|
+
flow.append(sec);
|
|
22264
23414
|
}
|
|
22265
|
-
|
|
23415
|
+
linkPRs(flow, findPRIn);
|
|
23416
|
+
main.append(flow);
|
|
23417
|
+
if (noteMode !== "hidden")
|
|
23418
|
+
main.append(bar.dock);
|
|
22266
23419
|
if (rail)
|
|
22267
23420
|
layout.append(rail);
|
|
22268
23421
|
layout.append(main);
|
|
@@ -22272,16 +23425,46 @@ function walkthrough(container, options) {
|
|
|
22272
23425
|
for (const n of notesOn(state, v.step.key))
|
|
22273
23426
|
renderNote(v, n);
|
|
22274
23427
|
}
|
|
23428
|
+
if (tocEl)
|
|
23429
|
+
pill = selectionPill(tocEl, {
|
|
23430
|
+
selected: () => viewOf(current)?.toc ?? null,
|
|
23431
|
+
rows: () => tocRows
|
|
23432
|
+
});
|
|
22275
23433
|
syncProgress();
|
|
22276
23434
|
current = null;
|
|
22277
23435
|
fromScroll();
|
|
22278
23436
|
placeMark();
|
|
22279
23437
|
bar.sync();
|
|
23438
|
+
syncReserve();
|
|
22280
23439
|
win.requestAnimationFrame(() => win.requestAnimationFrame(() => {
|
|
22281
23440
|
if (!disposed && !reduced())
|
|
22282
23441
|
root.dataset.settled = "";
|
|
22283
23442
|
}));
|
|
22284
23443
|
};
|
|
23444
|
+
const more = (text) => {
|
|
23445
|
+
const box = el2(doc, "div", "knobs-wt-more");
|
|
23446
|
+
const body = el2(doc, "div", "knobs-wt-more-text");
|
|
23447
|
+
for (const para of text.split(/\n\s*\n/))
|
|
23448
|
+
if (para.trim())
|
|
23449
|
+
body.append(prose2(doc, "p", "", para.trim()));
|
|
23450
|
+
discs.push(disclosure(box, { label: "More", content: body }));
|
|
23451
|
+
return box;
|
|
23452
|
+
};
|
|
23453
|
+
const tocRow = (label, sub, run, section) => {
|
|
23454
|
+
const b = el2(doc, "button", sub ? "knobs-wt-toc-row knobs-wt-toc-sub" : "knobs-wt-toc-row");
|
|
23455
|
+
b.type = "button";
|
|
23456
|
+
if (section)
|
|
23457
|
+
b.dataset.section = section;
|
|
23458
|
+
const t = el2(doc, "span", "knobs-wt-toc-label");
|
|
23459
|
+
t.textContent = label;
|
|
23460
|
+
const e = el2(doc, "span", "knobs-wt-toc-end");
|
|
23461
|
+
b.title = label;
|
|
23462
|
+
b.append(t, e);
|
|
23463
|
+
b.addEventListener("mousedown", (ev) => ev.preventDefault());
|
|
23464
|
+
b.addEventListener("click", run);
|
|
23465
|
+
tocRows.push(b);
|
|
23466
|
+
return b;
|
|
23467
|
+
};
|
|
22285
23468
|
const actions = (rail) => {
|
|
22286
23469
|
const row = el2(doc, "div", "knobs-wt-actions");
|
|
22287
23470
|
const btn = (text, run, primary = false) => {
|
|
@@ -22322,37 +23505,38 @@ function walkthrough(container, options) {
|
|
|
22322
23505
|
toast("Couldn't reach the clipboard", { tone: "warn", look, doc });
|
|
22323
23506
|
}
|
|
22324
23507
|
};
|
|
22325
|
-
const stepView = (step) => {
|
|
22326
|
-
const card = el2(doc, "article", "knobs-wt-step knobs-surface");
|
|
23508
|
+
const stepView = (step, group) => {
|
|
23509
|
+
const card = el2(doc, "article", options.cards ? "knobs-wt-step knobs-surface" : "knobs-wt-step");
|
|
22327
23510
|
card.id = `wt-${step.key.replace("/", "--")}`;
|
|
22328
23511
|
card.tabIndex = -1;
|
|
22329
23512
|
card.dataset.key = step.key;
|
|
22330
|
-
card.setAttribute("aria-label",
|
|
23513
|
+
card.setAttribute("aria-label", plainMarkdown(step.title));
|
|
22331
23514
|
const head = el2(doc, "header", "knobs-wt-step-head");
|
|
22332
|
-
const num = el2(doc, "span", "knobs-wt-num");
|
|
22333
|
-
num.textContent = step.number;
|
|
22334
23515
|
const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
|
|
22335
|
-
h3.
|
|
22336
|
-
head.append(
|
|
22337
|
-
card.append(head);
|
|
23516
|
+
h3.innerHTML = inlineMarkdown(step.title);
|
|
23517
|
+
head.append(h3);
|
|
22338
23518
|
if (step.caption)
|
|
22339
|
-
|
|
23519
|
+
head.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
|
|
23520
|
+
if (step.more)
|
|
23521
|
+
head.append(more(step.more));
|
|
23522
|
+
card.append(head);
|
|
22340
23523
|
const slots = [];
|
|
22341
23524
|
const onEvent = (e) => record({ ...e, step: step.key });
|
|
22342
23525
|
let media = null;
|
|
22343
23526
|
if (step.media.length) {
|
|
22344
23527
|
media = el2(doc, "div", "knobs-wt-media");
|
|
22345
|
-
media.style.setProperty("--kw-n", String(Math.min(step.media.length,
|
|
23528
|
+
media.style.setProperty("--kw-n", String(Math.min(step.media.length, step.columns)));
|
|
22346
23529
|
for (const m of step.media)
|
|
22347
23530
|
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
22348
23531
|
card.append(media);
|
|
22349
23532
|
}
|
|
22350
23533
|
let taste = null;
|
|
22351
|
-
if (step.question)
|
|
23534
|
+
if (step.question && review)
|
|
22352
23535
|
card.append(prose2(doc, "p", "knobs-wt-question", step.question));
|
|
22353
23536
|
if (step.ask === "pick") {
|
|
22354
23537
|
taste = tasteTest(card, {
|
|
22355
23538
|
...look,
|
|
23539
|
+
pickable: review,
|
|
22356
23540
|
options: step.options,
|
|
22357
23541
|
picked: state.steps[step.key]?.pick ?? null,
|
|
22358
23542
|
onPick: (id) => pick(step.key, id),
|
|
@@ -22361,7 +23545,8 @@ function walkthrough(container, options) {
|
|
|
22361
23545
|
media ??= taste.element;
|
|
22362
23546
|
}
|
|
22363
23547
|
const notes = el2(doc, "div", "knobs-wt-notes");
|
|
22364
|
-
|
|
23548
|
+
if (review)
|
|
23549
|
+
card.append(notes);
|
|
22365
23550
|
card.addEventListener("focusin", () => {
|
|
22366
23551
|
if (scroll.to)
|
|
22367
23552
|
return;
|
|
@@ -22370,16 +23555,13 @@ function walkthrough(container, options) {
|
|
|
22370
23555
|
});
|
|
22371
23556
|
let toc = null;
|
|
22372
23557
|
let glyph = null;
|
|
22373
|
-
if (
|
|
22374
|
-
toc =
|
|
22375
|
-
|
|
22376
|
-
|
|
22377
|
-
|
|
22378
|
-
|
|
22379
|
-
toc
|
|
22380
|
-
toc.append(glyph, label);
|
|
22381
|
-
toc.addEventListener("click", () => go(step.key));
|
|
22382
|
-
tocEl.append(toc);
|
|
23558
|
+
if (group) {
|
|
23559
|
+
toc = tocRow(plainMarkdown(step.title), true, () => go(step.key));
|
|
23560
|
+
if (review) {
|
|
23561
|
+
glyph = el2(doc, "span", "knobs-wt-toc-glyph");
|
|
23562
|
+
toc.querySelector(".knobs-wt-toc-end").append(glyph);
|
|
23563
|
+
}
|
|
23564
|
+
group.append(toc);
|
|
22383
23565
|
}
|
|
22384
23566
|
return { step, card, media, notes, toc, glyph, taste, slots };
|
|
22385
23567
|
};
|
|
@@ -22438,19 +23620,25 @@ function walkthrough(container, options) {
|
|
|
22438
23620
|
setFull(false);
|
|
22439
23621
|
return go(next);
|
|
22440
23622
|
}
|
|
23623
|
+
if ((key === "Home" || key === "End") && views.length) {
|
|
23624
|
+
claim();
|
|
23625
|
+
if (full)
|
|
23626
|
+
setFull(false);
|
|
23627
|
+
return go(views[key === "Home" ? 0 : views.length - 1].step.key);
|
|
23628
|
+
}
|
|
22441
23629
|
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
22442
23630
|
const d = (key === "ArrowLeft" ? -1 : 1) * (e.shiftKey ? 2 : 0.5);
|
|
22443
23631
|
if (seekBy(d))
|
|
22444
23632
|
claim();
|
|
22445
23633
|
return;
|
|
22446
23634
|
}
|
|
22447
|
-
if (key === "n") {
|
|
23635
|
+
if (key === "n" && noteMode !== "hidden") {
|
|
22448
23636
|
claim();
|
|
22449
|
-
bar.
|
|
23637
|
+
bar.setOpen(true, true);
|
|
22450
23638
|
return;
|
|
22451
23639
|
}
|
|
22452
23640
|
const v = viewOf(current);
|
|
22453
|
-
if (!v || e.shiftKey)
|
|
23641
|
+
if (!v || e.shiftKey || !review)
|
|
22454
23642
|
return;
|
|
22455
23643
|
const choice = digitChoice(v.step, state.steps[v.step.key], key);
|
|
22456
23644
|
if (choice === undefined)
|
|
@@ -22525,6 +23713,12 @@ function walkthrough(container, options) {
|
|
|
22525
23713
|
win.removeEventListener(type, stopScroll);
|
|
22526
23714
|
doc.removeEventListener("keydown", onKey);
|
|
22527
23715
|
unregisterHints();
|
|
23716
|
+
bar.unobserve();
|
|
23717
|
+
pill?.dispose();
|
|
23718
|
+
for (const d of discs)
|
|
23719
|
+
d.dispose();
|
|
23720
|
+
if (padded)
|
|
23721
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
22528
23722
|
for (const v of views) {
|
|
22529
23723
|
v.slots.forEach((s) => s.dispose());
|
|
22530
23724
|
v.taste?.dispose();
|
|
@@ -22609,6 +23803,7 @@ export {
|
|
|
22609
23803
|
mediaKind,
|
|
22610
23804
|
mediaSlot,
|
|
22611
23805
|
menu,
|
|
23806
|
+
minutes,
|
|
22612
23807
|
modeForKey,
|
|
22613
23808
|
motionBlur,
|
|
22614
23809
|
moveHead,
|
|
@@ -22628,6 +23823,7 @@ export {
|
|
|
22628
23823
|
plainAccess,
|
|
22629
23824
|
planBento,
|
|
22630
23825
|
planPill,
|
|
23826
|
+
player,
|
|
22631
23827
|
popover,
|
|
22632
23828
|
railSegments,
|
|
22633
23829
|
rank,
|