dsh-milestone 0.6.3 → 0.6.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.
Files changed (3) hide show
  1. package/README.md +17 -1
  2. package/lib/client.js +581 -73
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -68,6 +68,7 @@ npx @deepseek-ai/dsh web # → http://127.0.0.1:3080
68
68
  | 个性化与效率 | 个性化外观:强调色 / 图标圆点大小 / 距侧边距离 / 位置左右(设置内即调即存) | |
69
69
  | 个性化与效率 | 语言切换:跟随系统 / 中文 / English,设置内一键切换 | |
70
70
  | 个性化与效率 | 点击外部关闭:搜索 / 列表等浮层自动收起 | |
71
+ | 个性化与效率 | 新手教程:首次使用教练气泡引导,锚定真实组件(点击真实推进),设置内可重看 | |
71
72
  | 发布运维 | 更新检测:6h 缓存自动检查,新版徽章,一键去 npm | |
72
73
  | 发布运维 | 设置推广区:GitHub / Star / Issue / npm 四入口 | |
73
74
 
@@ -164,7 +165,22 @@ shell.overlay (root scope)
164
165
  ## 更新日志
165
166
 
166
167
  <details>
167
- <summary>v0.6.3 / v0.6.2 / v0.6.1 / v0.6.0(点击展开)</summary>
168
+ <summary>v0.6.5 / v0.6.4 / v0.6.3 / v0.6.2 / v0.6.1 / v0.6.0(点击展开)</summary>
169
+
170
+ **v0.6.5** · 真实组件教练教程 + 设置对比度修复 · 386 项测试
171
+
172
+ - **新手教程改为教练气泡(coach-mark)**:气泡锚定真实组件——欢迎 → 点展开箭头(真实点击自动推进)→ 点设置齿轮(真实打开自动推进,设置开着气泡挂起)→ 圆点 → 完成;目标高亮环 + 就近气泡 + 进度点 + 随时跳过,全部双语。
173
+ - **设置模态白色背景修复**:UA 默认按钮底色漏出导致浅底浅字不可读,基础态补透明规则(Playwright 计算色实测验证)。
174
+
175
+ > [GitHub Release v0.6.5](https://github.com/SnowCrescenter-tech/dsh-milestone/releases/tag/v0.6.5)
176
+
177
+ **v0.6.4** · 新手教程 · 385 项测试
178
+
179
+ - **首次使用引导**:第一次安装后进入首个可用会话时弹出教程(全局持久化,**印象即写**——欢迎页一显示即记录,关页/刷新不重弹;想再看走设置里的「重新查看教程」)。
180
+ - 4 步教学 + 内置演示:迷你圆点条 hover/点击、玩具搜索与收藏、个性化与设置图例、更新检测与支持;进度点 + 上一步/下一步 + 随时跳过,全部双语。
181
+ - 设置与教程模态视觉共用 `modal-tokens.ts` 单一来源。
182
+
183
+ > [GitHub Release v0.6.4](https://github.com/SnowCrescenter-tech/dsh-milestone/releases/tag/v0.6.4)
168
184
 
169
185
  **v0.6.3** · 聚焦高级设置 + 设置模态重设计 · 363 项测试
170
186
 
package/lib/client.js CHANGED
@@ -795,7 +795,41 @@ window.__ModuleLoader__.load({
795
795
  /** Language option: force Chinese copy. */
796
796
  "settings.lang.zh": "中文",
797
797
  /** Language option: force English copy. */
798
- "settings.lang.en": "English"
798
+ "settings.lang.en": "English",
799
+ /** 0.6.5 tour: bubble 0 title (also the bubble's aria-label). */
800
+ "tour.welcome.title": "欢迎使用 dsh-milestone",
801
+ /** 0.6.5 tour: bubble 0 description — the REAL rail list anchor. */
802
+ "tour.welcome.desc": "这是你的会话导航条:每条提问一个圆点,点击跳转,悬停查看元信息。",
803
+ /** 0.6.5 tour: bubble 1 title — the expand arrow. */
804
+ "tour.step1.title": "展开工具栏",
805
+ /** 0.6.5 tour: bubble 1 description — what clicking REALLY does (auto-advance on the real click). */
806
+ "tour.step1.desc": "点这里展开全部功能键:搜索、列表、收藏、聚焦、更新检测与设置都在里面。",
807
+ /** 0.6.5 tour: bubble 2 title — the settings gear. */
808
+ "tour.step2.title": "打开设置",
809
+ /** 0.6.5 tour: bubble 2 description — what opening settings contains (auto-advance on the real open). */
810
+ "tour.step2.desc": "打开设置:钉住常用键、个性化外观、切换语言、搭配「聚焦」。",
811
+ /** 0.6.5 tour: bubble 3 title — the dots (real hover/click behavior). */
812
+ "tour.step3.title": "圆点导航",
813
+ /** 0.6.5 tour: bubble 3 description. */
814
+ "tour.step3.desc": "每个圆点 = 一条提问——点击跳转,悬停查看时间、模型与用量。",
815
+ /** 0.6.5 tour: bubble 4 title — done. */
816
+ "tour.step4.title": "开始使用",
817
+ /** 0.6.5 tour: bubble 4 description — finish line. */
818
+ "tour.step4.desc": "去试试吧;有问题欢迎到 GitHub 提 Issue。",
819
+ /** 0.6.5 tour: primary action on bubble 0 (begin) and bubble 4 (finish). */
820
+ "tour.start": "开始使用",
821
+ /** 0.6.5 tour: forward navigation (bubbles 1–3; the real-click auto-advance comes first). */
822
+ "tour.next": "下一步",
823
+ /** 0.6.5 tour: back navigation (bubbles 1–4). */
824
+ "tour.prev": "上一步",
825
+ /** 0.6.5 tour: corner skip — every bubble, persists the flag. */
826
+ "tour.skip": "跳过",
827
+ /** 0.6.5 tour: progress text `第 n / 5 步`. */
828
+ "tour.step.label": "第 {n} / 5 步",
829
+ /** 0.6.5 tour: aria-label on one progress dot. */
830
+ "tour.step.short": "第 {n} 步",
831
+ /** 0.6.5 settings footer action: replay the tour (data-onboarding-reopen kept). */
832
+ "tour.reopen": "重新查看教程"
799
833
  };
800
834
  const en = {
801
835
  "jump.to": "Jump to message {n}",
@@ -900,7 +934,24 @@ window.__ModuleLoader__.load({
900
934
  "settings.language": "Language",
901
935
  "settings.lang.system": "Follow system",
902
936
  "settings.lang.zh": "Chinese",
903
- "settings.lang.en": "English"
937
+ "settings.lang.en": "English",
938
+ "tour.welcome.title": "Welcome to dsh-milestone",
939
+ "tour.welcome.desc": "This is your session milestone rail: every prompt is a dot — click to jump, hover for metadata.",
940
+ "tour.step1.title": "Expand the toolbar",
941
+ "tour.step1.desc": "Click to reveal every function key: search, list, bookmarks, focus, update check, and settings.",
942
+ "tour.step2.title": "Open settings",
943
+ "tour.step2.desc": "Open settings: pin your favorite keys, personalize the look, switch language, and tune focus.",
944
+ "tour.step3.title": "Dot navigation",
945
+ "tour.step3.desc": "Each dot is one prompt — click to jump, hover for time, model, and usage.",
946
+ "tour.step4.title": "Get started",
947
+ "tour.step4.desc": "Go try it — questions and issues are welcome on GitHub.",
948
+ "tour.start": "Get started",
949
+ "tour.next": "Next",
950
+ "tour.prev": "Back",
951
+ "tour.skip": "Skip",
952
+ "tour.step.label": "Step {n} of 5",
953
+ "tour.step.short": "Step {n}",
954
+ "tour.reopen": "Replay the tour"
904
955
  };
905
956
  /**
906
957
  * Interpolate `{name}` placeholders with params, matching the harness t seat's
@@ -1328,6 +1379,414 @@ window.__ModuleLoader__.load({
1328
1379
  ]
1329
1380
  });
1330
1381
  }
1382
+ const MODAL_FG = "#e6e8ee";
1383
+ const MODAL_TITLE = "#c7cede";
1384
+ const MODAL_TEXT = "#b9c2d4";
1385
+ const MODAL_HINT = "#8b96ab";
1386
+ const MODAL_BORDER = "rgba(255, 255, 255, 0.14)";
1387
+ const MODAL_TIP_BG = "#222834";
1388
+ //#endregion
1389
+ //#region src/client/onboarding-store.ts
1390
+ /**
1391
+ * onboarding-store: the persistence layer for the 0.6.4 first-run tutorial —
1392
+ * a single "has the user seen it" flag with NO payload.
1393
+ *
1394
+ * Storage contract: one localStorage key (`dsh-milestone.onboarded`) whose
1395
+ * VALUE is exactly the string `'1'` when the tutorial was completed or
1396
+ * skipped. Anything else (absent key, `'0'`, `'true'`, garbage) means "never
1397
+ * shown" and re-triggers the tutorial.
1398
+ *
1399
+ * Both accessors swallow storage failures silently (SSR, sandboxed iframe,
1400
+ * quota): the tutorial is a best-effort enhancement — a broken storage must
1401
+ * never crash the rail, and a user in that environment simply sees the
1402
+ * tutorial once per page load instead of once ever.
1403
+ */
1404
+ /** The single localStorage key holding the onboarding "seen" flag. */
1405
+ const ONBOARDED_KEY = "dsh-milestone.onboarded";
1406
+ /**
1407
+ * True when the user already completed or skipped the tutorial (the stored
1408
+ * value is exactly `'1'`). Storage unavailability degrades to `false`.
1409
+ */
1410
+ function readOnboardedFlag() {
1411
+ try {
1412
+ return localStorage.getItem(ONBOARDED_KEY) === "1";
1413
+ } catch {
1414
+ return false;
1415
+ }
1416
+ }
1417
+ /**
1418
+ * Persist the tutorial as seen/completed by writing the literal string `'1'`.
1419
+ * Storage failures are swallowed — the flag simply will not survive a reload.
1420
+ */
1421
+ function writeOnboardedFlag() {
1422
+ try {
1423
+ localStorage.setItem(ONBOARDED_KEY, "1");
1424
+ } catch {}
1425
+ }
1426
+ //#endregion
1427
+ //#region src/client/MilestoneTour.tsx
1428
+ /**
1429
+ * MilestoneTour: the 0.6.5 first-run coach-bubble tutorial.
1430
+ *
1431
+ * Unlike the deleted 0.6.4 MilestoneOnboarding modal (built-in toy demos on a
1432
+ * fake overlay), this tour never fakes anything. Each of the 5 bubbles anchors
1433
+ * a REAL rail element (`data-rail-list`, `data-toolbar-expand`,
1434
+ * `data-toolbar-settings`, the first `data-rail-dot`, the rail root), explains
1435
+ * what clicking that control ACTUALLY does, and auto-advances by OBSERVING the
1436
+ * live state the rail already owns:
1437
+ * - bubble 1 (expand arrow) waits for `toolbarExpanded` → true — the user
1438
+ * really clicked the arrow (「下一步」 remains a fallback);
1439
+ * - bubble 2 (settings gear) waits for `settingsOpen` → true — the settings
1440
+ * panel appearing IS the proof — and SUSPENDS while the modal is open
1441
+ * (state is kept; closing settings resumes the bubble at the current step);
1442
+ * - bubble 3 (dots) needs no interaction — hover/click are explained.
1443
+ *
1444
+ * Trigger/ownership lives in MilestoneRail (mount timer + settings reopen);
1445
+ * this component is presentation + state machine only. It persists the
1446
+ * `dsh-milestone.onboarded` flag itself via onboarding-store on IMPRESSION
1447
+ * (showing bubble 0 is enough) and on every close path (skip / Esc / finish).
1448
+ *
1449
+ * Positioning: `position: fixed`, opened on the target's FREE side (rail on
1450
+ * the right → bubble left of the target; rail on the left → bubble right of
1451
+ * it), measured with getBoundingClientRect and clamped to the viewport.
1452
+ * Re-measured on step changes, whenever the anchor may have (un)mounted (the
1453
+ * forced toolbar expansion), and on window resize. There is NO overlay and the
1454
+ * bubble never covers its own target — the user is supposed to CLICK the real
1455
+ * controls, so pointer-events live only on the bubble box itself.
1456
+ *
1457
+ * Anchor guarantee: entering any step ≥ 2 calls `onSetToolbarExpanded(true)`
1458
+ * because `data-toolbar-settings` renders only while the toolbar is expanded
1459
+ * (or the gear pinned) — the 「下一步」 fallback path lands there un-expanded.
1460
+ *
1461
+ * Visual language reuses modal-tokens (MODAL_TIP_BG panel, one border tone,
1462
+ * the 12/8px radius scale, three text tiers) and the rail root's inherited
1463
+ * `--ms-accent*` CSS variables. The highlight ring is zero-asset: a
1464
+ * `data-tour-highlight` attribute + one injected CSS rule.
1465
+ */
1466
+ /** The tour bubble floats above every other rail layer (settings overlay 105). */
1467
+ const TOUR_Z = 106;
1468
+ /** Gap between the target element and the bubble (px). */
1469
+ const TOUR_GAP = 12;
1470
+ /** Bubble width (px) — the left-edge positioning math clamps against it. */
1471
+ const TOUR_WIDTH = 280;
1472
+ /** Minimum padding between the bubble and the viewport edges (px). */
1473
+ const VIEWPORT_PAD = 8;
1474
+ /** Fallback bubble height used when the layout has not settled (px). */
1475
+ const TOUR_HEIGHT_FALLBACK = 120;
1476
+ /** Progress-dot count — the 5 bubble steps (0 = welcome … 4 = done). */
1477
+ const STEP_COUNT = [
1478
+ 0,
1479
+ 1,
1480
+ 2,
1481
+ 3,
1482
+ 4
1483
+ ];
1484
+ /**
1485
+ * Static tour styling that `:hover`/`:focus-visible`/reduced-motion need (the
1486
+ * `:focus-visible` ring and the base-state backgrounds inline styles cannot
1487
+ * duplicate). BASE-states first — the UA default button face must never flood
1488
+ * through on the dark bubble (that exact bug already shipped once).
1489
+ */
1490
+ const TOUR_CSS = `
1491
+ @keyframes ms-tour-fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
1492
+ [data-tour-bubble] { animation: ms-tour-fade 160ms ease; }
1493
+ /* BASE-state backgrounds for every bubble control (transparent or themed). */
1494
+ [data-tour-skip] { background: transparent; }
1495
+ [data-tour-prev] { background: rgba(255, 255, 255, 0.06); }
1496
+ [data-tour-primary] { background: var(--ms-accent-bg); color: var(--ms-accent-soft); }
1497
+ /* Hover washes on top of the explicit base states. */
1498
+ [data-tour-skip]:hover { background: rgba(255, 255, 255, 0.08); }
1499
+ [data-tour-prev]:hover:not(:disabled) { background: rgba(255, 255, 255, 0.12); }
1500
+ [data-tour-primary]:hover { background: rgba(255, 255, 255, 0.14); }
1501
+ /* ONE accent focus ring for keyboard use. */
1502
+ [data-tour-skip]:focus-visible, [data-tour-prev]:focus-visible, [data-tour-primary]:focus-visible {
1503
+ box-shadow: 0 0 0 2px var(--ms-accent-soft);
1504
+ }
1505
+ /* The real-target highlight ring: accent halo + a subtle scale hint. */
1506
+ [data-tour-highlight] {
1507
+ box-shadow: 0 0 0 2px var(--ms-accent-soft), 0 0 0 4px var(--ms-accent);
1508
+ transform: scale(1.04);
1509
+ transition: box-shadow 140ms ease, transform 140ms ease;
1510
+ }
1511
+ @media (prefers-reduced-motion: reduce) {
1512
+ [data-tour-bubble] { animation: none; }
1513
+ [data-tour-highlight] { transform: none; transition: none; }
1514
+ [data-tour-skip], [data-tour-prev], [data-tour-primary] { transition: none; }
1515
+ }
1516
+ `;
1517
+ /** Rail root — every step's fallback anchor and bubble 4's target. */
1518
+ function railRoot() {
1519
+ return document.querySelector("[data-side]");
1520
+ }
1521
+ const STEP_DEFS = [
1522
+ {
1523
+ titleKey: "tour.welcome.title",
1524
+ descKey: "tour.welcome.desc",
1525
+ anchor: () => document.querySelector("[data-rail-list]")
1526
+ },
1527
+ {
1528
+ titleKey: "tour.step1.title",
1529
+ descKey: "tour.step1.desc",
1530
+ anchor: () => document.querySelector("[data-toolbar-expand]")
1531
+ },
1532
+ {
1533
+ titleKey: "tour.step2.title",
1534
+ descKey: "tour.step2.desc",
1535
+ anchor: () => document.querySelector("[data-toolbar-settings]")
1536
+ },
1537
+ {
1538
+ titleKey: "tour.step3.title",
1539
+ descKey: "tour.step3.desc",
1540
+ anchor: () => document.querySelector("[data-rail-dot]") ?? railRoot()
1541
+ },
1542
+ {
1543
+ titleKey: "tour.step4.title",
1544
+ descKey: "tour.step4.desc",
1545
+ anchor: () => railRoot()
1546
+ }
1547
+ ];
1548
+ /** Clamp `value` into [min, max], never letting min exceed max. */
1549
+ function clamp(value, min, max) {
1550
+ return Math.min(Math.max(value, min), Math.max(min, max));
1551
+ }
1552
+ function MilestoneTour({ t, side, toolbarExpanded, settingsOpen, onSetToolbarExpanded, onClose }) {
1553
+ const [step, setStep] = (0, react.useState)(0);
1554
+ const [pos, setPos] = (0, react.useState)(null);
1555
+ const bubbleRef = (0, react.useRef)(null);
1556
+ const primaryRef = (0, react.useRef)(null);
1557
+ const stepDef = STEP_DEFS[step];
1558
+ (0, react.useEffect)(() => {
1559
+ writeOnboardedFlag();
1560
+ }, []);
1561
+ /** Skip / finish / Escape converge here: persist, then close. */
1562
+ const finish = (0, react.useCallback)(() => {
1563
+ writeOnboardedFlag();
1564
+ onClose();
1565
+ }, [onClose]);
1566
+ (0, react.useEffect)(() => {
1567
+ if (settingsOpen) return;
1568
+ const onKey = (e) => {
1569
+ if (e.key !== "Escape") return;
1570
+ finish();
1571
+ };
1572
+ window.addEventListener("keydown", onKey);
1573
+ return () => window.removeEventListener("keydown", onKey);
1574
+ }, [finish, settingsOpen]);
1575
+ (0, react.useEffect)(() => {
1576
+ if (step === 1 && toolbarExpanded) setStep(2);
1577
+ }, [step, toolbarExpanded]);
1578
+ (0, react.useEffect)(() => {
1579
+ if (step === 2 && settingsOpen) setStep(3);
1580
+ }, [step, settingsOpen]);
1581
+ (0, react.useEffect)(() => {
1582
+ if (step >= 2 && !toolbarExpanded) onSetToolbarExpanded(true);
1583
+ }, [
1584
+ step,
1585
+ toolbarExpanded,
1586
+ onSetToolbarExpanded
1587
+ ]);
1588
+ /** Measure the current anchor and place the bubble on its free side. */
1589
+ const measure = (0, react.useCallback)(() => {
1590
+ const anchor = STEP_DEFS[step].anchor();
1591
+ const bubble = bubbleRef.current;
1592
+ if (anchor === null || bubble === null) {
1593
+ setPos(null);
1594
+ return;
1595
+ }
1596
+ const rect = anchor.getBoundingClientRect();
1597
+ const bw = bubble.offsetWidth || TOUR_WIDTH;
1598
+ const bh = bubble.offsetHeight || TOUR_HEIGHT_FALLBACK;
1599
+ const left = clamp(side === "left" ? rect.right + TOUR_GAP : rect.left - TOUR_GAP - bw, VIEWPORT_PAD, window.innerWidth - bw - VIEWPORT_PAD);
1600
+ const top = clamp(rect.top + rect.height / 2 - bh / 2, VIEWPORT_PAD, window.innerHeight - bh - VIEWPORT_PAD);
1601
+ setPos({
1602
+ left,
1603
+ top
1604
+ });
1605
+ }, [step, side]);
1606
+ (0, react.useLayoutEffect)(() => {
1607
+ measure();
1608
+ window.addEventListener("resize", measure);
1609
+ return () => window.removeEventListener("resize", measure);
1610
+ }, [
1611
+ measure,
1612
+ toolbarExpanded,
1613
+ settingsOpen
1614
+ ]);
1615
+ (0, react.useEffect)(() => {
1616
+ document.querySelectorAll("[data-tour-highlight]").forEach((el) => el.removeAttribute("data-tour-highlight"));
1617
+ const anchor = STEP_DEFS[step].anchor();
1618
+ if (anchor !== null) anchor.setAttribute("data-tour-highlight", "");
1619
+ return () => {
1620
+ document.querySelectorAll("[data-tour-highlight]").forEach((el) => el.removeAttribute("data-tour-highlight"));
1621
+ };
1622
+ }, [
1623
+ step,
1624
+ toolbarExpanded,
1625
+ settingsOpen
1626
+ ]);
1627
+ (0, react.useEffect)(() => {
1628
+ if (settingsOpen) return;
1629
+ primaryRef.current?.focus();
1630
+ }, [step, settingsOpen]);
1631
+ const goNext = () => setStep((s) => Math.min(STEP_COUNT.length - 1, s + 1));
1632
+ const goPrev = () => setStep((s) => Math.max(0, s - 1));
1633
+ if (settingsOpen) return null;
1634
+ const isLast = step === STEP_COUNT.length - 1;
1635
+ const primaryLabel = step === 0 || isLast ? t("tour.start") : t("tour.next");
1636
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1637
+ ref: bubbleRef,
1638
+ "data-tour-bubble": true,
1639
+ "data-tour-step": step,
1640
+ role: "dialog",
1641
+ "aria-label": t(stepDef.titleKey),
1642
+ style: {
1643
+ position: "fixed",
1644
+ left: pos?.left,
1645
+ top: pos?.top,
1646
+ width: TOUR_WIDTH,
1647
+ maxWidth: "calc(100vw - 24px)",
1648
+ boxSizing: "border-box",
1649
+ zIndex: TOUR_Z,
1650
+ padding: 14,
1651
+ background: MODAL_TIP_BG,
1652
+ color: MODAL_FG,
1653
+ borderRadius: 12,
1654
+ border: `1px solid ${MODAL_BORDER}`,
1655
+ boxShadow: "0 12px 36px rgba(0, 0, 0, 0.45)"
1656
+ },
1657
+ children: [
1658
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: TOUR_CSS }),
1659
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1660
+ style: {
1661
+ display: "flex",
1662
+ alignItems: "flex-start",
1663
+ justifyContent: "space-between",
1664
+ gap: 8
1665
+ },
1666
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1667
+ "data-tour-title": true,
1668
+ style: {
1669
+ fontSize: 14,
1670
+ fontWeight: 700,
1671
+ color: MODAL_FG,
1672
+ lineHeight: 1.35
1673
+ },
1674
+ children: t(stepDef.titleKey)
1675
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1676
+ type: "button",
1677
+ "data-tour-skip": true,
1678
+ onClick: finish,
1679
+ style: {
1680
+ flexShrink: 0,
1681
+ background: "transparent",
1682
+ border: "none",
1683
+ padding: "2px 6px",
1684
+ borderRadius: 8,
1685
+ cursor: "pointer",
1686
+ color: MODAL_HINT,
1687
+ fontSize: 12,
1688
+ lineHeight: 1.4
1689
+ },
1690
+ children: t("tour.skip")
1691
+ })]
1692
+ }),
1693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1694
+ "data-tour-desc": true,
1695
+ style: {
1696
+ marginTop: 6,
1697
+ fontSize: 12.5,
1698
+ lineHeight: 1.5,
1699
+ color: MODAL_TEXT
1700
+ },
1701
+ children: t(stepDef.descKey)
1702
+ }),
1703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
1704
+ style: {
1705
+ display: "flex",
1706
+ alignItems: "center",
1707
+ justifyContent: "space-between",
1708
+ gap: 10,
1709
+ marginTop: 12
1710
+ },
1711
+ children: [
1712
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1713
+ type: "button",
1714
+ "data-tour-prev": true,
1715
+ disabled: step === 0,
1716
+ onClick: goPrev,
1717
+ style: {
1718
+ flexShrink: 0,
1719
+ background: "rgba(255, 255, 255, 0.06)",
1720
+ border: `1px solid ${MODAL_BORDER}`,
1721
+ borderRadius: 8,
1722
+ padding: "5px 12px",
1723
+ cursor: step === 0 ? "default" : "pointer",
1724
+ color: step === 0 ? MODAL_HINT : MODAL_TEXT,
1725
+ fontSize: 12,
1726
+ lineHeight: 1.4,
1727
+ opacity: step === 0 ? .55 : 1
1728
+ },
1729
+ children: t("tour.prev")
1730
+ }),
1731
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1732
+ style: {
1733
+ display: "flex",
1734
+ flexDirection: "column",
1735
+ alignItems: "center",
1736
+ gap: 5,
1737
+ minWidth: 74
1738
+ },
1739
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1740
+ "data-tour-progress": true,
1741
+ style: {
1742
+ fontSize: 11.5,
1743
+ color: MODAL_HINT,
1744
+ lineHeight: 1.2
1745
+ },
1746
+ children: t("tour.step.label", { n: step + 1 })
1747
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1748
+ style: {
1749
+ display: "flex",
1750
+ gap: 4
1751
+ },
1752
+ children: STEP_COUNT.map((n) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1753
+ "data-tour-progress-dot": true,
1754
+ "data-active": step === n ? "true" : void 0,
1755
+ "aria-label": t("tour.step.short", { n: n + 1 }),
1756
+ "aria-current": step === n ? "step" : void 0,
1757
+ style: {
1758
+ width: 14,
1759
+ height: 4,
1760
+ borderRadius: 2,
1761
+ background: step === n ? "var(--ms-accent)" : "rgba(255, 255, 255, 0.18)"
1762
+ }
1763
+ }, n))
1764
+ })]
1765
+ }),
1766
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1767
+ type: "button",
1768
+ ref: primaryRef,
1769
+ "data-tour-primary": true,
1770
+ onClick: isLast ? finish : goNext,
1771
+ style: {
1772
+ flexShrink: 0,
1773
+ background: "var(--ms-accent-bg)",
1774
+ color: "var(--ms-accent-soft)",
1775
+ border: "1px solid var(--ms-accent)",
1776
+ borderRadius: 8,
1777
+ padding: "5px 14px",
1778
+ cursor: "pointer",
1779
+ fontSize: 12.5,
1780
+ fontWeight: 600,
1781
+ lineHeight: 1.4
1782
+ },
1783
+ children: primaryLabel
1784
+ })
1785
+ ]
1786
+ })
1787
+ ]
1788
+ });
1789
+ }
1331
1790
  //#endregion
1332
1791
  //#region src/client/MilestoneRailTooltip.tsx
1333
1792
  /**
@@ -2279,7 +2738,7 @@ window.__ModuleLoader__.load({
2279
2738
  * Installed plugin version. Injected at build time as
2280
2739
  * `__DSH_MILESTONE_VERSION__`; falls back to `0.0.0-dev` when unbuilt.
2281
2740
  */
2282
- const PLUGIN_VERSION = "0.6.3";
2741
+ const PLUGIN_VERSION = "0.6.5";
2283
2742
  //#endregion
2284
2743
  //#region src/client/MilestoneRail.tsx
2285
2744
  /**
@@ -2324,6 +2783,13 @@ window.__ModuleLoader__.load({
2324
2783
  * hover descriptions, the personalization controls, and the support-us card
2325
2784
  * grid); everything the modal changes persists under `dsh-milestone.toolbar`.
2326
2785
  */
2786
+ /**
2787
+ * Settings modal shared palette + geometry — ONE source in modal-tokens.ts,
2788
+ * also consumed by the 0.6.4 onboarding tutorial modal so the two dialogs
2789
+ * cannot drift. Dark panel on a dark host, three text tiers (primary /
2790
+ * section title / hint + muted), one border tone, a 12px panel / 8px control
2791
+ * radius scale and a 4-unit spacing scale (4 / 8 / 12 / 16 / 20).
2792
+ */
2327
2793
  /** Minimum user messages before the rail adds value. */
2328
2794
  const MIN_MARKS = 2;
2329
2795
  const PREVIEW_LENGTH = 80;
@@ -2422,22 +2888,6 @@ window.__ModuleLoader__.load({
2422
2888
  }
2423
2889
  return rules.join("\n");
2424
2890
  }
2425
- /**
2426
- * Settings modal shared palette + geometry — one source for the inline
2427
- * styles AND the static MODAL_CSS block below so they cannot drift. Dark
2428
- * panel on a dark host, three text tiers (primary / section title / hint +
2429
- * muted), one border tone, a 12px panel / 8px control radius scale and a
2430
- * 4-unit spacing scale (4 / 8 / 12 / 16 / 20).
2431
- */
2432
- const MODAL_BG = "rgba(20, 24, 32, 0.98)";
2433
- const MODAL_FG = "#e6e8ee";
2434
- const MODAL_TITLE = "#c7cede";
2435
- const MODAL_TEXT = "#b9c2d4";
2436
- const MODAL_HINT = "#8b96ab";
2437
- const MODAL_BORDER = "rgba(255, 255, 255, 0.14)";
2438
- const MODAL_TIP_BG = "#222834";
2439
- const MODAL_RADIUS_PANEL = 12;
2440
- const MODAL_RADIUS_CONTROL = 8;
2441
2891
  /** Near-row description tip: how far its right edge sits from the row's right
2442
2892
  * edge — clears the 32px switch + its 10px padding. */
2443
2893
  const MODAL_TIP_RIGHT = 54;
@@ -2470,12 +2920,21 @@ window.__ModuleLoader__.load({
2470
2920
  [data-personal-toggle]:hover, [data-focus-toggle-settings]:hover { background: rgba(255, 255, 255, 0.05); }
2471
2921
  [data-focus-option]:hover { background: rgba(255, 255, 255, 0.04); }
2472
2922
  [data-toolbar-settings-close]:hover { background: rgba(255, 255, 255, 0.08); }
2473
- [data-toolbar-settings-reset] { background: rgba(255, 255, 255, 0.06); }
2474
- [data-toolbar-settings-reset]:hover { background: rgba(255, 255, 255, 0.1); }
2923
+ [data-toolbar-settings-reset], [data-onboarding-reopen] { background: rgba(255, 255, 255, 0.06); }
2924
+ [data-toolbar-settings-reset]:hover, [data-onboarding-reopen]:hover { background: rgba(255, 255, 255, 0.1); }
2925
+ /* BASE state reset: every modal surface must sit transparent on the dark
2926
+ panel — without it the UA default button face (light gray) floods through
2927
+ and rows become unreadable light-on-light. Hover washes above take over
2928
+ on interaction. */
2929
+ [data-toolbar-pin-toggle], [data-personal-toggle], [data-focus-toggle-settings],
2930
+ [data-toolbar-settings-close], [data-focus-option] {
2931
+ background: transparent;
2932
+ }
2475
2933
  /* ONE accent ring for keyboard focus on every modal control. */
2476
2934
  [data-toolbar-pin-toggle]:focus-visible, [data-personal-toggle]:focus-visible,
2477
2935
  [data-focus-toggle-settings]:focus-visible,
2478
- [data-toolbar-settings-close]:focus-visible, [data-toolbar-settings-reset]:focus-visible {
2936
+ [data-toolbar-settings-close]:focus-visible, [data-toolbar-settings-reset]:focus-visible,
2937
+ [data-onboarding-reopen]:focus-visible {
2479
2938
  box-shadow: 0 0 0 2px var(--ms-accent-soft);
2480
2939
  }
2481
2940
  /* Near-row description tip: a rotated square peeks out of the LEFT edge so
@@ -2518,7 +2977,7 @@ window.__ModuleLoader__.load({
2518
2977
  width: "100%",
2519
2978
  padding: "8px 10px",
2520
2979
  border: "none",
2521
- borderRadius: MODAL_RADIUS_CONTROL,
2980
+ borderRadius: 8,
2522
2981
  cursor: "pointer",
2523
2982
  color: MODAL_TITLE,
2524
2983
  fontSize: 13,
@@ -2551,6 +3010,9 @@ window.__ModuleLoader__.load({
2551
3010
  /** B4 update-check: mount-time silent check delay (ms) — give the harness
2552
3011
  * time to settle before hitting the registry. */
2553
3012
  const UPDATE_CHECK_MOUNT_DELAY = 1500;
3013
+ /** 0.6.5 first-run coach tour: mount-time show delay (ms) — let the rail settle
3014
+ * before the first bubble pops. */
3015
+ const ONBOARDING_MOUNT_DELAY = 800;
2554
3016
  /** Initial state: no check has completed yet, nothing to show. */
2555
3017
  const NO_UPDATE_CHECK = {
2556
3018
  phase: "idle",
@@ -2778,6 +3240,8 @@ window.__ModuleLoader__.load({
2778
3240
  const [expandHovered, setExpandHovered] = (0, react.useState)(false);
2779
3241
  const [settingsHovered, setSettingsHovered] = (0, react.useState)(false);
2780
3242
  const [settingsOpen, setSettingsOpen] = (0, react.useState)(false);
3243
+ const [tourOpen, setTourOpen] = (0, react.useState)(false);
3244
+ const [tourRun, setTourRun] = (0, react.useState)(0);
2781
3245
  /** The feature whose near-row description tip is currently visible
2782
3246
  * (`null` = none — tips only appear on hover/focus of their own row). */
2783
3247
  const [descFeature, setDescFeature] = (0, react.useState)(null);
@@ -2857,6 +3321,12 @@ window.__ModuleLoader__.load({
2857
3321
  const timer = window.setTimeout(runUpdateCheck, UPDATE_CHECK_MOUNT_DELAY);
2858
3322
  return () => window.clearTimeout(timer);
2859
3323
  }, []);
3324
+ (0, react.useEffect)(() => {
3325
+ const timer = window.setTimeout(() => {
3326
+ if (!readOnboardedFlag()) setTourOpen(true);
3327
+ }, ONBOARDING_MOUNT_DELAY);
3328
+ return () => window.clearTimeout(timer);
3329
+ }, []);
2860
3330
  useOutsideDismiss(updatePanelRef, updateOpen, () => {
2861
3331
  setUpdateOpen(false);
2862
3332
  updateBtnRef.current?.focus();
@@ -3020,6 +3490,15 @@ window.__ModuleLoader__.load({
3020
3490
  setSettingsOpen(false);
3021
3491
  settingsBtnRef.current?.focus();
3022
3492
  };
3493
+ /** 0.6.5: settings → 重新查看教程 — close settings and replay the coach
3494
+ * tour immediately (the flag may or may not be set; skipping/completing it
3495
+ * re-persists the flag anyway). The `tourRun` bump remounts the tour so the
3496
+ * replay always restarts from bubble 0. */
3497
+ const reopenTour = () => {
3498
+ setSettingsOpen(false);
3499
+ setTourRun((n) => n + 1);
3500
+ setTourOpen(true);
3501
+ };
3023
3502
  /** B1: a feature renders while the toolbar is EXPANDED or while it is pinned. */
3024
3503
  const featureVisible = (id) => toolbarExpanded || pinned.includes(id);
3025
3504
  /** Base chrome-button style: accent-defined active tint, scaled hit area. */
@@ -3503,9 +3982,9 @@ window.__ModuleLoader__.load({
3503
3982
  maxHeight: "78vh",
3504
3983
  overflowY: "auto",
3505
3984
  padding: 20,
3506
- background: MODAL_BG,
3507
- color: MODAL_FG,
3508
- borderRadius: MODAL_RADIUS_PANEL,
3985
+ background: "rgba(20, 24, 32, 0.98)",
3986
+ color: "#e6e8ee",
3987
+ borderRadius: 12,
3509
3988
  boxShadow: "0 24px 64px rgba(0, 0, 0, 0.55)",
3510
3989
  scrollbarWidth: "thin",
3511
3990
  scrollbarColor: "rgba(255, 255, 255, 0.2) transparent"
@@ -3524,7 +4003,7 @@ window.__ModuleLoader__.load({
3524
4003
  style: {
3525
4004
  fontSize: 15,
3526
4005
  fontWeight: 600,
3527
- color: MODAL_FG
4006
+ color: "#e6e8ee"
3528
4007
  },
3529
4008
  children: t("settings.title")
3530
4009
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -3543,8 +4022,8 @@ window.__ModuleLoader__.load({
3543
4022
  border: "none",
3544
4023
  padding: 0,
3545
4024
  cursor: "pointer",
3546
- color: MODAL_HINT,
3547
- borderRadius: MODAL_RADIUS_CONTROL,
4025
+ color: "#8b96ab",
4026
+ borderRadius: 8,
3548
4027
  lineHeight: 1
3549
4028
  },
3550
4029
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
@@ -3569,7 +4048,7 @@ window.__ModuleLoader__.load({
3569
4048
  style: {
3570
4049
  fontSize: 13,
3571
4050
  fontWeight: 600,
3572
- color: MODAL_TITLE,
4051
+ color: "#c7cede",
3573
4052
  marginBottom: 4
3574
4053
  },
3575
4054
  children: t("settings.section.features")
@@ -3578,7 +4057,7 @@ window.__ModuleLoader__.load({
3578
4057
  "data-settings-pin-hint": true,
3579
4058
  style: {
3580
4059
  fontSize: 12,
3581
- color: MODAL_HINT,
4060
+ color: "#8b96ab",
3582
4061
  lineHeight: 1.5,
3583
4062
  marginBottom: 10
3584
4063
  },
@@ -3619,9 +4098,9 @@ window.__ModuleLoader__.load({
3619
4098
  width: "100%",
3620
4099
  padding: "8px 10px",
3621
4100
  border: "none",
3622
- borderRadius: MODAL_RADIUS_CONTROL,
4101
+ borderRadius: 8,
3623
4102
  cursor: "pointer",
3624
- color: MODAL_FG,
4103
+ color: "#e6e8ee",
3625
4104
  fontSize: 13,
3626
4105
  textAlign: "left"
3627
4106
  },
@@ -3667,11 +4146,11 @@ window.__ModuleLoader__.load({
3667
4146
  maxWidth: "55%",
3668
4147
  transform: `translateY(-50%) translateX(${active ? 0 : 4}px)`,
3669
4148
  padding: "5px 10px",
3670
- borderRadius: MODAL_RADIUS_CONTROL,
3671
- background: MODAL_TIP_BG,
3672
- border: `1px solid ${MODAL_BORDER}`,
4149
+ borderRadius: 8,
4150
+ background: "#222834",
4151
+ border: `1px solid rgba(255, 255, 255, 0.14)`,
3673
4152
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.35)",
3674
- color: MODAL_TEXT,
4153
+ color: "#b9c2d4",
3675
4154
  fontSize: 12,
3676
4155
  lineHeight: 1.45,
3677
4156
  opacity: active ? 1 : 0,
@@ -3743,7 +4222,7 @@ window.__ModuleLoader__.load({
3743
4222
  "data-settings-personal-hint": true,
3744
4223
  style: {
3745
4224
  fontSize: 12,
3746
- color: MODAL_HINT,
4225
+ color: "#8b96ab",
3747
4226
  lineHeight: 1.5,
3748
4227
  padding: "0 6px"
3749
4228
  },
@@ -3759,7 +4238,7 @@ window.__ModuleLoader__.load({
3759
4238
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3760
4239
  style: {
3761
4240
  fontSize: 12.5,
3762
- color: MODAL_HINT,
4241
+ color: "#8b96ab",
3763
4242
  width: 90,
3764
4243
  flexShrink: 0
3765
4244
  },
@@ -3797,7 +4276,7 @@ window.__ModuleLoader__.load({
3797
4276
  alignItems: "center",
3798
4277
  gap: 6,
3799
4278
  fontSize: 12.5,
3800
- color: MODAL_TEXT,
4279
+ color: "#b9c2d4",
3801
4280
  cursor: "pointer"
3802
4281
  },
3803
4282
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -3828,7 +4307,7 @@ window.__ModuleLoader__.load({
3828
4307
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3829
4308
  style: {
3830
4309
  fontSize: 12.5,
3831
- color: MODAL_HINT,
4310
+ color: "#8b96ab",
3832
4311
  width: 90,
3833
4312
  flexShrink: 0
3834
4313
  },
@@ -3852,7 +4331,7 @@ window.__ModuleLoader__.load({
3852
4331
  "data-icon-size-value": true,
3853
4332
  style: {
3854
4333
  fontSize: 12.5,
3855
- color: MODAL_TEXT,
4334
+ color: "#b9c2d4",
3856
4335
  width: 40
3857
4336
  },
3858
4337
  children: [iconSize, "px"]
@@ -3870,7 +4349,7 @@ window.__ModuleLoader__.load({
3870
4349
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3871
4350
  style: {
3872
4351
  fontSize: 12.5,
3873
- color: MODAL_HINT,
4352
+ color: "#8b96ab",
3874
4353
  width: 90,
3875
4354
  flexShrink: 0
3876
4355
  },
@@ -3894,7 +4373,7 @@ window.__ModuleLoader__.load({
3894
4373
  "data-inset-value": true,
3895
4374
  style: {
3896
4375
  fontSize: 12.5,
3897
- color: MODAL_TEXT,
4376
+ color: "#b9c2d4",
3898
4377
  width: 40
3899
4378
  },
3900
4379
  children: [inset, "px"]
@@ -3914,7 +4393,7 @@ window.__ModuleLoader__.load({
3914
4393
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3915
4394
  style: {
3916
4395
  fontSize: 12.5,
3917
- color: MODAL_HINT,
4396
+ color: "#8b96ab",
3918
4397
  width: 90,
3919
4398
  flexShrink: 0
3920
4399
  },
@@ -3926,7 +4405,7 @@ window.__ModuleLoader__.load({
3926
4405
  alignItems: "center",
3927
4406
  gap: 5,
3928
4407
  fontSize: 13,
3929
- color: MODAL_FG,
4408
+ color: "#e6e8ee",
3930
4409
  cursor: "pointer"
3931
4410
  },
3932
4411
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -3944,7 +4423,7 @@ window.__ModuleLoader__.load({
3944
4423
  alignItems: "center",
3945
4424
  gap: 5,
3946
4425
  fontSize: 13,
3947
- color: MODAL_FG,
4426
+ color: "#e6e8ee",
3948
4427
  cursor: "pointer"
3949
4428
  },
3950
4429
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4014,7 +4493,7 @@ window.__ModuleLoader__.load({
4014
4493
  "data-settings-focus-hint": true,
4015
4494
  style: {
4016
4495
  fontSize: 12,
4017
- color: MODAL_HINT,
4496
+ color: "#8b96ab",
4018
4497
  lineHeight: 1.5,
4019
4498
  padding: "0 6px"
4020
4499
  },
@@ -4027,9 +4506,9 @@ window.__ModuleLoader__.load({
4027
4506
  alignItems: "center",
4028
4507
  gap: 8,
4029
4508
  padding: "6px 8px",
4030
- borderRadius: MODAL_RADIUS_CONTROL,
4509
+ borderRadius: 8,
4031
4510
  fontSize: 13,
4032
- color: MODAL_FG,
4511
+ color: "#e6e8ee",
4033
4512
  cursor: "pointer"
4034
4513
  },
4035
4514
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4046,9 +4525,9 @@ window.__ModuleLoader__.load({
4046
4525
  alignItems: "center",
4047
4526
  gap: 8,
4048
4527
  padding: "6px 8px",
4049
- borderRadius: MODAL_RADIUS_CONTROL,
4528
+ borderRadius: 8,
4050
4529
  fontSize: 13,
4051
- color: MODAL_FG,
4530
+ color: "#e6e8ee",
4052
4531
  cursor: "pointer"
4053
4532
  },
4054
4533
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4065,9 +4544,9 @@ window.__ModuleLoader__.load({
4065
4544
  alignItems: "center",
4066
4545
  gap: 8,
4067
4546
  padding: "6px 8px",
4068
- borderRadius: MODAL_RADIUS_CONTROL,
4547
+ borderRadius: 8,
4069
4548
  fontSize: 13,
4070
- color: MODAL_FG,
4549
+ color: "#e6e8ee",
4071
4550
  cursor: "pointer"
4072
4551
  },
4073
4552
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4088,7 +4567,7 @@ window.__ModuleLoader__.load({
4088
4567
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4089
4568
  style: {
4090
4569
  fontSize: 12.5,
4091
- color: MODAL_HINT,
4570
+ color: "#8b96ab",
4092
4571
  width: 90,
4093
4572
  flexShrink: 0
4094
4573
  },
@@ -4112,7 +4591,7 @@ window.__ModuleLoader__.load({
4112
4591
  "data-focus-opacity-value": true,
4113
4592
  style: {
4114
4593
  fontSize: 12.5,
4115
- color: MODAL_TEXT,
4594
+ color: "#b9c2d4",
4116
4595
  width: 44
4117
4596
  },
4118
4597
  children: [Math.round(prefs.focus.opacity * 100), "%"]
@@ -4131,7 +4610,7 @@ window.__ModuleLoader__.load({
4131
4610
  style: {
4132
4611
  fontSize: 13,
4133
4612
  fontWeight: 600,
4134
- color: MODAL_TITLE,
4613
+ color: "#c7cede",
4135
4614
  marginBottom: 8
4136
4615
  },
4137
4616
  children: t("settings.language")
@@ -4154,7 +4633,7 @@ window.__ModuleLoader__.load({
4154
4633
  alignItems: "center",
4155
4634
  gap: 5,
4156
4635
  fontSize: 13,
4157
- color: MODAL_FG,
4636
+ color: "#e6e8ee",
4158
4637
  cursor: "pointer"
4159
4638
  },
4160
4639
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4174,7 +4653,7 @@ window.__ModuleLoader__.load({
4174
4653
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4175
4654
  style: {
4176
4655
  fontSize: 12,
4177
- color: MODAL_HINT,
4656
+ color: "#8b96ab",
4178
4657
  marginBottom: 10
4179
4658
  },
4180
4659
  children: t("settings.support")
@@ -4275,25 +4754,54 @@ window.__ModuleLoader__.load({
4275
4754
  ]
4276
4755
  })]
4277
4756
  }),
4278
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4279
- type: "button",
4280
- "data-toolbar-settings-reset": true,
4281
- onClick: onResetAll,
4757
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4758
+ "data-toolbar-settings-actions": true,
4282
4759
  style: {
4283
- display: "block",
4284
- margin: "16px auto 2px",
4285
- padding: "7px 16px",
4286
- border: `1px solid ${MODAL_BORDER}`,
4287
- borderRadius: MODAL_RADIUS_CONTROL,
4288
- cursor: "pointer",
4289
- color: MODAL_TEXT,
4290
- fontSize: 12.5
4760
+ display: "flex",
4761
+ alignItems: "center",
4762
+ justifyContent: "center",
4763
+ gap: 10,
4764
+ margin: "16px auto 2px"
4291
4765
  },
4292
- children: t("settings.reset")
4766
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4767
+ type: "button",
4768
+ "data-toolbar-settings-reset": true,
4769
+ onClick: onResetAll,
4770
+ style: {
4771
+ padding: "7px 16px",
4772
+ border: `1px solid rgba(255, 255, 255, 0.14)`,
4773
+ borderRadius: 8,
4774
+ cursor: "pointer",
4775
+ color: "#b9c2d4",
4776
+ fontSize: 12.5
4777
+ },
4778
+ children: t("settings.reset")
4779
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4780
+ type: "button",
4781
+ "data-onboarding-reopen": true,
4782
+ onClick: reopenTour,
4783
+ style: {
4784
+ padding: "7px 16px",
4785
+ border: `1px solid rgba(255, 255, 255, 0.14)`,
4786
+ borderRadius: 8,
4787
+ cursor: "pointer",
4788
+ color: "#b9c2d4",
4789
+ fontSize: 12.5
4790
+ },
4791
+ children: t("tour.reopen")
4792
+ })]
4293
4793
  })
4294
4794
  ]
4295
4795
  })
4296
4796
  }),
4797
+ tourOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MilestoneTour, {
4798
+ t,
4799
+ side,
4800
+ toolbarExpanded,
4801
+ settingsOpen,
4802
+ onSetToolbarExpanded: setToolbarExpanded,
4803
+ onClose: () => setTourOpen(false)
4804
+ }, tourRun),
4297
4805
  updateOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4298
4806
  ref: updatePanelRef,
4299
4807
  "data-update-panel": true,
@@ -4330,7 +4838,7 @@ window.__ModuleLoader__.load({
4330
4838
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4331
4839
  style: { color: "#8b96ab" },
4332
4840
  children: [t("update.current"), ": "]
4333
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "0.6.3" })] }),
4841
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "0.6.5" })] }),
4334
4842
  updateCheck.phase === "ok" && updateCheck.latest !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4335
4843
  "data-update-latest": true,
4336
4844
  children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-milestone",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Git-style milestone timeline for DeepSeek Harness: hover for metadata, click to jump to any message. 会话里程碑导航条:圆点时间线,定位并跳转到每条提问。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",