@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-react.js
CHANGED
|
@@ -596,6 +596,8 @@ var compareCss = `
|
|
|
596
596
|
.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}
|
|
597
597
|
.knobs-compare[data-frame="flat"] .knobs-cmp-stage{border-radius:0}
|
|
598
598
|
.knobs-compare[data-mode="wipe"] .knobs-cmp-stage{cursor:ew-resize}
|
|
599
|
+
/* Videos: a click on the stage plays and pauses. */
|
|
600
|
+
.knobs-compare[data-video]:not([data-mode="wipe"],[data-zoomed]) .knobs-cmp-stage{cursor:pointer}
|
|
599
601
|
/* Unzoomed, a finger still scrolls the page up and down; zoomed, the stage takes every gesture. */
|
|
600
602
|
.knobs-compare[data-zoomed] .knobs-cmp-stage{cursor:grab;touch-action:none}
|
|
601
603
|
.knobs-compare[data-panning],.knobs-compare[data-panning] *{cursor:grabbing!important}
|
|
@@ -605,14 +607,28 @@ var compareCss = `
|
|
|
605
607
|
.knobs-cmp-canvas{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}
|
|
606
608
|
.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}
|
|
607
609
|
.knobs-compare[data-renderer="gpu"] .knobs-cmp-media{opacity:0}
|
|
610
|
+
/* The media comes in with its first frames: a fade and a 4px blur on the default spring. */
|
|
611
|
+
.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)}
|
|
612
|
+
.knobs-compare:not([data-ready]) :is(.knobs-cmp-canvas,.knobs-cmp-media){opacity:0;filter:blur(4px)}
|
|
608
613
|
/* Glass: what's behind shows through, blurred, on the knobs tokens. */
|
|
609
614
|
.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);
|
|
610
615
|
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)))}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
.knobs-cmp-
|
|
615
|
-
.knobs-cmp-
|
|
616
|
+
/* ✗ Before · ✓ After: Before quieter (fg-3), After in full text. Neutral: no colour of its own. */
|
|
617
|
+
.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);
|
|
618
|
+
white-space:nowrap;pointer-events:none;will-change:transform}
|
|
619
|
+
.knobs-cmp-label[data-side="before"]{color:var(--_k-fg-3)}
|
|
620
|
+
.knobs-cmp-label[data-side="after"]{color:var(--_k-fg)}
|
|
621
|
+
/* Fusing, the mark folds away and the label is its name. */
|
|
622
|
+
.knobs-cmp-mark{flex:none;display:flex;justify-content:flex-end;overflow:hidden}
|
|
623
|
+
.knobs-cmp-mark svg{display:block;flex:none;width:12px;height:12px}
|
|
624
|
+
/* The fuse's seam: a blurred strip over where the sides meet, soft at both sides. */
|
|
625
|
+
.knobs-cmp-seam{position:absolute;left:0;top:0;width:8px;height:0;opacity:0;pointer-events:none;will-change:transform,opacity;
|
|
626
|
+
-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)}
|
|
627
|
+
/* The wipe: a hairline down the line with a raised grip in its middle (at the pointer's height
|
|
628
|
+
while dragged); a wider strip takes the hand and the keys (a slider). It fades in with the
|
|
629
|
+
fuse; wiping, line and grip brighten. */
|
|
630
|
+
.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}
|
|
631
|
+
.knobs-cmp-handle[data-on]{pointer-events:auto}
|
|
616
632
|
.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)}
|
|
617
633
|
.knobs-compare[data-dragging] .knobs-cmp-handle::before{background:var(--_ku-cmp-line)}
|
|
618
634
|
.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);
|
|
@@ -644,6 +660,27 @@ var compareCss = `
|
|
|
644
660
|
@media(prefers-reduced-motion:reduce){:is(.knobs-compare,.knobs-cmp-strip) :where(*,::before,::after){transition-duration:.12s!important}}
|
|
645
661
|
`;
|
|
646
662
|
|
|
663
|
+
// src/ui/player-css.ts
|
|
664
|
+
var playerCss = `
|
|
665
|
+
:where(.knobs-player,.knobs-player *){box-sizing:border-box}
|
|
666
|
+
.knobs-ui.knobs-player{--_kp-stage:var(--_k-compare-stage);display:flex;flex-direction:column;gap:6px;width:100%;outline:none;
|
|
667
|
+
font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
|
|
668
|
+
: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)}
|
|
669
|
+
.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}
|
|
670
|
+
.knobs-player[data-frame="flat"] .knobs-player-frame{border-radius:0}
|
|
671
|
+
.knobs-player-media{position:absolute;inset:0;display:block;width:100%;height:100%;margin:0;padding:0;border:0;object-fit:contain;
|
|
672
|
+
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)}
|
|
673
|
+
.knobs-player[data-ready] .knobs-player-media{opacity:1;filter:none}
|
|
674
|
+
.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;
|
|
675
|
+
opacity:0;filter:blur(4px);scale:.96;
|
|
676
|
+
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);
|
|
677
|
+
box-shadow:inset 0 0 0 .5px var(--_k-border),inset 0 1px 0 var(--_k-rim);
|
|
678
|
+
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)}
|
|
679
|
+
.knobs-player-glyph svg{width:16px;height:16px}
|
|
680
|
+
.knobs-player-glyph[data-flash]{opacity:1;filter:none;scale:1}
|
|
681
|
+
.knobs-player-line{flex:none;min-height:0}
|
|
682
|
+
`;
|
|
683
|
+
|
|
647
684
|
// src/ui/overlay-css.ts
|
|
648
685
|
var overlayCss = `
|
|
649
686
|
.knobs-layers{position:fixed;inset:0;z-index:2147480005;pointer-events:none}
|
|
@@ -1332,6 +1369,22 @@ var init_schema = __esm(() => {
|
|
|
1332
1369
|
source: css("var(--k-warn)"),
|
|
1333
1370
|
doc: "Modified lines."
|
|
1334
1371
|
},
|
|
1372
|
+
{
|
|
1373
|
+
name: "before",
|
|
1374
|
+
tier: "semantic",
|
|
1375
|
+
type: "color",
|
|
1376
|
+
group: "Data",
|
|
1377
|
+
source: css("var(--k-fg-3)"),
|
|
1378
|
+
doc: "Before in a comparison, and only Before: its label and side of the seam. Neutral unless a theme gives it a colour."
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
name: "after",
|
|
1382
|
+
tier: "semantic",
|
|
1383
|
+
type: "color",
|
|
1384
|
+
group: "Data",
|
|
1385
|
+
source: css("var(--k-fg)"),
|
|
1386
|
+
doc: "After in a comparison, and only After."
|
|
1387
|
+
},
|
|
1335
1388
|
{
|
|
1336
1389
|
name: "series-1",
|
|
1337
1390
|
tier: "semantic",
|
|
@@ -1422,6 +1475,150 @@ var init_schema = __esm(() => {
|
|
|
1422
1475
|
source: value("288px"),
|
|
1423
1476
|
doc: "Panel width."
|
|
1424
1477
|
},
|
|
1478
|
+
{
|
|
1479
|
+
name: "space-inside",
|
|
1480
|
+
tier: "semantic",
|
|
1481
|
+
type: "length",
|
|
1482
|
+
group: "Space",
|
|
1483
|
+
source: css("var(--k-unit)"),
|
|
1484
|
+
doc: "Parts of one thing: an icon and its label, a meta line and its title."
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
name: "space-sibling",
|
|
1488
|
+
tier: "semantic",
|
|
1489
|
+
type: "length",
|
|
1490
|
+
group: "Space",
|
|
1491
|
+
source: css("calc(var(--k-unit) * 2)"),
|
|
1492
|
+
doc: "Siblings in a group: buttons in a row, a list item's lines."
|
|
1493
|
+
},
|
|
1494
|
+
{
|
|
1495
|
+
name: "space-title",
|
|
1496
|
+
tier: "semantic",
|
|
1497
|
+
type: "length",
|
|
1498
|
+
group: "Space",
|
|
1499
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1500
|
+
doc: "A heading and what it heads."
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
name: "space-group",
|
|
1504
|
+
tier: "semantic",
|
|
1505
|
+
type: "length",
|
|
1506
|
+
group: "Space",
|
|
1507
|
+
source: css("calc(var(--k-unit) * 12)"),
|
|
1508
|
+
doc: "Groups inside a section (prose, video, diff), stacked media, feed items (a hairline in the middle)."
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
name: "space-section",
|
|
1512
|
+
tier: "semantic",
|
|
1513
|
+
type: "length",
|
|
1514
|
+
group: "Space",
|
|
1515
|
+
source: css("calc(var(--k-unit) * 24)"),
|
|
1516
|
+
doc: "Sections of a page (the intro, the updates, each PR), a hairline in the middle."
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
name: "space-column",
|
|
1520
|
+
tier: "semantic",
|
|
1521
|
+
type: "length",
|
|
1522
|
+
group: "Space",
|
|
1523
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1524
|
+
doc: "Columns: a contents rail and the page, media side by side."
|
|
1525
|
+
},
|
|
1526
|
+
{
|
|
1527
|
+
name: "pad-page",
|
|
1528
|
+
tier: "semantic",
|
|
1529
|
+
type: "length",
|
|
1530
|
+
group: "Space",
|
|
1531
|
+
source: css("calc(var(--k-unit) * 6)"),
|
|
1532
|
+
doc: "A page's edge; 16px under 640px wide."
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
name: "pad-card",
|
|
1536
|
+
tier: "semantic",
|
|
1537
|
+
type: "length",
|
|
1538
|
+
group: "Space",
|
|
1539
|
+
source: css("calc(var(--k-unit) * 3)"),
|
|
1540
|
+
doc: "Inside a card or popover."
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
name: "type-heading",
|
|
1544
|
+
tier: "semantic",
|
|
1545
|
+
type: "length",
|
|
1546
|
+
group: "Type",
|
|
1547
|
+
source: value("20px"),
|
|
1548
|
+
doc: "A page's title, weight 500."
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
name: "leading-heading",
|
|
1552
|
+
tier: "semantic",
|
|
1553
|
+
type: "length",
|
|
1554
|
+
group: "Type",
|
|
1555
|
+
source: value("28px"),
|
|
1556
|
+
doc: "Line height for type-heading."
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
name: "type-title",
|
|
1560
|
+
tier: "semantic",
|
|
1561
|
+
type: "length",
|
|
1562
|
+
group: "Type",
|
|
1563
|
+
source: value("16px"),
|
|
1564
|
+
doc: "Section titles (under their kicker), weight 500."
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
name: "leading-title",
|
|
1568
|
+
tier: "semantic",
|
|
1569
|
+
type: "length",
|
|
1570
|
+
group: "Type",
|
|
1571
|
+
source: value("24px"),
|
|
1572
|
+
doc: "Line height for type-title."
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
name: "type-body",
|
|
1576
|
+
tier: "semantic",
|
|
1577
|
+
type: "length",
|
|
1578
|
+
group: "Type",
|
|
1579
|
+
source: value("13px"),
|
|
1580
|
+
doc: "Prose, questions, list rows, step titles; 400, or 500 for emphasis."
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
name: "leading-body",
|
|
1584
|
+
tier: "semantic",
|
|
1585
|
+
type: "length",
|
|
1586
|
+
group: "Type",
|
|
1587
|
+
source: value("20px"),
|
|
1588
|
+
doc: "Line height for type-body."
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
name: "type-label",
|
|
1592
|
+
tier: "semantic",
|
|
1593
|
+
type: "length",
|
|
1594
|
+
group: "Type",
|
|
1595
|
+
source: value("12px"),
|
|
1596
|
+
doc: "Mono inside body text: code and paths."
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
name: "leading-label",
|
|
1600
|
+
tier: "semantic",
|
|
1601
|
+
type: "length",
|
|
1602
|
+
group: "Type",
|
|
1603
|
+
source: value("16px"),
|
|
1604
|
+
doc: "Line height for type-label."
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
name: "type-small",
|
|
1608
|
+
tier: "semantic",
|
|
1609
|
+
type: "length",
|
|
1610
|
+
group: "Type",
|
|
1611
|
+
source: value("11px"),
|
|
1612
|
+
doc: "Meta, controls, keys, timestamps; mono inside labels."
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
name: "leading-small",
|
|
1616
|
+
tier: "semantic",
|
|
1617
|
+
type: "length",
|
|
1618
|
+
group: "Type",
|
|
1619
|
+
source: value("16px"),
|
|
1620
|
+
doc: "Line height for type-small."
|
|
1621
|
+
},
|
|
1425
1622
|
{
|
|
1426
1623
|
name: "font-size",
|
|
1427
1624
|
tier: "semantic",
|
|
@@ -2386,16 +2583,18 @@ function injectTokens(doc) {
|
|
|
2386
2583
|
style.textContent = rootCss;
|
|
2387
2584
|
doc.head.append(style);
|
|
2388
2585
|
}
|
|
2389
|
-
var ROOT_CLASS = "knobs-root", extras, spring, rootCss;
|
|
2586
|
+
var ROOT_CLASS = "knobs-root", extras, narrow, spring, rootCss;
|
|
2390
2587
|
var init_root = __esm(() => {
|
|
2391
2588
|
init_knobs();
|
|
2392
2589
|
init_css();
|
|
2393
2590
|
init_glide();
|
|
2394
2591
|
init_motion();
|
|
2395
2592
|
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))}`;
|
|
2593
|
+
narrow = `@media(max-width:639.98px){:where(.${ROOT_CLASS}){--_k-pad-page:var(--k-pad-page,calc(var(--_k-unit) * 4))}}`;
|
|
2396
2594
|
spring = `:where(:root,:host){--k-fill-ease:${DEFAULT_LINEAR.easing};--k-fill-ms:${DEFAULT_LINEAR.ms}}`;
|
|
2397
2595
|
rootCss = `${tokensCss(knobs)}
|
|
2398
2596
|
${extras}
|
|
2597
|
+
${narrow}
|
|
2399
2598
|
${spring}
|
|
2400
2599
|
${DRIVERS}
|
|
2401
2600
|
${motionCss}`;
|
|
@@ -2606,6 +2805,12 @@ var css2 = `
|
|
|
2606
2805
|
--_ku-pane-bg and --_ku-pane-ring so this reaches them. */
|
|
2607
2806
|
: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;
|
|
2608
2807
|
--_ku-divider:var(--_k-split-gutter);--_kd-bg:transparent}
|
|
2808
|
+
/* What draws its box without those: a picker's card keeps its fill as the highlight but drops its
|
|
2809
|
+
ring; a timeline's track drops its well for a hairline under the lane; an inline panel sheds its
|
|
2810
|
+
card (--k-chrome 0). A full-window step is the one raised exception (it is the surface). */
|
|
2811
|
+
:is(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-picker-card,.knobs-ui[data-nested] .knobs-picker-card{box-shadow:none}
|
|
2812
|
+
: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)}
|
|
2813
|
+
:where(.knobs-surface,.knobs-pane:not([data-nested])>.knobs-pane-clip) .knobs-panel.knobs-inline:not(.knobs-page){--k-chrome:0}
|
|
2609
2814
|
/* Only the pieces' own elements take their type and resets: what you put in a pane is yours. */
|
|
2610
2815
|
.knobs-ui{box-sizing:border-box}
|
|
2611
2816
|
: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}
|
|
@@ -2831,8 +3036,6 @@ var css2 = `
|
|
|
2831
3036
|
.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}
|
|
2832
3037
|
.knobs-tl-track:hover .knobs-tl-hover{opacity:1}
|
|
2833
3038
|
.knobs-timeline[data-scrubbing] .knobs-tl-hover{opacity:0}
|
|
2834
|
-
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
2835
|
-
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
2836
3039
|
.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}
|
|
2837
3040
|
.knobs-tl-tag[data-on]{opacity:1}
|
|
2838
3041
|
/* The lane (variant: "lane"): one slim track of ticks under a compare or a video; markers are
|
|
@@ -2848,7 +3051,26 @@ var css2 = `
|
|
|
2848
3051
|
.knobs-timeline[data-variant="lane"] .knobs-tl-head::before{top:0}
|
|
2849
3052
|
.knobs-timeline[data-variant="lane"] .knobs-tl-head::after{content:none}
|
|
2850
3053
|
.knobs-timeline[data-variant="lane"] .knobs-tl-tag{top:2px;bottom:auto}
|
|
2851
|
-
|
|
3054
|
+
/* The line (variant: "line"): a player's progress under its media. One 2px line, fg-3 with fg
|
|
3055
|
+
filling it, a segment per chapter; it thickens under the pointer and while scrubbing. The
|
|
3056
|
+
chapter and time under the pointer float over it; nothing else shows. */
|
|
3057
|
+
.knobs-ui.knobs-timeline[data-variant="line"]{height:auto;min-height:0;padding:0;gap:0}
|
|
3058
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-transport{display:none}
|
|
3059
|
+
.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}
|
|
3060
|
+
.knobs-timeline[data-variant="line"] :is(.knobs-tl-ruler,.knobs-tl-lane,.knobs-tl-hover,.knobs-tl-head,.knobs-tl-rlabel){display:none}
|
|
3061
|
+
.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)}
|
|
3062
|
+
.knobs-tl-seg{position:absolute;left:0;top:0;height:100%;overflow:hidden;border-radius:1px;background:var(--_k-fg-3);will-change:transform}
|
|
3063
|
+
.knobs-tl-seg-fill{position:absolute;inset:0;background:var(--_k-fg);transform-origin:0 0;will-change:transform}
|
|
3064
|
+
.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}
|
|
3065
|
+
.knobs-timeline[data-variant="line"] .knobs-tl-range{top:3px;bottom:3px;border-radius:3px}
|
|
3066
|
+
.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)}
|
|
3067
|
+
.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);
|
|
3068
|
+
-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:inset 0 0 0 .5px var(--_k-border)}
|
|
3069
|
+
.knobs-tl-tag-label{color:var(--_k-fg-2)}
|
|
3070
|
+
.knobs-tl-tag-label:empty{display:none}
|
|
3071
|
+
@media(prefers-reduced-motion:reduce){.knobs-timeline :where(*,::before,::after){transition:none!important}}
|
|
3072
|
+
@media(prefers-reduced-motion:reduce){:is(.knobs-tree,.knobs-split>.knobs-divider,.knobs-pane-head,.knobs-pane-rail) :where(*,::before,::after){transition:none!important}}
|
|
3073
|
+
`, uiCss = () => aliased(css2 + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + compareCss + playerCss + selectionPillCss) + rolling_css_default, lookDefaults, tune = (s, m) => {
|
|
2852
3074
|
s.omega = m.omega;
|
|
2853
3075
|
s.zeta = m.zeta;
|
|
2854
3076
|
return s;
|
|
@@ -2971,19 +3193,19 @@ var init_diff_css = __esm(() => {
|
|
|
2971
3193
|
@property --kd-fb{syntax:"<length>";inherits:false;initial-value:0px}
|
|
2972
3194
|
: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))}
|
|
2973
3195
|
:where(.knobs-diff,.knobs-diff *,.knobs-diff-files,.knobs-diff-files *){box-sizing:border-box}
|
|
2974
|
-
.knobs-ui.knobs-diff{--kd-bg:var(--k-diff-bg,var(--_kd-bg,
|
|
3196
|
+
.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);
|
|
2975
3197
|
--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);
|
|
2976
3198
|
--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;
|
|
2977
3199
|
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;
|
|
2978
3200
|
letter-spacing:normal;word-spacing:normal;text-transform:none;-webkit-font-smoothing:antialiased}
|
|
2979
3201
|
.knobs-ui.knobs-diff[data-height="auto"]{height:auto}
|
|
2980
|
-
.knobs-diff::after{content:"";position:absolute;inset:0;z-index:3;
|
|
3202
|
+
.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}
|
|
2981
3203
|
.knobs-diff [hidden],.knobs-diff-files [hidden]{display:none!important}
|
|
2982
3204
|
.knobs-diff svg{display:block;flex:none}
|
|
2983
|
-
.knobs-ui.knobs-diff[data-on="
|
|
2984
|
-
/*
|
|
3205
|
+
.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)}
|
|
3206
|
+
/* A hairline under the header, firmer once the code has scrolled under it. */
|
|
2985
3207
|
.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);
|
|
2986
|
-
box-shadow:inset 0 -1px
|
|
3208
|
+
box-shadow:inset 0 -1px var(--_k-border-subtle);transition:box-shadow .15s;user-select:none;-webkit-user-select:none}
|
|
2987
3209
|
.knobs-diff[data-scrolled]>.knobs-diff-head{box-shadow:inset 0 -1px var(--_k-border)}
|
|
2988
3210
|
.knobs-diff-path{flex:0 1 auto;min-width:0;overflow:hidden;white-space:nowrap}
|
|
2989
3211
|
.knobs-diff-dir,.knobs-diff-from{color:var(--_k-fg-3)}
|
|
@@ -3021,6 +3243,15 @@ var init_diff_css = __esm(() => {
|
|
|
3021
3243
|
.knobs-ui .knobs-diff-viewed[aria-pressed="true"]{color:var(--_k-fg);background:var(--_ku-wash)}
|
|
3022
3244
|
.knobs-diff-viewed svg{width:16px;height:16px}
|
|
3023
3245
|
.knobs-diff-viewed[aria-pressed="true"] svg{color:var(--kd-add)}
|
|
3246
|
+
/* Narrow, the header gives up words before anything is cut off at its end: Viewed keeps its
|
|
3247
|
+
check, then the counts' bar goes, then the counts; the path fades at its end throughout. */
|
|
3248
|
+
.knobs-diff-head,.knobs-diff-part-head{container-type:inline-size}
|
|
3249
|
+
@container (max-width:520px){
|
|
3250
|
+
.knobs-diff-viewed-label{display:none}
|
|
3251
|
+
.knobs-ui .knobs-diff-viewed{width:var(--_k-control-h);padding:0;justify-content:center}
|
|
3252
|
+
.knobs-diff-counts .knobs-diff-bar{display:none}
|
|
3253
|
+
}
|
|
3254
|
+
@container (max-width:400px){.knobs-diff-counts{display:none}.knobs-diff-nav>span{min-width:2.6em}}
|
|
3024
3255
|
.knobs-diff-path{transition:opacity .2s}
|
|
3025
3256
|
.knobs-diff[data-viewed]>.knobs-diff-head .knobs-diff-path,.knobs-diff-part[data-viewed] .knobs-diff-path{opacity:.6}
|
|
3026
3257
|
/* Split | Unified: the selection pill on the one picked, its bright copy the picked one's text; a
|
|
@@ -3085,24 +3316,26 @@ var init_diff_css = __esm(() => {
|
|
|
3085
3316
|
--diffs-bg-deletion-number-override:color-mix(in srgb,var(--kd-del) 55%,var(--kd-solid));
|
|
3086
3317
|
--diffs-bg-addition-emphasis-override:color-mix(in srgb,var(--kd-add) 22%,transparent);
|
|
3087
3318
|
--diffs-bg-deletion-emphasis-override:color-mix(in srgb,var(--kd-del) 22%,transparent);
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
--diffs-bg-
|
|
3319
|
+
/* Unchanged lines and the folds between hunks sit on the void; only a split's missing lines
|
|
3320
|
+
are faintly filled. */
|
|
3321
|
+
--diffs-bg-separator-override:var(--kd-solid);
|
|
3322
|
+
--diffs-bg-context-override:var(--kd-solid);
|
|
3323
|
+
--diffs-bg-buffer-override:color-mix(in srgb,var(--_k-fg) 2.5%,var(--kd-solid));
|
|
3091
3324
|
--diffs-bg-selection-override:var(--_k-accent);
|
|
3092
3325
|
--diffs-fg-number-override:var(--_k-fg-3);
|
|
3093
3326
|
}
|
|
3094
|
-
/* diffReview
|
|
3095
|
-
is pinned to its right edge, so it slides out from under the diff), parted
|
|
3096
|
-
|
|
3097
|
-
.knobs-ui.knobs-diff-review{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
3327
|
+
/* diffReview, on the void as the diff is: the file list a drawer at its left (its width springs;
|
|
3328
|
+
the list inside is pinned to its right edge, so it slides out from under the diff), parted
|
|
3329
|
+
from the diff by a hairline; one hairline runs under both headers and one under it all. */
|
|
3330
|
+
.knobs-ui.knobs-diff-review{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden;
|
|
3098
3331
|
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}
|
|
3099
|
-
.knobs-diff-review::after{content:"";position:absolute;inset:0;z-index:5;
|
|
3332
|
+
.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}
|
|
3100
3333
|
:where(.knobs-diff-review,.knobs-diff-review *){box-sizing:border-box}
|
|
3101
|
-
.knobs-diff-drawer{position:relative;flex:none;width:0;height:100%;overflow:hidden;box-shadow:inset -1px 0 var(--_k-border)}
|
|
3334
|
+
.knobs-diff-drawer{position:relative;flex:none;width:0;height:100%;overflow:hidden;box-shadow:inset -1px 0 var(--_k-border-subtle)}
|
|
3102
3335
|
.knobs-diff-drawer[data-shut]{visibility:hidden}
|
|
3103
3336
|
.knobs-diff-drawer-in{position:absolute;top:0;bottom:0;right:0;display:flex;flex-direction:column}
|
|
3104
3337
|
.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);
|
|
3105
|
-
user-select:none;-webkit-user-select:none}
|
|
3338
|
+
box-shadow:inset 0 -1px var(--_k-border-subtle);user-select:none;-webkit-user-select:none}
|
|
3106
3339
|
.knobs-diff-drawer-title{font-weight:var(--_k-weight-title)}
|
|
3107
3340
|
.knobs-diff-drawer-count{color:var(--_k-fg-3);font-size:var(--_k-text-meta);font-variant-numeric:tabular-nums}
|
|
3108
3341
|
.knobs-diff-drawer-in>.knobs-diff-files{flex:1;min-height:0;height:auto}
|
|
@@ -3114,10 +3347,11 @@ var init_diff_css = __esm(() => {
|
|
|
3114
3347
|
.knobs-ui .knobs-diff-toggle[aria-pressed]:not(:hover,:focus-visible){background:transparent}
|
|
3115
3348
|
/* diffReview's file list: a filter over a compact tree, a status letter, the counts and their
|
|
3116
3349
|
bar on each file; one highlight glides to the file on show. Viewed files dim, with a tick. */
|
|
3117
|
-
.knobs-diff-files{--k-row:var(--k-diff-row,28px);display:flex;flex-direction:column;height:100%;min-height:0;padding-top:
|
|
3350
|
+
.knobs-diff-files{--k-row:var(--k-diff-row,28px);display:flex;flex-direction:column;height:100%;min-height:0;padding-top:4px}
|
|
3118
3351
|
.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;
|
|
3119
|
-
border-radius:max(6px,var(--_ku-row-radius));
|
|
3120
|
-
|
|
3352
|
+
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}
|
|
3353
|
+
/* The filter is a line of text, no box; focused, a hairline ring. */
|
|
3354
|
+
.knobs-diff-filter:focus-within{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_k-accent) 45%,transparent)}
|
|
3121
3355
|
.knobs-diff-filter svg{width:12px;height:12px;flex:none}
|
|
3122
3356
|
.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}
|
|
3123
3357
|
.knobs-ui .knobs-diff-filter>input::placeholder{color:var(--_k-fg-3)}
|
|
@@ -6042,7 +6276,10 @@ function codeDiff(container, options) {
|
|
|
6042
6276
|
const viewedToggle = () => {
|
|
6043
6277
|
const b = make("button", "knobs-diff-viewed");
|
|
6044
6278
|
b.type = "button";
|
|
6045
|
-
|
|
6279
|
+
const label = make("span", "knobs-diff-viewed-label");
|
|
6280
|
+
label.textContent = "Viewed";
|
|
6281
|
+
b.append(make("span", ""), label);
|
|
6282
|
+
b.setAttribute("aria-label", "Viewed");
|
|
6046
6283
|
return b;
|
|
6047
6284
|
};
|
|
6048
6285
|
const paintViewed = (b, on) => {
|
|
@@ -8329,6 +8566,17 @@ function currentMarker(markers, t, fps) {
|
|
|
8329
8566
|
best = m;
|
|
8330
8567
|
return best;
|
|
8331
8568
|
}
|
|
8569
|
+
function minutes(t) {
|
|
8570
|
+
const s = Math.max(0, Math.floor(t + 0.000001));
|
|
8571
|
+
const h = Math.floor(s / 3600);
|
|
8572
|
+
const m = Math.floor(s % 3600 / 60);
|
|
8573
|
+
const ss = String(s % 60).padStart(2, "0");
|
|
8574
|
+
return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
8575
|
+
}
|
|
8576
|
+
function chapterBounds(times, duration) {
|
|
8577
|
+
const inside = times.filter((t) => t > 0.000001 && t < duration - 0.000001);
|
|
8578
|
+
return [0, ...[...new Set(inside)].sort((a, b) => a - b), duration];
|
|
8579
|
+
}
|
|
8332
8580
|
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;
|
|
8333
8581
|
var init_timeline_model = __esm(() => {
|
|
8334
8582
|
SECOND_STEPS = [0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600];
|
|
@@ -8346,7 +8594,8 @@ function timeline(container, options) {
|
|
|
8346
8594
|
let speed = options.speed ?? 1;
|
|
8347
8595
|
let repeat = options.repeat ?? true;
|
|
8348
8596
|
const arrows = options.arrows ?? "frames";
|
|
8349
|
-
const
|
|
8597
|
+
const line = options.variant === "line";
|
|
8598
|
+
const lane = line || options.variant === "lane";
|
|
8350
8599
|
let time = Math.min(duration, Math.max(0, options.time ?? 0));
|
|
8351
8600
|
let playing = false;
|
|
8352
8601
|
let markers = [...options.markers ?? []];
|
|
@@ -8381,7 +8630,7 @@ function timeline(container, options) {
|
|
|
8381
8630
|
root.setAttribute("aria-keyshortcuts", "Space ArrowLeft ArrowRight , . Home End [ ] I O M");
|
|
8382
8631
|
applyLook2(root, options);
|
|
8383
8632
|
if (lane)
|
|
8384
|
-
root.dataset.variant = "lane";
|
|
8633
|
+
root.dataset.variant = line ? "line" : "lane";
|
|
8385
8634
|
const transport = el("div", "knobs-tl-transport");
|
|
8386
8635
|
const playBtn = el("button", "knobs-tl-play");
|
|
8387
8636
|
playBtn.type = "button";
|
|
@@ -8394,6 +8643,10 @@ function timeline(container, options) {
|
|
|
8394
8643
|
const hover = el("div", "knobs-tl-hover");
|
|
8395
8644
|
const tag = el("span", "knobs-tl-tag");
|
|
8396
8645
|
tag.setAttribute("aria-hidden", "true");
|
|
8646
|
+
const tagLabel = el("span", "knobs-tl-tag-label");
|
|
8647
|
+
const tagTime = el("span", "knobs-tl-tag-time");
|
|
8648
|
+
tag.append(tagLabel, tagTime);
|
|
8649
|
+
const segs = el("div", "knobs-tl-segs");
|
|
8397
8650
|
const head = el("div", "knobs-tl-head");
|
|
8398
8651
|
head.id = `${id}-head`;
|
|
8399
8652
|
head.setAttribute("role", "slider");
|
|
@@ -8401,11 +8654,13 @@ function timeline(container, options) {
|
|
|
8401
8654
|
head.setAttribute("aria-valuemin", "0");
|
|
8402
8655
|
head.setAttribute("aria-valuemax", String(duration));
|
|
8403
8656
|
track.append(canvas, markerLane, hover, head, tag);
|
|
8657
|
+
if (line)
|
|
8658
|
+
track.insertBefore(segs, markerLane);
|
|
8404
8659
|
root.append(transport, track);
|
|
8405
8660
|
container.append(root);
|
|
8406
8661
|
let width = 1;
|
|
8407
8662
|
let height = 1;
|
|
8408
|
-
const fitView = () => clampView({ start: 0, span: duration }, duration, { pad: 0.02 });
|
|
8663
|
+
const fitView = () => clampView({ start: 0, span: duration }, duration, { pad: line ? 0 : 0.02 });
|
|
8409
8664
|
let target = fitView();
|
|
8410
8665
|
const vStart = new Spring(target.start, INSTANT2.omega, 1, 0.00001);
|
|
8411
8666
|
const vSpan = new Spring(target.span, INSTANT2.omega, 1, 0.00001);
|
|
@@ -8414,13 +8669,13 @@ function timeline(container, options) {
|
|
|
8414
8669
|
const xOf = (t) => (t - vStart.x) * pxPerSec();
|
|
8415
8670
|
const tOf = (x) => vStart.x + x / pxPerSec();
|
|
8416
8671
|
const minSpan = () => Math.max(4 / fps, 0.05);
|
|
8417
|
-
const retarget = (next, motion = INSTANT2) => {
|
|
8418
|
-
target = clampView(next, duration, { pad: 0.04, minSpan: minSpan() });
|
|
8672
|
+
const retarget = (next, motion = INSTANT2, hand = false) => {
|
|
8673
|
+
target = clampView(next, duration, { pad: line ? 0 : 0.04, minSpan: minSpan() });
|
|
8419
8674
|
for (const s of [vStart, vSpan]) {
|
|
8420
8675
|
s.omega = motion.omega;
|
|
8421
8676
|
s.zeta = motion.zeta;
|
|
8422
8677
|
}
|
|
8423
|
-
if (reducedMotion(win) && motion === CALM) {
|
|
8678
|
+
if (hand || reducedMotion(win) && motion === CALM) {
|
|
8424
8679
|
vStart.snap(target.start);
|
|
8425
8680
|
vSpan.snap(target.span);
|
|
8426
8681
|
} else {
|
|
@@ -8446,6 +8701,8 @@ function timeline(container, options) {
|
|
|
8446
8701
|
};
|
|
8447
8702
|
let drawn = "";
|
|
8448
8703
|
const drawRuler = () => {
|
|
8704
|
+
if (line)
|
|
8705
|
+
return;
|
|
8449
8706
|
const v = view();
|
|
8450
8707
|
const key = `${v.start.toFixed(6)}:${v.span.toFixed(6)}:${width}:${height}:${units}:${fps}`;
|
|
8451
8708
|
if (key === drawn)
|
|
@@ -8533,6 +8790,8 @@ function timeline(container, options) {
|
|
|
8533
8790
|
n.title = `${m.label ? `${m.label} · ` : ""}${clock(m.time)}`;
|
|
8534
8791
|
}
|
|
8535
8792
|
placeMarkers();
|
|
8793
|
+
if (line)
|
|
8794
|
+
syncSegments();
|
|
8536
8795
|
};
|
|
8537
8796
|
const placeMarkers = () => {
|
|
8538
8797
|
for (const m of markers) {
|
|
@@ -8541,6 +8800,36 @@ function timeline(container, options) {
|
|
|
8541
8800
|
n.style.transform = `translateX(${xOf(m.time).toFixed(2)}px)`;
|
|
8542
8801
|
}
|
|
8543
8802
|
};
|
|
8803
|
+
let bounds = [];
|
|
8804
|
+
const segEls = [];
|
|
8805
|
+
const syncSegments = () => {
|
|
8806
|
+
bounds = chapterBounds(markers.map((m) => m.time), duration);
|
|
8807
|
+
while (segEls.length > bounds.length - 1)
|
|
8808
|
+
segEls.pop().el.remove();
|
|
8809
|
+
while (segEls.length < bounds.length - 1) {
|
|
8810
|
+
const n = el("i", "knobs-tl-seg");
|
|
8811
|
+
const fill = el("b", "knobs-tl-seg-fill");
|
|
8812
|
+
n.append(fill);
|
|
8813
|
+
segs.append(n);
|
|
8814
|
+
segEls.push({ el: n, fill });
|
|
8815
|
+
}
|
|
8816
|
+
placeSegments();
|
|
8817
|
+
};
|
|
8818
|
+
const placeSegments = () => {
|
|
8819
|
+
if (!line)
|
|
8820
|
+
return;
|
|
8821
|
+
const last = segEls.length - 1;
|
|
8822
|
+
segEls.forEach((s, i) => {
|
|
8823
|
+
const a = bounds[i];
|
|
8824
|
+
const b = bounds[i + 1];
|
|
8825
|
+
const x0 = xOf(a) + (i > 0 ? SEG_GAP / 2 : 0);
|
|
8826
|
+
const x1 = xOf(b) - (i < last ? SEG_GAP / 2 : 0);
|
|
8827
|
+
s.el.style.transform = `translateX(${x0.toFixed(2)}px)`;
|
|
8828
|
+
s.el.style.width = `${Math.max(0, x1 - x0).toFixed(2)}px`;
|
|
8829
|
+
const k = Math.min(1, Math.max(0, (shownHead - a) / Math.max(0.000000001, b - a)));
|
|
8830
|
+
s.fill.style.transform = `scaleX(${k.toFixed(4)})`;
|
|
8831
|
+
});
|
|
8832
|
+
};
|
|
8544
8833
|
const syncRanges = () => {
|
|
8545
8834
|
const keep = new Set(ranges.map((r) => r.id));
|
|
8546
8835
|
for (const [k, n] of rangeEls)
|
|
@@ -8557,7 +8846,7 @@ function timeline(container, options) {
|
|
|
8557
8846
|
b.dataset.edge = "end";
|
|
8558
8847
|
const label = el("span", "knobs-tl-rlabel");
|
|
8559
8848
|
n.append(label, a, b);
|
|
8560
|
-
track.insertBefore(n, markerLane);
|
|
8849
|
+
track.insertBefore(n, line ? segs : markerLane);
|
|
8561
8850
|
rangeEls.set(r.id, n);
|
|
8562
8851
|
if (built)
|
|
8563
8852
|
enter(n);
|
|
@@ -8609,6 +8898,7 @@ function timeline(container, options) {
|
|
|
8609
8898
|
let currentId = null;
|
|
8610
8899
|
const renderHead = () => {
|
|
8611
8900
|
head.style.transform = `translateX(${xOf(shownHead).toFixed(2)}px)`;
|
|
8901
|
+
placeSegments();
|
|
8612
8902
|
head.setAttribute("aria-valuenow", time.toFixed(3));
|
|
8613
8903
|
head.setAttribute("aria-valuetext", `${time.toFixed(2)} seconds, frame ${toFrame(time, fps)}`);
|
|
8614
8904
|
const cur = currentMarker(markers, time, fps)?.id ?? null;
|
|
@@ -8872,14 +9162,25 @@ function timeline(container, options) {
|
|
|
8872
9162
|
setTime(s.t, "scrub", s.shown, press);
|
|
8873
9163
|
root.toggleAttribute("data-stuck", s.stop !== null);
|
|
8874
9164
|
};
|
|
9165
|
+
let pointerX = null;
|
|
9166
|
+
const zoomAtHand = (factor) => zoom(factor, pointerX === null ? time : target.start + pointerX / width * target.span);
|
|
8875
9167
|
const showTag = (x) => {
|
|
8876
9168
|
const at = Math.min(duration, Math.max(0, tOf(x)));
|
|
8877
|
-
const text = `${at.toFixed(2)} s`;
|
|
8878
|
-
if (
|
|
8879
|
-
|
|
9169
|
+
const text = line ? minutes(at) : `${at.toFixed(2)} s`;
|
|
9170
|
+
if (tagTime.textContent !== text)
|
|
9171
|
+
tagTime.textContent = text;
|
|
9172
|
+
const label = line ? currentMarker(markers, at, fps)?.label ?? "" : "";
|
|
9173
|
+
if (tagLabel.textContent !== label)
|
|
9174
|
+
tagLabel.textContent = label;
|
|
8880
9175
|
const cx = Math.min(width, Math.max(0, x));
|
|
8881
|
-
|
|
8882
|
-
|
|
9176
|
+
if (line) {
|
|
9177
|
+
const w = tag.offsetWidth;
|
|
9178
|
+
const left = Math.min(Math.max(0, width - w), Math.max(0, cx - w / 2));
|
|
9179
|
+
tag.style.transform = `translateX(${left.toFixed(1)}px)`;
|
|
9180
|
+
} else {
|
|
9181
|
+
const flip = cx > width - tag.offsetWidth - 12;
|
|
9182
|
+
tag.style.transform = `translateX(${cx.toFixed(1)}px) translateX(${flip ? "calc(-100% - 4px)" : "4px"})`;
|
|
9183
|
+
}
|
|
8883
9184
|
tag.dataset.on = "";
|
|
8884
9185
|
};
|
|
8885
9186
|
const hideTag = () => delete tag.dataset.on;
|
|
@@ -8940,6 +9241,7 @@ function timeline(container, options) {
|
|
|
8940
9241
|
});
|
|
8941
9242
|
track.addEventListener("pointermove", (e) => {
|
|
8942
9243
|
const x = localX(e);
|
|
9244
|
+
pointerX = x;
|
|
8943
9245
|
hover.style.transform = `translateX(${x.toFixed(1)}px)`;
|
|
8944
9246
|
if (!drag || drag.kind === "scrub")
|
|
8945
9247
|
showTag(x);
|
|
@@ -9013,6 +9315,7 @@ function timeline(container, options) {
|
|
|
9013
9315
|
track.addEventListener("pointercancel", endDrag);
|
|
9014
9316
|
track.addEventListener("lostpointercapture", endDrag);
|
|
9015
9317
|
track.addEventListener("pointerleave", () => {
|
|
9318
|
+
pointerX = null;
|
|
9016
9319
|
if (drag)
|
|
9017
9320
|
return;
|
|
9018
9321
|
hover.style.transform = "translateX(-100px)";
|
|
@@ -9020,7 +9323,7 @@ function timeline(container, options) {
|
|
|
9020
9323
|
});
|
|
9021
9324
|
track.addEventListener("dblclick", (e) => {
|
|
9022
9325
|
if (lane)
|
|
9023
|
-
return;
|
|
9326
|
+
return fit();
|
|
9024
9327
|
const markerEl = e.target.closest(".knobs-tl-marker");
|
|
9025
9328
|
if (markerEl)
|
|
9026
9329
|
return rename(markerEl.dataset.id);
|
|
@@ -9031,18 +9334,40 @@ function timeline(container, options) {
|
|
|
9031
9334
|
rename(m.id);
|
|
9032
9335
|
});
|
|
9033
9336
|
track.addEventListener("wheel", (e) => {
|
|
9034
|
-
|
|
9337
|
+
const zooming = e.ctrlKey || e.metaKey;
|
|
9338
|
+
if (zooming && pinching)
|
|
9339
|
+
return e.preventDefault();
|
|
9340
|
+
const sideways = Math.abs(e.deltaX) > Math.abs(e.deltaY);
|
|
9341
|
+
if (lane && !zooming && !sideways)
|
|
9035
9342
|
return;
|
|
9036
9343
|
e.preventDefault();
|
|
9037
9344
|
const scale = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? height : 1;
|
|
9038
|
-
if (
|
|
9345
|
+
if (zooming) {
|
|
9039
9346
|
const at = target.start + localX(e) / width * target.span;
|
|
9040
|
-
|
|
9347
|
+
const k = Math.exp(-e.deltaY * scale * (e.ctrlKey ? 0.01 : 0.002));
|
|
9348
|
+
retarget(zoomView(target, k, at), INSTANT2, lane);
|
|
9041
9349
|
} else {
|
|
9042
|
-
const d = (
|
|
9043
|
-
retarget({ ...target, start: target.start + d / width * target.span });
|
|
9350
|
+
const d = (sideways ? e.deltaX : e.deltaY) * scale;
|
|
9351
|
+
retarget({ ...target, start: target.start + d / width * target.span }, INSTANT2, lane);
|
|
9044
9352
|
}
|
|
9045
9353
|
}, { passive: false });
|
|
9354
|
+
let pinchScale = 1;
|
|
9355
|
+
let pinching = false;
|
|
9356
|
+
const onGesture = (e) => {
|
|
9357
|
+
const g = e;
|
|
9358
|
+
e.preventDefault();
|
|
9359
|
+
if (e.type === "gesturestart")
|
|
9360
|
+
pinchScale = 1;
|
|
9361
|
+
pinching = e.type !== "gestureend";
|
|
9362
|
+
if (e.type !== "gesturechange")
|
|
9363
|
+
return;
|
|
9364
|
+
const s = g.scale ?? 1;
|
|
9365
|
+
const x = g.clientX !== undefined ? localX({ clientX: g.clientX }) : width / 2;
|
|
9366
|
+
retarget(zoomView(target, s / pinchScale, target.start + x / width * target.span), INSTANT2, true);
|
|
9367
|
+
pinchScale = s;
|
|
9368
|
+
};
|
|
9369
|
+
for (const type of ["gesturestart", "gesturechange", "gestureend"])
|
|
9370
|
+
track.addEventListener(type, onGesture);
|
|
9046
9371
|
root.addEventListener("keydown", (e) => {
|
|
9047
9372
|
if (e.target !== root || e.metaKey || e.ctrlKey) {
|
|
9048
9373
|
if ((e.metaKey || e.ctrlKey) && (e.key === "=" || e.key === "-" || e.key === "0") && e.target === root) {
|
|
@@ -9050,7 +9375,7 @@ function timeline(container, options) {
|
|
|
9050
9375
|
if (e.key === "0")
|
|
9051
9376
|
fit();
|
|
9052
9377
|
else
|
|
9053
|
-
|
|
9378
|
+
zoomAtHand(e.key === "=" ? 1.5 : 1 / 1.5);
|
|
9054
9379
|
}
|
|
9055
9380
|
return;
|
|
9056
9381
|
}
|
|
@@ -9132,18 +9457,12 @@ function timeline(container, options) {
|
|
|
9132
9457
|
return;
|
|
9133
9458
|
case "=":
|
|
9134
9459
|
case "+":
|
|
9135
|
-
if (lane)
|
|
9136
|
-
return;
|
|
9137
9460
|
claim();
|
|
9138
|
-
return
|
|
9461
|
+
return zoomAtHand(1.5);
|
|
9139
9462
|
case "-":
|
|
9140
|
-
if (lane)
|
|
9141
|
-
return;
|
|
9142
9463
|
claim();
|
|
9143
|
-
return
|
|
9464
|
+
return zoomAtHand(1 / 1.5);
|
|
9144
9465
|
case "0":
|
|
9145
|
-
if (lane)
|
|
9146
|
-
return;
|
|
9147
9466
|
claim();
|
|
9148
9467
|
return fit();
|
|
9149
9468
|
}
|
|
@@ -9359,7 +9678,7 @@ function timeline(container, options) {
|
|
|
9359
9678
|
};
|
|
9360
9679
|
return api;
|
|
9361
9680
|
}
|
|
9362
|
-
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>';
|
|
9681
|
+
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>';
|
|
9363
9682
|
var init_timeline = __esm(() => {
|
|
9364
9683
|
init_rgba();
|
|
9365
9684
|
init_motion();
|
|
@@ -9431,15 +9750,28 @@ function compareLayout(box, before, after) {
|
|
|
9431
9750
|
const shape = after.w > 0 && after.h > 0 ? after : before;
|
|
9432
9751
|
const pair = letterbox({ w: shape.w * 2, h: shape.h }, box);
|
|
9433
9752
|
const half = pair.w / 2;
|
|
9753
|
+
const fused = { x: pair.x + half / 2, y: pair.y, w: half, h: pair.h };
|
|
9434
9754
|
return {
|
|
9435
9755
|
side: {
|
|
9436
9756
|
before: letterbox(before, { x: pair.x, y: pair.y, w: half, h: pair.h }),
|
|
9437
9757
|
after: letterbox(after, { x: pair.x + half, y: pair.y, w: half, h: pair.h }),
|
|
9438
9758
|
split: pair.x + half
|
|
9439
9759
|
},
|
|
9440
|
-
overlay: { before: letterbox(before,
|
|
9760
|
+
overlay: { before: letterbox(before, fused), after: letterbox(after, fused) }
|
|
9441
9761
|
};
|
|
9442
9762
|
}
|
|
9763
|
+
function fuseFrame(L, before, after, k, wipe) {
|
|
9764
|
+
const t = Math.min(1, Math.max(0, k));
|
|
9765
|
+
const o = L.overlay;
|
|
9766
|
+
const left = Math.min(o.before.x, o.after.x);
|
|
9767
|
+
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);
|
|
9768
|
+
const cut = L.side.split + (line - L.side.split) * t;
|
|
9769
|
+
const contact = Math.max(0, Math.min(cut - after.x, before.x + before.w - cut));
|
|
9770
|
+
const feather = Math.min(contact, 1 + FUSE.feather * Math.sin(Math.PI * t));
|
|
9771
|
+
const overlap = before.x + before.w - after.x;
|
|
9772
|
+
const seam = t > 0.001 && overlap >= 0 ? Math.min(1, Math.max(0, overlap / FUSE.seamFade)) * Math.min(1, t * 4) : 0;
|
|
9773
|
+
return { cut, feather, seam, blur: t < 0.995 ? FUSE.blur * (1 - t) : 0 };
|
|
9774
|
+
}
|
|
9443
9775
|
function clampZoom(r) {
|
|
9444
9776
|
const w = Math.min(1, Math.max(1 / ZOOM_MAX, r.w));
|
|
9445
9777
|
const u = Math.min(1 - w, Math.max(0, r.u));
|
|
@@ -9525,7 +9857,15 @@ function stripPeaks(diffs, o = {}) {
|
|
|
9525
9857
|
});
|
|
9526
9858
|
return out;
|
|
9527
9859
|
}
|
|
9528
|
-
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,
|
|
9860
|
+
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) => {
|
|
9861
|
+
const f = Math.min(1, Math.max(0, fold));
|
|
9862
|
+
const open = 1 - f;
|
|
9863
|
+
return {
|
|
9864
|
+
width: mark * open,
|
|
9865
|
+
opacity: Math.min(1, Math.max(0, (open - 0.2) / 0.8)),
|
|
9866
|
+
blur: blur * Math.min(1, Math.max(0, (f - 0.25) / 0.75))
|
|
9867
|
+
};
|
|
9868
|
+
}, 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({
|
|
9529
9869
|
u: r.u - dx / Math.max(1, base.w) * r.w,
|
|
9530
9870
|
v: r.v - dy / Math.max(1, base.h) * r.h,
|
|
9531
9871
|
w: r.w
|
|
@@ -9548,6 +9888,7 @@ var init_compare_model = __esm(() => {
|
|
|
9548
9888
|
MODE_KEYS = { side: "s", wipe: "w", difference: "d" };
|
|
9549
9889
|
VIDEO = /\.(mp4|m4v|mov|webm|ogv|mkv)$/i;
|
|
9550
9890
|
SEEK_IDLE = { seeking: false, pending: null };
|
|
9891
|
+
FUSE = { feather: 24, blur: 4, seamFade: 48 };
|
|
9551
9892
|
ZOOM_FIT = { u: 0, v: 0, w: 1, h: 1 };
|
|
9552
9893
|
});
|
|
9553
9894
|
|
|
@@ -10442,11 +10783,6 @@ fn pm(c: vec4f) -> vec4f { return vec4f(c.rgb * c.a, c.a); }
|
|
|
10442
10783
|
|
|
10443
10784
|
fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
10444
10785
|
switch mode {
|
|
10445
|
-
case 1u: {
|
|
10446
|
-
let s = max(u.wipe.y, 0.5);
|
|
10447
|
-
let m = smoothstep(u.wipe.x - s, u.wipe.x + s, p.x);
|
|
10448
|
-
return pm(vec4f(mix(a.rgb, b.rgb, m), mix(a.a, b.a, m)));
|
|
10449
|
-
}
|
|
10450
10786
|
case 2u: {
|
|
10451
10787
|
let d = abs(a.rgb - b.rgb);
|
|
10452
10788
|
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);
|
|
@@ -10455,8 +10791,10 @@ fn composite(mode: u32, p: vec2f, a: vec4f, b: vec4f) -> vec4f {
|
|
|
10455
10791
|
}
|
|
10456
10792
|
default: {}
|
|
10457
10793
|
}
|
|
10458
|
-
// Side by side
|
|
10459
|
-
|
|
10794
|
+
// Side by side, fusing and wiping: Before over After, cut at the seam with its feather.
|
|
10795
|
+
let s = max(u.wipe.y, 0.5);
|
|
10796
|
+
let ka = a.a * (1.0 - smoothstep(u.wipe.x - s, u.wipe.x + s, p.x));
|
|
10797
|
+
return vec4f(a.rgb * ka + b.rgb * b.a * (1.0 - ka), ka + b.a * (1.0 - ka));
|
|
10460
10798
|
}
|
|
10461
10799
|
|
|
10462
10800
|
@fragment fn fs(@builtin(position) q: vec4f) -> @location(0) vec4f {
|
|
@@ -10858,6 +11196,29 @@ var init_compare_strip = __esm(() => {
|
|
|
10858
11196
|
DIFF = { w: 32, h: 18 };
|
|
10859
11197
|
});
|
|
10860
11198
|
|
|
11199
|
+
// src/ui/player.ts
|
|
11200
|
+
function playGlyph(doc) {
|
|
11201
|
+
const element = doc.createElement("span");
|
|
11202
|
+
element.className = "knobs-player-glyph";
|
|
11203
|
+
element.setAttribute("aria-hidden", "true");
|
|
11204
|
+
let timer = 0;
|
|
11205
|
+
const win = doc.defaultView;
|
|
11206
|
+
return {
|
|
11207
|
+
element,
|
|
11208
|
+
flash(playing) {
|
|
11209
|
+
element.innerHTML = playing ? PLAY2 : PAUSE;
|
|
11210
|
+
element.setAttribute("data-flash", "");
|
|
11211
|
+
win.clearTimeout(timer);
|
|
11212
|
+
timer = win.setTimeout(() => element.removeAttribute("data-flash"), FLASH_MS);
|
|
11213
|
+
},
|
|
11214
|
+
dispose: () => win.clearTimeout(timer)
|
|
11215
|
+
};
|
|
11216
|
+
}
|
|
11217
|
+
var FLASH_MS = 450;
|
|
11218
|
+
var init_player = __esm(() => {
|
|
11219
|
+
init_timeline();
|
|
11220
|
+
});
|
|
11221
|
+
|
|
10861
11222
|
// src/ui/compare.ts
|
|
10862
11223
|
function compare(container, options) {
|
|
10863
11224
|
const doc = container.ownerDocument;
|
|
@@ -10954,6 +11315,19 @@ function compare(container, options) {
|
|
|
10954
11315
|
const labels = [el("div", "knobs-cmp-label"), el("div", "knobs-cmp-label")];
|
|
10955
11316
|
labels[0].dataset.side = "before";
|
|
10956
11317
|
labels[1].dataset.side = "after";
|
|
11318
|
+
const setLabel = (index, text) => {
|
|
11319
|
+
const l = labels[index];
|
|
11320
|
+
if (!l.firstElementChild) {
|
|
11321
|
+
const mark = el("span", "knobs-cmp-mark");
|
|
11322
|
+
mark.innerHTML = icon(index === 0 ? "x" : "check", { small: true });
|
|
11323
|
+
l.append(mark, el("span", "knobs-cmp-name"));
|
|
11324
|
+
}
|
|
11325
|
+
const name = l.lastElementChild;
|
|
11326
|
+
if (name.textContent !== text)
|
|
11327
|
+
name.textContent = text;
|
|
11328
|
+
};
|
|
11329
|
+
const seam = el("div", "knobs-cmp-seam");
|
|
11330
|
+
seam.setAttribute("aria-hidden", "true");
|
|
10957
11331
|
const handle = el("div", "knobs-cmp-handle");
|
|
10958
11332
|
handle.setAttribute("role", "slider");
|
|
10959
11333
|
handle.setAttribute("aria-label", "Wipe");
|
|
@@ -10963,7 +11337,8 @@ function compare(container, options) {
|
|
|
10963
11337
|
grip.setAttribute("aria-hidden", "true");
|
|
10964
11338
|
handle.append(grip);
|
|
10965
11339
|
const note = el("div", "knobs-cmp-note");
|
|
10966
|
-
|
|
11340
|
+
const glyph = playGlyph(doc);
|
|
11341
|
+
stage.append(canvas, split, seam, labels[0], labels[1], handle, zoomPill, note, glyph.element);
|
|
10967
11342
|
root.append(bar, stage);
|
|
10968
11343
|
const wantsStrip = options.strip === true;
|
|
10969
11344
|
let tl = bound;
|
|
@@ -10978,7 +11353,7 @@ function compare(container, options) {
|
|
|
10978
11353
|
root.append(host);
|
|
10979
11354
|
tl = timeline(host, {
|
|
10980
11355
|
...look,
|
|
10981
|
-
variant: "
|
|
11356
|
+
variant: "line",
|
|
10982
11357
|
duration: 1,
|
|
10983
11358
|
fps: fps(),
|
|
10984
11359
|
arrows: { step: 0.5, shift: 2 },
|
|
@@ -10999,12 +11374,13 @@ function compare(container, options) {
|
|
|
10999
11374
|
let toMode = mode;
|
|
11000
11375
|
const wipeLine = new Spring(wipe, WIPE_CATCH.omega, WIPE_CATCH.zeta, 0.0001);
|
|
11001
11376
|
let wipeCatching = false;
|
|
11002
|
-
|
|
11377
|
+
const gripAt = new Spring(0.5, LAYOUT2.omega, LAYOUT2.zeta, 0.0001);
|
|
11003
11378
|
let loupeHeld = false;
|
|
11004
11379
|
let pointer = null;
|
|
11005
11380
|
let drag = null;
|
|
11006
11381
|
const touches = new Map;
|
|
11007
11382
|
let pinch = null;
|
|
11383
|
+
let press = null;
|
|
11008
11384
|
const zu = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
11009
11385
|
const zv = new Spring(0, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
11010
11386
|
const zw = new Spring(1, ZOOM.omega, ZOOM.zeta, 0.00001);
|
|
@@ -11291,6 +11667,8 @@ function compare(container, options) {
|
|
|
11291
11667
|
for (const s of sides) {
|
|
11292
11668
|
const st = s.el.style;
|
|
11293
11669
|
st.clipPath = "";
|
|
11670
|
+
st.maskImage = "";
|
|
11671
|
+
st.setProperty("-webkit-mask-image", "");
|
|
11294
11672
|
st.mixBlendMode = "";
|
|
11295
11673
|
st.opacity = "";
|
|
11296
11674
|
s.shown = null;
|
|
@@ -11517,43 +11895,65 @@ function compare(container, options) {
|
|
|
11517
11895
|
viewSent = key;
|
|
11518
11896
|
options.onView({ zoom: clampZoom(z), loop: l });
|
|
11519
11897
|
};
|
|
11520
|
-
const
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
return [at.before, at.after];
|
|
11524
|
-
}
|
|
11525
|
-
const ax = r.after.x + INSET + (r.after.w - labelW[1] - INSET * 2) * lay.x;
|
|
11526
|
-
return [
|
|
11527
|
-
{ x: r.before.x + INSET, opacity: 1 },
|
|
11528
|
-
{ x: ax, opacity: 1 }
|
|
11529
|
-
];
|
|
11898
|
+
const differenceWeight = () => {
|
|
11899
|
+
const f = Math.min(1, Math.max(0, fade.x));
|
|
11900
|
+
return (fromMode === "difference" ? 1 - f : 0) + (toMode === "difference" ? f : 0);
|
|
11530
11901
|
};
|
|
11531
11902
|
const placeGrip = (wr) => {
|
|
11532
|
-
const gy = gripTop(
|
|
11903
|
+
const gy = gripTop(wr.y + gripAt.x * wr.h, wr, GRIP.h) - wr.y;
|
|
11533
11904
|
grip.style.transform = `translate3d(0,${gy.toFixed(2)}px,0)`;
|
|
11534
11905
|
};
|
|
11906
|
+
let folded = 0;
|
|
11535
11907
|
const draw = () => {
|
|
11536
11908
|
dirty = false;
|
|
11909
|
+
if (!root.hasAttribute("data-ready") && sides.every((x) => x.shown || x.failed))
|
|
11910
|
+
root.setAttribute("data-ready", "");
|
|
11537
11911
|
const r = layoutNow();
|
|
11538
11912
|
const wr = wipeRect(r.L.overlay);
|
|
11539
|
-
const
|
|
11540
|
-
const
|
|
11541
|
-
const
|
|
11542
|
-
const
|
|
11543
|
-
|
|
11913
|
+
const k = Math.min(1, Math.max(0, lay.x));
|
|
11914
|
+
const fu = fuseFrame(r.L, r.before, r.after, k, wipeLine.x);
|
|
11915
|
+
const dw = differenceWeight();
|
|
11916
|
+
const fusing = 1 - dw;
|
|
11917
|
+
folded = k * fusing;
|
|
11918
|
+
const fold = labelFold(folded, MARK.w);
|
|
11919
|
+
const w = labelW.map((x) => x - (MARK.w - fold.width) - MARK.gap * folded);
|
|
11920
|
+
const ride = seamLabels(fu.cut, r.before.x, r.after.x + r.after.w, w[0], w[1], INSET);
|
|
11921
|
+
const apart = [r.before.x + INSET, r.after.x + INSET];
|
|
11922
|
+
const corner = [r.before.x + INSET, r.after.x + r.after.w - labelW[1] - INSET];
|
|
11923
|
+
const rides = [ride.before, ride.after];
|
|
11544
11924
|
const ys = [r.before.y + INSET, r.after.y + INSET];
|
|
11545
11925
|
for (const i of [0, 1]) {
|
|
11546
|
-
const
|
|
11547
|
-
|
|
11548
|
-
|
|
11926
|
+
const fused = apart[i] + (rides[i].x - apart[i]) * k;
|
|
11927
|
+
const x = fused + (corner[i] - fused) * dw;
|
|
11928
|
+
const opacity = (1 - k + k * rides[i].opacity) * fusing + dw;
|
|
11929
|
+
const l = labels[i];
|
|
11930
|
+
l.style.transform = `translate(${x.toFixed(2)}px,${ys[i].toFixed(2)}px)`;
|
|
11931
|
+
l.style.opacity = opacity.toFixed(3);
|
|
11932
|
+
const mark = l.firstElementChild;
|
|
11933
|
+
if (mark) {
|
|
11934
|
+
mark.style.width = `${fold.width.toFixed(2)}px`;
|
|
11935
|
+
mark.style.marginRight = `${(-MARK.gap * folded).toFixed(2)}px`;
|
|
11936
|
+
mark.style.opacity = fold.opacity.toFixed(3);
|
|
11937
|
+
mark.style.filter = fold.blur > 0.05 ? `blur(${fold.blur.toFixed(2)}px)` : "";
|
|
11938
|
+
}
|
|
11549
11939
|
}
|
|
11550
11940
|
const top = Math.min(r.L.side.before.y, r.L.side.after.y);
|
|
11551
11941
|
split.style.transform = `translate(${r.L.side.split.toFixed(2)}px,${top.toFixed(2)}px)`;
|
|
11552
11942
|
split.style.height = `${Math.max(0, r.L.side.after.h).toFixed(2)}px`;
|
|
11553
11943
|
split.style.opacity = String(Math.max(0, 1 - k * 2));
|
|
11944
|
+
const seamOn = fu.seam * fusing;
|
|
11945
|
+
const blur = fu.blur > 0.01 ? `blur(${fu.blur.toFixed(2)}px)` : "none";
|
|
11946
|
+
seam.style.transform = `translate(${fu.cut.toFixed(2)}px,${wr.y.toFixed(2)}px) translateX(-50%)`;
|
|
11947
|
+
seam.style.width = `${(8 + 2 * fu.feather).toFixed(2)}px`;
|
|
11948
|
+
seam.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
11949
|
+
seam.style.opacity = (blur === "none" ? 0 : seamOn).toFixed(3);
|
|
11950
|
+
seam.style.backdropFilter = blur;
|
|
11951
|
+
seam.style.setProperty("-webkit-backdrop-filter", blur);
|
|
11554
11952
|
handle.toggleAttribute("data-on", mode === "wipe");
|
|
11555
|
-
handle.style.transform = `translate(${
|
|
11953
|
+
handle.style.transform = `translate(${fu.cut.toFixed(2)}px,${wr.y.toFixed(2)}px)`;
|
|
11556
11954
|
handle.style.height = `${Math.max(0, wr.h).toFixed(2)}px`;
|
|
11955
|
+
handle.style.opacity = seamOn.toFixed(3);
|
|
11956
|
+
handle.style.filter = blur;
|
|
11557
11957
|
placeGrip(wr);
|
|
11558
11958
|
handle.setAttribute("aria-valuenow", String(Math.round(wipe * 100)));
|
|
11559
11959
|
handle.setAttribute("aria-valuetext", `${Math.round(wipe * 100)}% Before`);
|
|
@@ -11566,24 +11966,27 @@ function compare(container, options) {
|
|
|
11566
11966
|
if (pending)
|
|
11567
11967
|
return;
|
|
11568
11968
|
if (renderer === "dom") {
|
|
11569
|
-
const
|
|
11969
|
+
const cut = mode === "difference" ? null : fu;
|
|
11970
|
+
const place = (n, rect, clip, before) => {
|
|
11570
11971
|
const st = n.style;
|
|
11571
11972
|
st.transform = `translate(${rect.x.toFixed(2)}px,${rect.y.toFixed(2)}px)`;
|
|
11572
11973
|
st.width = `${rect.w.toFixed(2)}px`;
|
|
11573
11974
|
st.height = `${rect.h.toFixed(2)}px`;
|
|
11975
|
+
const edge = before && cut ? cut.cut + cut.feather : Number.POSITIVE_INFINITY;
|
|
11574
11976
|
const t = Math.max(0, clip.y - rect.y);
|
|
11575
11977
|
const l = Math.max(0, clip.x - rect.x);
|
|
11576
11978
|
const b = Math.max(0, rect.y + rect.h - (clip.y + clip.h));
|
|
11577
|
-
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w,
|
|
11979
|
+
const right = Math.max(0, rect.x + rect.w - Math.min(clip.x + clip.w, edge));
|
|
11578
11980
|
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)` : "";
|
|
11981
|
+
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)` : "";
|
|
11982
|
+
st.maskImage = mask;
|
|
11983
|
+
st.setProperty("-webkit-mask-image", mask);
|
|
11579
11984
|
};
|
|
11580
|
-
const cut = mode === "wipe" ? wx : Number.POSITIVE_INFINITY;
|
|
11581
11985
|
for (const s of sides) {
|
|
11582
11986
|
const rect = s.index === 0 ? r.zBefore : r.zAfter;
|
|
11583
11987
|
const clip = s.index === 0 ? r.before : r.after;
|
|
11584
|
-
|
|
11585
|
-
place(s.
|
|
11586
|
-
place(s.preview, rect, clip, at);
|
|
11988
|
+
place(s.el, rect, clip, s.index === 0);
|
|
11989
|
+
place(s.preview, rect, clip, s.index === 0);
|
|
11587
11990
|
if (s.index !== 0)
|
|
11588
11991
|
continue;
|
|
11589
11992
|
for (const n of [s.el, s.preview])
|
|
@@ -11603,8 +12006,8 @@ function compare(container, options) {
|
|
|
11603
12006
|
width: Math.max(1, Math.round(stageW * dpr)),
|
|
11604
12007
|
height: Math.max(1, Math.round(stageH * dpr)),
|
|
11605
12008
|
dpr,
|
|
11606
|
-
wipeX:
|
|
11607
|
-
soft: 0.75 * dpr,
|
|
12009
|
+
wipeX: fu.cut * dpr,
|
|
12010
|
+
soft: Math.max(0.75, fu.feather) * dpr,
|
|
11608
12011
|
from: MODE_INDEX[fromMode],
|
|
11609
12012
|
to: MODE_INDEX[toMode],
|
|
11610
12013
|
mix: Math.min(1, Math.max(0, fade.x)),
|
|
@@ -11631,6 +12034,7 @@ function compare(container, options) {
|
|
|
11631
12034
|
zu.step(dt);
|
|
11632
12035
|
zv.step(dt);
|
|
11633
12036
|
zw.step(dt);
|
|
12037
|
+
gripAt.step(dt);
|
|
11634
12038
|
const playing = isPlaying();
|
|
11635
12039
|
if (playing) {
|
|
11636
12040
|
const m = master();
|
|
@@ -11661,11 +12065,9 @@ function compare(container, options) {
|
|
|
11661
12065
|
pushFrame(s);
|
|
11662
12066
|
}
|
|
11663
12067
|
}
|
|
11664
|
-
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching;
|
|
12068
|
+
const moving = !lay.resting || !fade.resting || !zoomResting() || wipeCatching || !gripAt.resting;
|
|
11665
12069
|
if (moving)
|
|
11666
12070
|
dirty = true;
|
|
11667
|
-
if (auto && !lay.resting)
|
|
11668
|
-
fitHeight();
|
|
11669
12071
|
if (dirty)
|
|
11670
12072
|
draw();
|
|
11671
12073
|
return playing || moving;
|
|
@@ -11691,13 +12093,7 @@ function compare(container, options) {
|
|
|
11691
12093
|
zw.set(c.w);
|
|
11692
12094
|
requestDraw();
|
|
11693
12095
|
};
|
|
11694
|
-
const autoHeight = (w) =>
|
|
11695
|
-
const shape = sizeOf(sides[1]);
|
|
11696
|
-
const side = splitHeight(w, shape);
|
|
11697
|
-
const over = w * shape.h / shape.w;
|
|
11698
|
-
const h = side + (over - side) * lay.x;
|
|
11699
|
-
return Math.max(60, Math.min(win.innerHeight * 0.8, h));
|
|
11700
|
-
};
|
|
12096
|
+
const autoHeight = (w) => Math.max(60, Math.min(win.innerHeight * 0.8, splitHeight(w, sizeOf(sides[1]))));
|
|
11701
12097
|
const fitHeight = () => {
|
|
11702
12098
|
const h = autoHeight(stageW);
|
|
11703
12099
|
if (Math.abs(h - stageH) < 0.25)
|
|
@@ -11709,7 +12105,8 @@ function compare(container, options) {
|
|
|
11709
12105
|
const readColors = () => {
|
|
11710
12106
|
const c = tokenColor(win.getComputedStyle(root), "--_ku-cmp-diff", [0.49, 0.81, 0.61, 1]);
|
|
11711
12107
|
accent = [c[0], c[1], c[2]];
|
|
11712
|
-
|
|
12108
|
+
const unfold = MARK.w - labelFold(folded, MARK.w).width + MARK.gap * folded;
|
|
12109
|
+
labelW = [labels[0].offsetWidth + unfold, labels[1].offsetWidth + unfold];
|
|
11713
12110
|
requestDraw();
|
|
11714
12111
|
};
|
|
11715
12112
|
const measure = () => {
|
|
@@ -11800,8 +12197,10 @@ function compare(container, options) {
|
|
|
11800
12197
|
root.focus({ preventScroll: true });
|
|
11801
12198
|
touches.set(e.pointerId, p);
|
|
11802
12199
|
stage.setPointerCapture(e.pointerId);
|
|
12200
|
+
press = touches.size === 1 && mode !== "wipe" && master() ? p : null;
|
|
11803
12201
|
if (touches.size >= 2) {
|
|
11804
12202
|
e.preventDefault();
|
|
12203
|
+
press = null;
|
|
11805
12204
|
return startPinch();
|
|
11806
12205
|
}
|
|
11807
12206
|
if (mode === "wipe") {
|
|
@@ -11811,7 +12210,7 @@ function compare(container, options) {
|
|
|
11811
12210
|
if (inside && (grab.onLine || !zoomed())) {
|
|
11812
12211
|
drag = { kind: "wipe", offset: grab.offset };
|
|
11813
12212
|
root.dataset.dragging = "";
|
|
11814
|
-
|
|
12213
|
+
gripAt.snap(wr.h > 0 ? (p.y - wr.y) / wr.h : 0.5);
|
|
11815
12214
|
e.preventDefault();
|
|
11816
12215
|
if (!grab.onLine)
|
|
11817
12216
|
setWipe(wipeAt(p.x, wr), true, true);
|
|
@@ -11829,6 +12228,8 @@ function compare(container, options) {
|
|
|
11829
12228
|
const onMove = (e) => {
|
|
11830
12229
|
const p = local(e);
|
|
11831
12230
|
pointer = p;
|
|
12231
|
+
if (press && Math.hypot(p.x - press.x, p.y - press.y) > 4)
|
|
12232
|
+
press = null;
|
|
11832
12233
|
if (touches.has(e.pointerId))
|
|
11833
12234
|
touches.set(e.pointerId, p);
|
|
11834
12235
|
if (pinch && touches.size >= 2) {
|
|
@@ -11842,14 +12243,12 @@ function compare(container, options) {
|
|
|
11842
12243
|
pinch = { d, x: mid.x, y: mid.y };
|
|
11843
12244
|
return handZoom(zoomAbout(panned, k, q.pu, q.pv));
|
|
11844
12245
|
}
|
|
11845
|
-
if (
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
if (drag?.kind === "
|
|
11851
|
-
setWipe(wipeAt(p.x, wipeRect(layoutNow().L.overlay), drag.offset));
|
|
11852
|
-
else if (drag?.kind === "pan") {
|
|
12246
|
+
if (drag?.kind === "wipe") {
|
|
12247
|
+
const wr = wipeRect(layoutNow().L.overlay);
|
|
12248
|
+
gripAt.snap(wr.h > 0 ? (p.y - wr.y) / wr.h : 0.5);
|
|
12249
|
+
setWipe(wipeAt(p.x, wr, drag.offset));
|
|
12250
|
+
placeGrip(wr);
|
|
12251
|
+
} else if (drag?.kind === "pan") {
|
|
11853
12252
|
const dx = p.x - drag.x;
|
|
11854
12253
|
const dy = p.y - drag.y;
|
|
11855
12254
|
drag.x = p.x;
|
|
@@ -11860,11 +12259,23 @@ function compare(container, options) {
|
|
|
11860
12259
|
drawNow();
|
|
11861
12260
|
};
|
|
11862
12261
|
const endDrag = (e) => {
|
|
12262
|
+
if (press && e.type === "pointerup") {
|
|
12263
|
+
api.toggle();
|
|
12264
|
+
glyph.flash(isPlaying());
|
|
12265
|
+
}
|
|
12266
|
+
press = null;
|
|
11863
12267
|
touches.delete(e.pointerId);
|
|
11864
12268
|
if (touches.size < 2)
|
|
11865
12269
|
pinch = null;
|
|
11866
12270
|
if (!drag)
|
|
11867
12271
|
return;
|
|
12272
|
+
if (drag.kind === "wipe") {
|
|
12273
|
+
if (reducedMotion(win))
|
|
12274
|
+
gripAt.snap(0.5);
|
|
12275
|
+
else
|
|
12276
|
+
gripAt.set(0.5);
|
|
12277
|
+
requestDraw();
|
|
12278
|
+
}
|
|
11868
12279
|
drag = null;
|
|
11869
12280
|
delete root.dataset.dragging;
|
|
11870
12281
|
delete root.dataset.panning;
|
|
@@ -12014,8 +12425,9 @@ function compare(container, options) {
|
|
|
12014
12425
|
old.el.replaceWith(s.el);
|
|
12015
12426
|
old.preview.replaceWith(s.preview);
|
|
12016
12427
|
sides[index] = s;
|
|
12428
|
+
root.toggleAttribute("data-video", sides.some((x) => x.kind === "video"));
|
|
12017
12429
|
note.textContent = "";
|
|
12018
|
-
|
|
12430
|
+
setLabel(index, labelOf(index));
|
|
12019
12431
|
if (near)
|
|
12020
12432
|
loadSide(s);
|
|
12021
12433
|
readColors();
|
|
@@ -12026,8 +12438,9 @@ function compare(container, options) {
|
|
|
12026
12438
|
stage.insertBefore(sides[1].preview, labels[0]);
|
|
12027
12439
|
stage.insertBefore(sides[0].el, labels[0]);
|
|
12028
12440
|
stage.insertBefore(sides[0].preview, labels[0]);
|
|
12029
|
-
|
|
12030
|
-
|
|
12441
|
+
setLabel(0, labelOf(0));
|
|
12442
|
+
setLabel(1, labelOf(1));
|
|
12443
|
+
root.toggleAttribute("data-video", sides.some((s) => s.kind === "video"));
|
|
12031
12444
|
loupeBtn.setAttribute("aria-pressed", String(loupeOn));
|
|
12032
12445
|
loopBtn.setAttribute("aria-pressed", String(loopNow() !== null));
|
|
12033
12446
|
const modePill = modeList.length > 1 ? selectionPill(modes, {
|
|
@@ -12167,11 +12580,11 @@ function compare(container, options) {
|
|
|
12167
12580
|
if (before)
|
|
12168
12581
|
replace(0, before);
|
|
12169
12582
|
else if (next.before)
|
|
12170
|
-
|
|
12583
|
+
setLabel(0, next.before.label ?? "Before");
|
|
12171
12584
|
if (after)
|
|
12172
12585
|
replace(1, after);
|
|
12173
12586
|
else if (next.after)
|
|
12174
|
-
|
|
12587
|
+
setLabel(1, next.after.label ?? "After");
|
|
12175
12588
|
if (before || after)
|
|
12176
12589
|
strip?.update({ ...before ? { before } : {}, ...after ? { after } : {} });
|
|
12177
12590
|
if (next.before || next.after)
|
|
@@ -12228,6 +12641,7 @@ function compare(container, options) {
|
|
|
12228
12641
|
disposed = true;
|
|
12229
12642
|
loop.stop();
|
|
12230
12643
|
modePill?.dispose();
|
|
12644
|
+
glyph.dispose();
|
|
12231
12645
|
win.clearTimeout(releaseTimer);
|
|
12232
12646
|
ro.disconnect();
|
|
12233
12647
|
nearIo?.disconnect();
|
|
@@ -12257,7 +12671,7 @@ function compare(container, options) {
|
|
|
12257
12671
|
wake();
|
|
12258
12672
|
return api;
|
|
12259
12673
|
}
|
|
12260
|
-
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
12674
|
+
var LAYOUT2, FADE6, FADE_REDUCED, ZOOM, WIPE_CATCH, SLOP = 12, INSET = 8, GRIP, MARK, LOUPE, FAST_SEEK_FRAMES = 15, RELEASE_MS = 3000, MODE_LABEL;
|
|
12261
12675
|
var init_compare = __esm(() => {
|
|
12262
12676
|
init_motion();
|
|
12263
12677
|
init_page_hints();
|
|
@@ -12268,15 +12682,17 @@ var init_compare = __esm(() => {
|
|
|
12268
12682
|
init_icons();
|
|
12269
12683
|
init_look();
|
|
12270
12684
|
init_rgba();
|
|
12685
|
+
init_player();
|
|
12271
12686
|
init_selection_pill();
|
|
12272
12687
|
init_timeline();
|
|
12273
12688
|
init_timeline_model();
|
|
12274
|
-
LAYOUT2 = springMotion(
|
|
12689
|
+
LAYOUT2 = springMotion(SPRINGS.default);
|
|
12275
12690
|
FADE6 = springMotion(SPRINGS.snappy);
|
|
12276
12691
|
FADE_REDUCED = springMotion(FADE);
|
|
12277
12692
|
ZOOM = springMotion({ duration: 0.35, bounce: 0 });
|
|
12278
12693
|
WIPE_CATCH = springMotion(CATCH_UP);
|
|
12279
12694
|
GRIP = { w: 16, h: 28 };
|
|
12695
|
+
MARK = { w: 12, gap: 4 };
|
|
12280
12696
|
LOUPE = { r: 88, zoom: 4 };
|
|
12281
12697
|
MODE_LABEL = {
|
|
12282
12698
|
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();
|