@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-solid.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}`;
|
|
@@ -2605,6 +2804,12 @@ var css2 = `
|
|
|
2605
2804
|
--_ku-pane-bg and --_ku-pane-ring so this reaches them. */
|
|
2606
2805
|
: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;
|
|
2607
2806
|
--_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
|
|
2807
|
+
/* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
|
|
2808
|
+
ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
|
|
2809
|
+
card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
|
|
2810
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
|
|
2811
|
+
: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)}
|
|
2812
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
|
|
2608
2813
|
/* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
|
|
2609
2814
|
.knobs-ui{box-sizing:border-box}
|
|
2610
2815
|
: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}
|
|
@@ -2830,8 +3035,6 @@ var css2 = `
|
|
|
2830
3035
|
.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}
|
|
2831
3036
|
.knobs-tl-track:hover .knobs-tl-hover{opacity:1}
|
|
2832
3037
|
.knobs-timeline[data-scrubbing] .knobs-tl-hover{opacity:0}
|
|
2833
|
-
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
2834
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
2835
3038
|
.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}
|
|
2836
3039
|
.knobs-tl-tag[data-on]{opacity:1}
|
|
2837
3040
|
/* The lane (variant: "lane"): one slim track of ticks under a compare or a video; markers are
|
|
@@ -2847,7 +3050,26 @@ var css2 = `
|
|
|
2847
3050
|
.knobs-timeline[data-variant="lane"] .knobs-tl-head::before{top:0}
|
|
2848
3051
|
.knobs-timeline[data-variant="lane"] .knobs-tl-head::after{content:none}
|
|
2849
3052
|
.knobs-timeline[data-variant="lane"] .knobs-tl-tag{top:2px;bottom:auto}
|
|
2850
|
-
|
|
3053
|
+
/* The line (variant: "line"): a player's progress under its media. One 2px line, fg-3 with fg
|
|
3054
|
+
filling it, a segment per chapter; it thickens under the pointer and while scrubbing. The
|
|
3055
|
+
chapter and time under the pointer float over it; nothing else shows. */
|
|
3056
|
+
.knobs-ui.knobs-timeline[data-variant="line"]{height:auto;min-height:0;padding:0;gap:0}
|
|
3057
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-transport{display:none}
|
|
3058
|
+
.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}
|
|
3059
|
+
.knobs-timeline[data-variant="line"] :is(.knobs-tl-ruler,.knobs-tl-lane,.knobs-tl-hover,.knobs-tl-head,.knobs-tl-rlabel){display:none}
|
|
3060
|
+
.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)}
|
|
3061
|
+
.knobs-tl-seg{position:absolute;left:0;top:0;height:100%;overflow:hidden;border-radius:1px;background:var(--_k-fg-3);will-change:transform}
|
|
3062
|
+
.knobs-tl-seg-fill{position:absolute;inset:0;background:var(--_k-fg);transform-origin:0 0;will-change:transform}
|
|
3063
|
+
.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}
|
|
3064
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-range{top:3px;bottom:3px;border-radius:3px}
|
|
3065
|
+
.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)}
|
|
3066
|
+
.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);
|
|
3067
|
+
-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:inset 0 0 0 .5px var(--_k-border)}
|
|
3068
|
+
.knobs-tl-tag-label{color:var(--_k-fg-2)}
|
|
3069
|
+
.knobs-tl-tag-label:empty{display:none}
|
|
3070
|
+
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
3071
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
3072
|
+
`, uiCss = () => aliased(css2 + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + compareCss + playerCss + selectionPillCss) + rolling_css_default, lookDefaults, tune = (s, m) => {
|
|
2851
3073
|
s.omega = m.omega;
|
|
2852
3074
|
s.zeta = m.zeta;
|
|
2853
3075
|
return s;
|
|
@@ -2970,19 +3192,19 @@ var init_diff_css = __esm(() => {
|
|
|
2970
3192
|
@property --kd-fb{syntax:"<length>";inherits:false;initial-value:0px}
|
|
2971
3193
|
: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))}
|
|
2972
3194
|
:where(.knobs-diff,.knobs-diff *,.knobs-diff-files,.knobs-diff-files *){box-sizing:border-box}
|
|
2973
|
-
.knobs-ui.knobs-diff{--kd-bg:var(--k-diff-bg,var(--_kd-bg,
|
|
3195
|
+
.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);
|
|
2974
3196
|
--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);
|
|
2975
3197
|
--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;
|
|
2976
3198
|
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;
|
|
2977
3199
|
letter-spacing:normal;word-spacing:normal;text-transform:none;-webkit-font-smoothing:antialiased}
|
|
2978
3200
|
.knobs-ui.knobs-diff[data-height="auto"]{height:auto}
|
|
2979
|
-
.knobs-diff::after{content:"";position:absolute;inset:0;z-index:3;
|
|
3201
|
+
.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}
|
|
2980
3202
|
.knobs-diff [hidden],.knobs-diff-files [hidden]{display:none!important}
|
|
2981
3203
|
.knobs-diff svg{display:block;flex:none}
|
|
2982
|
-
.knobs-ui.knobs-diff[data-on="
|
|
2983
|
-
/*
|
|
3204
|
+
.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)}
|
|
3205
|
+
/* A hairline under the header, firmer once the code has scrolled under it. */
|
|
2984
3206
|
.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);
|
|
2985
|
-
box-shadow:inset 0 -1px
|
|
3207
|
+
box-shadow:inset 0 -1px var(--_k-border-subtle);transition:box-shadow .15s;user-select:none;-webkit-user-select:none}
|
|
2986
3208
|
.knobs-diff[data-scrolled]>.knobs-diff-head{box-shadow:inset 0 -1px var(--_k-border)}
|
|
2987
3209
|
.knobs-diff-path{flex:0 1 auto;min-width:0;overflow:hidden;white-space:nowrap}
|
|
2988
3210
|
.knobs-diff-dir,.knobs-diff-from{color:var(--_k-fg-3)}
|
|
@@ -3020,6 +3242,15 @@ var init_diff_css = __esm(() => {
|
|
|
3020
3242
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
3021
3243
|
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
3022
3244
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
3245
|
+
/* Narrow, the header gives up words before anything is cut off at its end: Viewed keeps its
|
|
3246
|
+
check, then the counts' bar goes, then the counts; the path fades at its end throughout. */
|
|
3247
|
+
.knobs-diff-head,.knobs-diff-part-head{container-type:inline-size}
|
|
3248
|
+
@container (max-width:520px){
|
|
3249
|
+
.knobs-diff-viewed-label{display:none}
|
|
3250
|
+
.knobs-ui .knobs-diff-viewed{width:var(--_k-control-h);padding:0;justify-content:center}
|
|
3251
|
+
.knobs-diff-counts .knobs-diff-bar{display:none}
|
|
3252
|
+
}
|
|
3253
|
+
@container (max-width:400px){.knobs-diff-counts{display:none}.knobs-diff-nav>span{min-width:2.6em}}
|
|
3023
3254
|
.knobs-diff-path{transition:opacity .2s}
|
|
3024
3255
|
.knobs-diff[data-viewed]>.knobs-diff-head .knobs-diff-path,.knobs-diff-part[data-viewed] .knobs-diff-path{opacity:.6}
|
|
3025
3256
|
/* Split | Unified: the selection pill on the one picked, its bright copy the picked one's text; a
|
|
@@ -3084,24 +3315,26 @@ var init_diff_css = __esm(() => {
|
|
|
3084
3315
|
--diffs-bg-deletion-number-override:color-mix(in srgb,var(--kd-del) 55%,var(--kd-solid));
|
|
3085
3316
|
--diffs-bg-addition-emphasis-override:color-mix(in srgb,var(--kd-add) 22%,transparent);
|
|
3086
3317
|
--diffs-bg-deletion-emphasis-override:color-mix(in srgb,var(--kd-del) 22%,transparent);
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
--diffs-bg-
|
|
3318
|
+
/* Unchanged lines and the folds between hunks sit on the void; only a split's missing lines
|
|
3319
|
+
are faintly filled. */
|
|
3320
|
+
--diffs-bg-separator-override:var(--kd-solid);
|
|
3321
|
+
--diffs-bg-context-override:var(--kd-solid);
|
|
3322
|
+
--diffs-bg-buffer-override:color-mix(in srgb,var(--_k-fg) 2.5%,var(--kd-solid));
|
|
3090
3323
|
--diffs-bg-selection-override:var(--_k-accent);
|
|
3091
3324
|
--diffs-fg-number-override:var(--_k-fg-3);
|
|
3092
3325
|
}
|
|
3093
|
-
/* diffReview
|
|
3094
|
-
is pinned to its right edge, so it slides out from under the diff), parted
|
|
3095
|
-
|
|
3096
|
-
.knobs-ui.knobs-diff-review{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
3326
|
+
/* diffReview, on the void as the diff is: the file list a drawer at its left (its width springs;
|
|
3327
|
+
the list inside is pinned to its right edge, so it slides out from under the diff), parted
|
|
3328
|
+
from the diff by a hairline; one hairline runs under both headers and one under it all. */
|
|
3329
|
+
.knobs-ui.knobs-diff-review{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
3097
3330
|
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}
|
|
3098
|
-
.knobs-diff-review::after{content:"";position:absolute;inset:0;z-index:5;
|
|
3331
|
+
.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}
|
|
3099
3332
|
:where(.knobs-diff-review,.knobs-diff-review *){box-sizing:border-box}
|
|
3100
|
-
.knobs-diff-drawer{position:relative;flex:none;width:0;height:100%;overflow:hidden;box-shadow:inset -1px 0 var(--_k-border)}
|
|
3333
|
+
.knobs-diff-drawer{position:relative;flex:none;width:0;height:100%;overflow:hidden;box-shadow:inset -1px 0 var(--_k-border-subtle)}
|
|
3101
3334
|
.knobs-diff-drawer[data-shut]{visibility:hidden}
|
|
3102
3335
|
.knobs-diff-drawer-in{position:absolute;top:0;bottom:0;right:0;display:flex;flex-direction:column}
|
|
3103
3336
|
.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);
|
|
3104
|
-
user-select:none;-webkit-user-select:none}
|
|
3337
|
+
box-shadow:inset 0 -1px var(--_k-border-subtle);user-select:none;-webkit-user-select:none}
|
|
3105
3338
|
.knobs-diff-drawer-title{font-weight:var(--_k-weight-title)}
|
|
3106
3339
|
.knobs-diff-drawer-count{color:var(--_k-fg-3);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums}
|
|
3107
3340
|
.knobs-diff-drawer-in>.knobs-diff-files{flex:1;min-height:0;height:auto}
|
|
@@ -3113,10 +3346,11 @@ var init_diff_css = __esm(() => {
|
|
|
3113
3346
|
.knobs-ui .knobs-diff-toggle[aria-pressed]:not(:hover,:focus-visible){background:transparent}
|
|
3114
3347
|
/* diffReview's file list: a filter over a compact tree, a status letter, the counts and their
|
|
3115
3348
|
bar on each file; one highlight glides to the file on show. Viewed files dim, with a tick. */
|
|
3116
|
-
.knobs-diff-files{--k-row:var(--k-diff-row,28px);display:flex;flex-direction:column;height:100%;min-height:0;padding-top:
|
|
3349
|
+
.knobs-diff-files{--k-row:var(--k-diff-row,28px);display:flex;flex-direction:column;height:100%;min-height:0;padding-top:4px}
|
|
3117
3350
|
.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;
|
|
3118
|
-
border-radius:max(6px,var(--_ku-row-radius));
|
|
3119
|
-
|
|
3351
|
+
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}
|
|
3352
|
+
/* The filter is a line of text, no box; focused, a hairline ring. */
|
|
3353
|
+
.knobs-diff-filter:focus-within{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_k-accent) 45%,transparent)}
|
|
3120
3354
|
.knobs-diff-filter svg{width:12px;height:12px;flex:none}
|
|
3121
3355
|
.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}
|
|
3122
3356
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
@@ -6041,7 +6275,10 @@ function codeDiff(container, options) {
|
|
|
6041
6275
|
const viewedToggle = () => {
|
|
6042
6276
|
const b = make("button", "knobs-diff-viewed");
|
|
6043
6277
|
b.type = "button";
|
|
6044
|
-
|
|
6278
|
+
const label = make("span", "knobs-diff-viewed-label");
|
|
6279
|
+
label.textContent = "Viewed";
|
|
6280
|
+
b.append(make("span", ""), label);
|
|
6281
|
+
b.setAttribute("aria-label", "Viewed");
|
|
6045
6282
|
return b;
|
|
6046
6283
|
};
|
|
6047
6284
|
const paintViewed = (b, on) => {
|
|
@@ -8328,6 +8565,17 @@ function currentMarker(markers, t, fps) {
|
|
|
8328
8565
|
best = m;
|
|
8329
8566
|
return best;
|
|
8330
8567
|
}
|
|
8568
|
+
function minutes(t) {
|
|
8569
|
+
const s = Math.max(0, Math.floor(t + 0.000001));
|
|
8570
|
+
const h = Math.floor(s / 3600);
|
|
8571
|
+
const m = Math.floor(s % 3600 / 60);
|
|
8572
|
+
const ss = String(s % 60).padStart(2, "0");
|
|
8573
|
+
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
8574
|
+
}
|
|
8575
|
+
function chapterBounds(times, duration) {
|
|
8576
|
+
const inside = times.filter((t) => t > 0.000001 && t < duration - 0.000001);
|
|
8577
|
+
return [0, ...[...new Set(inside)].sort((a, b) => a - b), duration];
|
|
8578
|
+
}
|
|
8331
8579
|
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;
|
|
8332
8580
|
var init_timeline_model = __esm(() => {
|
|
8333
8581
|
SECOND_STEPS = [0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600];
|
|
@@ -8345,7 +8593,8 @@ function timeline(container, options) {
|
|
|
8345
8593
|
let speed = options.speed ?? 1;
|
|
8346
8594
|
let repeat = options.repeat ?? true;
|
|
8347
8595
|
const arrows = options.arrows ?? "frames";
|
|
8348
|
-
const
|
|
8596
|
+
const line = options.variant === "line";
|
|
8597
|
+
const lane = line || options.variant === "lane";
|
|
8349
8598
|
let time = Math.min(duration, Math.max(0, options.time ?? 0));
|
|
8350
8599
|
let playing = false;
|
|
8351
8600
|
let markers = [...options.markers ?? []];
|
|
@@ -8380,7 +8629,7 @@ function timeline(container, options) {
|
|
|
8380
8629
|
root.setAttribute("aria-keyshortcuts", "Space ArrowLeft ArrowRight , . Home End [ ] I O M");
|
|
8381
8630
|
applyLook2(root, options);
|
|
8382
8631
|
if (lane)
|
|
8383
|
-
root.dataset.variant = "lane";
|
|
8632
|
+
root.dataset.variant = line ? "line" : "lane";
|
|
8384
8633
|
const transport = el("div", "knobs-tl-transport");
|
|
8385
8634
|
const playBtn = el("button", "knobs-tl-play");
|
|
8386
8635
|
playBtn.type = "button";
|
|
@@ -8393,6 +8642,10 @@ function timeline(container, options) {
|
|
|
8393
8642
|
const hover = el("div", "knobs-tl-hover");
|
|
8394
8643
|
const tag = el("span", "knobs-tl-tag");
|
|
8395
8644
|
tag.setAttribute("aria-hidden", "true");
|
|
8645
|
+
const tagLabel = el("span", "knobs-tl-tag-label");
|
|
8646
|
+
const tagTime = el("span", "knobs-tl-tag-time");
|
|
8647
|
+
tag.append(tagLabel, tagTime);
|
|
8648
|
+
const segs = el("div", "knobs-tl-segs");
|
|
8396
8649
|
const head = el("div", "knobs-tl-head");
|
|
8397
8650
|
head.id = `${id}-head`;
|
|
8398
8651
|
head.setAttribute("role", "slider");
|
|
@@ -8400,11 +8653,13 @@ function timeline(container, options) {
|
|
|
8400
8653
|
head.setAttribute("aria-valuemin", "0");
|
|
8401
8654
|
head.setAttribute("aria-valuemax", String(duration));
|
|
8402
8655
|
track.append(canvas, markerLane, hover, head, tag);
|
|
8656
|
+
if (line)
|
|
8657
|
+
track.insertBefore(segs, markerLane);
|
|
8403
8658
|
root.append(transport, track);
|
|
8404
8659
|
container.append(root);
|
|
8405
8660
|
let width = 1;
|
|
8406
8661
|
let height = 1;
|
|
8407
|
-
const fitView = () => clampView({ start: 0, span: duration }, duration, { pad: 0.02 });
|
|
8662
|
+
const fitView = () => clampView({ start: 0, span: duration }, duration, { pad: line ? 0 : 0.02 });
|
|
8408
8663
|
let target = fitView();
|
|
8409
8664
|
const vStart = new Spring(target.start, INSTANT2.omega, 1, 0.00001);
|
|
8410
8665
|
const vSpan = new Spring(target.span, INSTANT2.omega, 1, 0.00001);
|
|
@@ -8413,13 +8668,13 @@ function timeline(container, options) {
|
|
|
8413
8668
|
const xOf = (t) => (t - vStart.x) * pxPerSec();
|
|
8414
8669
|
const tOf = (x) => vStart.x + x / pxPerSec();
|
|
8415
8670
|
const minSpan = () => Math.max(4 / fps, 0.05);
|
|
8416
|
-
const retarget = (next, motion = INSTANT2) => {
|
|
8417
|
-
target = clampView(next, duration, { pad: 0.04, minSpan: minSpan() });
|
|
8671
|
+
const retarget = (next, motion = INSTANT2, hand = false) => {
|
|
8672
|
+
target = clampView(next, duration, { pad: line ? 0 : 0.04, minSpan: minSpan() });
|
|
8418
8673
|
for (const s of [vStart, vSpan]) {
|
|
8419
8674
|
s.omega = motion.omega;
|
|
8420
8675
|
s.zeta = motion.zeta;
|
|
8421
8676
|
}
|
|
8422
|
-
if (reducedMotion(win) && motion === CALM) {
|
|
8677
|
+
if (hand || reducedMotion(win) && motion === CALM) {
|
|
8423
8678
|
vStart.snap(target.start);
|
|
8424
8679
|
vSpan.snap(target.span);
|
|
8425
8680
|
} else {
|
|
@@ -8445,6 +8700,8 @@ function timeline(container, options) {
|
|
|
8445
8700
|
};
|
|
8446
8701
|
let drawn = "";
|
|
8447
8702
|
const drawRuler = () => {
|
|
8703
|
+
if (line)
|
|
8704
|
+
return;
|
|
8448
8705
|
const v = view();
|
|
8449
8706
|
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${height}:${units}:${fps}`;
|
|
8450
8707
|
if (key === drawn)
|
|
@@ -8532,6 +8789,8 @@ function timeline(container, options) {
|
|
|
8532
8789
|
n.title = `${m.label ? `${m.label} · ` : ""}${clock(m.time)}`;
|
|
8533
8790
|
}
|
|
8534
8791
|
placeMarkers();
|
|
8792
|
+
if (line)
|
|
8793
|
+
syncSegments();
|
|
8535
8794
|
};
|
|
8536
8795
|
const placeMarkers = () => {
|
|
8537
8796
|
for (const m of markers) {
|
|
@@ -8540,6 +8799,36 @@ function timeline(container, options) {
|
|
|
8540
8799
|
n.style.transform = `translateX(${xOf(m.time).toFixed(2)}px)`;
|
|
8541
8800
|
}
|
|
8542
8801
|
};
|
|
8802
|
+
let bounds = [];
|
|
8803
|
+
const segEls = [];
|
|
8804
|
+
const syncSegments = () => {
|
|
8805
|
+
bounds = chapterBounds(markers.map((m) => m.time), duration);
|
|
8806
|
+
while (segEls.length > bounds.length - 1)
|
|
8807
|
+
segEls.pop().el.remove();
|
|
8808
|
+
while (segEls.length < bounds.length - 1) {
|
|
8809
|
+
const n = el("i", "knobs-tl-seg");
|
|
8810
|
+
const fill = el("b", "knobs-tl-seg-fill");
|
|
8811
|
+
n.append(fill);
|
|
8812
|
+
segs.append(n);
|
|
8813
|
+
segEls.push({ el: n, fill });
|
|
8814
|
+
}
|
|
8815
|
+
placeSegments();
|
|
8816
|
+
};
|
|
8817
|
+
const placeSegments = () => {
|
|
8818
|
+
if (!line)
|
|
8819
|
+
return;
|
|
8820
|
+
const last = segEls.length - 1;
|
|
8821
|
+
segEls.forEach((s, i) => {
|
|
8822
|
+
const a = bounds[i];
|
|
8823
|
+
const b = bounds[i + 1];
|
|
8824
|
+
const x0 = xOf(a) + (i > 0 ? SEG_GAP / 2 : 0);
|
|
8825
|
+
const x1 = xOf(b) - (i < last ? SEG_GAP / 2 : 0);
|
|
8826
|
+
s.el.style.transform = `translateX(${x0.toFixed(2)}px)`;
|
|
8827
|
+
s.el.style.width = `${Math.max(0, x1 - x0).toFixed(2)}px`;
|
|
8828
|
+
const k = Math.min(1, Math.max(0, (shownHead - a) / Math.max(0.000000001, b - a)));
|
|
8829
|
+
s.fill.style.transform = `scaleX(${k.toFixed(4)})`;
|
|
8830
|
+
});
|
|
8831
|
+
};
|
|
8543
8832
|
const syncRanges = () => {
|
|
8544
8833
|
const keep = new Set(ranges.map((r) => r.id));
|
|
8545
8834
|
for (const [k, n] of rangeEls)
|
|
@@ -8556,7 +8845,7 @@ function timeline(container, options) {
|
|
|
8556
8845
|
b.dataset.edge = "end";
|
|
8557
8846
|
const label = el("span", "knobs-tl-rlabel");
|
|
8558
8847
|
n.append(label, a, b);
|
|
8559
|
-
track.insertBefore(n, markerLane);
|
|
8848
|
+
track.insertBefore(n, line ? segs : markerLane);
|
|
8560
8849
|
rangeEls.set(r.id, n);
|
|
8561
8850
|
if (built)
|
|
8562
8851
|
enter(n);
|
|
@@ -8608,6 +8897,7 @@ function timeline(container, options) {
|
|
|
8608
8897
|
let currentId = null;
|
|
8609
8898
|
const renderHead = () => {
|
|
8610
8899
|
head.style.transform = `translateX(${xOf(shownHead).toFixed(2)}px)`;
|
|
8900
|
+
placeSegments();
|
|
8611
8901
|
head.setAttribute("aria-valuenow", time.toFixed(3));
|
|
8612
8902
|
head.setAttribute("aria-valuetext", `${time.toFixed(2)} seconds, frame ${toFrame(time, fps)}`);
|
|
8613
8903
|
const cur = currentMarker(markers, time, fps)?.id ?? null;
|
|
@@ -8871,14 +9161,25 @@ function timeline(container, options) {
|
|
|
8871
9161
|
setTime(s.t, "scrub", s.shown, press);
|
|
8872
9162
|
root.toggleAttribute("data-stuck", s.stop !== null);
|
|
8873
9163
|
};
|
|
9164
|
+
let pointerX = null;
|
|
9165
|
+
const zoomAtHand = (factor) => zoom(factor, pointerX === null ? time : target.start + pointerX / width * target.span);
|
|
8874
9166
|
const showTag = (x) => {
|
|
8875
9167
|
const at = Math.min(duration, Math.max(0, tOf(x)));
|
|
8876
|
-
const text = `${at.toFixed(2)} s`;
|
|
8877
|
-
if (
|
|
8878
|
-
|
|
9168
|
+
const text = line ? minutes(at) : `${at.toFixed(2)} s`;
|
|
9169
|
+
if (tagTime.textContent !== text)
|
|
9170
|
+
tagTime.textContent = text;
|
|
9171
|
+
const label = line ? currentMarker(markers, at, fps)?.label ?? "" : "";
|
|
9172
|
+
if (tagLabel.textContent !== label)
|
|
9173
|
+
tagLabel.textContent = label;
|
|
8879
9174
|
const cx = Math.min(width, Math.max(0, x));
|
|
8880
|
-
|
|
8881
|
-
|
|
9175
|
+
if (line) {
|
|
9176
|
+
const w = tag.offsetWidth;
|
|
9177
|
+
const left = Math.min(Math.max(0, width - w), Math.max(0, cx - w / 2));
|
|
9178
|
+
tag.style.transform = `translateX(${left.toFixed(1)}px)`;
|
|
9179
|
+
} else {
|
|
9180
|
+
const flip = cx > width - tag.offsetWidth - 12;
|
|
9181
|
+
tag.style.transform = `translateX(${cx.toFixed(1)}px) translateX(${flip ? "calc(-100% - 4px)" : "4px"})`;
|
|
9182
|
+
}
|
|
8882
9183
|
tag.dataset.on = "";
|
|
8883
9184
|
};
|
|
8884
9185
|
const hideTag = () => delete tag.dataset.on;
|
|
@@ -8939,6 +9240,7 @@ function timeline(container, options) {
|
|
|
8939
9240
|
});
|
|
8940
9241
|
track.addEventListener("pointermove", (e) => {
|
|
8941
9242
|
const x = localX(e);
|
|
9243
|
+
pointerX = x;
|
|
8942
9244
|
hover.style.transform = `translateX(${x.toFixed(1)}px)`;
|
|
8943
9245
|
if (!drag || drag.kind === "scrub")
|
|
8944
9246
|
showTag(x);
|
|
@@ -9012,6 +9314,7 @@ function timeline(container, options) {
|
|
|
9012
9314
|
track.addEventListener("pointercancel", endDrag);
|
|
9013
9315
|
track.addEventListener("lostpointercapture", endDrag);
|
|
9014
9316
|
track.addEventListener("pointerleave", () => {
|
|
9317
|
+
pointerX = null;
|
|
9015
9318
|
if (drag)
|
|
9016
9319
|
return;
|
|
9017
9320
|
hover.style.transform = "translateX(-100px)";
|
|
@@ -9019,7 +9322,7 @@ function timeline(container, options) {
|
|
|
9019
9322
|
});
|
|
9020
9323
|
track.addEventListener("dblclick", (e) => {
|
|
9021
9324
|
if (lane)
|
|
9022
|
-
return;
|
|
9325
|
+
return fit();
|
|
9023
9326
|
const markerEl = e.target.closest(".knobs-tl-marker");
|
|
9024
9327
|
if (markerEl)
|
|
9025
9328
|
return rename(markerEl.dataset.id);
|
|
@@ -9030,18 +9333,40 @@ function timeline(container, options) {
|
|
|
9030
9333
|
rename(m.id);
|
|
9031
9334
|
});
|
|
9032
9335
|
track.addEventListener("wheel", (e) => {
|
|
9033
|
-
|
|
9336
|
+
const zooming = e.ctrlKey || e.metaKey;
|
|
9337
|
+
if (zooming && pinching)
|
|
9338
|
+
return e.preventDefault();
|
|
9339
|
+
const sideways = Math.abs(e.deltaX) > Math.abs(e.deltaY);
|
|
9340
|
+
if (lane && !zooming && !sideways)
|
|
9034
9341
|
return;
|
|
9035
9342
|
e.preventDefault();
|
|
9036
9343
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? height : 1;
|
|
9037
|
-
if (
|
|
9344
|
+
if (zooming) {
|
|
9038
9345
|
const at = target.start + localX(e) / width * target.span;
|
|
9039
|
-
|
|
9346
|
+
const k = Math.exp(-e.deltaY * scale * (e.ctrlKey ? 0.01 : 0.002));
|
|
9347
|
+
retarget(zoomView(target, k, at), INSTANT2, lane);
|
|
9040
9348
|
} else {
|
|
9041
|
-
const d = (
|
|
9042
|
-
retarget({ ...target, start: target.start + d / width * target.span });
|
|
9349
|
+
const d = (sideways ? e.deltaX : e.deltaY) * scale;
|
|
9350
|
+
retarget({ ...target, start: target.start + d / width * target.span }, INSTANT2, lane);
|
|
9043
9351
|
}
|
|
9044
9352
|
}, { passive: false });
|
|
9353
|
+
let pinchScale = 1;
|
|
9354
|
+
let pinching = false;
|
|
9355
|
+
const onGesture = (e) => {
|
|
9356
|
+
const g = e;
|
|
9357
|
+
e.preventDefault();
|
|
9358
|
+
if (e.type === "gesturestart")
|
|
9359
|
+
pinchScale = 1;
|
|
9360
|
+
pinching = e.type !== "gestureend";
|
|
9361
|
+
if (e.type !== "gesturechange")
|
|
9362
|
+
return;
|
|
9363
|
+
const s = g.scale ?? 1;
|
|
9364
|
+
const x = g.clientX !== undefined ? localX({ clientX: g.clientX }) : width / 2;
|
|
9365
|
+
retarget(zoomView(target, s / pinchScale, target.start + x / width * target.span), INSTANT2, true);
|
|
9366
|
+
pinchScale = s;
|
|
9367
|
+
};
|
|
9368
|
+
for (const type of ["gesturestart", "gesturechange", "gestureend"])
|
|
9369
|
+
track.addEventListener(type, onGesture);
|
|
9045
9370
|
root.addEventListener("keydown", (e) => {
|
|
9046
9371
|
if (e.target !== root || e.metaKey || e.ctrlKey) {
|
|
9047
9372
|
if ((e.metaKey || e.ctrlKey) && (e.key === "=" || e.key === "-" || e.key === "0") && e.target === root) {
|
|
@@ -9049,7 +9374,7 @@ function timeline(container, options) {
|
|
|
9049
9374
|
if (e.key === "0")
|
|
9050
9375
|
fit();
|
|
9051
9376
|
else
|
|
9052
|
-
|
|
9377
|
+
zoomAtHand(e.key === "=" ? 1.5 : 1 / 1.5);
|
|
9053
9378
|
}
|
|
9054
9379
|
return;
|
|
9055
9380
|
}
|
|
@@ -9131,18 +9456,12 @@ function timeline(container, options) {
|
|
|
9131
9456
|
return;
|
|
9132
9457
|
case "=":
|
|
9133
9458
|
case "+":
|
|
9134
|
-
if (lane)
|
|
9135
|
-
return;
|
|
9136
9459
|
claim();
|
|
9137
|
-
return
|
|
9460
|
+
return zoomAtHand(1.5);
|
|
9138
9461
|
case "-":
|
|
9139
|
-
if (lane)
|
|
9140
|
-
return;
|
|
9141
9462
|
claim();
|
|
9142
|
-
return
|
|
9463
|
+
return zoomAtHand(1 / 1.5);
|
|
9143
9464
|
case "0":
|
|
9144
|
-
if (lane)
|
|
9145
|
-
return;
|
|
9146
9465
|
claim();
|
|
9147
9466
|
return fit();
|
|
9148
9467
|
}
|
|
@@ -9358,7 +9677,7 @@ function timeline(container, options) {
|
|
|
9358
9677
|
};
|
|
9359
9678
|
return api;
|
|
9360
9679
|
}
|
|
9361
|
-
var RULER = 22, INSTANT2, CALM, GLIDE, uid2 = 0, PLAY2 = '<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>';
|
|
9680
|
+
var RULER = 22, SEG_GAP = 3, INSTANT2, CALM, GLIDE, uid2 = 0, PLAY2 = '<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>';
|
|
9362
9681
|
var init_timeline = __esm(() => {
|
|
9363
9682
|
init_rgba();
|
|
9364
9683
|
init_motion();
|
|
@@ -9430,15 +9749,28 @@ function compareLayout(box, before, after) {
|
|
|
9430
9749
|
const shape = after.w > 0 && after.h > 0 ? after : before;
|
|
9431
9750
|
const pair = letterbox({ w: shape.w * 2, h: shape.h }, box);
|
|
9432
9751
|
const half = pair.w / 2;
|
|
9752
|
+
const fused = { x: pair.x + half / 2, y: pair.y, w: half, h: pair.h };
|
|
9433
9753
|
return {
|
|
9434
9754
|
side: {
|
|
9435
9755
|
before: letterbox(before, { x: pair.x, y: pair.y, w: half, h: pair.h }),
|
|
9436
9756
|
after: letterbox(after, { x: pair.x + half, y: pair.y, w: half, h: pair.h }),
|
|
9437
9757
|
split: pair.x + half
|
|
9438
9758
|
},
|
|
9439
|
-
overlay: { before: letterbox(before,
|
|
9759
|
+
overlay: { before: letterbox(before, fused), after: letterbox(after, fused) }
|
|
9440
9760
|
};
|
|
9441
9761
|
}
|
|
9762
|
+
function fuseFrame(L, before, after, k, wipe) {
|
|
9763
|
+
const t = Math.min(1, Math.max(0, k));
|
|
9764
|
+
const o = L.overlay;
|
|
9765
|
+
const left = Math.min(o.before.x, o.after.x);
|
|
9766
|
+
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);
|
|
9767
|
+
const cut = L.side.split + (line - L.side.split) * t;
|
|
9768
|
+
const contact = Math.max(0, Math.min(cut - after.x, before.x + before.w - cut));
|
|
9769
|
+
const feather = Math.min(contact, 1 + FUSE.feather * Math.sin(Math.PI * t));
|
|
9770
|
+
const overlap = before.x + before.w - after.x;
|
|
9771
|
+
const seam = t > 0.001 && overlap >= 0 ? Math.min(1, Math.max(0, overlap / FUSE.seamFade)) * Math.min(1, t * 4) : 0;
|
|
9772
|
+
return { cut, feather, seam, blur: t < 0.995 ? FUSE.blur * (1 - t) : 0 };
|
|
9773
|
+
}
|
|
9442
9774
|
function clampZoom(r) {
|
|
9443
9775
|
const w = Math.min(1, Math.max(1 / ZOOM_MAX, r.w));
|
|
9444
9776
|
const u = Math.min(1 - w, Math.max(0, r.u));
|
|
@@ -9524,7 +9856,15 @@ function stripPeaks(diffs, o = {}) {
|
|
|
9524
9856
|
});
|
|
9525
9857
|
return out;
|
|
9526
9858
|
}
|
|
9527
|
-
var ALL_MODES, MODE_KEYS, modeKey = (mode) => MODE_KEYS[mode].toUpperCase(), VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), lastFrame = (duration, fps) => Math.max(0, Math.ceil(duration * fps - 0.0001) - 1), sameFrame = (a, b, fps) => frameOf(a, fps) === frameOf(b, fps), SEEK_IDLE,
|
|
9859
|
+
var ALL_MODES, MODE_KEYS, modeKey = (mode) => MODE_KEYS[mode].toUpperCase(), VIDEO, frameOf = (t, fps) => Math.max(0, Math.floor(t * fps + 0.0001)), lastFrame = (duration, fps) => Math.max(0, Math.ceil(duration * fps - 0.0001) - 1), sameFrame = (a, b, fps) => frameOf(a, fps) === frameOf(b, fps), SEEK_IDLE, FUSE, labelFold = (fold, mark, blur = 3) => {
|
|
9860
|
+
const f = Math.min(1, Math.max(0, fold));
|
|
9861
|
+
const open = 1 - f;
|
|
9862
|
+
return {
|
|
9863
|
+
width: mark * open,
|
|
9864
|
+
opacity: Math.min(1, Math.max(0, (open - 0.2) / 0.8)),
|
|
9865
|
+
blur: blur * Math.min(1, Math.max(0, (f - 0.25) / 0.75))
|
|
9866
|
+
};
|
|
9867
|
+
}, 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({
|
|
9528
9868
|
u: r.u - dx / Math.max(1, base.w) * r.w,
|
|
9529
9869
|
v: r.v - dy / Math.max(1, base.h) * r.h,
|
|
9530
9870
|
w: r.w
|
|
@@ -9547,6 +9887,7 @@ var init_compare_model = __esm(() => {
|
|
|
9547
9887
|
MODE_KEYS = { side: "s", wipe: "w", difference: "d" };
|
|
9548
9888
|
VIDEO = /\.(mp4|m4v|mov|webm|ogv|mkv)$/i;
|
|
9549
9889
|
SEEK_IDLE = { seeking: false, pending: null };
|
|
9890
|
+
FUSE = { feather: 24, blur: 4, seamFade: 48 };
|
|
9550
9891
|
ZOOM_FIT = { u: 0, v: 0, w: 1, h: 1 };
|
|
9551
9892
|
});
|
|
9552
9893
|
|
|
@@ -10441,11 +10782,6 @@ fn pm(c: vec4f) -> vec4f { return vec4f(c.rgb * c.a, c.a); }
|
|
|
10441
10782
|
|
|
10442
10783
|
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
10443
10784
|
switch mode {
|
|
10444
|
-
case 1u: {
|
|
10445
|
-
let s = max(u.wipe.y, 0.5);
|
|
10446
|
-
let m = smoothstep(u.wipe.x - s, u.wipe.x + s, p.x);
|
|
10447
|
-
return pm(vec4f(mix(a.rgb, b.rgb, m), mix(a.a, b.a, m)));
|
|
10448
|
-
}
|
|
10449
10785
|
case 2u: {
|
|
10450
10786
|
let d = abs(a.rgb - b.rgb);
|
|
10451
10787
|
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);
|
|
@@ -10454,8 +10790,10 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
|
10454
10790
|
}
|
|
10455
10791
|
default: {}
|
|
10456
10792
|
}
|
|
10457
|
-
// Side by side
|
|
10458
|
-
|
|
10793
|
+
// Side by side, fusing and wiping: Before over After, cut at the seam with its feather.
|
|
10794
|
+
let s = max(u.wipe.y, 0.5);
|
|
10795
|
+
let ka = a.a * (1.0 - smoothstep(u.wipe.x - s, u.wipe.x + s, p.x));
|
|
10796
|
+
return vec4f(a.rgb * ka + b.rgb * b.a * (1.0 - ka), ka + b.a * (1.0 - ka));
|
|
10459
10797
|
}
|
|
10460
10798
|
|
|
10461
10799
|
@fragment fn fs(@builtin(position) q: vec4f) -> @location(0) vec4f {
|
|
@@ -10857,6 +11195,29 @@ var init_compare_strip = __esm(() => {
|
|
|
10857
11195
|
DIFF = { w: 32, h: 18 };
|
|
10858
11196
|
});
|
|
10859
11197
|
|
|
11198
|
+
// src/ui/player.ts
|
|
11199
|
+
function playGlyph(doc) {
|
|
11200
|
+
const element = doc.createElement("span");
|
|
11201
|
+
element.className = "knobs-player-glyph";
|
|
11202
|
+
element.setAttribute("aria-hidden", "true");
|
|
11203
|
+
let timer = 0;
|
|
11204
|
+
const win = doc.defaultView;
|
|
11205
|
+
return {
|
|
11206
|
+
element,
|
|
11207
|
+
flash(playing) {
|
|
11208
|
+
element.innerHTML = playing ? PLAY2 : PAUSE;
|
|
11209
|
+
element.setAttribute("data-flash", "");
|
|
11210
|
+
win.clearTimeout(timer);
|
|
11211
|
+
timer = win.setTimeout(() => element.removeAttribute("data-flash"), FLASH_MS);
|
|
11212
|
+
},
|
|
11213
|
+
dispose: () => win.clearTimeout(timer)
|
|
11214
|
+
};
|
|
11215
|
+
}
|
|
11216
|
+
var FLASH_MS = 450;
|
|
11217
|
+
var init_player = __esm(() => {
|
|
11218
|
+
init_timeline();
|
|
11219
|
+
});
|
|
11220
|
+
|
|
10860
11221
|
// src/ui/compare.ts
|
|
10861
11222
|
function compare(container, options) {
|
|
10862
11223
|
const doc = container.ownerDocument;
|
|
@@ -10953,6 +11314,19 @@ function compare(container, options) {
|
|
|
10953
11314
|
const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
|
|
10954
11315
|
labels[0].dataset.side = "before";
|
|
10955
11316
|
labels[1].dataset.side = "after";
|
|
11317
|
+
const setLabel = (index, text) => {
|
|
11318
|
+
const l = labels[index];
|
|
11319
|
+
if (!l.firstElementChild) {
|
|
11320
|
+
const mark = el("span", "knobs-cmp-mark");
|
|
11321
|
+
mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
|
|
11322
|
+
l.append(mark, el("span", "knobs-cmp-name"));
|
|
11323
|
+
}
|
|
11324
|
+
const name = l.lastElementChild;
|
|
11325
|
+
if (name.textContent !== text)
|
|
11326
|
+
name.textContent = text;
|
|
11327
|
+
};
|
|
11328
|
+
const seam = el("div", "knobs-cmp-seam");
|
|
11329
|
+
seam.setAttribute("aria-hidden", "true");
|
|
10956
11330
|
const handle = el("div", "knobs-cmp-handle");
|
|
10957
11331
|
handle.setAttribute("role", "slider");
|
|
10958
11332
|
handle.setAttribute("aria-label", "Wipe");
|
|
@@ -10962,7 +11336,8 @@ function compare(container, options) {
|
|
|
10962
11336
|
grip.setAttribute("aria-hidden", "true");
|
|
10963
11337
|
handle.append(grip);
|
|
10964
11338
|
const note = el("div", "knobs-cmp-note");
|
|
10965
|
-
|
|
11339
|
+
const glyph = playGlyph(doc);
|
|
11340
|
+
stage.append(canvas, split, seam, labels[0], labels[1], handle, zoomPill, note, glyph.element);
|
|
10966
11341
|
root.append(bar, stage);
|
|
10967
11342
|
const wantsStrip = options.strip === true;
|
|
10968
11343
|
let tl = bound;
|
|
@@ -10977,7 +11352,7 @@ function compare(container, options) {
|
|
|
10977
11352
|
root.append(host);
|
|
10978
11353
|
tl = timeline(host, {
|
|
10979
11354
|
...look,
|
|
10980
|
-
variant: "
|
|
11355
|
+
variant: "line",
|
|
10981
11356
|
duration: 1,
|
|
10982
11357
|
fps: fps(),
|
|
10983
11358
|
arrows: { step: 0.5, shift: 2 },
|
|
@@ -10998,12 +11373,13 @@ function compare(container, options) {
|
|
|
10998
11373
|
let toMode = mode;
|
|
10999
11374
|
const wipeLine = new Spring(wipe, WIPE_CATCH.omega, WIPE_CATCH.zeta, 0.0001);
|
|
11000
11375
|
let wipeCatching = false;
|
|
11001
|
-
|
|
11376
|
+
const gripAt = new Spring(0.5, LAYOUT2.omega, LAYOUT2.zeta, 0.0001);
|
|
11002
11377
|
let loupeHeld = false;
|
|
11003
11378
|
let pointer = null;
|
|
11004
11379
|
let drag = null;
|
|
11005
11380
|
const touches = new Map;
|
|
11006
11381
|
let pinch = null;
|
|
11382
|
+
let press = null;
|
|
11007
11383
|
const zu = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
11008
11384
|
const zv = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
11009
11385
|
const zw = new Spring(1, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
@@ -11290,6 +11666,8 @@ function compare(container, options) {
|
|
|
11290
11666
|
for (const s of sides) {
|
|
11291
11667
|
const st = s.el.style;
|
|
11292
11668
|
st.clipPath = "";
|
|
11669
|
+
st.maskImage = "";
|
|
11670
|
+
st.setProperty("-webkit-mask-image", "");
|
|
11293
11671
|
st.mixBlendMode = "";
|
|
11294
11672
|
st.opacity = "";
|
|
11295
11673
|
s.shown = null;
|
|
@@ -11516,43 +11894,65 @@ function compare(container, options) {
|
|
|
11516
11894
|
viewSent = key;
|
|
11517
11895
|
options.onView({ zoom: clampZoom(z), loop: l });
|
|
11518
11896
|
};
|
|
11519
|
-
const
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
return [at.before, at.after];
|
|
11523
|
-
}
|
|
11524
|
-
const ax = r.after.x + INSET + (r.after.w - labelW[1] - INSET * 2) * lay.x;
|
|
11525
|
-
return [
|
|
11526
|
-
{ x: r.before.x + INSET, opacity: 1 },
|
|
11527
|
-
{ x: ax, opacity: 1 }
|
|
11528
|
-
];
|
|
11897
|
+
const differenceWeight = () => {
|
|
11898
|
+
const f = Math.min(1, Math.max(0, fade.x));
|
|
11899
|
+
return (fromMode === "difference" ? 1 - f : 0) + (toMode === "difference" ? f : 0);
|
|
11529
11900
|
};
|
|
11530
11901
|
const placeGrip = (wr) => {
|
|
11531
|
-
const gy = gripTop(
|
|
11902
|
+
const gy = gripTop(wr.y + gripAt.x * wr.h, wr, GRIP.h) - wr.y;
|
|
11532
11903
|
grip.style.transform = `translate3d(0,${gy.toFixed(2)}px,0)`;
|
|
11533
11904
|
};
|
|
11905
|
+
let folded = 0;
|
|
11534
11906
|
const draw = () => {
|
|
11535
11907
|
dirty = false;
|
|
11908
|
+
if (!root.hasAttribute("data-ready") && sides.every((x) => x.shown || x.failed))
|
|
11909
|
+
root.setAttribute("data-ready", "");
|
|
11536
11910
|
const r = layoutNow();
|
|
11537
11911
|
const wr = wipeRect(r.L.overlay);
|
|
11538
|
-
const
|
|
11539
|
-
const
|
|
11540
|
-
const
|
|
11541
|
-
const
|
|
11542
|
-
|
|
11912
|
+
const k = Math.min(1, Math.max(0, lay.x));
|
|
11913
|
+
const fu = fuseFrame(r.L, r.before, r.after, k, wipeLine.x);
|
|
11914
|
+
const dw = differenceWeight();
|
|
11915
|
+
const fusing = 1 - dw;
|
|
11916
|
+
folded = k * fusing;
|
|
11917
|
+
const fold = labelFold(folded, MARK.w);
|
|
11918
|
+
const w = labelW.map((x) => x - (MARK.w - fold.width) - MARK.gap * folded);
|
|
11919
|
+
const ride = seamLabels(fu.cut, r.before.x, r.after.x + r.after.w, w[0], w[1], INSET);
|
|
11920
|
+
const apart = [r.before.x + INSET, r.after.x + INSET];
|
|
11921
|
+
const corner = [r.before.x + INSET, r.after.x + r.after.w - labelW[1] - INSET];
|
|
11922
|
+
const rides = [ride.before, ride.after];
|
|
11543
11923
|
const ys = [r.before.y + INSET, r.after.y + INSET];
|
|
11544
11924
|
for (const i of [0, 1]) {
|
|
11545
|
-
const
|
|
11546
|
-
|
|
11547
|
-
|
|
11925
|
+
const fused = apart[i] + (rides[i].x - apart[i]) * k;
|
|
11926
|
+
const x = fused + (corner[i] - fused) * dw;
|
|
11927
|
+
const opacity = (1 - k + k * rides[i].opacity) * fusing + dw;
|
|
11928
|
+
const l = labels[i];
|
|
11929
|
+
l.style.transform = `translate(${x.toFixed(2)}px,${ys[i].toFixed(2)}px)`;
|
|
11930
|
+
l.style.opacity = opacity.toFixed(3);
|
|
11931
|
+
const mark = l.firstElementChild;
|
|
11932
|
+
if (mark) {
|
|
11933
|
+
mark.style.width = `${fold.width.toFixed(2)}px`;
|
|
11934
|
+
mark.style.marginRight = `${(-MARK.gap * folded).toFixed(2)}px`;
|
|
11935
|
+
mark.style.opacity = fold.opacity.toFixed(3);
|
|
11936
|
+
mark.style.filter = fold.blur > 0.05 ? `blur(${fold.blur.toFixed(2)}px)` : "";
|
|
11937
|
+
}
|
|
11548
11938
|
}
|
|
11549
11939
|
const top = Math.min(r.L.side.before.y, r.L.side.after.y);
|
|
11550
11940
|
split.style.transform = `translate(${r.L.side.split.toFixed(2)}px,${top.toFixed(2)}px)`;
|
|
11551
11941
|
split.style.height = `${Math.max(0, r.L.side.after.h).toFixed(2)}px`;
|
|
11552
11942
|
split.style.opacity = String(Math.max(0, 1 - k * 2));
|
|
11943
|
+
const seamOn = fu.seam * fusing;
|
|
11944
|
+
const blur = fu.blur > 0.01 ? `blur(${fu.blur.toFixed(2)}px)` : "none";
|
|
11945
|
+
seam.style.transform = `translate(${fu.cut.toFixed(2)}px,${wr.y.toFixed(2)}px) translateX(-50%)`;
|
|
11946
|
+
seam.style.width = `${(8 + 2 * fu.feather).toFixed(2)}px`;
|
|
11947
|
+
seam.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
11948
|
+
seam.style.opacity = (blur === "none" ? 0 : seamOn).toFixed(3);
|
|
11949
|
+
seam.style.backdropFilter = blur;
|
|
11950
|
+
seam.style.setProperty("-webkit-backdrop-filter", blur);
|
|
11553
11951
|
handle.toggleAttribute("data-on", mode === "wipe");
|
|
11554
|
-
handle.style.transform = `translate(${
|
|
11952
|
+
handle.style.transform = `translate(${fu.cut.toFixed(2)}px,${wr.y.toFixed(2)}px)`;
|
|
11555
11953
|
handle.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
11954
|
+
handle.style.opacity = seamOn.toFixed(3);
|
|
11955
|
+
handle.style.filter = blur;
|
|
11556
11956
|
placeGrip(wr);
|
|
11557
11957
|
handle.setAttribute("aria-valuenow", String(Math.round(wipe * 100)));
|
|
11558
11958
|
handle.setAttribute("aria-valuetext", `${Math.round(wipe * 100)}% Before`);
|
|
@@ -11565,24 +11965,27 @@ function compare(container, options) {
|
|
|
11565
11965
|
if (pending)
|
|
11566
11966
|
return;
|
|
11567
11967
|
if (renderer === "dom") {
|
|
11568
|
-
const
|
|
11968
|
+
const cut = mode === "difference" ? null : fu;
|
|
11969
|
+
const place = (n, rect, clip, before) => {
|
|
11569
11970
|
const st = n.style;
|
|
11570
11971
|
st.transform = `translate(${rect.x.toFixed(2)}px,${rect.y.toFixed(2)}px)`;
|
|
11571
11972
|
st.width = `${rect.w.toFixed(2)}px`;
|
|
11572
11973
|
st.height = `${rect.h.toFixed(2)}px`;
|
|
11974
|
+
const edge = before && cut ? cut.cut + cut.feather : Number.POSITIVE_INFINITY;
|
|
11573
11975
|
const t = Math.max(0, clip.y - rect.y);
|
|
11574
11976
|
const l = Math.max(0, clip.x - rect.x);
|
|
11575
11977
|
const b = Math.max(0, rect.y + rect.h - (clip.y + clip.h));
|
|
11576
|
-
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w,
|
|
11978
|
+
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w, edge));
|
|
11577
11979
|
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)` : "";
|
|
11980
|
+
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)` : "";
|
|
11981
|
+
st.maskImage = mask;
|
|
11982
|
+
st.setProperty("-webkit-mask-image", mask);
|
|
11578
11983
|
};
|
|
11579
|
-
const cut = mode === "wipe" ? wx : Number.POSITIVE_INFINITY;
|
|
11580
11984
|
for (const s of sides) {
|
|
11581
11985
|
const rect = s.index === 0 ? r.zBefore : r.zAfter;
|
|
11582
11986
|
const clip = s.index === 0 ? r.before : r.after;
|
|
11583
|
-
|
|
11584
|
-
place(s.
|
|
11585
|
-
place(s.preview, rect, clip, at);
|
|
11987
|
+
place(s.el, rect, clip, s.index === 0);
|
|
11988
|
+
place(s.preview, rect, clip, s.index === 0);
|
|
11586
11989
|
if (s.index !== 0)
|
|
11587
11990
|
continue;
|
|
11588
11991
|
for (const n of [s.el, s.preview])
|
|
@@ -11602,8 +12005,8 @@ function compare(container, options) {
|
|
|
11602
12005
|
width: Math.max(1, Math.round(stageW * dpr)),
|
|
11603
12006
|
height: Math.max(1, Math.round(stageH * dpr)),
|
|
11604
12007
|
dpr,
|
|
11605
|
-
wipeX:
|
|
11606
|
-
soft: 0.75 * dpr,
|
|
12008
|
+
wipeX: fu.cut * dpr,
|
|
12009
|
+
soft: Math.max(0.75, fu.feather) * dpr,
|
|
11607
12010
|
from: MODE_INDEX[fromMode],
|
|
11608
12011
|
to: MODE_INDEX[toMode],
|
|
11609
12012
|
mix: Math.min(1, Math.max(0, fade.x)),
|
|
@@ -11630,6 +12033,7 @@ function compare(container, options) {
|
|
|
11630
12033
|
zu.step(dt);
|
|
11631
12034
|
zv.step(dt);
|
|
11632
12035
|
zw.step(dt);
|
|
12036
|
+
gripAt.step(dt);
|
|
11633
12037
|
const playing = isPlaying();
|
|
11634
12038
|
if (playing) {
|
|
11635
12039
|
const m = master();
|
|
@@ -11660,11 +12064,9 @@ function compare(container, options) {
|
|
|
11660
12064
|
pushFrame(s);
|
|
11661
12065
|
}
|
|
11662
12066
|
}
|
|
11663
|
-
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching;
|
|
12067
|
+
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching || !gripAt.resting;
|
|
11664
12068
|
if (moving)
|
|
11665
12069
|
dirty = true;
|
|
11666
|
-
if (auto && !lay.resting)
|
|
11667
|
-
fitHeight();
|
|
11668
12070
|
if (dirty)
|
|
11669
12071
|
draw();
|
|
11670
12072
|
return playing || moving;
|
|
@@ -11690,13 +12092,7 @@ function compare(container, options) {
|
|
|
11690
12092
|
zw.set(c.w);
|
|
11691
12093
|
requestDraw();
|
|
11692
12094
|
};
|
|
11693
|
-
const autoHeight = (w) =>
|
|
11694
|
-
const shape = sizeOf(sides[1]);
|
|
11695
|
-
const side = splitHeight(w, shape);
|
|
11696
|
-
const over = w * shape.h / shape.w;
|
|
11697
|
-
const h = side + (over - side) * lay.x;
|
|
11698
|
-
return Math.max(60, Math.min(win.innerHeight * 0.8, h));
|
|
11699
|
-
};
|
|
12095
|
+
const autoHeight = (w) => Math.max(60, Math.min(win.innerHeight * 0.8, splitHeight(w, sizeOf(sides[1]))));
|
|
11700
12096
|
const fitHeight = () => {
|
|
11701
12097
|
const h = autoHeight(stageW);
|
|
11702
12098
|
if (Math.abs(h - stageH) < 0.25)
|
|
@@ -11708,7 +12104,8 @@ function compare(container, options) {
|
|
|
11708
12104
|
const readColors = () => {
|
|
11709
12105
|
const c = tokenColor(win.getComputedStyle(root), "--_ku-cmp-diff", [0.49, 0.81, 0.61, 1]);
|
|
11710
12106
|
accent = [c[0], c[1], c[2]];
|
|
11711
|
-
|
|
12107
|
+
const unfold = MARK.w - labelFold(folded, MARK.w).width + MARK.gap * folded;
|
|
12108
|
+
labelW = [labels[0].offsetWidth + unfold, labels[1].offsetWidth + unfold];
|
|
11712
12109
|
requestDraw();
|
|
11713
12110
|
};
|
|
11714
12111
|
const measure = () => {
|
|
@@ -11799,8 +12196,10 @@ function compare(container, options) {
|
|
|
11799
12196
|
root.focus({ preventScroll: true });
|
|
11800
12197
|
touches.set(e.pointerId, p);
|
|
11801
12198
|
stage.setPointerCapture(e.pointerId);
|
|
12199
|
+
press = touches.size === 1 && mode !== "wipe" && master() ? p : null;
|
|
11802
12200
|
if (touches.size >= 2) {
|
|
11803
12201
|
e.preventDefault();
|
|
12202
|
+
press = null;
|
|
11804
12203
|
return startPinch();
|
|
11805
12204
|
}
|
|
11806
12205
|
if (mode === "wipe") {
|
|
@@ -11810,7 +12209,7 @@ function compare(container, options) {
|
|
|
11810
12209
|
if (inside && (grab.onLine || !zoomed())) {
|
|
11811
12210
|
drag = { kind: "wipe", offset: grab.offset };
|
|
11812
12211
|
root.dataset.dragging = "";
|
|
11813
|
-
|
|
12212
|
+
gripAt.snap(wr.h > 0 ? (p.y - wr.y) / wr.h : 0.5);
|
|
11814
12213
|
e.preventDefault();
|
|
11815
12214
|
if (!grab.onLine)
|
|
11816
12215
|
setWipe(wipeAt(p.x, wr), true, true);
|
|
@@ -11828,6 +12227,8 @@ function compare(container, options) {
|
|
|
11828
12227
|
const onMove = (e) => {
|
|
11829
12228
|
const p = local(e);
|
|
11830
12229
|
pointer = p;
|
|
12230
|
+
if (press && Math.hypot(p.x - press.x, p.y - press.y) > 4)
|
|
12231
|
+
press = null;
|
|
11831
12232
|
if (touches.has(e.pointerId))
|
|
11832
12233
|
touches.set(e.pointerId, p);
|
|
11833
12234
|
if (pinch && touches.size >= 2) {
|
|
@@ -11841,14 +12242,12 @@ function compare(container, options) {
|
|
|
11841
12242
|
pinch = { d, x: mid.x, y: mid.y };
|
|
11842
12243
|
return handZoom(zoomAbout(panned, k, q.pu, q.pv));
|
|
11843
12244
|
}
|
|
11844
|
-
if (
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
if (drag?.kind === "
|
|
11850
|
-
setWipe(wipeAt(p.x, wipeRect(layoutNow().L.overlay), drag.offset));
|
|
11851
|
-
else if (drag?.kind === "pan") {
|
|
12245
|
+
if (drag?.kind === "wipe") {
|
|
12246
|
+
const wr = wipeRect(layoutNow().L.overlay);
|
|
12247
|
+
gripAt.snap(wr.h > 0 ? (p.y - wr.y) / wr.h : 0.5);
|
|
12248
|
+
setWipe(wipeAt(p.x, wr, drag.offset));
|
|
12249
|
+
placeGrip(wr);
|
|
12250
|
+
} else if (drag?.kind === "pan") {
|
|
11852
12251
|
const dx = p.x - drag.x;
|
|
11853
12252
|
const dy = p.y - drag.y;
|
|
11854
12253
|
drag.x = p.x;
|
|
@@ -11859,11 +12258,23 @@ function compare(container, options) {
|
|
|
11859
12258
|
drawNow();
|
|
11860
12259
|
};
|
|
11861
12260
|
const endDrag = (e) => {
|
|
12261
|
+
if (press && e.type === "pointerup") {
|
|
12262
|
+
api.toggle();
|
|
12263
|
+
glyph.flash(isPlaying());
|
|
12264
|
+
}
|
|
12265
|
+
press = null;
|
|
11862
12266
|
touches.delete(e.pointerId);
|
|
11863
12267
|
if (touches.size < 2)
|
|
11864
12268
|
pinch = null;
|
|
11865
12269
|
if (!drag)
|
|
11866
12270
|
return;
|
|
12271
|
+
if (drag.kind === "wipe") {
|
|
12272
|
+
if (reducedMotion(win))
|
|
12273
|
+
gripAt.snap(0.5);
|
|
12274
|
+
else
|
|
12275
|
+
gripAt.set(0.5);
|
|
12276
|
+
requestDraw();
|
|
12277
|
+
}
|
|
11867
12278
|
drag = null;
|
|
11868
12279
|
delete root.dataset.dragging;
|
|
11869
12280
|
delete root.dataset.panning;
|
|
@@ -12013,8 +12424,9 @@ function compare(container, options) {
|
|
|
12013
12424
|
old.el.replaceWith(s.el);
|
|
12014
12425
|
old.preview.replaceWith(s.preview);
|
|
12015
12426
|
sides[index] = s;
|
|
12427
|
+
root.toggleAttribute("data-video", sides.some((x) => x.kind === "video"));
|
|
12016
12428
|
note.textContent = "";
|
|
12017
|
-
|
|
12429
|
+
setLabel(index, labelOf(index));
|
|
12018
12430
|
if (near)
|
|
12019
12431
|
loadSide(s);
|
|
12020
12432
|
readColors();
|
|
@@ -12025,8 +12437,9 @@ function compare(container, options) {
|
|
|
12025
12437
|
stage.insertBefore(sides[1].preview, labels[0]);
|
|
12026
12438
|
stage.insertBefore(sides[0].el, labels[0]);
|
|
12027
12439
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
12028
|
-
|
|
12029
|
-
|
|
12440
|
+
setLabel(0, labelOf(0));
|
|
12441
|
+
setLabel(1, labelOf(1));
|
|
12442
|
+
root.toggleAttribute("data-video", sides.some((s) => s.kind === "video"));
|
|
12030
12443
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
12031
12444
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
12032
12445
|
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
@@ -12166,11 +12579,11 @@ function compare(container, options) {
|
|
|
12166
12579
|
if (before)
|
|
12167
12580
|
replace(0, before);
|
|
12168
12581
|
else if (next.before)
|
|
12169
|
-
|
|
12582
|
+
setLabel(0, next.before.label ?? "Before");
|
|
12170
12583
|
if (after)
|
|
12171
12584
|
replace(1, after);
|
|
12172
12585
|
else if (next.after)
|
|
12173
|
-
|
|
12586
|
+
setLabel(1, next.after.label ?? "After");
|
|
12174
12587
|
if (before || after)
|
|
12175
12588
|
strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
|
|
12176
12589
|
if (next.before || next.after)
|
|
@@ -12227,6 +12640,7 @@ function compare(container, options) {
|
|
|
12227
12640
|
disposed = true;
|
|
12228
12641
|
loop.stop();
|
|
12229
12642
|
modePill?.dispose();
|
|
12643
|
+
glyph.dispose();
|
|
12230
12644
|
win.clearTimeout(releaseTimer);
|
|
12231
12645
|
ro.disconnect();
|
|
12232
12646
|
nearIo?.disconnect();
|
|
@@ -12256,7 +12670,7 @@ function compare(container, options) {
|
|
|
12256
12670
|
wake();
|
|
12257
12671
|
return api;
|
|
12258
12672
|
}
|
|
12259
|
-
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
12673
|
+
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, MARK, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
12260
12674
|
var init_compare = __esm(() => {
|
|
12261
12675
|
init_motion();
|
|
12262
12676
|
init_page_hints();
|
|
@@ -12267,15 +12681,17 @@ var init_compare = __esm(() => {
|
|
|
12267
12681
|
init_icons();
|
|
12268
12682
|
init_look();
|
|
12269
12683
|
init_rgba();
|
|
12684
|
+
init_player();
|
|
12270
12685
|
init_selection_pill();
|
|
12271
12686
|
init_timeline();
|
|
12272
12687
|
init_timeline_model();
|
|
12273
|
-
LAYOUT2 = springMotion(
|
|
12688
|
+
LAYOUT2 = springMotion(SPRINGS.default);
|
|
12274
12689
|
FADE6 = springMotion(SPRINGS.snappy);
|
|
12275
12690
|
FADE_REDUCED = springMotion(FADE);
|
|
12276
12691
|
ZOOM = springMotion({ duration: 0.35, bounce: 0 });
|
|
12277
12692
|
WIPE_CATCH = springMotion(CATCH_UP);
|
|
12278
12693
|
GRIP = { w: 16, h: 28 };
|
|
12694
|
+
MARK = { w: 12, gap: 4 };
|
|
12279
12695
|
LOUPE = { r: 88, zoom: 4 };
|
|
12280
12696
|
MODE_LABEL = {
|
|
12281
12697
|
side: { short: "Side", long: "Side by side" },
|
|
@@ -16714,7 +17130,9 @@ function confirm(options) {
|
|
|
16714
17130
|
}
|
|
16715
17131
|
|
|
16716
17132
|
// src/ui/walkthrough.ts
|
|
17133
|
+
init_icons();
|
|
16717
17134
|
init_look();
|
|
17135
|
+
init_selection_pill();
|
|
16718
17136
|
|
|
16719
17137
|
// src/ui/toast.ts
|
|
16720
17138
|
init_look();
|
|
@@ -16780,399 +17198,11 @@ function toast(message, options = {}) {
|
|
|
16780
17198
|
};
|
|
16781
17199
|
}
|
|
16782
17200
|
|
|
16783
|
-
// src/ui/walkthrough-
|
|
16784
|
-
init_compare_model();
|
|
16785
|
-
init_glide();
|
|
16786
|
-
init_look();
|
|
16787
|
-
|
|
16788
|
-
// src/ui/walkthrough-css.ts
|
|
17201
|
+
// src/ui/walkthrough-blocks.ts
|
|
16789
17202
|
init_motion();
|
|
16790
|
-
|
|
16791
|
-
|
|
16792
|
-
|
|
16793
|
-
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
16794
|
-
.knobs-ui.knobs-walkthrough{--kw-snappy:${snappy3.easing};--kw-snappy-ms:${snappy3.duration}ms;--kw-calm:${calm.easing};--kw-calm-ms:${calm.duration}ms;
|
|
16795
|
-
--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));
|
|
16796
|
-
--kw-card:var(--_ku-pane-bg);--kw-card-ring:var(--_ku-pane-ring);--kw-pad:16px;--kw-ink:var(--k-walkthrough-ink,#ff375f);
|
|
16797
|
-
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;
|
|
16798
|
-
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
16799
|
-
.knobs-walkthrough [hidden]{display:none!important}
|
|
16800
|
-
.knobs-walkthrough :is(h1,h2,h3,p){margin:0;font:inherit;letter-spacing:inherit}
|
|
16801
|
-
.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}
|
|
16802
|
-
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
16803
|
-
.knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
|
|
16804
|
-
: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;
|
|
16805
|
-
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
16806
|
-
|
|
16807
|
-
/* ——— layout: the rail beside the column; one column where it's narrow ——— */
|
|
16808
|
-
.knobs-wt-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;align-items:start}
|
|
16809
|
-
.knobs-wt-main{display:flex;flex-direction:column;gap:56px;min-width:0;max-width:1120px;padding-bottom:40vh}
|
|
16810
|
-
@container knobs-wt (max-width:880px){.knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:0}.knobs-wt-main{gap:44px}}
|
|
16811
|
-
|
|
16812
|
-
/* ——— the page's head ——— */
|
|
16813
|
-
.knobs-wt-head{display:flex;flex-direction:column;gap:10px}
|
|
16814
|
-
.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}
|
|
16815
|
-
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
16816
|
-
.knobs-wt-meta{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2px)}
|
|
16817
|
-
.knobs-wt-meta>span{display:inline-flex;gap:6px;white-space:nowrap}
|
|
16818
|
-
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono);font-size:calc(1em - .5px)}
|
|
16819
|
-
|
|
16820
|
-
/* ——— a section: a PR or topic ——— */
|
|
16821
|
-
.knobs-wt-section{display:flex;flex-direction:column;gap:14px;min-width:0}
|
|
16822
|
-
.knobs-wt-shead{display:flex;flex-direction:column;gap:6px;scroll-margin-top:16px}
|
|
16823
|
-
.knobs-wt-kicker{display:flex;align-items:center;gap:10px;font-size:calc(var(--kw-text) - 2px);color:var(--_k-fg-3)}
|
|
16824
|
-
.knobs-wt-kicker a{font-family:var(--_k-mono);color:var(--_k-fg-2);text-decoration:none}
|
|
16825
|
-
.knobs-wt-kicker a:hover{color:var(--_k-fg)}
|
|
16826
|
-
.knobs-wt-stitle{font-size:calc(var(--kw-text) + 4px)!important;font-weight:var(--_k-weight-title)!important;line-height:1.3}
|
|
16827
|
-
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
16828
|
-
.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;
|
|
16829
|
-
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
16830
|
-
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
16831
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
16832
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
16833
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
16834
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
16835
|
-
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
16836
|
-
|
|
16837
|
-
/* ——— a step: one card ——— */
|
|
16838
|
-
.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);
|
|
16839
|
-
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
16840
|
-
.knobs-walkthrough[data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
16841
|
-
.knobs-wt-step-head{display:flex;align-items:baseline;gap:10px;min-width:0}
|
|
16842
|
-
.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}
|
|
16843
|
-
.knobs-wt-stepTitle{flex:1;min-width:0;font-weight:var(--_k-weight-title)!important}
|
|
16844
|
-
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);margin-top:-6px!important}
|
|
16845
|
-
.knobs-wt-question{font-weight:var(--_k-weight-label)!important}
|
|
16846
|
-
/* The step Kit is on: its number lights, and its choices show their keys. */
|
|
16847
|
-
.knobs-wt-step[data-current] .knobs-wt-num{color:var(--_k-fg)}
|
|
16848
|
-
.knobs-wt-media{display:grid;grid-template-columns:repeat(var(--kw-n,1),minmax(0,1fr));gap:12px;min-width:0}
|
|
16849
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
16850
|
-
|
|
16851
|
-
/* ——— the feed: the agent's updates and answers, newest first, compact ——— */
|
|
16852
|
-
.knobs-wt-feed{margin-top:-24px}
|
|
16853
|
-
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;max-height:260px;overflow:auto;scrollbar-width:none;display:flex;flex-direction:column}
|
|
16854
|
-
.knobs-wt-feed-list::-webkit-scrollbar{display:none}
|
|
16855
|
-
.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)}
|
|
16856
|
-
.knobs-wt-fi+.knobs-wt-fi{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
16857
|
-
.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}
|
|
16858
|
-
.knobs-wt-fi-kind{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 2.5px);font-weight:var(--_k-weight-label)}
|
|
16859
|
-
.knobs-wt-fi[data-kind="qa"] .knobs-wt-fi-kind{color:var(--kw-info)}
|
|
16860
|
-
.knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
16861
|
-
.knobs-wt-fi-q{color:var(--_k-fg-2)}
|
|
16862
|
-
.knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
|
|
16863
|
-
: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;
|
|
16864
|
-
padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
|
|
16865
|
-
.knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16866
|
-
|
|
16867
|
-
/* ——— a step's sent notes ——— */
|
|
16868
|
-
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
16869
|
-
.knobs-wt-notes:empty{display:none}
|
|
16870
|
-
.knobs-wt-n{display:flex;align-items:flex-start;gap:10px;padding:6px 0;overflow:hidden;
|
|
16871
|
-
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)}
|
|
16872
|
-
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
16873
|
-
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
16874
|
-
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
16875
|
-
.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}
|
|
16876
|
-
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
16877
|
-
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
16878
|
-
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;font-size:calc(var(--kw-text) - 1px)}
|
|
16879
|
-
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
16880
|
-
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:6px;background:var(--_k-fill)}
|
|
16881
|
-
.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}
|
|
16882
|
-
|
|
16883
|
-
/* ——— the note bar, docked at the bottom of the column ——— */
|
|
16884
|
-
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;margin-top:-24px}
|
|
16885
|
-
.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);
|
|
16886
|
-
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
16887
|
-
.knobs-wt-on{padding-top:3px;color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 2.5px);white-space:nowrap;overflow:hidden;
|
|
16888
|
-
-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)}
|
|
16889
|
-
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
16890
|
-
: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;
|
|
16891
|
-
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
16892
|
-
.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)}
|
|
16893
|
-
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
16894
|
-
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
16895
|
-
.knobs-wt-attach:empty{display:none}
|
|
16896
|
-
.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}
|
|
16897
|
-
.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}
|
|
16898
|
-
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16899
|
-
.knobs-wt-x svg{width:10px;height:10px}
|
|
16900
|
-
.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);
|
|
16901
|
-
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
16902
|
-
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16903
|
-
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
16904
|
-
.knobs-wt-tool svg{width:15px;height:15px}
|
|
16905
|
-
.knobs-wt-rec{font-size:calc(var(--kw-text) - 2.5px);font-variant-numeric:tabular-nums}
|
|
16906
|
-
.knobs-wt-rec:empty{display:none}
|
|
16907
|
-
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
16908
|
-
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
16909
|
-
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
16910
|
-
.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);
|
|
16911
|
-
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;
|
|
16912
|
-
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)}
|
|
16913
|
-
.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)}
|
|
16914
|
-
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
16915
|
-
|
|
16916
|
-
/* ——— ink over a step's media ——— */
|
|
16917
|
-
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
16918
|
-
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
16919
|
-
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
16920
|
-
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
16921
|
-
|
|
16922
|
-
/* ——— full-window: the step over the page, its media filling it; its place held in the page ——— */
|
|
16923
|
-
.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}
|
|
16924
|
-
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
16925
|
-
.knobs-wt-hold-card{flex:none}
|
|
16926
|
-
.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)}
|
|
16927
|
-
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
16928
|
-
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
16929
|
-
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
16930
|
-
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
16931
|
-
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
16932
|
-
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
16933
|
-
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
16934
|
-
|
|
16935
|
-
/* ——— a taste test: the options side by side, Kit's pick lit and the rest stepping back ——— */
|
|
16936
|
-
.knobs-wt-options{display:grid;grid-template-columns:repeat(var(--kw-n,2),minmax(0,1fr));gap:10px}
|
|
16937
|
-
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
16938
|
-
.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);
|
|
16939
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16940
|
-
.knobs-wt-option[data-picked]{background:color-mix(in srgb,var(--_k-accent) 12%,var(--_ku-wash))}
|
|
16941
|
-
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16942
|
-
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
16943
|
-
.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}
|
|
16944
|
-
.knobs-ui .knobs-wt-pick:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
16945
|
-
.knobs-wt-letter{flex:none;font:var(--_k-weight-title) calc(var(--kw-text) - 1px)/1 var(--_k-font);color:var(--_k-fg)}
|
|
16946
|
-
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
16947
|
-
.knobs-wt-suggested{flex:none;font-size:calc(var(--kw-text) - 3px);color:var(--_k-fg-3)}
|
|
16948
|
-
.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;
|
|
16949
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16950
|
-
.knobs-wt-check svg{width:12px;height:12px}
|
|
16951
|
-
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
16952
|
-
.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);
|
|
16953
|
-
font:var(--_k-weight-label) calc(var(--kw-text) - 4px)/1 var(--_k-font);font-variant-numeric:tabular-nums;opacity:.5;transition:opacity .15s}
|
|
16954
|
-
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
16955
|
-
.knobs-wt-ocap{color:var(--_k-fg-2);font-size:calc(var(--kw-text) - 1px);padding:0 4px}
|
|
16956
|
-
|
|
16957
|
-
/* ——— the rail: progress, contents, export ——— */
|
|
16958
|
-
.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)}
|
|
16959
|
-
.knobs-wt-progress{display:flex;flex-direction:column;gap:7px}
|
|
16960
|
-
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2);font-variant-numeric:tabular-nums}
|
|
16961
|
-
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
16962
|
-
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
16963
|
-
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
16964
|
-
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
16965
|
-
/* The contents: no box, one text spine for sections and steps (the steps' dots hang in the
|
|
16966
|
-
gutter left of it), and one pill behind the current step that springs between rows. */
|
|
16967
|
-
.knobs-wt-toc{position:relative;flex:1 1 auto;min-height:0;overflow:auto;scrollbar-width:none;margin:0 -8px;padding:0 0 8px}
|
|
16968
|
-
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
16969
|
-
.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;
|
|
16970
|
-
-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)}
|
|
16971
|
-
.knobs-wt-toc-section:first-of-type{padding-top:2px}
|
|
16972
|
-
.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}
|
|
16973
|
-
.knobs-wt-toc-mark[data-on]{opacity:1}
|
|
16974
|
-
.knobs-walkthrough[data-settled] .knobs-wt-toc-mark{transition:opacity .15s}
|
|
16975
|
-
.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}
|
|
16976
|
-
.knobs-ui .knobs-wt-toc-step:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
16977
|
-
.knobs-wt-toc-step[aria-current="step"]{color:var(--_k-fg)}
|
|
16978
|
-
.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)}
|
|
16979
|
-
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
16980
|
-
.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);
|
|
16981
|
-
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
16982
|
-
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
16983
|
-
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
16984
|
-
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
16985
|
-
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
16986
|
-
.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;
|
|
16987
|
-
transition:background .15s,color .15s}
|
|
16988
|
-
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16989
|
-
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
16990
|
-
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
16991
|
-
.knobs-wt-keys{color:var(--_k-fg-3);font-size:calc(var(--kw-text) - 3px);line-height:1.6}
|
|
16992
|
-
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
16993
|
-
/* Narrow: the rail becomes a bar along the top, with the progress and the export only. */
|
|
16994
|
-
@container knobs-wt (max-width:880px){
|
|
16995
|
-
.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)}
|
|
16996
|
-
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
16997
|
-
.knobs-wt-step,.knobs-wt-shead{scroll-margin-top:60px}
|
|
16998
|
-
}
|
|
16999
|
-
|
|
17000
|
-
/* ——— media slots ——— */
|
|
17001
|
-
.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);
|
|
17002
|
-
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
17003
|
-
.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}
|
|
17004
|
-
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
17005
|
-
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
17006
|
-
(92 px), and the frame strip with its gap (158 px). */
|
|
17007
|
-
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
17008
|
-
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
17009
|
-
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
17010
|
-
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
17011
|
-
.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)}
|
|
17012
|
-
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
17013
|
-
.knobs-wt-frame[data-natural]{aspect-ratio:auto}
|
|
17014
|
-
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
17015
|
-
.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);
|
|
17016
|
-
font:calc(var(--k-walkthrough-text,14px) - 2px)/1.55 var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
17017
|
-
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
17018
|
-
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
17019
|
-
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
17020
|
-
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
17021
|
-
.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)}
|
|
17022
|
-
.knobs-wt-mlabel{color:var(--_k-fg-2);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
|
|
17023
|
-
.knobs-wt-mvalue{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
|
|
17024
|
-
.knobs-wt-mfrom{color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) + 2px)}
|
|
17025
|
-
.knobs-wt-mto{font-size:calc(var(--k-walkthrough-text,14px) + 12px);font-weight:var(--_k-weight-title);line-height:1}
|
|
17026
|
-
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
17027
|
-
.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)}
|
|
17028
|
-
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
17029
|
-
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
17030
|
-
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
17031
|
-
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
17032
|
-
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
17033
|
-
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
17034
|
-
.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)}
|
|
17035
|
-
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:.62em;border-radius:50%;background:var(--kw-tone)}
|
|
17036
|
-
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
17037
|
-
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
17038
|
-
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
17039
|
-
.knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
17040
|
-
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
17041
|
-
.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)}
|
|
17042
|
-
|
|
17043
|
-
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
17044
|
-
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
17045
|
-
: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)}
|
|
17046
|
-
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
17047
|
-
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
17048
|
-
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
17049
|
-
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
17050
|
-
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
17051
|
-
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
17052
|
-
.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);
|
|
17053
|
-
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
17054
|
-
.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)}
|
|
17055
|
-
|
|
17056
|
-
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
17057
|
-
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
17058
|
-
.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)}
|
|
17059
|
-
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
17060
|
-
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
17061
|
-
.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)}
|
|
17062
|
-
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
|
|
17063
|
-
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
17064
|
-
.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}
|
|
17065
|
-
.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)}
|
|
17066
|
-
.knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
|
|
17067
|
-
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
17068
|
-
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
17069
|
-
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
17070
|
-
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
17071
|
-
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
17072
|
-
.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))}
|
|
17073
|
-
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
17074
|
-
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
17075
|
-
.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))}
|
|
17076
|
-
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
17077
|
-
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
17078
|
-
.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}
|
|
17079
|
-
.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}
|
|
17080
|
-
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
17081
|
-
@container knobs-wt-slot (max-width:520px){
|
|
17082
|
-
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
17083
|
-
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
17084
|
-
}
|
|
17085
|
-
|
|
17086
|
-
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
17087
|
-
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
17088
|
-
.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)}
|
|
17089
|
-
.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);
|
|
17090
|
-
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
17091
|
-
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
17092
|
-
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
17093
|
-
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
17094
|
-
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
17095
|
-
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
17096
|
-
.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)}
|
|
17097
|
-
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
17098
|
-
.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}
|
|
17099
|
-
.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)}
|
|
17100
|
-
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
17101
|
-
.knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
17102
|
-
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
17103
|
-
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
17104
|
-
.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}
|
|
17105
|
-
.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}
|
|
17106
|
-
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
17107
|
-
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
17108
|
-
.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)}
|
|
17109
|
-
.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)}
|
|
17110
|
-
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
17111
|
-
.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)}
|
|
17112
|
-
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
17113
|
-
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
17114
|
-
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
17115
|
-
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
17116
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
17117
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
17118
|
-
@container knobs-wt-slot (max-width:520px){
|
|
17119
|
-
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
17120
|
-
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
17121
|
-
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
17122
|
-
}
|
|
17123
|
-
|
|
17124
|
-
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
17125
|
-
(the top one under the head), and thin bars show on hover. */
|
|
17126
|
-
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
17127
|
-
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
17128
|
-
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
17129
|
-
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
17130
|
-
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
17131
|
-
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
17132
|
-
.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)}
|
|
17133
|
-
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
17134
|
-
@supports (animation-timeline:scroll()){
|
|
17135
|
-
.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;
|
|
17136
|
-
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%;
|
|
17137
|
-
--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)));
|
|
17138
|
-
--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)));
|
|
17139
|
-
-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}
|
|
17140
|
-
}
|
|
17141
|
-
.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)}
|
|
17142
|
-
.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)}
|
|
17143
|
-
.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;
|
|
17144
|
-
background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
17145
|
-
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
17146
|
-
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
17147
|
-
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
17148
|
-
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
17149
|
-
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
17150
|
-
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
17151
|
-
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
17152
|
-
.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}
|
|
17153
|
-
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
17154
|
-
.knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
|
|
17155
|
-
.knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
|
|
17156
|
-
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
17157
|
-
|
|
17158
|
-
/* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
|
|
17159
|
-
.knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
|
|
17160
|
-
.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;
|
|
17161
|
-
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
|
|
17162
|
-
.knobs-wt-chapter-mark[data-on]{opacity:1}
|
|
17163
|
-
.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);
|
|
17164
|
-
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)}
|
|
17165
|
-
.knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
17166
|
-
.knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
|
|
17167
|
-
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
|
|
17168
|
-
.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)}
|
|
17169
|
-
.knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
|
|
17170
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
17171
|
-
`;
|
|
17172
|
-
|
|
17173
|
-
// src/ui/walkthrough-blocks.ts
|
|
17174
|
-
init_motion();
|
|
17175
|
-
init_look();
|
|
17203
|
+
init_icons();
|
|
17204
|
+
init_look();
|
|
17205
|
+
init_selection_pill();
|
|
17176
17206
|
|
|
17177
17207
|
// src/ui/walkthrough-model.ts
|
|
17178
17208
|
var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
|
|
@@ -17379,7 +17409,15 @@ function fillTable(m) {
|
|
|
17379
17409
|
out[k] = fillCell(v);
|
|
17380
17410
|
return out;
|
|
17381
17411
|
});
|
|
17382
|
-
|
|
17412
|
+
const primary = columns.find((c) => c.key === m.primary)?.key ?? columns[0]?.key ?? "";
|
|
17413
|
+
return {
|
|
17414
|
+
kind: "table",
|
|
17415
|
+
columns,
|
|
17416
|
+
rows,
|
|
17417
|
+
...m.caption ? { caption: m.caption } : {},
|
|
17418
|
+
stack: m.stack ?? "auto",
|
|
17419
|
+
primary
|
|
17420
|
+
};
|
|
17383
17421
|
}
|
|
17384
17422
|
function fillChapters(chapters) {
|
|
17385
17423
|
const id = uniqueIds();
|
|
@@ -17452,6 +17490,8 @@ function normalizeWalkthrough(doc) {
|
|
|
17452
17490
|
...step.caption ? { caption: step.caption } : {},
|
|
17453
17491
|
...step.question ? { question: step.question } : {},
|
|
17454
17492
|
media: list.map((m) => fillMedia(m, doc.base)),
|
|
17493
|
+
columns: Math.max(1, Math.min(3, Math.round(step.columns ?? 1))),
|
|
17494
|
+
...step.more?.trim() ? { more: step.more.trim() } : {},
|
|
17455
17495
|
options,
|
|
17456
17496
|
ask
|
|
17457
17497
|
};
|
|
@@ -17463,8 +17503,10 @@ function normalizeWalkthrough(doc) {
|
|
|
17463
17503
|
id,
|
|
17464
17504
|
title: s.title,
|
|
17465
17505
|
...link ? { link } : {},
|
|
17506
|
+
...typeof s.kicker === "string" && s.kicker.trim() ? { kicker: s.kicker.trim() } : {},
|
|
17466
17507
|
...s.status ? { status: s.status } : {},
|
|
17467
17508
|
...s.summary ? { summary: s.summary } : {},
|
|
17509
|
+
...s.more?.trim() ? { more: s.more.trim() } : {},
|
|
17468
17510
|
steps: own
|
|
17469
17511
|
};
|
|
17470
17512
|
});
|
|
@@ -17473,30 +17515,95 @@ function normalizeWalkthrough(doc) {
|
|
|
17473
17515
|
value
|
|
17474
17516
|
}));
|
|
17475
17517
|
const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
|
|
17518
|
+
const extra = (x) => ({
|
|
17519
|
+
...x.status?.trim() ? { status: x.status.trim() } : {},
|
|
17520
|
+
trail: (x.trail ?? []).filter((t) => typeof t === "string" && t.trim())
|
|
17521
|
+
});
|
|
17476
17522
|
const feed = sortFeed([
|
|
17477
|
-
...(doc.updates ?? []).map((u) => ({
|
|
17523
|
+
...(doc.updates ?? []).map((u) => ({
|
|
17524
|
+
kind: "update",
|
|
17525
|
+
at: parseAt(u.at),
|
|
17526
|
+
text: u.text,
|
|
17527
|
+
step: stepRef(u.step),
|
|
17528
|
+
...extra(u)
|
|
17529
|
+
})),
|
|
17478
17530
|
...(doc.qa ?? []).map((x) => ({
|
|
17479
17531
|
kind: "qa",
|
|
17480
17532
|
at: parseAt(x.at),
|
|
17481
17533
|
text: x.a,
|
|
17482
17534
|
q: x.q,
|
|
17483
|
-
step: stepRef(x.step)
|
|
17535
|
+
step: stepRef(x.step),
|
|
17536
|
+
...extra(x)
|
|
17484
17537
|
}))
|
|
17485
17538
|
]);
|
|
17486
17539
|
return {
|
|
17487
17540
|
id: doc.id,
|
|
17488
17541
|
title: doc.title,
|
|
17489
17542
|
...doc.summary ? { summary: doc.summary } : {},
|
|
17543
|
+
...doc.more?.trim() ? { more: doc.more.trim() } : {},
|
|
17490
17544
|
meta,
|
|
17491
17545
|
feed,
|
|
17492
17546
|
verdicts: ((doc.verdicts?.length) ? doc.verdicts : DEFAULT_VERDICTS).map((v) => ({
|
|
17493
17547
|
id: slug(v),
|
|
17494
17548
|
label: label(v)
|
|
17495
17549
|
})),
|
|
17496
|
-
sections,
|
|
17497
|
-
steps
|
|
17550
|
+
sections: withKickers(sections, doc.sections, doc.kickers),
|
|
17551
|
+
steps,
|
|
17552
|
+
prs: knownPRs(doc, sections),
|
|
17553
|
+
...repoOf(doc) ? { repo: repoOf(doc) } : {}
|
|
17498
17554
|
};
|
|
17499
17555
|
}
|
|
17556
|
+
var prNumber = (href) => /\/(?:pull|merge_requests)\/(\d+)(?:[/?#]|$)/.exec(href)?.[1] ?? null;
|
|
17557
|
+
var repoOf = (doc) => doc.repo?.trim().replace(/^https?:\/\/github\.com\//, "").replace(/\/+$/, "") || undefined;
|
|
17558
|
+
function knownPRs(doc, sections) {
|
|
17559
|
+
const out = {};
|
|
17560
|
+
const repo = repoOf(doc);
|
|
17561
|
+
for (const s of sections) {
|
|
17562
|
+
const n = s.link && prNumber(s.link.href);
|
|
17563
|
+
if (n)
|
|
17564
|
+
out[n] = { href: s.link.href.replace(/(\/pull\/\d+).*$/, "$1") };
|
|
17565
|
+
}
|
|
17566
|
+
for (const [k, pr] of Object.entries(doc.prs ?? {})) {
|
|
17567
|
+
const n = k.replace(/^#/, "");
|
|
17568
|
+
if (!/^\d+$/.test(n))
|
|
17569
|
+
continue;
|
|
17570
|
+
out[n] = { ...out[n], ...pr };
|
|
17571
|
+
}
|
|
17572
|
+
if (repo) {
|
|
17573
|
+
for (const n of Object.keys(out))
|
|
17574
|
+
if (!out[n].href)
|
|
17575
|
+
out[n] = { ...out[n], href: `https://github.com/${repo}/pull/${n}` };
|
|
17576
|
+
}
|
|
17577
|
+
return out;
|
|
17578
|
+
}
|
|
17579
|
+
function findPR(prs, n, repo) {
|
|
17580
|
+
const known = prs[n];
|
|
17581
|
+
if (known)
|
|
17582
|
+
return known;
|
|
17583
|
+
return repo ? { href: `https://github.com/${repo}/pull/${n}` } : null;
|
|
17584
|
+
}
|
|
17585
|
+
var isPullRequest = (href) => /\/(?:pull|merge_requests)\/\d+(?:[/?#]|$)/.test(href);
|
|
17586
|
+
function withKickers(sections, source, kickers = "pr") {
|
|
17587
|
+
if (kickers === false)
|
|
17588
|
+
return [...sections];
|
|
17589
|
+
const noun = typeof kickers === "object" ? kickers.noun.trim() : "PR";
|
|
17590
|
+
const counted = typeof kickers === "object" ? sections : sections.filter((s) => s.link && isPullRequest(s.link.href));
|
|
17591
|
+
return sections.map((s, i) => {
|
|
17592
|
+
const own = source[i]?.kicker;
|
|
17593
|
+
if (own !== undefined || s.kicker)
|
|
17594
|
+
return s;
|
|
17595
|
+
const at = counted.indexOf(s);
|
|
17596
|
+
return at < 0 ? s : { ...s, kicker: `${noun} ${at + 1} of ${counted.length}`.trim() };
|
|
17597
|
+
});
|
|
17598
|
+
}
|
|
17599
|
+
function tableStacks(stack, room, natural) {
|
|
17600
|
+
if (stack !== "auto")
|
|
17601
|
+
return stack === "always";
|
|
17602
|
+
return room > 0 && natural > room + 1;
|
|
17603
|
+
}
|
|
17604
|
+
function noteBarReserve(bar, inset, gap) {
|
|
17605
|
+
return Math.max(0, Math.ceil(bar)) + inset + gap;
|
|
17606
|
+
}
|
|
17500
17607
|
function parseAt(at) {
|
|
17501
17608
|
if (!at)
|
|
17502
17609
|
return null;
|
|
@@ -17781,6 +17888,9 @@ function feedbackMarkdown(fb, verdicts) {
|
|
|
17781
17888
|
`;
|
|
17782
17889
|
}
|
|
17783
17890
|
var escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
17891
|
+
function plainMarkdown(text) {
|
|
17892
|
+
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();
|
|
17893
|
+
}
|
|
17784
17894
|
function inlineMarkdown(text) {
|
|
17785
17895
|
const codes = [];
|
|
17786
17896
|
let s = text.replace(/`([^`\n]+)`/g, (_, c) => {
|
|
@@ -17801,6 +17911,10 @@ function inlineMarkdown(text) {
|
|
|
17801
17911
|
}
|
|
17802
17912
|
|
|
17803
17913
|
// src/ui/walkthrough-blocks.ts
|
|
17914
|
+
var GLYPH = {
|
|
17915
|
+
go: icon("caretRight", { small: true }),
|
|
17916
|
+
caret: icon("caretRight", { small: true })
|
|
17917
|
+
};
|
|
17804
17918
|
var el = (doc, tag, cls) => {
|
|
17805
17919
|
const n = doc.createElement(tag);
|
|
17806
17920
|
if (cls)
|
|
@@ -17830,9 +17944,10 @@ function stepButton(doc, ref, steps) {
|
|
|
17830
17944
|
const s = ref && steps?.find(ref);
|
|
17831
17945
|
if (!s || !steps)
|
|
17832
17946
|
return null;
|
|
17833
|
-
const b =
|
|
17947
|
+
const b = el(doc, "button", "knobs-wt-steplink");
|
|
17948
|
+
b.innerHTML = GLYPH.go;
|
|
17834
17949
|
b.type = "button";
|
|
17835
|
-
b.title = `Go to
|
|
17950
|
+
b.title = `Go to “${s.title}”`;
|
|
17836
17951
|
b.setAttribute("aria-label", b.title);
|
|
17837
17952
|
b.addEventListener("click", (e) => {
|
|
17838
17953
|
e.stopPropagation();
|
|
@@ -17957,7 +18072,7 @@ function mountStack(host, m, steps) {
|
|
|
17957
18072
|
if (target && steps) {
|
|
17958
18073
|
const title = text(doc, "button", "knobs-wt-stitle", it.title);
|
|
17959
18074
|
title.type = "button";
|
|
17960
|
-
title.title = `Go to
|
|
18075
|
+
title.title = `Go to “${target.title}”`;
|
|
17961
18076
|
title.addEventListener("click", (e) => {
|
|
17962
18077
|
e.stopPropagation();
|
|
17963
18078
|
steps.go(target.key);
|
|
@@ -18012,175 +18127,861 @@ function delta(doc, d) {
|
|
|
18012
18127
|
s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
|
|
18013
18128
|
return s;
|
|
18014
18129
|
}
|
|
18015
|
-
function
|
|
18016
|
-
|
|
18017
|
-
|
|
18018
|
-
|
|
18019
|
-
|
|
18020
|
-
|
|
18021
|
-
|
|
18022
|
-
|
|
18023
|
-
|
|
18024
|
-
|
|
18025
|
-
|
|
18026
|
-
|
|
18027
|
-
|
|
18028
|
-
|
|
18029
|
-
|
|
18030
|
-
|
|
18031
|
-
|
|
18032
|
-
|
|
18033
|
-
|
|
18034
|
-
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18040
|
-
|
|
18041
|
-
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
|
|
18046
|
-
|
|
18047
|
-
|
|
18048
|
-
|
|
18049
|
-
|
|
18050
|
-
|
|
18051
|
-
|
|
18052
|
-
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
|
|
18056
|
-
|
|
18057
|
-
|
|
18058
|
-
|
|
18059
|
-
|
|
18060
|
-
|
|
18061
|
-
|
|
18062
|
-
|
|
18063
|
-
|
|
18064
|
-
|
|
18065
|
-
|
|
18066
|
-
|
|
18067
|
-
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
|
|
18072
|
-
|
|
18073
|
-
|
|
18074
|
-
|
|
18075
|
-
|
|
18076
|
-
|
|
18077
|
-
|
|
18078
|
-
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
|
|
18087
|
-
|
|
18088
|
-
|
|
18089
|
-
|
|
18090
|
-
|
|
18091
|
-
|
|
18092
|
-
}
|
|
18093
|
-
|
|
18094
|
-
|
|
18130
|
+
function cellContent(doc, into, cell, steps) {
|
|
18131
|
+
let content;
|
|
18132
|
+
if (cell.badge) {
|
|
18133
|
+
content = link(doc, "knobs-wt-chip", cell.text, cell.href);
|
|
18134
|
+
content.dataset.tone = cell.badge;
|
|
18135
|
+
} else {
|
|
18136
|
+
const inner = cell.code ? text(doc, "code", "", cell.text) : null;
|
|
18137
|
+
if (cell.href) {
|
|
18138
|
+
content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
|
|
18139
|
+
if (inner)
|
|
18140
|
+
content.append(inner);
|
|
18141
|
+
} else
|
|
18142
|
+
content = inner ?? text(doc, "span", "", cell.text);
|
|
18143
|
+
if (cell.tone) {
|
|
18144
|
+
content.classList.add("knobs-wt-ctone");
|
|
18145
|
+
content.dataset.tone = cell.tone;
|
|
18146
|
+
}
|
|
18147
|
+
}
|
|
18148
|
+
into.append(content);
|
|
18149
|
+
const go = stepButton(doc, cell.step, steps);
|
|
18150
|
+
if (go)
|
|
18151
|
+
into.append(go);
|
|
18152
|
+
}
|
|
18153
|
+
var cellAttrs = (td, c) => {
|
|
18154
|
+
td.dataset.align = c.align;
|
|
18155
|
+
if (c.mono)
|
|
18156
|
+
td.dataset.mono = "";
|
|
18157
|
+
};
|
|
18158
|
+
function mountTable(host, m, steps) {
|
|
18159
|
+
const doc = host.ownerDocument;
|
|
18160
|
+
const win = doc.defaultView;
|
|
18161
|
+
const box = el(doc, "div", "knobs-wt-tablebox");
|
|
18162
|
+
const scroller = el(doc, "div", "knobs-wt-table");
|
|
18163
|
+
const table = el(doc, "table");
|
|
18164
|
+
if (m.caption)
|
|
18165
|
+
table.append(text(doc, "caption", "", m.caption));
|
|
18166
|
+
const head = el(doc, "thead");
|
|
18167
|
+
const hr = el(doc, "tr");
|
|
18168
|
+
for (const c of m.columns) {
|
|
18169
|
+
const th = text(doc, "th", "", c.label);
|
|
18170
|
+
th.scope = "col";
|
|
18171
|
+
th.dataset.align = c.align;
|
|
18172
|
+
hr.append(th);
|
|
18173
|
+
}
|
|
18174
|
+
head.append(hr);
|
|
18175
|
+
const body = el(doc, "tbody");
|
|
18176
|
+
for (const r of m.rows) {
|
|
18177
|
+
const tr = el(doc, "tr");
|
|
18178
|
+
for (const c of m.columns) {
|
|
18179
|
+
const td = el(doc, "td");
|
|
18180
|
+
cellAttrs(td, c);
|
|
18181
|
+
const cell = r[c.key];
|
|
18182
|
+
if (cell) {
|
|
18183
|
+
if (cell.text.length > 40 && !c.mono && !cell.code)
|
|
18184
|
+
td.dataset.long = "";
|
|
18185
|
+
cellContent(doc, td, cell, steps);
|
|
18186
|
+
}
|
|
18187
|
+
tr.append(td);
|
|
18188
|
+
}
|
|
18189
|
+
body.append(tr);
|
|
18190
|
+
}
|
|
18191
|
+
table.append(head, body);
|
|
18192
|
+
scroller.append(table);
|
|
18193
|
+
const stack = el(doc, "div", "knobs-wt-tstack");
|
|
18194
|
+
stack.setAttribute("role", "list");
|
|
18195
|
+
if (m.caption)
|
|
18196
|
+
stack.setAttribute("aria-label", m.caption);
|
|
18197
|
+
const primary = m.columns.find((c) => c.key === m.primary) ?? m.columns[0];
|
|
18198
|
+
for (const r of m.rows) {
|
|
18199
|
+
const item = el(doc, "div", "knobs-wt-trow");
|
|
18200
|
+
item.setAttribute("role", "listitem");
|
|
18201
|
+
const title = el(doc, "div", "knobs-wt-ttitle");
|
|
18202
|
+
if (primary) {
|
|
18203
|
+
cellAttrs(title, primary);
|
|
18204
|
+
const cell = r[primary.key];
|
|
18205
|
+
if (cell)
|
|
18206
|
+
cellContent(doc, title, cell, steps);
|
|
18207
|
+
}
|
|
18208
|
+
const line = el(doc, "div", "knobs-wt-tline");
|
|
18209
|
+
line.append(title);
|
|
18210
|
+
const badges = el(doc, "div", "knobs-wt-tbadges");
|
|
18211
|
+
for (const c of m.columns) {
|
|
18212
|
+
const cell = r[c.key];
|
|
18213
|
+
if (c !== primary && cell?.badge)
|
|
18214
|
+
cellContent(doc, badges, cell, steps);
|
|
18215
|
+
}
|
|
18216
|
+
if (badges.childNodes.length)
|
|
18217
|
+
line.append(badges);
|
|
18218
|
+
item.append(line);
|
|
18219
|
+
const terms = el(doc, "dl", "knobs-wt-tterms");
|
|
18220
|
+
for (const c of m.columns) {
|
|
18221
|
+
if (c === primary)
|
|
18222
|
+
continue;
|
|
18223
|
+
const cell = r[c.key];
|
|
18224
|
+
if (!cell || cell.text === "" || cell.badge)
|
|
18225
|
+
continue;
|
|
18226
|
+
const dd = el(doc, "dd");
|
|
18227
|
+
cellAttrs(dd, c);
|
|
18228
|
+
dd.removeAttribute("data-align");
|
|
18229
|
+
cellContent(doc, dd, cell, steps);
|
|
18230
|
+
terms.append(text(doc, "dt", "", c.label), dd);
|
|
18231
|
+
}
|
|
18232
|
+
if (terms.childNodes.length)
|
|
18233
|
+
item.append(terms);
|
|
18234
|
+
stack.append(item);
|
|
18235
|
+
}
|
|
18236
|
+
if (m.caption)
|
|
18237
|
+
stack.append(text(doc, "p", "knobs-wt-tcaption", m.caption));
|
|
18238
|
+
box.append(scroller, stack);
|
|
18239
|
+
host.append(box);
|
|
18240
|
+
let natural = 0;
|
|
18241
|
+
const measureNatural = () => {
|
|
18242
|
+
if (!box.isConnected)
|
|
18243
|
+
return 0;
|
|
18244
|
+
const was = box.dataset.stacked;
|
|
18245
|
+
delete box.dataset.stacked;
|
|
18246
|
+
box.dataset.measure = "";
|
|
18247
|
+
const w = table.getBoundingClientRect().width;
|
|
18248
|
+
delete box.dataset.measure;
|
|
18249
|
+
if (was !== undefined)
|
|
18250
|
+
box.dataset.stacked = was;
|
|
18251
|
+
return w;
|
|
18252
|
+
};
|
|
18253
|
+
const measure = () => {
|
|
18254
|
+
if (!natural)
|
|
18255
|
+
natural = measureNatural();
|
|
18256
|
+
const stacked = tableStacks(m.stack, box.clientWidth, natural);
|
|
18257
|
+
box.toggleAttribute("data-stacked", stacked);
|
|
18258
|
+
scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
|
|
18259
|
+
const scrolls = !stacked && (scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1);
|
|
18260
|
+
if (scrolls) {
|
|
18261
|
+
scroller.tabIndex = 0;
|
|
18262
|
+
scroller.setAttribute("role", "region");
|
|
18263
|
+
scroller.setAttribute("aria-label", m.caption ?? "Table");
|
|
18264
|
+
} else {
|
|
18265
|
+
scroller.removeAttribute("tabindex");
|
|
18266
|
+
scroller.removeAttribute("role");
|
|
18267
|
+
scroller.removeAttribute("aria-label");
|
|
18268
|
+
}
|
|
18269
|
+
};
|
|
18270
|
+
if (m.stack === "always")
|
|
18271
|
+
box.dataset.stacked = "";
|
|
18272
|
+
const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
|
|
18273
|
+
ro?.observe(box);
|
|
18274
|
+
measure();
|
|
18275
|
+
doc.fonts?.ready.then(() => {
|
|
18276
|
+
if (!box.isConnected)
|
|
18277
|
+
return;
|
|
18278
|
+
natural = 0;
|
|
18279
|
+
measure();
|
|
18280
|
+
});
|
|
18281
|
+
return {
|
|
18282
|
+
dispose: () => {
|
|
18283
|
+
ro?.disconnect();
|
|
18284
|
+
box.remove();
|
|
18285
|
+
},
|
|
18286
|
+
context: () => ({ kind: "table" })
|
|
18287
|
+
};
|
|
18288
|
+
}
|
|
18289
|
+
function chapterPills(host, chapters, io) {
|
|
18290
|
+
const doc = host.ownerDocument;
|
|
18291
|
+
const list = el(doc, "div", "knobs-wt-chapters");
|
|
18292
|
+
list.setAttribute("role", "group");
|
|
18293
|
+
list.setAttribute("aria-label", "Chapters");
|
|
18294
|
+
let at = -2;
|
|
18295
|
+
const rows = chapters.map((c, i) => {
|
|
18296
|
+
const b = el(doc, "button", "knobs-wt-chapter");
|
|
18297
|
+
b.type = "button";
|
|
18298
|
+
b.append(text(doc, "span", "knobs-wt-chapter-n", String(i + 1)));
|
|
18299
|
+
b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
|
|
18300
|
+
b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
|
|
18301
|
+
b.addEventListener("click", () => {
|
|
18302
|
+
io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
|
|
18303
|
+
io.seek(c.start);
|
|
18304
|
+
select(i);
|
|
18305
|
+
});
|
|
18306
|
+
list.append(b);
|
|
18307
|
+
return b;
|
|
18308
|
+
});
|
|
18309
|
+
host.append(list);
|
|
18310
|
+
const pill = selectionPill(list, {
|
|
18311
|
+
selected: () => rows[at] ?? null,
|
|
18312
|
+
rows: () => rows
|
|
18313
|
+
});
|
|
18314
|
+
const select = (i) => {
|
|
18315
|
+
if (i === at)
|
|
18316
|
+
return;
|
|
18317
|
+
at = i;
|
|
18318
|
+
rows.forEach((b, k) => k === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
18319
|
+
pill.update();
|
|
18320
|
+
};
|
|
18321
|
+
const sync = () => select(chapterAt(chapters, io.now()));
|
|
18322
|
+
sync();
|
|
18323
|
+
return {
|
|
18324
|
+
sync,
|
|
18325
|
+
get current() {
|
|
18326
|
+
return chapters[at] ?? null;
|
|
18327
|
+
},
|
|
18328
|
+
dispose() {
|
|
18329
|
+
pill.dispose();
|
|
18330
|
+
list.remove();
|
|
18331
|
+
}
|
|
18332
|
+
};
|
|
18333
|
+
}
|
|
18334
|
+
function disclosure(host, options) {
|
|
18335
|
+
const doc = host.ownerDocument;
|
|
18336
|
+
const win = doc.defaultView;
|
|
18337
|
+
let open = options.open === true;
|
|
18338
|
+
const root = el(doc, "div", "knobs-wt-disc");
|
|
18339
|
+
const toggle = el(doc, "button", "knobs-wt-disc-toggle");
|
|
18340
|
+
toggle.type = "button";
|
|
18341
|
+
toggle.innerHTML = GLYPH.caret;
|
|
18342
|
+
toggle.append(text(doc, "span", "", options.label));
|
|
18343
|
+
if (options.count !== undefined)
|
|
18344
|
+
toggle.append(text(doc, "span", "knobs-wt-disc-count", String(options.count)));
|
|
18345
|
+
const viewport = el(doc, "div", "knobs-wt-disc-body");
|
|
18346
|
+
const content = el(doc, "div", "knobs-wt-disc-content");
|
|
18347
|
+
content.append(options.content);
|
|
18348
|
+
viewport.append(content);
|
|
18349
|
+
root.append(toggle, viewport);
|
|
18350
|
+
host.append(root);
|
|
18351
|
+
const STATE = springMotion(SPRINGS.default);
|
|
18352
|
+
const h = new Spring(0, STATE.omega, STATE.zeta, 0.25);
|
|
18353
|
+
let full = 0;
|
|
18354
|
+
const paint = (moving) => {
|
|
18355
|
+
const k = full > 0 ? Math.max(0, Math.min(1, h.x / full)) : open ? 1 : 0;
|
|
18356
|
+
viewport.style.height = !moving && open ? "" : `${Math.max(0, h.x).toFixed(2)}px`;
|
|
18357
|
+
viewport.toggleAttribute("data-moving", moving);
|
|
18358
|
+
content.style.opacity = (open ? Math.min(1, k * 1.25) : Math.max(0, k * 1.5 - 0.5)).toFixed(3);
|
|
18359
|
+
};
|
|
18360
|
+
const loop = frameLoop(win, (dt) => {
|
|
18361
|
+
h.step(dt);
|
|
18362
|
+
const moving = !h.resting;
|
|
18363
|
+
paint(moving);
|
|
18364
|
+
return moving;
|
|
18365
|
+
});
|
|
18366
|
+
const sync = () => {
|
|
18367
|
+
root.toggleAttribute("data-open", open);
|
|
18368
|
+
toggle.setAttribute("aria-expanded", String(open));
|
|
18369
|
+
viewport.inert = !open;
|
|
18370
|
+
};
|
|
18371
|
+
sync();
|
|
18372
|
+
h.snap(0);
|
|
18373
|
+
paint(false);
|
|
18374
|
+
if (open) {
|
|
18375
|
+
viewport.style.height = "";
|
|
18376
|
+
content.style.opacity = "1";
|
|
18377
|
+
}
|
|
18378
|
+
const api = {
|
|
18379
|
+
element: root,
|
|
18380
|
+
get open() {
|
|
18381
|
+
return open;
|
|
18382
|
+
},
|
|
18383
|
+
toggle(next = !open) {
|
|
18384
|
+
if (next === open)
|
|
18385
|
+
return;
|
|
18386
|
+
open = next;
|
|
18387
|
+
sync();
|
|
18388
|
+
full = content.offsetHeight;
|
|
18389
|
+
if (reducedMotion(win)) {
|
|
18390
|
+
loop.stop();
|
|
18391
|
+
h.snap(open ? full : 0);
|
|
18392
|
+
viewport.style.height = open ? "" : "0px";
|
|
18393
|
+
content.style.opacity = open ? "1" : "0";
|
|
18394
|
+
return;
|
|
18395
|
+
}
|
|
18396
|
+
if (h.resting)
|
|
18397
|
+
h.snap(open ? 0 : full);
|
|
18398
|
+
h.set(open ? full : 0);
|
|
18399
|
+
paint(true);
|
|
18400
|
+
loop.wake();
|
|
18401
|
+
},
|
|
18402
|
+
dispose() {
|
|
18403
|
+
loop.stop();
|
|
18404
|
+
root.remove();
|
|
18405
|
+
}
|
|
18406
|
+
};
|
|
18407
|
+
toggle.addEventListener("click", () => api.toggle());
|
|
18408
|
+
return api;
|
|
18409
|
+
}
|
|
18410
|
+
var PR_PATHS = {
|
|
18411
|
+
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",
|
|
18412
|
+
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"
|
|
18413
|
+
};
|
|
18414
|
+
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>`;
|
|
18415
|
+
var PR_STATE = { merged: "Merged", open: "Open", draft: "Draft", closed: "Closed" };
|
|
18416
|
+
function prChip(doc, n, pr) {
|
|
18417
|
+
const chip = el(doc, pr.href ? "a" : "span", "knobs-wt-pr");
|
|
18418
|
+
if (pr.href) {
|
|
18419
|
+
chip.setAttribute("href", pr.href);
|
|
18420
|
+
chip.setAttribute("target", "_blank");
|
|
18421
|
+
chip.setAttribute("rel", "noreferrer");
|
|
18422
|
+
}
|
|
18423
|
+
if (pr.state)
|
|
18424
|
+
chip.dataset.state = pr.state;
|
|
18425
|
+
chip.innerHTML = prGlyph(pr.state === "merged");
|
|
18426
|
+
chip.append(text(doc, "span", "", `#${n}`));
|
|
18427
|
+
const tip = [`#${n}`, pr.title, pr.state ? PR_STATE[pr.state] : ""].filter(Boolean).join(" · ");
|
|
18428
|
+
chip.title = tip;
|
|
18429
|
+
chip.setAttribute("aria-label", `Pull request ${tip}`);
|
|
18430
|
+
return chip;
|
|
18431
|
+
}
|
|
18432
|
+
var PR_URL = /^https?:\/\/[^/]+\/.+\/(?:pull|merge_requests)\/(\d+)\/?(?:[?#].*)?$/;
|
|
18433
|
+
var PR_REF = /(^|[^\w&/#])#(\d{3,7})\b/g;
|
|
18434
|
+
function linkPRs(root, find) {
|
|
18435
|
+
const doc = root.ownerDocument;
|
|
18436
|
+
for (const a of Array.from(root.querySelectorAll("a[href]"))) {
|
|
18437
|
+
if (a.classList.contains("knobs-wt-pr") || a.closest(".knobs-wt-slot,button"))
|
|
18438
|
+
continue;
|
|
18439
|
+
const n = PR_URL.exec(a.getAttribute("href") ?? "")?.[1];
|
|
18440
|
+
const words = a.textContent?.trim() ?? "";
|
|
18441
|
+
if (!n || !(words === `#${n}` || words === n || words === a.getAttribute("href")))
|
|
18442
|
+
continue;
|
|
18443
|
+
a.replaceWith(prChip(doc, n, { href: a.href, ...find(n) }));
|
|
18444
|
+
}
|
|
18445
|
+
const walker = doc.createTreeWalker(root, 5);
|
|
18446
|
+
const hits = [];
|
|
18447
|
+
for (let t = walker.nextNode();t; t = walker.nextNode()) {
|
|
18448
|
+
if (t.nodeType !== 3)
|
|
18449
|
+
continue;
|
|
18450
|
+
const p = t.parentElement;
|
|
18451
|
+
if (!p || p.closest("a,code,pre,button,.knobs-wt-slot,.knobs-wt-pr"))
|
|
18452
|
+
continue;
|
|
18453
|
+
PR_REF.lastIndex = 0;
|
|
18454
|
+
if (PR_REF.test(t.nodeValue ?? ""))
|
|
18455
|
+
hits.push(t);
|
|
18456
|
+
}
|
|
18457
|
+
for (const t of hits) {
|
|
18458
|
+
const value = t.nodeValue ?? "";
|
|
18459
|
+
const frag = doc.createDocumentFragment();
|
|
18460
|
+
let last = 0;
|
|
18461
|
+
let changed = false;
|
|
18462
|
+
PR_REF.lastIndex = 0;
|
|
18463
|
+
for (let m = PR_REF.exec(value);m; m = PR_REF.exec(value)) {
|
|
18464
|
+
const pr = find(m[2]);
|
|
18465
|
+
if (!pr)
|
|
18466
|
+
continue;
|
|
18467
|
+
const at = m.index + m[1].length;
|
|
18468
|
+
frag.append(value.slice(last, at), prChip(doc, m[2], pr));
|
|
18469
|
+
last = at + m[2].length + 1;
|
|
18470
|
+
changed = true;
|
|
18471
|
+
}
|
|
18472
|
+
if (!changed)
|
|
18473
|
+
continue;
|
|
18474
|
+
frag.append(value.slice(last));
|
|
18475
|
+
t.replaceWith(frag);
|
|
18476
|
+
}
|
|
18477
|
+
}
|
|
18478
|
+
|
|
18479
|
+
// src/ui/walkthrough-media.ts
|
|
18480
|
+
init_compare_model();
|
|
18481
|
+
init_glide();
|
|
18482
|
+
init_icons();
|
|
18483
|
+
init_look();
|
|
18484
|
+
|
|
18485
|
+
// src/ui/walkthrough-css.ts
|
|
18486
|
+
init_motion();
|
|
18487
|
+
var snappy3 = springCss(SPRINGS.snappy);
|
|
18488
|
+
var calm = springCss(SPRINGS.calm);
|
|
18489
|
+
var state = springCss(SPRINGS.default);
|
|
18490
|
+
var quick = springCss(FADE);
|
|
18491
|
+
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)";
|
|
18492
|
+
var walkthroughCss = `
|
|
18493
|
+
:where(.knobs-walkthrough,.knobs-walkthrough *,.knobs-wt-slot,.knobs-wt-slot *){box-sizing:border-box}
|
|
18494
|
+
.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;
|
|
18495
|
+
--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));
|
|
18496
|
+
--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);
|
|
18497
|
+
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;
|
|
18498
|
+
letter-spacing:normal;-webkit-font-smoothing:antialiased}
|
|
18499
|
+
.knobs-walkthrough [hidden]{display:none!important}
|
|
18500
|
+
/* (0,0,1): a host's element rules stop here, and every class rule below wins over it. */
|
|
18501
|
+
:where(.knobs-walkthrough) :is(h1,h2,h3,p,ol,ul,dl,dd){margin:0;font:inherit;letter-spacing:inherit}
|
|
18502
|
+
.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}
|
|
18503
|
+
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
18504
|
+
.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)}
|
|
18505
|
+
: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;
|
|
18506
|
+
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
18507
|
+
|
|
18508
|
+
/* ——— layout: the contents rail sticky at the left edge (right if asked), and the column centred
|
|
18509
|
+
in the room beside it, up to --kw-width: media take the column, prose stops at the measure.
|
|
18510
|
+
One column where it's narrow ——— */
|
|
18511
|
+
.knobs-wt-layout{display:grid;grid-template-columns:var(--kw-rail-w) minmax(0,1fr);gap:var(--_k-space-column);align-items:start}
|
|
18512
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-layout{grid-template-columns:minmax(0,1fr) var(--kw-rail-w)}
|
|
18513
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-main{grid-column:1;grid-row:1}
|
|
18514
|
+
.knobs-walkthrough[data-rail="right"] .knobs-wt-rail{grid-column:2;grid-row:1}
|
|
18515
|
+
.knobs-walkthrough[data-rail="none"] .knobs-wt-layout{grid-template-columns:minmax(0,1fr)}
|
|
18516
|
+
.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}
|
|
18517
|
+
/* The intro, the updates and each section: a section's room apart, the hairline in the middle. */
|
|
18518
|
+
.knobs-wt-flow{display:flex;flex-direction:column;gap:calc(var(--_k-space-section) / 2);min-width:0}
|
|
18519
|
+
.knobs-wt-flow>*+*{padding-top:calc(var(--_k-space-section) / 2);box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
18520
|
+
@container knobs-wt (max-width:960px){.knobs-walkthrough[data-rail] .knobs-wt-layout{grid-template-columns:minmax(0,1fr);gap:var(--_k-space-title)}
|
|
18521
|
+
.knobs-walkthrough[data-rail] .knobs-wt-layout>*{grid-column:auto;grid-row:auto}}
|
|
18522
|
+
|
|
18523
|
+
/* ——— one line of facts: small, faint, joined by ·, its trailing edge fading ——— */
|
|
18524
|
+
.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}}
|
|
18525
|
+
.knobs-wt-metaline>*{flex:none}
|
|
18526
|
+
.knobs-wt-metaline>*+*::before{content:"·";margin-right:var(--_k-space-inside);color:var(--_k-fg-3)}
|
|
18527
|
+
.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)}
|
|
18528
|
+
.knobs-walkthrough .knobs-wt-metaline a:not(.knobs-wt-pr):hover{color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18529
|
+
.knobs-wt-metaline svg{align-self:center;width:12px;height:12px;margin-left:2px}
|
|
18530
|
+
/* A pull request: a small chip, its state's icon and number in a quiet tint of the state (open
|
|
18531
|
+
the success hue, merged the violet series, draft and closed neutral), its title on hover. */
|
|
18532
|
+
.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;
|
|
18533
|
+
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;
|
|
18534
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
18535
|
+
.knobs-ui .knobs-wt-pr[data-state="open"]{--kw-pr:color-mix(in oklch,var(--_k-ok) 60%,var(--_k-fg-2))}
|
|
18536
|
+
.knobs-ui .knobs-wt-pr[data-state="merged"]{--kw-pr:color-mix(in oklch,var(--_k-series-5) 60%,var(--_k-fg-2))}
|
|
18537
|
+
.knobs-ui .knobs-wt-pr:is([data-state="draft"],[data-state="closed"]){--kw-pr:var(--_k-fg-3)}
|
|
18538
|
+
.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)}
|
|
18539
|
+
.knobs-wt-pr svg{flex:none}
|
|
18540
|
+
.knobs-wt-metaline .knobs-wt-pr{align-self:center;margin:0}
|
|
18541
|
+
.knobs-wt-kicker-lead{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
18542
|
+
.knobs-wt-metaline [data-status="on"]{color:var(--_k-fg)}
|
|
18543
|
+
.knobs-wt-metaline [data-status="warn"]{color:var(--_k-warn)}
|
|
18544
|
+
|
|
18545
|
+
/* ——— the page's head ——— */
|
|
18546
|
+
.knobs-wt-head{display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
18547
|
+
.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}
|
|
18548
|
+
.knobs-wt-summary{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18549
|
+
.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)}
|
|
18550
|
+
.knobs-wt-meta>span{display:inline-flex;gap:var(--_k-space-inside);white-space:nowrap}
|
|
18551
|
+
.knobs-wt-meta b{font-weight:var(--_k-weight);color:var(--_k-fg-2);font-family:var(--_k-mono)}
|
|
18552
|
+
|
|
18553
|
+
/* ——— a section: a PR or topic. Its kicker leads the meta line, its title under it (16/24, under
|
|
18554
|
+
the page's 20/28), both on the column's edge ——— */
|
|
18555
|
+
.knobs-wt-section{display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
18556
|
+
.knobs-wt-sintro{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0}
|
|
18557
|
+
.knobs-wt-shead{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0;scroll-margin-top:16px}
|
|
18558
|
+
.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}
|
|
18559
|
+
.knobs-wt-ssum{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18560
|
+
.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;
|
|
18561
|
+
--kw-tone:var(--_k-fg-2);color:var(--kw-tone);background:color-mix(in srgb,var(--kw-tone) 14%,transparent)}
|
|
18562
|
+
.knobs-wt-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
18563
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18564
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
18565
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18566
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
18567
|
+
:is(.knobs-wt-chip,.knobs-wt-toc-glyph)[data-tone="dim"]{--kw-tone:var(--_k-fg-2)}
|
|
18568
|
+
|
|
18569
|
+
/* ——— a step: on the page by default, a group's room between steps with a hairline in the middle;
|
|
18570
|
+
or (cards) one card each, the one surface its pieces sit on ——— */
|
|
18571
|
+
.knobs-walkthrough:not([data-cards]) .knobs-wt-step:not([data-full]){padding:0;border-radius:0;background:transparent;box-shadow:none}
|
|
18572
|
+
.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}
|
|
18573
|
+
.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);
|
|
18574
|
+
scroll-margin-top:16px;outline:none;container:knobs-wt-step / inline-size}
|
|
18575
|
+
.knobs-walkthrough[data-cards]{--kw-under:var(--kw-card)}
|
|
18576
|
+
.knobs-walkthrough[data-cards][data-frame="flat"] .knobs-wt-step{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
18577
|
+
.knobs-wt-step-head{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
18578
|
+
.knobs-wt-stepTitle{min-width:0;font-weight:var(--kw-strong)!important;text-wrap:balance}
|
|
18579
|
+
.knobs-wt-caption{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18580
|
+
.knobs-wt-question{font-weight:var(--kw-strong)!important;max-width:var(--kw-measure)}
|
|
18581
|
+
.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}
|
|
18582
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-media{grid-template-columns:minmax(0,1fr)}}
|
|
18583
|
+
|
|
18584
|
+
/* ——— the feed: updates and answers, newest first. Tight inside an item (4 / 8 / 4), a group's
|
|
18585
|
+
room between items with the hairline in the middle; no boxes ——— */
|
|
18586
|
+
.knobs-wt-feed{display:flex;flex-direction:column;gap:var(--_k-space-title);min-width:0;scroll-margin-top:16px}
|
|
18587
|
+
.knobs-wt-feed-head{display:flex;align-items:baseline;gap:var(--_k-space-sibling)}
|
|
18588
|
+
.knobs-wt-feed-title{font-weight:var(--kw-strong)!important}
|
|
18589
|
+
.knobs-wt-feed-count{font-size:var(--_k-type-small);line-height:var(--_k-leading-small);color:var(--_k-fg-3)}
|
|
18590
|
+
.knobs-wt-feed-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--_k-space-group);min-width:0}
|
|
18591
|
+
.knobs-wt-fi{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
18592
|
+
.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)}
|
|
18593
|
+
.knobs-wt-fi-q,.knobs-wt-fi-a{display:flex;flex-direction:column;gap:var(--_k-space-inside);min-width:0}
|
|
18594
|
+
.knobs-wt-fi-ask{max-width:var(--kw-measure);color:var(--_k-fg);font-weight:var(--kw-strong);text-wrap:pretty}
|
|
18595
|
+
.knobs-wt-fi-text{max-width:var(--kw-measure);color:var(--_k-fg);text-wrap:pretty}
|
|
18596
|
+
.knobs-wt-fi-answer{max-width:var(--kw-measure);color:var(--_k-fg-2);text-wrap:pretty}
|
|
18597
|
+
: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;
|
|
18598
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
18599
|
+
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18600
|
+
: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;
|
|
18601
|
+
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)}
|
|
18602
|
+
.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)}
|
|
18603
|
+
.knobs-wt-steplink svg{width:12px;height:12px}
|
|
18604
|
+
|
|
18605
|
+
/* ——— a disclosure: a small faint toggle with a caret, no fill. The body's height springs (in
|
|
18606
|
+
script) and its content fades in place, top-anchored, under a soft bottom mask ——— */
|
|
18607
|
+
.knobs-wt-disc{display:flex;flex-direction:column;min-width:0}
|
|
18608
|
+
.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;
|
|
18609
|
+
border-radius:calc(var(--_k-radius) / 2);transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
18610
|
+
.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)}
|
|
18611
|
+
.knobs-ui .knobs-wt-disc-toggle:focus-visible{box-shadow:0 0 0 2px var(--_k-focus)}
|
|
18612
|
+
.knobs-wt-disc-toggle svg{flex:none;width:12px;height:12px;transition:rotate var(--kw-state-ms) var(--kw-state)}
|
|
18613
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-toggle svg{rotate:90deg}
|
|
18614
|
+
.knobs-wt-disc-count{color:var(--_k-fg-3)}
|
|
18615
|
+
.knobs-wt-disc-body{overflow:hidden}
|
|
18616
|
+
.knobs-wt-disc[data-open]>.knobs-wt-disc-body:not([data-moving]){overflow:visible}
|
|
18617
|
+
.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)}
|
|
18618
|
+
.knobs-wt-disc-content{padding-top:var(--_k-space-inside)}
|
|
18619
|
+
/* "More" under a caption or summary: the rest of its words, in the same voice. */
|
|
18620
|
+
.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}
|
|
18621
|
+
/* A trail sits on the toggle's label edge: faint lines, the time trailing. */
|
|
18622
|
+
.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}
|
|
18623
|
+
.knobs-wt-trail li{display:flex;align-items:baseline;gap:var(--_k-space-sibling);min-width:0;white-space:nowrap}
|
|
18624
|
+
.knobs-wt-trail-text{flex:0 1 auto;min-width:0;overflow:hidden;${fade2}}
|
|
18625
|
+
.knobs-wt-trail-at{flex:none}
|
|
18626
|
+
|
|
18627
|
+
/* ——— a step's sent notes ——— */
|
|
18628
|
+
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
18629
|
+
.knobs-wt-notes:empty{display:none}
|
|
18630
|
+
.knobs-wt-n{display:flex;align-items:flex-start;gap:var(--_k-space-sibling);padding:6px 0;overflow:hidden;
|
|
18631
|
+
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)}
|
|
18632
|
+
.knobs-wt-n[data-entering]{opacity:0;filter:blur(3px)}
|
|
18633
|
+
.knobs-wt-n[data-leaving]{opacity:0;filter:blur(3px);padding-block:0}
|
|
18634
|
+
.knobs-wt-n+.knobs-wt-n{box-shadow:inset 0 1px 0 var(--_k-border-subtle)}
|
|
18635
|
+
.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)}
|
|
18636
|
+
.knobs-wt-n-meta[data-seek]{cursor:pointer}
|
|
18637
|
+
.knobs-wt-n-meta[data-seek]:hover{color:var(--_k-fg)}
|
|
18638
|
+
.knobs-wt-n-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
18639
|
+
.knobs-wt-n-voice{height:30px;max-width:320px}
|
|
18640
|
+
.knobs-wt-n-ink{display:block;width:120px;max-height:80px;border-radius:calc(var(--_k-radius) / 2);background:var(--_k-fill)}
|
|
18641
|
+
.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}
|
|
18642
|
+
|
|
18643
|
+
/* ——— the note bar, docked at the bottom of the column. It holds its own place at the page's end
|
|
18644
|
+
(so the last step stays clear of it), and script keeps its height as the scroller's
|
|
18645
|
+
scroll-padding-bottom ——— */
|
|
18646
|
+
.knobs-wt-dock{position:sticky;bottom:12px;z-index:40;display:grid;pointer-events:none}
|
|
18647
|
+
.knobs-wt-dock>*{pointer-events:auto}
|
|
18648
|
+
.knobs-wt-dock>:is(.knobs-wt-notebar,.knobs-wt-launch){grid-area:1/1}
|
|
18649
|
+
.knobs-wt-dock[data-mode="docked"]>.knobs-wt-launch{display:none}
|
|
18650
|
+
/* Collapsed: the launcher and the bar swap in place, a quick fade with a little scale and blur
|
|
18651
|
+
from the launcher's corner; the exit is the shorter. */
|
|
18652
|
+
: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);
|
|
18653
|
+
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%;
|
|
18654
|
+
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)}
|
|
18655
|
+
.knobs-ui .knobs-wt-launch:is(:hover,:focus-visible){color:var(--_k-fg)}
|
|
18656
|
+
.knobs-ui .knobs-wt-launch:focus-visible{box-shadow:var(--_k-focus-ring)}
|
|
18657
|
+
.knobs-wt-launch svg{width:16px;height:16px}
|
|
18658
|
+
.knobs-wt-launch kbd{font:inherit;font-weight:var(--_k-weight);color:var(--_k-fg-3)}
|
|
18659
|
+
.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)}
|
|
18660
|
+
.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;
|
|
18661
|
+
transition-duration:calc(var(--kw-quick-ms) * .8)}
|
|
18662
|
+
.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);
|
|
18663
|
+
box-shadow:var(--_ku-pane-ring),var(--_k-shadow-overlay)}
|
|
18664
|
+
.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}}
|
|
18665
|
+
.knobs-wt-row{display:flex;align-items:flex-end;gap:4px}
|
|
18666
|
+
: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;
|
|
18667
|
+
border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
18668
|
+
.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)}
|
|
18669
|
+
.knobs-ui .knobs-wt-input::placeholder{color:var(--_k-fg-3)}
|
|
18670
|
+
.knobs-wt-attach{display:flex;gap:4px;align-items:center;align-self:center}
|
|
18671
|
+
.knobs-wt-attach:empty{display:none}
|
|
18672
|
+
.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}
|
|
18673
|
+
.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}
|
|
18674
|
+
.knobs-ui .knobs-wt-x:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
18675
|
+
.knobs-wt-x svg{width:12px;height:12px}
|
|
18676
|
+
.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);
|
|
18677
|
+
color:var(--_k-fg-2);cursor:pointer;transition:background .15s,color .15s}
|
|
18678
|
+
.knobs-ui .knobs-wt-tool:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
18679
|
+
.knobs-ui .knobs-wt-tool[aria-pressed="true"]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
18680
|
+
.knobs-wt-tool svg{width:16px;height:16px}
|
|
18681
|
+
.knobs-wt-rec{font-size:var(--_k-type-small)}
|
|
18682
|
+
.knobs-wt-rec:empty{display:none}
|
|
18683
|
+
.knobs-ui .knobs-wt-tool[data-send]{color:var(--_k-fg-3)}
|
|
18684
|
+
.knobs-ui .knobs-wt-tool[data-send][data-ready]{background:var(--_k-accent);color:var(--_k-bg)}
|
|
18685
|
+
/* Back: in place over the bar for a few seconds after a note moves the page on. */
|
|
18686
|
+
.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;
|
|
18687
|
+
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;
|
|
18688
|
+
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)}
|
|
18689
|
+
.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)}
|
|
18690
|
+
.knobs-ui .knobs-wt-back:hover{background:var(--_k-fill-selected)}
|
|
18691
|
+
.knobs-wt-back svg{flex:none;width:12px;height:12px}
|
|
18692
|
+
.knobs-wt-back-label{min-width:0;overflow:hidden;white-space:nowrap;${fade2}}
|
|
18693
|
+
|
|
18694
|
+
/* ——— ink over a step's media ——— */
|
|
18695
|
+
.knobs-wt-media,.knobs-wt-options{position:relative}
|
|
18696
|
+
.knobs-wt-ink{position:absolute;inset:0;z-index:5;width:100%;height:100%;overflow:visible;pointer-events:none;touch-action:none}
|
|
18697
|
+
.knobs-wt-ink[data-on]{pointer-events:auto;cursor:crosshair}
|
|
18698
|
+
.knobs-wt-ink path{fill:none;stroke:var(--kw-ink);stroke-width:3px;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
|
|
18699
|
+
|
|
18700
|
+
/* ——— full-window: the step over the page above the note bar, its media filling it; its place held
|
|
18701
|
+
in the page. The one raised surface ——— */
|
|
18702
|
+
.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}
|
|
18703
|
+
.knobs-wt-scrim[data-on]{pointer-events:auto}
|
|
18704
|
+
.knobs-wt-hold-card{flex:none}
|
|
18705
|
+
.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)}
|
|
18706
|
+
.knobs-wt-step[data-full]::before{content:none}
|
|
18707
|
+
.knobs-wt-step[data-full]>:not(.knobs-wt-media){flex:none}
|
|
18708
|
+
.knobs-wt-step[data-full] .knobs-wt-notes{display:none}
|
|
18709
|
+
.knobs-wt-step[data-full]>.knobs-wt-media{flex:1;min-height:0;grid-auto-rows:minmax(0,1fr)}
|
|
18710
|
+
.knobs-wt-step[data-full] .knobs-wt-slot{display:flex;flex-direction:column;min-height:0}
|
|
18711
|
+
.knobs-wt-step[data-full] .knobs-wt-body{flex:1;min-height:0}
|
|
18712
|
+
.knobs-wt-step[data-full] .knobs-wt-fit{height:100%;transition:none}
|
|
18713
|
+
.knobs-wt-step[data-full] .knobs-wt-frame{height:100%;aspect-ratio:auto}
|
|
18714
|
+
|
|
18715
|
+
/* ——— a taste test: the options side by side, Kit's pick checked and the rest stepping back. On
|
|
18716
|
+
the step's card, so no fill of their own ——— */
|
|
18717
|
+
.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)}
|
|
18718
|
+
@container knobs-wt-step (max-width:640px){.knobs-wt-options{grid-template-columns:minmax(0,1fr)}}
|
|
18719
|
+
.knobs-wt-option{position:relative;display:flex;flex-direction:column;gap:var(--_k-space-sibling);min-width:0}
|
|
18720
|
+
.knobs-wt-option>:not(.knobs-wt-pick){transition:opacity var(--kw-snappy-ms) var(--kw-snappy)}
|
|
18721
|
+
.knobs-wt-options[data-has-pick] .knobs-wt-option:not([data-picked])>:not(.knobs-wt-pick){opacity:.55}
|
|
18722
|
+
.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;
|
|
18723
|
+
transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
18724
|
+
.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)}
|
|
18725
|
+
.knobs-wt-letter{flex:none;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
18726
|
+
.knobs-wt-olabel{flex:1;min-width:0;font-weight:var(--kw-strong);color:var(--_k-fg)}
|
|
18727
|
+
.knobs-wt-suggested{flex:none;font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
18728
|
+
.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;
|
|
18729
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),color var(--kw-snappy-ms) var(--kw-snappy)}
|
|
18730
|
+
.knobs-wt-check svg{width:12px;height:12px}
|
|
18731
|
+
.knobs-wt-option[data-picked] .knobs-wt-check{background:var(--_k-accent);color:var(--_k-bg)}
|
|
18732
|
+
.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);
|
|
18733
|
+
font:var(--kw-strong) var(--_k-type-small)/1 var(--_k-font);opacity:.5;transition:opacity .15s}
|
|
18734
|
+
.knobs-wt-step[data-current] .knobs-wt-key{opacity:1}
|
|
18735
|
+
.knobs-wt-ocap{color:var(--_k-fg-2);max-width:var(--kw-measure)}
|
|
18736
|
+
|
|
18737
|
+
/* ——— the rail: progress, contents, export ——— */
|
|
18738
|
+
.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)}
|
|
18739
|
+
.knobs-wt-progress{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
18740
|
+
.knobs-wt-count{display:flex;align-items:baseline;justify-content:space-between;color:var(--_k-fg-2)}
|
|
18741
|
+
.knobs-wt-count b{color:var(--_k-fg);font-weight:var(--kw-strong)}
|
|
18742
|
+
.knobs-wt-bar{position:relative;height:4px;border-radius:2px;overflow:hidden;background:var(--_k-fill)}
|
|
18743
|
+
.knobs-wt-fill{position:absolute;inset:0;border-radius:inherit;background:var(--_k-accent);transform-origin:0 50%;transform:scaleX(var(--kw-done,0))}
|
|
18744
|
+
.knobs-walkthrough[data-settled] .knobs-wt-fill{transition:transform var(--kw-calm-ms) var(--kw-calm)}
|
|
18745
|
+
/* The contents: every row on one text edge and in one colour, title rows (32 high, the control
|
|
18746
|
+
radius) and the steps under them (20 high, half of it), bled out so their text sits on the
|
|
18747
|
+
rail's edge; the selection pill slides to the current step, and base rows never brighten. */
|
|
18748
|
+
.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}
|
|
18749
|
+
.knobs-wt-toc::-webkit-scrollbar{display:none}
|
|
18750
|
+
.knobs-wt-toc-group{display:flex;flex-direction:column;min-width:0}
|
|
18751
|
+
.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;
|
|
18752
|
+
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;
|
|
18753
|
+
transition:color calc(var(--_k-hover-out) * 1ms)}
|
|
18754
|
+
.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)}
|
|
18755
|
+
.knobs-ui .knobs-wt-toc-row:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18756
|
+
.knobs-ui .knobs-wt-toc-row:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
18757
|
+
.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)}
|
|
18758
|
+
.knobs-wt-toc-label{min-width:0;overflow:hidden;${fade2}}
|
|
18759
|
+
.knobs-pick-copy .knobs-wt-toc-end{color:var(--_k-fg-2)}
|
|
18760
|
+
/* A step's state: an open ring, a filled dot once answered, nothing to answer a faint ring. */
|
|
18761
|
+
.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);
|
|
18762
|
+
transition:background var(--kw-snappy-ms) var(--kw-snappy),box-shadow var(--kw-snappy-ms) var(--kw-snappy)}
|
|
18763
|
+
.knobs-wt-toc-glyph[data-tone="accent"]{--kw-tone:var(--_k-accent)}
|
|
18764
|
+
.knobs-wt-toc-glyph[data-done]{background:var(--kw-tone)}
|
|
18765
|
+
.knobs-wt-toc-glyph[data-tone="none"]{box-shadow:inset 0 0 0 1px var(--_k-border)}
|
|
18766
|
+
.knobs-wt-actions{display:flex;flex-wrap:wrap;gap:4px}
|
|
18767
|
+
.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;
|
|
18768
|
+
transition:background .15s,color .15s}
|
|
18769
|
+
.knobs-ui .knobs-wt-btn:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
18770
|
+
.knobs-ui .knobs-wt-btn[data-primary]{background:var(--_k-fill-selected);color:var(--_k-fg)}
|
|
18771
|
+
.knobs-ui .knobs-wt-btn[data-primary]:is(:hover,:focus-visible){background:color-mix(in srgb,var(--_k-fg) 16%,transparent)}
|
|
18772
|
+
.knobs-wt-keys{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
18773
|
+
.knobs-wt-keys kbd{font:inherit;color:var(--_k-fg-2)}
|
|
18774
|
+
/* Narrow: the contents go; with review on, the rail becomes a bar along the top with the
|
|
18775
|
+
progress and the export. */
|
|
18776
|
+
@container knobs-wt (max-width:960px){
|
|
18777
|
+
.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)}
|
|
18778
|
+
.knobs-wt-progress{flex:1}.knobs-wt-toc,.knobs-wt-keys{display:none}
|
|
18779
|
+
.knobs-walkthrough:not([data-review]) .knobs-wt-rail{display:none}
|
|
18780
|
+
.knobs-wt-step,.knobs-wt-shead,.knobs-wt-feed{scroll-margin-top:60px}
|
|
18781
|
+
}
|
|
18782
|
+
|
|
18783
|
+
/* ——— media slots. Only a picture's frame (a quiet fill while it loads or letterboxes) and a code
|
|
18784
|
+
block (a well) are bounded; a metric, a callout, a table, a stack and a history sit on the page,
|
|
18785
|
+
set apart by space, hairlines and their own colours. On a card (.knobs-surface) code drops its
|
|
18786
|
+
well for hairlines, so nothing draws a fill and a ring of its own there ——— */
|
|
18787
|
+
.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);
|
|
18788
|
+
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);
|
|
18789
|
+
--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)}
|
|
18790
|
+
.knobs-surface .knobs-wt-slot{--kw-frame-r:calc(var(--_k-radius-panel) - 4px)}
|
|
18791
|
+
/* A slot's label: sentence case as written, small and faint, never a heading. */
|
|
18792
|
+
.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}}
|
|
18793
|
+
.knobs-wt-body{min-width:0}
|
|
18794
|
+
/* One frame for every slot that has one (a picture, a video, a code block, a compare's stage, a
|
|
18795
|
+
slot still loading): the panel radius and a quiet fill, no ring; concentric on a card. */
|
|
18796
|
+
.knobs-wt-slot .knobs-cmp-stage{border-radius:var(--kw-frame-r)}
|
|
18797
|
+
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
18798
|
+
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
18799
|
+
(92 px), and the frame strip with its gap (158 px). */
|
|
18800
|
+
.knobs-wt-fit{width:100%;height:calc(100cqw / 2 / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
18801
|
+
.knobs-wt-fit[data-overlay]{height:calc(100cqw / var(--kw-aspect,1.7778) + var(--kw-chrome,92px))}
|
|
18802
|
+
.knobs-wt-fit[data-strip]{--kw-chrome:158px}
|
|
18803
|
+
.knobs-wt-fit[data-settled]{transition:height var(--k-wt-calm-ms,${calm.duration}ms) ${calm.easing}}
|
|
18804
|
+
.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)}
|
|
18805
|
+
.knobs-wt-frame>:is(video,img){position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;margin:0;border:0}
|
|
18806
|
+
.knobs-wt-frame[data-natural]{aspect-ratio:auto;background:transparent}
|
|
18807
|
+
.knobs-wt-frame[data-natural]>img{position:static;height:auto}
|
|
18808
|
+
.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);
|
|
18809
|
+
font:var(--_k-type-label)/var(--_k-leading-body) var(--_k-mono);white-space:pre;tab-size:2;scrollbar-width:thin}
|
|
18810
|
+
.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)}
|
|
18811
|
+
.knobs-wt-code[data-terminal]{white-space:pre-wrap;overflow-wrap:anywhere}
|
|
18812
|
+
.knobs-wt-prompt{color:var(--_k-fg-3);user-select:none;-webkit-user-select:none}
|
|
18813
|
+
.knobs-wt-cmd{color:var(--_k-fg);font-weight:var(--_k-weight-label)}
|
|
18814
|
+
.knobs-wt-out{color:var(--_k-fg-2)}
|
|
18815
|
+
.knobs-wt-metric{display:flex;flex-direction:column;gap:var(--_k-space-sibling)}
|
|
18816
|
+
.knobs-wt-mlabel{color:var(--_k-fg-2)}
|
|
18817
|
+
.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"}
|
|
18818
|
+
.knobs-wt-mfrom{color:var(--_k-fg-3)}
|
|
18819
|
+
.knobs-wt-mto{font-size:var(--_k-type-title);line-height:var(--_k-leading-title);font-weight:var(--_k-weight-label)}
|
|
18820
|
+
.knobs-wt-mof{color:var(--_k-fg-3)}
|
|
18821
|
+
.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)}
|
|
18822
|
+
.knobs-wt-mdelta[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18823
|
+
.knobs-wt-mdelta[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18824
|
+
.knobs-wt-mtrack{position:relative;height:4px;border-radius:2px;background:color-mix(in srgb,var(--_k-fg) 8%,transparent)}
|
|
18825
|
+
.knobs-wt-mtrack>span{position:absolute;top:0;bottom:0;left:0;border-radius:inherit}
|
|
18826
|
+
.knobs-wt-mtrack>.knobs-wt-mafter{background:var(--_k-accent)}
|
|
18827
|
+
.knobs-wt-mtrack>.knobs-wt-mbefore{background:color-mix(in srgb,var(--_k-fg) 30%,transparent)}
|
|
18828
|
+
.knobs-wt-callout{--kw-tone:var(--kw-info);display:flex;gap:var(--_k-space-sibling);max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
18829
|
+
.knobs-wt-callout::before{content:"";flex:none;width:6px;height:6px;margin-top:7px;border-radius:50%;background:var(--kw-tone)}
|
|
18830
|
+
.knobs-wt-callout[data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18831
|
+
.knobs-wt-callout[data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
18832
|
+
.knobs-wt-callout[data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18833
|
+
.knobs-wt-text{max-width:var(--kw-measure);color:var(--_k-fg-2)}
|
|
18834
|
+
.knobs-wt-hold{border-radius:var(--kw-frame-r);background:var(--_k-fill)}
|
|
18835
|
+
.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)}
|
|
18836
|
+
|
|
18837
|
+
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
18838
|
+
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
18839
|
+
: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)}
|
|
18840
|
+
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
18841
|
+
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
18842
|
+
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
18843
|
+
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
18844
|
+
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
18845
|
+
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
18846
|
+
.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);
|
|
18847
|
+
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
18848
|
+
.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)}
|
|
18849
|
+
|
|
18850
|
+
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
18851
|
+
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
18852
|
+
.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)}
|
|
18853
|
+
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
18854
|
+
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
18855
|
+
.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)}
|
|
18856
|
+
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:var(--_k-type-small);font-variant-numeric:tabular-nums}
|
|
18857
|
+
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
18858
|
+
.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}
|
|
18859
|
+
.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)}
|
|
18860
|
+
.knobs-wt-hage{color:var(--_k-fg-3);font-size:var(--_k-type-small);line-height:var(--_k-leading-small)}
|
|
18861
|
+
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
18862
|
+
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
18863
|
+
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
18864
|
+
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
18865
|
+
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
18866
|
+
.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))}
|
|
18867
|
+
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
18868
|
+
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
18869
|
+
.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))}
|
|
18870
|
+
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
18871
|
+
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
18872
|
+
.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}
|
|
18873
|
+
.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}
|
|
18874
|
+
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
18875
|
+
@container knobs-wt-slot (max-width:520px){
|
|
18876
|
+
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
18877
|
+
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
18878
|
+
}
|
|
18879
|
+
|
|
18880
|
+
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
18881
|
+
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
18882
|
+
.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)}
|
|
18883
|
+
.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);
|
|
18884
|
+
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
18885
|
+
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
18886
|
+
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
18887
|
+
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18888
|
+
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
18889
|
+
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
18890
|
+
.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)}
|
|
18891
|
+
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
18892
|
+
.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}
|
|
18893
|
+
.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)}
|
|
18894
|
+
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
18895
|
+
.knobs-wt-trunk{font:var(--_k-weight-label) var(--_k-type-label)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
18896
|
+
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
18897
|
+
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
18898
|
+
.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}
|
|
18899
|
+
.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}
|
|
18900
|
+
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
18901
|
+
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
18902
|
+
.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)}
|
|
18903
|
+
.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)}
|
|
18904
|
+
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
18905
|
+
.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)}
|
|
18906
|
+
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
18907
|
+
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
18908
|
+
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
18909
|
+
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
18910
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
18911
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
18912
|
+
@container knobs-wt-slot (max-width:520px){
|
|
18913
|
+
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
18914
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
18915
|
+
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
18095
18916
|
}
|
|
18096
|
-
|
|
18097
|
-
|
|
18098
|
-
|
|
18099
|
-
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
|
|
18104
|
-
|
|
18105
|
-
|
|
18106
|
-
|
|
18107
|
-
|
|
18108
|
-
|
|
18109
|
-
|
|
18110
|
-
|
|
18111
|
-
|
|
18112
|
-
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
|
|
18124
|
-
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
draw();
|
|
18133
|
-
return !x.resting || !y.resting || !w.resting;
|
|
18134
|
-
});
|
|
18135
|
-
let at = -2;
|
|
18136
|
-
let shown = false;
|
|
18137
|
-
const place = (snap) => {
|
|
18138
|
-
const p = pills[at];
|
|
18139
|
-
if (!p) {
|
|
18140
|
-
mark.removeAttribute("data-on");
|
|
18141
|
-
pills.forEach((b) => b.removeAttribute("aria-current"));
|
|
18142
|
-
shown = false;
|
|
18143
|
-
return;
|
|
18144
|
-
}
|
|
18145
|
-
pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
18146
|
-
const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
|
|
18147
|
-
if (snap || !shown || reducedMotion(win)) {
|
|
18148
|
-
x.snap(to[0]);
|
|
18149
|
-
y.snap(to[1]);
|
|
18150
|
-
w.snap(to[2]);
|
|
18151
|
-
draw();
|
|
18152
|
-
} else {
|
|
18153
|
-
x.set(to[0]);
|
|
18154
|
-
y.set(to[1]);
|
|
18155
|
-
w.set(to[2]);
|
|
18156
|
-
loop.wake();
|
|
18157
|
-
}
|
|
18158
|
-
mark.style.height = `${p.offsetHeight}px`;
|
|
18159
|
-
mark.dataset.on = "";
|
|
18160
|
-
shown = true;
|
|
18161
|
-
};
|
|
18162
|
-
const sync = () => {
|
|
18163
|
-
const next = chapterAt(chapters, io.now());
|
|
18164
|
-
if (next === at)
|
|
18165
|
-
return;
|
|
18166
|
-
at = next;
|
|
18167
|
-
place(false);
|
|
18168
|
-
};
|
|
18169
|
-
sync();
|
|
18170
|
-
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
|
|
18171
|
-
ro?.observe(bar);
|
|
18172
|
-
return {
|
|
18173
|
-
sync,
|
|
18174
|
-
get current() {
|
|
18175
|
-
return chapters[at] ?? null;
|
|
18176
|
-
},
|
|
18177
|
-
dispose() {
|
|
18178
|
-
loop.stop();
|
|
18179
|
-
ro?.disconnect();
|
|
18180
|
-
bar.remove();
|
|
18181
|
-
}
|
|
18182
|
-
};
|
|
18917
|
+
|
|
18918
|
+
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
18919
|
+
(the top one under the head), and thin bars show on hover. */
|
|
18920
|
+
/* Too narrow for its columns, each row becomes a block: its primary cell titling the rest as term
|
|
18921
|
+
and value, the blocks parted by hairlines. Scrolling sideways is the last resort (stack: never). */
|
|
18922
|
+
.knobs-wt-tablebox{min-width:0}
|
|
18923
|
+
.knobs-wt-tablebox[data-measure] table{width:min-content}
|
|
18924
|
+
.knobs-wt-tstack{display:none;flex-direction:column;min-width:0}
|
|
18925
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-table{display:none}
|
|
18926
|
+
.knobs-wt-tablebox[data-stacked]>.knobs-wt-tstack{display:flex}
|
|
18927
|
+
.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)}
|
|
18928
|
+
.knobs-wt-trow:first-child{padding-top:0}
|
|
18929
|
+
.knobs-wt-trow:last-of-type{padding-bottom:0;box-shadow:none}
|
|
18930
|
+
.knobs-wt-tline{display:flex;align-items:baseline;justify-content:space-between;gap:var(--_k-space-title);min-width:0}
|
|
18931
|
+
.knobs-wt-tbadges{flex:none;display:flex;align-items:center;gap:var(--_k-space-inside)}
|
|
18932
|
+
.knobs-wt-ttitle{flex:1 1 auto;min-width:0;color:var(--_k-fg);font-weight:var(--_k-weight-label);overflow-wrap:anywhere}
|
|
18933
|
+
.knobs-wt-ttitle[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label)}
|
|
18934
|
+
.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}
|
|
18935
|
+
.knobs-wt-tterms dt{color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
18936
|
+
.knobs-wt-tterms dd{min-width:0;color:var(--_k-fg-2);overflow-wrap:anywhere}
|
|
18937
|
+
.knobs-wt-tterms dd[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg)}
|
|
18938
|
+
.knobs-wt-tcaption{padding-top:var(--_k-space-sibling);color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
18939
|
+
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
18940
|
+
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
18941
|
+
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
18942
|
+
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
18943
|
+
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
18944
|
+
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
18945
|
+
.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)}
|
|
18946
|
+
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:var(--kw-frame-r)}
|
|
18947
|
+
@supports (animation-timeline:scroll()){
|
|
18948
|
+
.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;
|
|
18949
|
+
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%;
|
|
18950
|
+
--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)));
|
|
18951
|
+
--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)));
|
|
18952
|
+
-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}
|
|
18183
18953
|
}
|
|
18954
|
+
.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)}
|
|
18955
|
+
.knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:var(--_k-type-small)}
|
|
18956
|
+
.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;
|
|
18957
|
+
background:var(--kw-under,var(--_k-pane-bg));box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
18958
|
+
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
18959
|
+
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
18960
|
+
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
18961
|
+
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
18962
|
+
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
18963
|
+
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
18964
|
+
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
18965
|
+
.knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:var(--_k-type-label);color:var(--_k-fg);white-space:nowrap}
|
|
18966
|
+
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
18967
|
+
.knobs-ui :is(.knobs-wt-table,.knobs-wt-tstack) a.knobs-wt-chip{text-decoration:none}
|
|
18968
|
+
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
18969
|
+
|
|
18970
|
+
/* Chapters: a readout list under a video or compare: number, label, start; the selection pill
|
|
18971
|
+
on the one playing, its rows bled out so their text sits on the media's edge. */
|
|
18972
|
+
.knobs-wt-body:has(>.knobs-wt-chapters){display:flex;flex-direction:column;gap:var(--_k-space-title)}
|
|
18973
|
+
.knobs-wt-chapters{position:relative;display:flex;flex-direction:column;margin:0 calc(var(--_k-space-sibling) * -1)}
|
|
18974
|
+
.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);
|
|
18975
|
+
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)}
|
|
18976
|
+
.knobs-ui .knobs-wt-chapter:is(:hover,:focus-visible){color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
18977
|
+
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 1px var(--_k-focus)}
|
|
18978
|
+
.knobs-wt-chapter-n{font-size:var(--_k-type-small);color:var(--_k-fg-3)}
|
|
18979
|
+
.knobs-wt-chapter-label{min-width:0;overflow:hidden;${fade2}}
|
|
18980
|
+
.knobs-wt-chapter-time{font:var(--_k-weight) var(--_k-type-small)/1 var(--_k-mono);color:var(--_k-fg-3)}
|
|
18981
|
+
.knobs-pick-copy :is(.knobs-wt-chapter-n,.knobs-wt-chapter-time){color:var(--_k-fg-2)}
|
|
18982
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
18983
|
+
@media(prefers-reduced-motion:reduce){.knobs-wt-disc-content{transition:opacity .15s}}
|
|
18984
|
+
`;
|
|
18184
18985
|
|
|
18185
18986
|
// src/ui/walkthrough-media.ts
|
|
18186
18987
|
function injectWalkthroughStyles(doc) {
|
|
@@ -18709,7 +19510,7 @@ function mediaSlot(container, options) {
|
|
|
18709
19510
|
}
|
|
18710
19511
|
};
|
|
18711
19512
|
}
|
|
18712
|
-
var CHECK3 =
|
|
19513
|
+
var CHECK3 = icon("check", { small: true });
|
|
18713
19514
|
|
|
18714
19515
|
// src/ui/walkthrough.ts
|
|
18715
19516
|
var el2 = (doc, tag, cls) => {
|
|
@@ -18727,16 +19528,20 @@ var lookOf2 = (o) => ({
|
|
|
18727
19528
|
...o.preset ? { preset: o.preset } : {},
|
|
18728
19529
|
...o.theme ? { theme: o.theme } : {}
|
|
18729
19530
|
});
|
|
18730
|
-
var
|
|
19531
|
+
var grid2 = (v) => Math.round(v * 64) / 64;
|
|
18731
19532
|
var ICON = {
|
|
18732
|
-
full:
|
|
18733
|
-
exit:
|
|
18734
|
-
pen:
|
|
18735
|
-
mic:
|
|
19533
|
+
full: icon("cornersOut"),
|
|
19534
|
+
exit: icon("cornersIn"),
|
|
19535
|
+
pen: icon("pencilSimple"),
|
|
19536
|
+
mic: icon("microphone"),
|
|
18736
19537
|
stop: svg('<rect x="4.5" y="4.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none"/>'),
|
|
18737
|
-
send:
|
|
18738
|
-
close:
|
|
19538
|
+
send: icon("paperPlaneRight"),
|
|
19539
|
+
close: icon("x", { small: true }),
|
|
19540
|
+
back: icon("arrowLeft", { small: true }),
|
|
19541
|
+
out: icon("arrowUpRight", { small: true })
|
|
18739
19542
|
};
|
|
19543
|
+
var DOCK_INSET = 12;
|
|
19544
|
+
var DOCK_GAP = 12;
|
|
18740
19545
|
var CALM2 = springMotion(SPRINGS.calm);
|
|
18741
19546
|
var SMOOTH = springMotion(SPRINGS.smooth);
|
|
18742
19547
|
var BACK_MS = 4500;
|
|
@@ -18752,16 +19557,25 @@ function tasteTest(container, options) {
|
|
|
18752
19557
|
...o.media !== undefined ? { media: fillMedia(o.media) } : {},
|
|
18753
19558
|
suggested: o.suggested === true
|
|
18754
19559
|
});
|
|
18755
|
-
|
|
19560
|
+
const pickable = options.pickable !== false;
|
|
19561
|
+
let picked = pickable ? options.picked ?? null : null;
|
|
18756
19562
|
const root = el2(doc, "div", "knobs-wt-options");
|
|
18757
|
-
|
|
18758
|
-
|
|
19563
|
+
if (pickable) {
|
|
19564
|
+
root.setAttribute("role", "radiogroup");
|
|
19565
|
+
root.setAttribute("aria-label", "Options");
|
|
19566
|
+
} else
|
|
19567
|
+
root.dataset.static = "";
|
|
18759
19568
|
root.style.setProperty("--kw-n", String(Math.min(list.length, 3)));
|
|
18760
19569
|
if (!container.closest(".knobs-ui"))
|
|
18761
19570
|
applyLook2(root, options);
|
|
18762
19571
|
const slots = [];
|
|
18763
19572
|
const tiles = list.map((o, i) => {
|
|
18764
19573
|
const tile = el2(doc, "div", "knobs-wt-option");
|
|
19574
|
+
if (!pickable) {
|
|
19575
|
+
const name = el2(doc, "span", "knobs-wt-slot-label");
|
|
19576
|
+
name.textContent = o.label;
|
|
19577
|
+
tile.append(name);
|
|
19578
|
+
}
|
|
18765
19579
|
const pick = el2(doc, "button", "knobs-wt-pick");
|
|
18766
19580
|
pick.type = "button";
|
|
18767
19581
|
pick.setAttribute("role", "radio");
|
|
@@ -18790,7 +19604,8 @@ function tasteTest(container, options) {
|
|
|
18790
19604
|
api.pick(next);
|
|
18791
19605
|
options.onPick?.(next);
|
|
18792
19606
|
});
|
|
18793
|
-
|
|
19607
|
+
if (pickable)
|
|
19608
|
+
tile.append(pick);
|
|
18794
19609
|
if (o.media)
|
|
18795
19610
|
slots.push(mediaSlot(tile, {
|
|
18796
19611
|
...look,
|
|
@@ -18869,8 +19684,13 @@ function walkthrough(container, options) {
|
|
|
18869
19684
|
let count = null;
|
|
18870
19685
|
let fill = null;
|
|
18871
19686
|
let tocEl = null;
|
|
18872
|
-
let
|
|
19687
|
+
let pill = null;
|
|
19688
|
+
let tocRows = [];
|
|
19689
|
+
let discs = [];
|
|
18873
19690
|
let full = null;
|
|
19691
|
+
const review = options.review === true;
|
|
19692
|
+
const noteMode = review ? options.noteBar ?? "collapsed" : "hidden";
|
|
19693
|
+
let reserve = noteBarReserve(52, DOCK_INSET, DOCK_GAP);
|
|
18874
19694
|
const viewOf = (key) => views.find((v) => v.step.key === key);
|
|
18875
19695
|
const feedback = () => collectFeedback(page, state);
|
|
18876
19696
|
const markdown = () => feedbackMarkdown(feedback(), page.verdicts);
|
|
@@ -18894,9 +19714,6 @@ function walkthrough(container, options) {
|
|
|
18894
19714
|
else
|
|
18895
19715
|
run();
|
|
18896
19716
|
};
|
|
18897
|
-
const pillY = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
18898
|
-
const pillH = new Spring(0, CALM2.omega, CALM2.zeta, 0.25);
|
|
18899
|
-
let pillPlaced = false;
|
|
18900
19717
|
const scroll = {
|
|
18901
19718
|
spring: new Spring(0, CALM2.omega, CALM2.zeta, 0.5),
|
|
18902
19719
|
to: null,
|
|
@@ -18904,13 +19721,6 @@ function walkthrough(container, options) {
|
|
|
18904
19721
|
};
|
|
18905
19722
|
const motion = frameLoop(win, (dt) => {
|
|
18906
19723
|
let more = false;
|
|
18907
|
-
if (mark) {
|
|
18908
|
-
pillY.step(dt);
|
|
18909
|
-
pillH.step(dt);
|
|
18910
|
-
mark.style.transform = `translateY(${grid3(pillY.x)}px)`;
|
|
18911
|
-
mark.style.height = `${grid3(pillY.x + pillH.x) - grid3(pillY.x)}px`;
|
|
18912
|
-
more ||= !pillY.resting || !pillH.resting;
|
|
18913
|
-
}
|
|
18914
19724
|
if (scroll.to && scroll.el) {
|
|
18915
19725
|
scroll.spring.set(scrollTarget(scroll.to, scroll.el));
|
|
18916
19726
|
scroll.spring.step(dt);
|
|
@@ -18974,21 +19784,12 @@ function walkthrough(container, options) {
|
|
|
18974
19784
|
v.glyph.dataset.tone = v.step.ask === "none" ? "none" : verdict ? verdictTone(verdict, page.verdicts.findIndex((x) => x.id === verdict)) : done ? "accent" : "dim";
|
|
18975
19785
|
};
|
|
18976
19786
|
const placeMark = () => {
|
|
18977
|
-
if (!
|
|
19787
|
+
if (!pill || !tocEl)
|
|
18978
19788
|
return;
|
|
19789
|
+
pill.update();
|
|
18979
19790
|
const row = viewOf(current)?.toc;
|
|
18980
19791
|
if (!row)
|
|
18981
|
-
return
|
|
18982
|
-
mark.dataset.on = "";
|
|
18983
|
-
if (!pillPlaced || reduced()) {
|
|
18984
|
-
pillY.snap(row.offsetTop);
|
|
18985
|
-
pillH.snap(row.offsetHeight);
|
|
18986
|
-
pillPlaced = true;
|
|
18987
|
-
} else {
|
|
18988
|
-
pillY.set(row.offsetTop);
|
|
18989
|
-
pillH.set(row.offsetHeight);
|
|
18990
|
-
}
|
|
18991
|
-
motion.wake();
|
|
19792
|
+
return;
|
|
18992
19793
|
const top = row.offsetTop;
|
|
18993
19794
|
const bottom = top + row.offsetHeight;
|
|
18994
19795
|
if (top < tocEl.scrollTop + 8)
|
|
@@ -19005,6 +19806,9 @@ function walkthrough(container, options) {
|
|
|
19005
19806
|
const v = viewOf(key);
|
|
19006
19807
|
v?.card.setAttribute("data-current", "");
|
|
19007
19808
|
v?.toc?.setAttribute("aria-current", "step");
|
|
19809
|
+
for (const r of tocRows)
|
|
19810
|
+
if (r.dataset.section)
|
|
19811
|
+
r.toggleAttribute("data-active", r.dataset.section === v?.step.section);
|
|
19008
19812
|
if (key)
|
|
19009
19813
|
record({ what: "step", step: key });
|
|
19010
19814
|
placeMark();
|
|
@@ -19021,6 +19825,16 @@ function walkthrough(container, options) {
|
|
|
19021
19825
|
else
|
|
19022
19826
|
break;
|
|
19023
19827
|
}
|
|
19828
|
+
const s = scrollerOf(root);
|
|
19829
|
+
if (s.scrollTop > 0 && s.scrollTop >= s.scrollHeight - s.clientHeight - 2) {
|
|
19830
|
+
const bottom = (s === doc.scrollingElement ? win.innerHeight : s.getBoundingClientRect().bottom) - reserve;
|
|
19831
|
+
for (let i = views.length - 1;i >= 0; i--) {
|
|
19832
|
+
if (views[i].card.getBoundingClientRect().top < bottom) {
|
|
19833
|
+
pick = views[i].step.key;
|
|
19834
|
+
break;
|
|
19835
|
+
}
|
|
19836
|
+
}
|
|
19837
|
+
}
|
|
19024
19838
|
setCurrent(pick);
|
|
19025
19839
|
};
|
|
19026
19840
|
let scrollRaf = 0;
|
|
@@ -19063,15 +19877,20 @@ function walkthrough(container, options) {
|
|
|
19063
19877
|
};
|
|
19064
19878
|
const scrim = el2(doc, "div", "knobs-wt-scrim");
|
|
19065
19879
|
scrim.addEventListener("click", () => setFull(false));
|
|
19066
|
-
const fullRect = () => ({
|
|
19880
|
+
const fullRect = () => ({
|
|
19881
|
+
x: DOCK_INSET,
|
|
19882
|
+
y: DOCK_INSET,
|
|
19883
|
+
w: win.innerWidth - DOCK_INSET * 2,
|
|
19884
|
+
h: win.innerHeight - DOCK_INSET - reserve
|
|
19885
|
+
});
|
|
19067
19886
|
const placeFull = (f) => {
|
|
19068
19887
|
const a = f.hold.getBoundingClientRect();
|
|
19069
19888
|
const b = fullRect();
|
|
19070
19889
|
const k = reduced() ? Math.round(f.p.target) : f.p.x;
|
|
19071
|
-
const left =
|
|
19072
|
-
const top =
|
|
19073
|
-
const right =
|
|
19074
|
-
const bottom =
|
|
19890
|
+
const left = grid2(a.left + (b.x - a.left) * k);
|
|
19891
|
+
const top = grid2(a.top + (b.y - a.top) * k);
|
|
19892
|
+
const right = grid2(a.right + (b.x + b.w - a.right) * k);
|
|
19893
|
+
const bottom = grid2(a.bottom + (b.y + b.h - a.bottom) * k);
|
|
19075
19894
|
const s = f.v.card.style;
|
|
19076
19895
|
s.left = `${left}px`;
|
|
19077
19896
|
s.top = `${top}px`;
|
|
@@ -19208,6 +20027,7 @@ function walkthrough(container, options) {
|
|
|
19208
20027
|
ink.on = true;
|
|
19209
20028
|
ink.layer.dataset.on = "";
|
|
19210
20029
|
root.dataset.inking = "";
|
|
20030
|
+
bar.setOpen(true);
|
|
19211
20031
|
bar.sync();
|
|
19212
20032
|
};
|
|
19213
20033
|
const voice = {
|
|
@@ -19247,6 +20067,7 @@ function walkthrough(container, options) {
|
|
|
19247
20067
|
});
|
|
19248
20068
|
voice.recorder = rec;
|
|
19249
20069
|
voice.started = performance.now();
|
|
20070
|
+
bar.setOpen(true);
|
|
19250
20071
|
rec.start();
|
|
19251
20072
|
voice.timer = win.setInterval(() => bar.sync(), 250);
|
|
19252
20073
|
bar.sync();
|
|
@@ -19273,7 +20094,10 @@ function walkthrough(container, options) {
|
|
|
19273
20094
|
if (!v)
|
|
19274
20095
|
return;
|
|
19275
20096
|
backTo = key;
|
|
19276
|
-
backPill.
|
|
20097
|
+
backPill.innerHTML = ICON.back;
|
|
20098
|
+
const words = el2(doc, "span", "knobs-wt-back-label");
|
|
20099
|
+
words.textContent = `Back to ${plainMarkdown(v.step.title)}`;
|
|
20100
|
+
backPill.append(words);
|
|
19277
20101
|
backPill.dataset.on = "";
|
|
19278
20102
|
win.clearTimeout(backTimer);
|
|
19279
20103
|
backTimer = win.setTimeout(hideBack, BACK_MS);
|
|
@@ -19305,7 +20129,41 @@ function walkthrough(container, options) {
|
|
|
19305
20129
|
sendBtn.dataset.send = "";
|
|
19306
20130
|
row.append(input, attach, fullBtn, penBtn, micBtn, sendBtn);
|
|
19307
20131
|
box.append(on, row);
|
|
19308
|
-
|
|
20132
|
+
const launch = el2(doc, "button", "knobs-wt-launch");
|
|
20133
|
+
launch.type = "button";
|
|
20134
|
+
launch.innerHTML = ICON.pen;
|
|
20135
|
+
launch.append("Note");
|
|
20136
|
+
const kbd = el2(doc, "kbd");
|
|
20137
|
+
kbd.textContent = "n";
|
|
20138
|
+
launch.append(kbd);
|
|
20139
|
+
launch.setAttribute("aria-label", "Write a note (n)");
|
|
20140
|
+
launch.addEventListener("click", () => setOpen(true, true));
|
|
20141
|
+
dock.dataset.mode = noteMode;
|
|
20142
|
+
dock.append(backPill, box, launch);
|
|
20143
|
+
let open = noteMode !== "collapsed";
|
|
20144
|
+
const setOpen = (on, focus = false) => {
|
|
20145
|
+
if (noteMode === "collapsed" && on !== open) {
|
|
20146
|
+
open = on;
|
|
20147
|
+
dock.toggleAttribute("data-open", on);
|
|
20148
|
+
box.inert = !on;
|
|
20149
|
+
launch.inert = on;
|
|
20150
|
+
syncReserve();
|
|
20151
|
+
}
|
|
20152
|
+
if (on && focus)
|
|
20153
|
+
input.focus({ preventScroll: true });
|
|
20154
|
+
};
|
|
20155
|
+
dock.toggleAttribute("data-open", open);
|
|
20156
|
+
box.inert = !open;
|
|
20157
|
+
launch.inert = open;
|
|
20158
|
+
const empty = () => !input.value.trim() && !voice.pending && !voice.recorder && !ink.on && !ink.paths.length;
|
|
20159
|
+
const onOutside = (e) => {
|
|
20160
|
+
if (open && noteMode === "collapsed" && !dock.contains(e.target) && empty())
|
|
20161
|
+
setOpen(false);
|
|
20162
|
+
};
|
|
20163
|
+
doc.addEventListener("pointerdown", onOutside, true);
|
|
20164
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => syncReserve()) : null;
|
|
20165
|
+
ro?.observe(box);
|
|
20166
|
+
ro?.observe(launch);
|
|
19309
20167
|
const fit = () => {
|
|
19310
20168
|
input.style.height = "auto";
|
|
19311
20169
|
input.style.height = `${Math.min(140, input.scrollHeight)}px`;
|
|
@@ -19321,6 +20179,8 @@ function walkthrough(container, options) {
|
|
|
19321
20179
|
} else if (e.key === "Escape") {
|
|
19322
20180
|
e.preventDefault();
|
|
19323
20181
|
input.blur();
|
|
20182
|
+
if (empty())
|
|
20183
|
+
setOpen(false);
|
|
19324
20184
|
viewOf(current)?.card.focus({ preventScroll: true });
|
|
19325
20185
|
}
|
|
19326
20186
|
});
|
|
@@ -19340,13 +20200,13 @@ function walkthrough(container, options) {
|
|
|
19340
20200
|
const sync = () => {
|
|
19341
20201
|
const v = viewOf(current);
|
|
19342
20202
|
const ctx = describeMedia(mediaContext(v));
|
|
19343
|
-
const where = v ?
|
|
20203
|
+
const where = v ? plainMarkdown(v.step.title) : "General note";
|
|
19344
20204
|
const text = ctx ? `${where} · ${ctx}` : where;
|
|
19345
20205
|
if (text !== lastOn) {
|
|
19346
20206
|
on.textContent = text;
|
|
19347
20207
|
lastOn = text;
|
|
19348
20208
|
}
|
|
19349
|
-
input.placeholder = v ?
|
|
20209
|
+
input.placeholder = v ? "A note on this step… (n)" : "A note on the whole page… (n)";
|
|
19350
20210
|
const attached = `${voice.pending?.url ?? ""}|${ink.paths.length}`;
|
|
19351
20211
|
if (attached !== lastAttached) {
|
|
19352
20212
|
lastAttached = attached;
|
|
@@ -19385,14 +20245,45 @@ function walkthrough(container, options) {
|
|
|
19385
20245
|
};
|
|
19386
20246
|
return {
|
|
19387
20247
|
dock,
|
|
20248
|
+
box,
|
|
20249
|
+
launch,
|
|
19388
20250
|
input,
|
|
19389
20251
|
sync,
|
|
20252
|
+
get open() {
|
|
20253
|
+
return open;
|
|
20254
|
+
},
|
|
20255
|
+
setOpen,
|
|
20256
|
+
empty,
|
|
20257
|
+
unobserve: () => {
|
|
20258
|
+
ro?.disconnect();
|
|
20259
|
+
doc.removeEventListener("pointerdown", onOutside, true);
|
|
20260
|
+
},
|
|
19390
20261
|
clear() {
|
|
19391
20262
|
input.value = "";
|
|
19392
20263
|
fit();
|
|
19393
20264
|
}
|
|
19394
20265
|
};
|
|
19395
20266
|
})();
|
|
20267
|
+
let padded = null;
|
|
20268
|
+
function syncReserve() {
|
|
20269
|
+
if (disposed)
|
|
20270
|
+
return;
|
|
20271
|
+
const h = (bar.open ? bar.box : bar.launch).offsetHeight;
|
|
20272
|
+
if (noteMode === "hidden")
|
|
20273
|
+
reserve = 0;
|
|
20274
|
+
else if (h)
|
|
20275
|
+
reserve = noteBarReserve(h, DOCK_INSET, DOCK_GAP);
|
|
20276
|
+
root.style.setProperty("--kw-reserve", `${reserve}px`);
|
|
20277
|
+
const s = scrollerOf(root);
|
|
20278
|
+
if (padded?.el !== s) {
|
|
20279
|
+
if (padded)
|
|
20280
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
20281
|
+
padded = { el: s, was: s.style.scrollPaddingBottom };
|
|
20282
|
+
}
|
|
20283
|
+
s.style.scrollPaddingBottom = `${reserve}px`;
|
|
20284
|
+
if (full)
|
|
20285
|
+
placeFull(full);
|
|
20286
|
+
}
|
|
19396
20287
|
const ticker = win.setInterval(() => !doc.hidden && bar.sync(), 500);
|
|
19397
20288
|
const send = (text = bar.input.value) => {
|
|
19398
20289
|
if (voice.recorder)
|
|
@@ -19428,6 +20319,10 @@ function walkthrough(container, options) {
|
|
|
19428
20319
|
syncProgress();
|
|
19429
20320
|
emit();
|
|
19430
20321
|
bar.sync();
|
|
20322
|
+
if (noteMode === "collapsed") {
|
|
20323
|
+
bar.input.blur();
|
|
20324
|
+
bar.setOpen(false);
|
|
20325
|
+
}
|
|
19431
20326
|
if (v && options.advance !== false) {
|
|
19432
20327
|
const to = adjacentStep(views.map((x) => x.step.key), v.step.key, 1);
|
|
19433
20328
|
if (to && to !== v.step.key) {
|
|
@@ -19435,7 +20330,8 @@ function walkthrough(container, options) {
|
|
|
19435
20330
|
setFull(false);
|
|
19436
20331
|
go(to);
|
|
19437
20332
|
showBack(v.step.key);
|
|
19438
|
-
|
|
20333
|
+
if (noteMode === "docked")
|
|
20334
|
+
bar.input.focus({ preventScroll: true });
|
|
19439
20335
|
}
|
|
19440
20336
|
}
|
|
19441
20337
|
};
|
|
@@ -19522,28 +20418,121 @@ function walkthrough(container, options) {
|
|
|
19522
20418
|
row.addEventListener("transitionend", done, { once: true });
|
|
19523
20419
|
win.setTimeout(done, 600);
|
|
19524
20420
|
};
|
|
20421
|
+
const metaLine = (cls) => el2(doc, "div", `knobs-wt-metaline ${cls}`);
|
|
20422
|
+
const metaText = (line, text, cls) => {
|
|
20423
|
+
const s = el2(doc, "span", cls);
|
|
20424
|
+
s.textContent = text;
|
|
20425
|
+
line.append(s);
|
|
20426
|
+
return s;
|
|
20427
|
+
};
|
|
20428
|
+
const findPRIn = (n) => findPR(page.prs, n, page.repo);
|
|
20429
|
+
const metaLink = (line, text, href) => {
|
|
20430
|
+
const n = prNumber(href);
|
|
20431
|
+
if (n) {
|
|
20432
|
+
const chip = prChip(doc, n, { href, ...findPRIn(n) });
|
|
20433
|
+
line.append(chip);
|
|
20434
|
+
return chip;
|
|
20435
|
+
}
|
|
20436
|
+
const a = el2(doc, "a");
|
|
20437
|
+
a.href = href;
|
|
20438
|
+
a.target = "_blank";
|
|
20439
|
+
a.rel = "noreferrer";
|
|
20440
|
+
a.textContent = text;
|
|
20441
|
+
a.insertAdjacentHTML("beforeend", ICON.out);
|
|
20442
|
+
line.append(a);
|
|
20443
|
+
return a;
|
|
20444
|
+
};
|
|
20445
|
+
const feedItem = (f, now) => {
|
|
20446
|
+
const li = el2(doc, "li", "knobs-wt-fi");
|
|
20447
|
+
li.dataset.kind = f.kind;
|
|
20448
|
+
const q = el2(doc, "div", "knobs-wt-fi-q");
|
|
20449
|
+
const meta = metaLine("knobs-wt-fi-meta");
|
|
20450
|
+
if (f.at !== null) {
|
|
20451
|
+
const when = metaText(meta, ago(f.at, now));
|
|
20452
|
+
when.title = new Date(f.at).toLocaleString();
|
|
20453
|
+
} else
|
|
20454
|
+
metaText(meta, f.kind === "qa" ? "Answer" : "Update");
|
|
20455
|
+
const step = f.step ? page.steps.find((s) => s.key === f.step) : undefined;
|
|
20456
|
+
if (step) {
|
|
20457
|
+
const section = page.sections.find((s) => s.id === step.section);
|
|
20458
|
+
const b = el2(doc, "button", "knobs-wt-fi-step");
|
|
20459
|
+
b.type = "button";
|
|
20460
|
+
b.textContent = section?.link?.label ?? plainMarkdown(step.title);
|
|
20461
|
+
b.title = `Go to “${plainMarkdown(step.title)}”`;
|
|
20462
|
+
b.addEventListener("click", () => go(step.key));
|
|
20463
|
+
meta.append(b);
|
|
20464
|
+
}
|
|
20465
|
+
if (f.status) {
|
|
20466
|
+
const id = f.status.toLowerCase();
|
|
20467
|
+
const shipped = /^(ship|shipped|merged|done)$/.test(id);
|
|
20468
|
+
const changes = /^(changes?|changes queued)$/.test(id);
|
|
20469
|
+
const s = metaText(meta, shipped ? "Shipped" : changes ? "Changes queued" : f.status);
|
|
20470
|
+
s.dataset.status = shipped ? "on" : changes ? "warn" : "";
|
|
20471
|
+
}
|
|
20472
|
+
q.append(meta);
|
|
20473
|
+
if (f.q)
|
|
20474
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-ask", f.q));
|
|
20475
|
+
else
|
|
20476
|
+
q.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
20477
|
+
li.append(q);
|
|
20478
|
+
if (f.q || f.trail.length) {
|
|
20479
|
+
const a = el2(doc, "div", "knobs-wt-fi-a");
|
|
20480
|
+
if (f.q)
|
|
20481
|
+
a.append(prose2(doc, "div", "knobs-wt-fi-answer", f.text));
|
|
20482
|
+
if (f.trail.length) {
|
|
20483
|
+
const list = el2(doc, "ol", "knobs-wt-trail");
|
|
20484
|
+
for (const line of f.trail) {
|
|
20485
|
+
const i = line.indexOf(" · ");
|
|
20486
|
+
const row = el2(doc, "li");
|
|
20487
|
+
const words = el2(doc, "span", "knobs-wt-trail-text");
|
|
20488
|
+
words.textContent = i < 0 ? line : line.slice(i + 3);
|
|
20489
|
+
row.append(words);
|
|
20490
|
+
if (i >= 0) {
|
|
20491
|
+
const at = el2(doc, "span", "knobs-wt-trail-at");
|
|
20492
|
+
at.textContent = line.slice(0, i);
|
|
20493
|
+
row.append(at);
|
|
20494
|
+
}
|
|
20495
|
+
list.append(row);
|
|
20496
|
+
}
|
|
20497
|
+
discs.push(disclosure(a, { label: "Context", count: f.trail.length, content: list }));
|
|
20498
|
+
}
|
|
20499
|
+
li.append(a);
|
|
20500
|
+
}
|
|
20501
|
+
return li;
|
|
20502
|
+
};
|
|
19525
20503
|
const build = () => {
|
|
19526
20504
|
for (const v of views) {
|
|
19527
20505
|
v.slots.forEach((s) => s.dispose());
|
|
19528
20506
|
v.taste?.dispose();
|
|
19529
20507
|
}
|
|
20508
|
+
for (const d of discs)
|
|
20509
|
+
d.dispose();
|
|
20510
|
+
discs = [];
|
|
20511
|
+
pill?.dispose();
|
|
20512
|
+
pill = null;
|
|
20513
|
+
tocRows = [];
|
|
19530
20514
|
if (full) {
|
|
19531
20515
|
full.p.snap(0);
|
|
19532
20516
|
closeFull();
|
|
19533
20517
|
}
|
|
19534
20518
|
clearInk();
|
|
19535
20519
|
views = [];
|
|
19536
|
-
pillPlaced = false;
|
|
19537
20520
|
root.textContent = "";
|
|
19538
20521
|
root.removeAttribute("data-settled");
|
|
20522
|
+
root.dataset.rail = options.rail === false ? "none" : options.rail === "right" ? "right" : "left";
|
|
20523
|
+
root.toggleAttribute("data-cards", options.cards === true);
|
|
20524
|
+
root.toggleAttribute("data-review", review);
|
|
19539
20525
|
const layout = el2(doc, "div", "knobs-wt-layout");
|
|
19540
20526
|
const main = el2(doc, "div", "knobs-wt-main");
|
|
20527
|
+
const flow = el2(doc, "div", "knobs-wt-flow");
|
|
19541
20528
|
const head = el2(doc, "header", "knobs-wt-head");
|
|
19542
20529
|
const h1 = el2(doc, "h1", "knobs-wt-title");
|
|
19543
20530
|
h1.textContent = page.title;
|
|
19544
20531
|
head.append(h1);
|
|
19545
20532
|
if (page.summary)
|
|
19546
20533
|
head.append(prose2(doc, "p", "knobs-wt-summary", page.summary));
|
|
20534
|
+
if (page.more)
|
|
20535
|
+
head.append(more(page.more));
|
|
19547
20536
|
if (page.meta.length) {
|
|
19548
20537
|
const meta = el2(doc, "div", "knobs-wt-meta");
|
|
19549
20538
|
for (const m of page.meta) {
|
|
@@ -19564,57 +20553,51 @@ function walkthrough(container, options) {
|
|
|
19564
20553
|
}
|
|
19565
20554
|
head.append(meta);
|
|
19566
20555
|
}
|
|
19567
|
-
|
|
20556
|
+
flow.append(head);
|
|
20557
|
+
let feedEl = null;
|
|
19568
20558
|
if (page.feed.length) {
|
|
19569
|
-
|
|
19570
|
-
|
|
19571
|
-
|
|
20559
|
+
feedEl = el2(doc, "section", "knobs-wt-feed");
|
|
20560
|
+
feedEl.id = "wt-latest";
|
|
20561
|
+
feedEl.setAttribute("aria-label", "Updates and answers");
|
|
20562
|
+
const fh = el2(doc, "header", "knobs-wt-feed-head");
|
|
20563
|
+
const h = el2(doc, "h2", "knobs-wt-feed-title");
|
|
20564
|
+
h.textContent = page.feed.some((f) => f.kind === "qa") ? "Updates & Q&A" : "Updates";
|
|
20565
|
+
const n = el2(doc, "span", "knobs-wt-feed-count");
|
|
20566
|
+
n.textContent = String(page.feed.length);
|
|
20567
|
+
fh.append(h, n);
|
|
20568
|
+
const list = el2(doc, "ol", "knobs-wt-feed-list");
|
|
19572
20569
|
const now = Date.now();
|
|
19573
|
-
for (const f of page.feed)
|
|
19574
|
-
|
|
19575
|
-
|
|
19576
|
-
|
|
19577
|
-
when.textContent = f.at === null ? "" : ago(f.at, now);
|
|
19578
|
-
if (f.at !== null)
|
|
19579
|
-
when.title = new Date(f.at).toLocaleString();
|
|
19580
|
-
const kind = el2(doc, "span", "knobs-wt-fi-kind");
|
|
19581
|
-
kind.textContent = f.kind === "qa" ? "Answer" : "Update";
|
|
19582
|
-
const body = el2(doc, "div", "knobs-wt-fi-body");
|
|
19583
|
-
if (f.q)
|
|
19584
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
|
|
19585
|
-
body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
19586
|
-
li.append(when, kind, body);
|
|
19587
|
-
if (f.step) {
|
|
19588
|
-
const target = f.step;
|
|
19589
|
-
const link = el2(doc, "button", "knobs-wt-fi-step");
|
|
19590
|
-
link.type = "button";
|
|
19591
|
-
link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
|
|
19592
|
-
link.title = "Go to the step";
|
|
19593
|
-
link.addEventListener("click", () => go(target));
|
|
19594
|
-
li.append(link);
|
|
19595
|
-
}
|
|
19596
|
-
list.append(li);
|
|
19597
|
-
}
|
|
19598
|
-
feed.append(list);
|
|
19599
|
-
main.append(feed);
|
|
20570
|
+
for (const f of page.feed)
|
|
20571
|
+
list.append(feedItem(f, now));
|
|
20572
|
+
feedEl.append(fh, list);
|
|
20573
|
+
flow.append(feedEl);
|
|
19600
20574
|
}
|
|
19601
20575
|
let rail = null;
|
|
19602
|
-
count = fill = tocEl =
|
|
20576
|
+
count = fill = tocEl = null;
|
|
19603
20577
|
if (options.rail !== false) {
|
|
19604
20578
|
rail = el2(doc, "aside", "knobs-wt-rail");
|
|
19605
|
-
rail.setAttribute("aria-label", "
|
|
19606
|
-
const progress = el2(doc, "div", "knobs-wt-progress");
|
|
19607
|
-
count = el2(doc, "div", "knobs-wt-count");
|
|
19608
|
-
const meter = el2(doc, "div", "knobs-wt-bar");
|
|
19609
|
-
fill = el2(doc, "div", "knobs-wt-fill");
|
|
19610
|
-
meter.append(fill);
|
|
19611
|
-
progress.append(count, meter);
|
|
20579
|
+
rail.setAttribute("aria-label", "Contents");
|
|
19612
20580
|
tocEl = el2(doc, "nav", "knobs-wt-toc");
|
|
19613
20581
|
tocEl.setAttribute("aria-label", "Contents");
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
|
|
19617
|
-
|
|
20582
|
+
if (feedEl) {
|
|
20583
|
+
const group = el2(doc, "div", "knobs-wt-toc-group");
|
|
20584
|
+
const target = feedEl;
|
|
20585
|
+
group.append(tocRow("Latest", false, () => target.scrollIntoView({ block: "start", behavior: reduced() ? "auto" : "smooth" })));
|
|
20586
|
+
tocEl.append(group);
|
|
20587
|
+
}
|
|
20588
|
+
if (review) {
|
|
20589
|
+
const progress = el2(doc, "div", "knobs-wt-progress");
|
|
20590
|
+
count = el2(doc, "div", "knobs-wt-count");
|
|
20591
|
+
const meter = el2(doc, "div", "knobs-wt-bar");
|
|
20592
|
+
fill = el2(doc, "div", "knobs-wt-fill");
|
|
20593
|
+
meter.append(fill);
|
|
20594
|
+
progress.append(count, meter);
|
|
20595
|
+
rail.append(progress);
|
|
20596
|
+
}
|
|
20597
|
+
rail.append(tocEl);
|
|
20598
|
+
if (review)
|
|
20599
|
+
rail.append(actions(true));
|
|
20600
|
+
if (review && options.keys !== false) {
|
|
19618
20601
|
const keys = el2(doc, "div", "knobs-wt-keys");
|
|
19619
20602
|
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" : "");
|
|
19620
20603
|
rail.append(keys);
|
|
@@ -19624,45 +20607,47 @@ function walkthrough(container, options) {
|
|
|
19624
20607
|
const sec = el2(doc, "section", "knobs-wt-section");
|
|
19625
20608
|
sec.id = `wt-${section.id}`;
|
|
19626
20609
|
const sh = el2(doc, "header", "knobs-wt-shead");
|
|
19627
|
-
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
if (section.status) {
|
|
19638
|
-
const s = statusLook(section.status);
|
|
19639
|
-
const chip = el2(doc, "span", "knobs-wt-chip");
|
|
19640
|
-
chip.dataset.tone = s.tone;
|
|
19641
|
-
chip.textContent = s.label;
|
|
19642
|
-
kicker.append(chip);
|
|
20610
|
+
const status = review ? section.status : undefined;
|
|
20611
|
+
if (section.kicker || section.link || status) {
|
|
20612
|
+
const meta = metaLine("knobs-wt-kicker");
|
|
20613
|
+
if (section.kicker)
|
|
20614
|
+
metaText(meta, section.kicker, "knobs-wt-kicker-lead");
|
|
20615
|
+
if (section.link)
|
|
20616
|
+
metaLink(meta, section.link.label, section.link.href);
|
|
20617
|
+
if (status) {
|
|
20618
|
+
const s = statusLook(status);
|
|
20619
|
+
metaText(meta, s.label, "knobs-wt-status").dataset.tone = s.tone;
|
|
19643
20620
|
}
|
|
19644
|
-
sh.append(
|
|
20621
|
+
sh.append(meta);
|
|
19645
20622
|
}
|
|
19646
|
-
const h2 = el2(doc, "h2", "knobs-wt-
|
|
19647
|
-
h2.
|
|
20623
|
+
const h2 = el2(doc, "h2", "knobs-wt-heading");
|
|
20624
|
+
h2.innerHTML = inlineMarkdown(section.title);
|
|
19648
20625
|
sh.append(h2);
|
|
20626
|
+
const intro = el2(doc, "div", "knobs-wt-sintro");
|
|
20627
|
+
intro.append(sh);
|
|
19649
20628
|
if (section.summary)
|
|
19650
|
-
|
|
19651
|
-
|
|
20629
|
+
intro.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
|
|
20630
|
+
if (section.more)
|
|
20631
|
+
intro.append(more(section.more));
|
|
20632
|
+
sec.append(intro);
|
|
20633
|
+
let group = null;
|
|
19652
20634
|
if (tocEl) {
|
|
19653
|
-
|
|
19654
|
-
|
|
19655
|
-
|
|
19656
|
-
tocEl.append(
|
|
20635
|
+
group = el2(doc, "div", "knobs-wt-toc-group");
|
|
20636
|
+
const first = section.steps[0]?.key;
|
|
20637
|
+
group.append(tocRow(plainMarkdown(section.title), false, () => first ? go(first) : undefined, section.id));
|
|
20638
|
+
tocEl.append(group);
|
|
19657
20639
|
}
|
|
19658
20640
|
for (const step of section.steps) {
|
|
19659
|
-
const v = stepView(step);
|
|
20641
|
+
const v = stepView(step, group);
|
|
19660
20642
|
sec.append(v.card);
|
|
19661
20643
|
views.push(v);
|
|
19662
20644
|
}
|
|
19663
|
-
|
|
20645
|
+
flow.append(sec);
|
|
19664
20646
|
}
|
|
19665
|
-
|
|
20647
|
+
linkPRs(flow, findPRIn);
|
|
20648
|
+
main.append(flow);
|
|
20649
|
+
if (noteMode !== "hidden")
|
|
20650
|
+
main.append(bar.dock);
|
|
19666
20651
|
if (rail)
|
|
19667
20652
|
layout.append(rail);
|
|
19668
20653
|
layout.append(main);
|
|
@@ -19672,16 +20657,46 @@ function walkthrough(container, options) {
|
|
|
19672
20657
|
for (const n of notesOn(state, v.step.key))
|
|
19673
20658
|
renderNote(v, n);
|
|
19674
20659
|
}
|
|
20660
|
+
if (tocEl)
|
|
20661
|
+
pill = selectionPill(tocEl, {
|
|
20662
|
+
selected: () => viewOf(current)?.toc ?? null,
|
|
20663
|
+
rows: () => tocRows
|
|
20664
|
+
});
|
|
19675
20665
|
syncProgress();
|
|
19676
20666
|
current = null;
|
|
19677
20667
|
fromScroll();
|
|
19678
20668
|
placeMark();
|
|
19679
20669
|
bar.sync();
|
|
20670
|
+
syncReserve();
|
|
19680
20671
|
win.requestAnimationFrame(() => win.requestAnimationFrame(() => {
|
|
19681
20672
|
if (!disposed && !reduced())
|
|
19682
20673
|
root.dataset.settled = "";
|
|
19683
20674
|
}));
|
|
19684
20675
|
};
|
|
20676
|
+
const more = (text) => {
|
|
20677
|
+
const box = el2(doc, "div", "knobs-wt-more");
|
|
20678
|
+
const body = el2(doc, "div", "knobs-wt-more-text");
|
|
20679
|
+
for (const para of text.split(/\n\s*\n/))
|
|
20680
|
+
if (para.trim())
|
|
20681
|
+
body.append(prose2(doc, "p", "", para.trim()));
|
|
20682
|
+
discs.push(disclosure(box, { label: "More", content: body }));
|
|
20683
|
+
return box;
|
|
20684
|
+
};
|
|
20685
|
+
const tocRow = (label, sub, run, section) => {
|
|
20686
|
+
const b = el2(doc, "button", sub ? "knobs-wt-toc-row knobs-wt-toc-sub" : "knobs-wt-toc-row");
|
|
20687
|
+
b.type = "button";
|
|
20688
|
+
if (section)
|
|
20689
|
+
b.dataset.section = section;
|
|
20690
|
+
const t = el2(doc, "span", "knobs-wt-toc-label");
|
|
20691
|
+
t.textContent = label;
|
|
20692
|
+
const e = el2(doc, "span", "knobs-wt-toc-end");
|
|
20693
|
+
b.title = label;
|
|
20694
|
+
b.append(t, e);
|
|
20695
|
+
b.addEventListener("mousedown", (ev) => ev.preventDefault());
|
|
20696
|
+
b.addEventListener("click", run);
|
|
20697
|
+
tocRows.push(b);
|
|
20698
|
+
return b;
|
|
20699
|
+
};
|
|
19685
20700
|
const actions = (rail) => {
|
|
19686
20701
|
const row = el2(doc, "div", "knobs-wt-actions");
|
|
19687
20702
|
const btn = (text, run, primary = false) => {
|
|
@@ -19722,37 +20737,38 @@ function walkthrough(container, options) {
|
|
|
19722
20737
|
toast("Couldn't reach the clipboard", { tone: "warn", look, doc });
|
|
19723
20738
|
}
|
|
19724
20739
|
};
|
|
19725
|
-
const stepView = (step) => {
|
|
19726
|
-
const card = el2(doc, "article", "knobs-wt-step knobs-surface");
|
|
20740
|
+
const stepView = (step, group) => {
|
|
20741
|
+
const card = el2(doc, "article", options.cards ? "knobs-wt-step knobs-surface" : "knobs-wt-step");
|
|
19727
20742
|
card.id = `wt-${step.key.replace("/", "--")}`;
|
|
19728
20743
|
card.tabIndex = -1;
|
|
19729
20744
|
card.dataset.key = step.key;
|
|
19730
|
-
card.setAttribute("aria-label",
|
|
20745
|
+
card.setAttribute("aria-label", plainMarkdown(step.title));
|
|
19731
20746
|
const head = el2(doc, "header", "knobs-wt-step-head");
|
|
19732
|
-
const num = el2(doc, "span", "knobs-wt-num");
|
|
19733
|
-
num.textContent = step.number;
|
|
19734
20747
|
const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
|
|
19735
|
-
h3.
|
|
19736
|
-
head.append(
|
|
19737
|
-
card.append(head);
|
|
20748
|
+
h3.innerHTML = inlineMarkdown(step.title);
|
|
20749
|
+
head.append(h3);
|
|
19738
20750
|
if (step.caption)
|
|
19739
|
-
|
|
20751
|
+
head.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
|
|
20752
|
+
if (step.more)
|
|
20753
|
+
head.append(more(step.more));
|
|
20754
|
+
card.append(head);
|
|
19740
20755
|
const slots = [];
|
|
19741
20756
|
const onEvent = (e) => record({ ...e, step: step.key });
|
|
19742
20757
|
let media = null;
|
|
19743
20758
|
if (step.media.length) {
|
|
19744
20759
|
media = el2(doc, "div", "knobs-wt-media");
|
|
19745
|
-
media.style.setProperty("--kw-n", String(Math.min(step.media.length,
|
|
20760
|
+
media.style.setProperty("--kw-n", String(Math.min(step.media.length, step.columns)));
|
|
19746
20761
|
for (const m of step.media)
|
|
19747
20762
|
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
19748
20763
|
card.append(media);
|
|
19749
20764
|
}
|
|
19750
20765
|
let taste = null;
|
|
19751
|
-
if (step.question)
|
|
20766
|
+
if (step.question && review)
|
|
19752
20767
|
card.append(prose2(doc, "p", "knobs-wt-question", step.question));
|
|
19753
20768
|
if (step.ask === "pick") {
|
|
19754
20769
|
taste = tasteTest(card, {
|
|
19755
20770
|
...look,
|
|
20771
|
+
pickable: review,
|
|
19756
20772
|
options: step.options,
|
|
19757
20773
|
picked: state.steps[step.key]?.pick ?? null,
|
|
19758
20774
|
onPick: (id) => pick(step.key, id),
|
|
@@ -19761,7 +20777,8 @@ function walkthrough(container, options) {
|
|
|
19761
20777
|
media ??= taste.element;
|
|
19762
20778
|
}
|
|
19763
20779
|
const notes = el2(doc, "div", "knobs-wt-notes");
|
|
19764
|
-
|
|
20780
|
+
if (review)
|
|
20781
|
+
card.append(notes);
|
|
19765
20782
|
card.addEventListener("focusin", () => {
|
|
19766
20783
|
if (scroll.to)
|
|
19767
20784
|
return;
|
|
@@ -19770,16 +20787,13 @@ function walkthrough(container, options) {
|
|
|
19770
20787
|
});
|
|
19771
20788
|
let toc = null;
|
|
19772
20789
|
let glyph = null;
|
|
19773
|
-
if (
|
|
19774
|
-
toc =
|
|
19775
|
-
|
|
19776
|
-
|
|
19777
|
-
|
|
19778
|
-
|
|
19779
|
-
toc
|
|
19780
|
-
toc.append(glyph, label);
|
|
19781
|
-
toc.addEventListener("click", () => go(step.key));
|
|
19782
|
-
tocEl.append(toc);
|
|
20790
|
+
if (group) {
|
|
20791
|
+
toc = tocRow(plainMarkdown(step.title), true, () => go(step.key));
|
|
20792
|
+
if (review) {
|
|
20793
|
+
glyph = el2(doc, "span", "knobs-wt-toc-glyph");
|
|
20794
|
+
toc.querySelector(".knobs-wt-toc-end").append(glyph);
|
|
20795
|
+
}
|
|
20796
|
+
group.append(toc);
|
|
19783
20797
|
}
|
|
19784
20798
|
return { step, card, media, notes, toc, glyph, taste, slots };
|
|
19785
20799
|
};
|
|
@@ -19838,19 +20852,25 @@ function walkthrough(container, options) {
|
|
|
19838
20852
|
setFull(false);
|
|
19839
20853
|
return go(next);
|
|
19840
20854
|
}
|
|
20855
|
+
if ((key === "Home" || key === "End") && views.length) {
|
|
20856
|
+
claim();
|
|
20857
|
+
if (full)
|
|
20858
|
+
setFull(false);
|
|
20859
|
+
return go(views[key === "Home" ? 0 : views.length - 1].step.key);
|
|
20860
|
+
}
|
|
19841
20861
|
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
19842
20862
|
const d = (key === "ArrowLeft" ? -1 : 1) * (e.shiftKey ? 2 : 0.5);
|
|
19843
20863
|
if (seekBy(d))
|
|
19844
20864
|
claim();
|
|
19845
20865
|
return;
|
|
19846
20866
|
}
|
|
19847
|
-
if (key === "n") {
|
|
20867
|
+
if (key === "n" && noteMode !== "hidden") {
|
|
19848
20868
|
claim();
|
|
19849
|
-
bar.
|
|
20869
|
+
bar.setOpen(true, true);
|
|
19850
20870
|
return;
|
|
19851
20871
|
}
|
|
19852
20872
|
const v = viewOf(current);
|
|
19853
|
-
if (!v || e.shiftKey)
|
|
20873
|
+
if (!v || e.shiftKey || !review)
|
|
19854
20874
|
return;
|
|
19855
20875
|
const choice = digitChoice(v.step, state.steps[v.step.key], key);
|
|
19856
20876
|
if (choice === undefined)
|
|
@@ -19925,6 +20945,12 @@ function walkthrough(container, options) {
|
|
|
19925
20945
|
win.removeEventListener(type, stopScroll);
|
|
19926
20946
|
doc.removeEventListener("keydown", onKey);
|
|
19927
20947
|
unregisterHints();
|
|
20948
|
+
bar.unobserve();
|
|
20949
|
+
pill?.dispose();
|
|
20950
|
+
for (const d of discs)
|
|
20951
|
+
d.dispose();
|
|
20952
|
+
if (padded)
|
|
20953
|
+
padded.el.style.scrollPaddingBottom = padded.was;
|
|
19928
20954
|
for (const v of views) {
|
|
19929
20955
|
v.slots.forEach((s) => s.dispose());
|
|
19930
20956
|
v.taste?.dispose();
|