dsh-milestone 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +10 -1
  2. package/lib/client.js +1150 -79
  3. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -795,7 +795,73 @@ 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.4 onboarding: welcome title (also the tutorial dialog's aria-label). */
800
+ "onboarding.welcome.title": "欢迎使用 dsh-milestone",
801
+ /** 0.6.4 onboarding: one-line positioning statement on the welcome page. */
802
+ "onboarding.welcome.subtitle": "一条附着在会话侧边的里程碑导航:悬停圆点看元信息,点击跳到任意提问。",
803
+ /** 0.6.4 onboarding: primary action on the welcome page → step 1. */
804
+ "onboarding.start": "开始引导",
805
+ /** 0.6.4 onboarding: skip action — persists the flag and closes, on EVERY page. */
806
+ "onboarding.skip": "跳过",
807
+ /** 0.6.4 onboarding: step-page progress text `第 n / 4 步`. */
808
+ "onboarding.step.label": "第 {n} / 4 步",
809
+ /** 0.6.4 onboarding: aria-label on one progress dot. */
810
+ "onboarding.step.short": "第 {n} 步",
811
+ /** 0.6.4 onboarding: step-page back navigation. */
812
+ "onboarding.prev": "上一步",
813
+ /** 0.6.4 onboarding: step-page forward navigation (steps 1–3). */
814
+ "onboarding.next": "下一步",
815
+ /** 0.6.4 onboarding: step-4 primary action — persists the flag and closes. */
816
+ "onboarding.finish": "开始使用",
817
+ /** 0.6.4 onboarding: step 1 title — the dot timeline. */
818
+ "onboarding.step1.title": "圆点时间线",
819
+ /** 0.6.4 onboarding: step 1 line 1. */
820
+ "onboarding.step1.desc1": "每条提问在侧边对应一个圆点,自上而下按时间排列。",
821
+ /** 0.6.4 onboarding: step 1 line 2. */
822
+ "onboarding.step1.desc2": "悬停圆点,查看该轮元信息(用时、首字、模型与 Token)。",
823
+ /** 0.6.4 onboarding: step 1 line 3. */
824
+ "onboarding.step1.desc3": "点击任意圆点,会话立即跳到那条提问。",
825
+ /** 0.6.4 onboarding: step 2 title — in-rail search & bookmarks. */
826
+ "onboarding.step2.title": "搜索与收藏",
827
+ /** 0.6.4 onboarding: step 2 line 1. */
828
+ "onboarding.step2.desc1": "输入关键词过滤圆点,只点亮匹配项并显示 N / M 计数;Enter 逐个跳转,Esc 关闭。",
829
+ /** 0.6.4 onboarding: step 2 line 2. */
830
+ "onboarding.step2.desc2": "星标收藏重要消息,再用「只看收藏」一键过滤。",
831
+ /** 0.6.4 onboarding: step 3 title — personalization & settings. */
832
+ "onboarding.step3.title": "个性化与设置",
833
+ /** 0.6.4 onboarding: step 3 line 1. */
834
+ "onboarding.step3.desc1": "调整强调色、圆点大小、距边距离与左右位置,即调即存。",
835
+ /** 0.6.4 onboarding: step 3 line 2. */
836
+ "onboarding.step3.desc2": "切换界面语言、搭配「聚焦」效果,或把常用功能 pin 在折叠外。",
837
+ /** 0.6.4 onboarding: step 4 title — update detection & support. */
838
+ "onboarding.step4.title": "更新检测与支持",
839
+ /** 0.6.4 onboarding: step 4 line 1. */
840
+ "onboarding.step4.desc1": "挂载后自动检查 npm 新版本;有新版本时工具栏会亮起提示。",
841
+ /** 0.6.4 onboarding: step 4 line 2. */
842
+ "onboarding.step4.desc2": "喜欢这个插件?欢迎 Star、提交 Issue,或通过 npm 安装升级。",
843
+ /** 0.6.4 onboarding demo: fake message 1 (step 1 dots / step 2 corpus). */
844
+ "onboarding.demo.m1": "帮我优化这段代码",
845
+ /** 0.6.4 onboarding demo: fake message 2. */
846
+ "onboarding.demo.m2": "解释这个报错",
847
+ /** 0.6.4 onboarding demo: fake message 3. */
848
+ "onboarding.demo.m3": "再检查边界条件",
849
+ /** 0.6.4 onboarding demo: fake message 4. */
850
+ "onboarding.demo.m4": "写个单元测试",
851
+ /** 0.6.4 onboarding demo: fake message 5. */
852
+ "onboarding.demo.m5": "总结一下方案",
853
+ /** 0.6.4 onboarding demo (step 1): hint under the toy dot rail. */
854
+ "onboarding.demo.hoverHint": "试试悬停与点击圆点",
855
+ /** 0.6.4 onboarding demo (step 2): hint under the toy search/favorite. */
856
+ "onboarding.demo.searchHint": "试试输入「报错」,或点星标切换只看收藏",
857
+ /** 0.6.4 onboarding demo (step 3): the 展开箭头 → 齿轮 → 设置 path hint. */
858
+ "onboarding.demo.settingsPath": "展开箭头 → 齿轮 → 设置",
859
+ /** 0.6.4 onboarding demo (step 3): legend label for the focus mix. */
860
+ "onboarding.demo.focusMix": "聚焦搭配",
861
+ /** 0.6.4 onboarding demo (step 3): legend label for pinning features. */
862
+ "onboarding.demo.pin": "pin 固定",
863
+ /** 0.6.4 settings footer action: replay the tutorial. */
864
+ "onboarding.reopen": "重新查看教程"
799
865
  };
800
866
  const en = {
801
867
  "jump.to": "Jump to message {n}",
@@ -900,7 +966,40 @@ window.__ModuleLoader__.load({
900
966
  "settings.language": "Language",
901
967
  "settings.lang.system": "Follow system",
902
968
  "settings.lang.zh": "Chinese",
903
- "settings.lang.en": "English"
969
+ "settings.lang.en": "English",
970
+ "onboarding.welcome.title": "Welcome to dsh-milestone",
971
+ "onboarding.welcome.subtitle": "A milestone rail beside your conversation: hover a dot for metadata, click any dot to jump.",
972
+ "onboarding.start": "Start the tour",
973
+ "onboarding.skip": "Skip",
974
+ "onboarding.step.label": "Step {n} of 4",
975
+ "onboarding.step.short": "Step {n}",
976
+ "onboarding.prev": "Back",
977
+ "onboarding.next": "Next",
978
+ "onboarding.finish": "Get started",
979
+ "onboarding.step1.title": "The dot timeline",
980
+ "onboarding.step1.desc1": "Every prompt is a dot on the side rail, listed top to bottom in time order.",
981
+ "onboarding.step1.desc2": "Hover a dot to see that turn’s metadata (duration, first token, model, tokens).",
982
+ "onboarding.step1.desc3": "Click any dot to jump the conversation straight to that prompt.",
983
+ "onboarding.step2.title": "Search & bookmarks",
984
+ "onboarding.step2.desc1": "Type to filter the dots — matches light up with an N / M counter; Enter jumps, Esc closes.",
985
+ "onboarding.step2.desc2": "Star a message to bookmark it, then use “Bookmarks only” to filter.",
986
+ "onboarding.step3.title": "Personalize & settings",
987
+ "onboarding.step3.desc1": "Tune the accent color, dot size, edge distance, and left/right side — saved as you adjust.",
988
+ "onboarding.step3.desc2": "Switch the UI language, compose your focus effect, or pin features outside the collapse.",
989
+ "onboarding.step4.title": "Updates & support",
990
+ "onboarding.step4.desc1": "A silent check runs after mount; when a new version exists, the toolbar shows a hint.",
991
+ "onboarding.step4.desc2": "Enjoying the plugin? Star us, file an issue, or upgrade via npm.",
992
+ "onboarding.demo.m1": "Help me optimize this code",
993
+ "onboarding.demo.m2": "Explain this error",
994
+ "onboarding.demo.m3": "Check the edge cases again",
995
+ "onboarding.demo.m4": "Write a unit test",
996
+ "onboarding.demo.m5": "Summarize the plan",
997
+ "onboarding.demo.hoverHint": "Try hovering and clicking the dots",
998
+ "onboarding.demo.searchHint": "Try typing “error”, or tap the star for bookmarks-only",
999
+ "onboarding.demo.settingsPath": "Expand arrow → gear → Settings",
1000
+ "onboarding.demo.focusMix": "Focus mix",
1001
+ "onboarding.demo.pin": "Pin keys",
1002
+ "onboarding.reopen": "Replay the tour"
904
1003
  };
905
1004
  /**
906
1005
  * Interpolate `{name}` placeholders with params, matching the harness t seat's
@@ -1329,6 +1428,950 @@ window.__ModuleLoader__.load({
1329
1428
  });
1330
1429
  }
1331
1430
  //#endregion
1431
+ //#region src/client/modal-tokens.ts
1432
+ /**
1433
+ * modal-tokens: the ONE source for the settings modal's dark-panel palette and
1434
+ * radius scale, shared with the 0.6.4 onboarding tutorial modal so the two
1435
+ * dialogs cannot drift (same dark panel on a dark host, same three text tiers,
1436
+ * same 12px panel / 8px control radius, same border tone).
1437
+ *
1438
+ * The static MODAL_CSS block (hover/focus-visible/reduced-motion rules) stays
1439
+ * in MilestoneRail.tsx because it also styles the settings modal's own chrome
1440
+ * (`[data-support-card]`, `[data-toolbar-*]`, ...); the onboarding modal
1441
+ * carries its own small ONBOARDING_CSS block for its own controls, built from
1442
+ * these same tokens. MilestoneRail.tsx imports these constants verbatim so a
1443
+ * future palette change edits exactly one file.
1444
+ */
1445
+ const MODAL_BG = "rgba(20, 24, 32, 0.98)";
1446
+ const MODAL_FG = "#e6e8ee";
1447
+ const MODAL_TITLE = "#c7cede";
1448
+ const MODAL_TEXT = "#b9c2d4";
1449
+ const MODAL_HINT = "#8b96ab";
1450
+ const MODAL_BORDER = "rgba(255, 255, 255, 0.14)";
1451
+ const MODAL_TIP_BG = "#222834";
1452
+ //#endregion
1453
+ //#region src/client/onboarding-store.ts
1454
+ /**
1455
+ * onboarding-store: the persistence layer for the 0.6.4 first-run tutorial —
1456
+ * a single "has the user seen it" flag with NO payload.
1457
+ *
1458
+ * Storage contract: one localStorage key (`dsh-milestone.onboarded`) whose
1459
+ * VALUE is exactly the string `'1'` when the tutorial was completed or
1460
+ * skipped. Anything else (absent key, `'0'`, `'true'`, garbage) means "never
1461
+ * shown" and re-triggers the tutorial.
1462
+ *
1463
+ * Both accessors swallow storage failures silently (SSR, sandboxed iframe,
1464
+ * quota): the tutorial is a best-effort enhancement — a broken storage must
1465
+ * never crash the rail, and a user in that environment simply sees the
1466
+ * tutorial once per page load instead of once ever.
1467
+ */
1468
+ /** The single localStorage key holding the onboarding "seen" flag. */
1469
+ const ONBOARDED_KEY = "dsh-milestone.onboarded";
1470
+ /**
1471
+ * True when the user already completed or skipped the tutorial (the stored
1472
+ * value is exactly `'1'`). Storage unavailability degrades to `false`.
1473
+ */
1474
+ function readOnboardedFlag() {
1475
+ try {
1476
+ return localStorage.getItem(ONBOARDED_KEY) === "1";
1477
+ } catch {
1478
+ return false;
1479
+ }
1480
+ }
1481
+ /**
1482
+ * Persist the tutorial as seen/completed by writing the literal string `'1'`.
1483
+ * Storage failures are swallowed — the flag simply will not survive a reload.
1484
+ */
1485
+ function writeOnboardedFlag() {
1486
+ try {
1487
+ localStorage.setItem(ONBOARDED_KEY, "1");
1488
+ } catch {}
1489
+ }
1490
+ //#endregion
1491
+ //#region src/client/version-meta.ts
1492
+ /**
1493
+ * Installed plugin version. Injected at build time as
1494
+ * `__DSH_MILESTONE_VERSION__`; falls back to `0.0.0-dev` when unbuilt.
1495
+ */
1496
+ const PLUGIN_VERSION = "0.6.4";
1497
+ /** Main repository of dsh-milestone (as referenced by README.md). */
1498
+ const PLUGIN_REPO_URL = "https://github.com/SnowCrescenter-tech/dsh-milestone";
1499
+ /** npm package page (install channel promoted in the settings menu). */
1500
+ const PLUGIN_NPM_URL = "https://www.npmjs.com/package/dsh-milestone";
1501
+ //#endregion
1502
+ //#region src/client/MilestoneOnboarding.tsx
1503
+ /**
1504
+ * MilestoneOnboarding: the 0.6.4 first-run tutorial modal.
1505
+ *
1506
+ * Trigger/ownership lives in MilestoneRail (mount timer + settings reopen);
1507
+ * this component is a fully SELF-CONTAINED dialog: it carries the welcome
1508
+ * page, the 4 step pages with built-in toy demos, step progress, and the
1509
+ * close paths (skip / finish / Escape), and it persists the
1510
+ * `dsh-milestone.onboarded` flag itself via onboarding-store.
1511
+ *
1512
+ * Visual language is copied from the settings modal (MilestoneRail's
1513
+ * MODAL_CSS): dark `rgba(20, 24, 32, 0.98)` panel, three text tiers, 12px
1514
+ * panel / 8px control radii, one accent (inherited through the rail root's
1515
+ * `--ms-accent*` CSS variables), and a small ONBOARDING_CSS block for the
1516
+ * hover / :focus-visible / reduced-motion rules inline styles cannot express.
1517
+ *
1518
+ * Deliberate non-features:
1519
+ * - NO outside-pointerdown dismissal (a misclick must never swallow the
1520
+ * tutorial — the requirement explicitly keeps it off).
1521
+ * - Escape ALWAYS means "skip": it persists the flag and closes.
1522
+ * - The flag is written on IMPRESSION (the welcome page showing is enough);
1523
+ * skip / finish / Escape re-assert it. A mid-tour refresh/crash never
1524
+ * re-pops — replay lives in settings 重新查看教程.
1525
+ */
1526
+ /** Step-page count — the progress indicator shape. */
1527
+ const STEP_COUNT = [
1528
+ 1,
1529
+ 2,
1530
+ 3,
1531
+ 4
1532
+ ];
1533
+ /** The onboarding modal floats above every other rail layer (settings 105). */
1534
+ const ONBOARDING_Z = 110;
1535
+ /** Fake messages the step-1/step-2 demos run on (zh AND en keys exist). */
1536
+ const DEMO_MESSAGE_KEYS = [
1537
+ "onboarding.demo.m1",
1538
+ "onboarding.demo.m2",
1539
+ "onboarding.demo.m3",
1540
+ "onboarding.demo.m4",
1541
+ "onboarding.demo.m5"
1542
+ ];
1543
+ /** Fake per-turn durations for the step-1 hover tooltip (unit text is locale-neutral). */
1544
+ const DEMO_DURATIONS = [
1545
+ "6.2s",
1546
+ "13.4s",
1547
+ "5.1s",
1548
+ "22.0s",
1549
+ "9.8s"
1550
+ ];
1551
+ /**
1552
+ * Static onboarding-modal styling that needs `:hover`/`:focus-visible`
1553
+ * (inline styles cannot express them): one accent focus ring for every
1554
+ * control, hover washes, the demo-link micro-lift, the panel fade-in, and the
1555
+ * reduced-motion kill — mirrors the settings MODAL_CSS pattern. Accent values
1556
+ * come from the rail root's CSS variables (`--ms-accent*`), inherited into
1557
+ * this fixed layer because the overlay renders inside the rail root.
1558
+ */
1559
+ const ONBOARDING_CSS = `
1560
+ @keyframes ms-onboarding-fade { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
1561
+ [data-onboarding-panel] { animation: ms-onboarding-fade 160ms ease; }
1562
+ [data-onboarding-skip]:hover { background: rgba(255, 255, 255, 0.08); }
1563
+ [data-onboarding-prev]:hover, [data-onboarding-next]:hover, [data-onboarding-start]:hover, [data-onboarding-finish]:hover { background: rgba(255, 255, 255, 0.1); }
1564
+ [data-onboarding-skip]:focus-visible, [data-onboarding-prev]:focus-visible,
1565
+ [data-onboarding-next]:focus-visible, [data-onboarding-start]:focus-visible,
1566
+ [data-onboarding-finish]:focus-visible, [data-demo-star]:focus-visible,
1567
+ [data-demo-dot]:focus-visible, [data-demo-search-input]:focus-visible {
1568
+ box-shadow: 0 0 0 2px var(--ms-accent-soft);
1569
+ }
1570
+ [data-demo-link] { transition: transform 120ms ease, border-color 120ms ease, background 120ms ease; }
1571
+ [data-demo-link]:hover { transform: translateY(-2px); border-color: var(--ms-accent); background: rgba(255, 255, 255, 0.09); }
1572
+ @media (prefers-reduced-motion: reduce) {
1573
+ [data-onboarding-panel] { animation: none; }
1574
+ [data-onboarding-skip], [data-onboarding-prev], [data-onboarding-next],
1575
+ [data-onboarding-start], [data-onboarding-finish], [data-demo-link] { transition: none; }
1576
+ }
1577
+ `;
1578
+ /** Primary (accent) dialog action — start / next / finish. */
1579
+ const PRIMARY_BUTTON = {
1580
+ background: "var(--ms-accent-bg)",
1581
+ color: "var(--ms-accent-soft)",
1582
+ border: "1px solid var(--ms-accent)",
1583
+ borderRadius: 8,
1584
+ padding: "7px 18px",
1585
+ fontSize: 13,
1586
+ fontWeight: 600,
1587
+ cursor: "pointer"
1588
+ };
1589
+ /** Secondary dialog action — back / welcome skip. */
1590
+ const GHOST_BUTTON = {
1591
+ background: "rgba(255, 255, 255, 0.06)",
1592
+ color: MODAL_TEXT,
1593
+ border: `1px solid ${MODAL_BORDER}`,
1594
+ borderRadius: 8,
1595
+ padding: "7px 16px",
1596
+ fontSize: 12.5,
1597
+ cursor: "pointer"
1598
+ };
1599
+ /** Corner skip (step pages) — the quietest of the three button tiers. */
1600
+ const SKIP_BUTTON = {
1601
+ background: "transparent",
1602
+ color: MODAL_HINT,
1603
+ border: "none",
1604
+ padding: "4px 8px",
1605
+ borderRadius: 8,
1606
+ fontSize: 12,
1607
+ cursor: "pointer"
1608
+ };
1609
+ /** Resolve the five fake demo messages through the active locale. */
1610
+ function demoMessages(t) {
1611
+ return DEMO_MESSAGE_KEYS.map((key) => t(key));
1612
+ }
1613
+ /**
1614
+ * Step-1 demo: a toy dot rail with the REAL dot visual — accent gradient dots,
1615
+ * hover enlarges + shows a fake metadata tooltip (position + duration), click
1616
+ * marks the dot with the white ring. All local state; nothing touches real
1617
+ * session data.
1618
+ */
1619
+ function DemoDotRail({ t, accent }) {
1620
+ const messages = demoMessages(t);
1621
+ const [hoverIndex, setHoverIndex] = (0, react.useState)(null);
1622
+ const [activeIndex, setActiveIndex] = (0, react.useState)(null);
1623
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1624
+ "data-demo-dots": true,
1625
+ children: [
1626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1627
+ "data-demo-dot-row": true,
1628
+ style: {
1629
+ display: "flex",
1630
+ alignItems: "center",
1631
+ justifyContent: "center",
1632
+ gap: 22
1633
+ },
1634
+ children: messages.map((msg, i) => {
1635
+ const hovered = hoverIndex === i;
1636
+ const active = activeIndex === i;
1637
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1638
+ type: "button",
1639
+ "data-demo-dot": i,
1640
+ "data-active": active ? "true" : void 0,
1641
+ "aria-label": msg,
1642
+ "aria-pressed": active,
1643
+ onMouseEnter: () => setHoverIndex(i),
1644
+ onMouseLeave: () => setHoverIndex(null),
1645
+ onFocus: () => setHoverIndex(i),
1646
+ onBlur: () => setHoverIndex(null),
1647
+ onClick: () => setActiveIndex(i),
1648
+ style: {
1649
+ width: 36,
1650
+ height: 36,
1651
+ display: "flex",
1652
+ alignItems: "center",
1653
+ justifyContent: "center",
1654
+ background: "transparent",
1655
+ border: "none",
1656
+ padding: 0,
1657
+ cursor: "pointer",
1658
+ borderRadius: "50%"
1659
+ },
1660
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
1661
+ width: 13,
1662
+ height: 13,
1663
+ borderRadius: "50%",
1664
+ background: dotColor(i, messages.length, accent),
1665
+ boxShadow: active ? "0 0 0 3px rgba(255, 255, 255, 0.9)" : hovered ? "0 0 0 3px rgba(255, 255, 255, 0.35)" : "none",
1666
+ transform: hovered || active ? "scale(1.35)" : "scale(1)",
1667
+ transition: "transform 120ms ease, box-shadow 120ms ease"
1668
+ } })
1669
+ }, msg);
1670
+ })
1671
+ }),
1672
+ hoverIndex !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1673
+ "data-demo-tooltip": true,
1674
+ style: {
1675
+ marginTop: 8,
1676
+ textAlign: "center",
1677
+ fontSize: 12,
1678
+ color: "#b9c2d4",
1679
+ lineHeight: 1.5
1680
+ },
1681
+ children: [
1682
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("pos.of", {
1683
+ n: hoverIndex + 1,
1684
+ m: messages.length
1685
+ }) }),
1686
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: " · " }),
1687
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("duration.label", { name: DEMO_DURATIONS[hoverIndex] }) })
1688
+ ]
1689
+ }),
1690
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1691
+ "data-demo-hint": true,
1692
+ style: {
1693
+ marginTop: 8,
1694
+ textAlign: "center",
1695
+ fontSize: 12,
1696
+ color: MODAL_HINT
1697
+ },
1698
+ children: t("onboarding.demo.hoverHint")
1699
+ })
1700
+ ]
1701
+ });
1702
+ }
1703
+ /**
1704
+ * Step-2 demo: a toy search box that filters the demo messages (N / M count)
1705
+ * plus one bookmark star — active = solid star + "bookmarks only" row list.
1706
+ * Local state only; the real rail/search/bookmarks are untouched.
1707
+ */
1708
+ function DemoSearch({ t, accent }) {
1709
+ const messages = demoMessages(t);
1710
+ const starIndex = 1;
1711
+ const [query, setQuery] = (0, react.useState)("");
1712
+ const [favOnly, setFavOnly] = (0, react.useState)(false);
1713
+ const lower = query.trim().toLowerCase();
1714
+ const visible = favOnly ? messages.filter((_, i) => i === starIndex) : messages;
1715
+ const matches = lower === "" ? visible.length : visible.filter((m) => m.toLowerCase().includes(lower)).length;
1716
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1717
+ "data-demo-search": true,
1718
+ children: [
1719
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1720
+ style: {
1721
+ display: "flex",
1722
+ alignItems: "center",
1723
+ gap: 8
1724
+ },
1725
+ children: [
1726
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1727
+ "data-demo-search-input": true,
1728
+ type: "text",
1729
+ value: query,
1730
+ onChange: (e) => setQuery(e.target.value),
1731
+ placeholder: t("search.placeholder"),
1732
+ "aria-label": t("search.label"),
1733
+ style: {
1734
+ flex: 1,
1735
+ minWidth: 0,
1736
+ padding: "6px 10px",
1737
+ borderRadius: 8,
1738
+ border: `1px solid ${MODAL_BORDER}`,
1739
+ background: "rgba(255, 255, 255, 0.05)",
1740
+ color: MODAL_FG,
1741
+ fontSize: 12.5,
1742
+ outline: "none"
1743
+ }
1744
+ }),
1745
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1746
+ "data-demo-search-count": true,
1747
+ style: {
1748
+ fontSize: 12,
1749
+ color: MODAL_TEXT,
1750
+ whiteSpace: "nowrap"
1751
+ },
1752
+ children: [
1753
+ matches,
1754
+ " / ",
1755
+ visible.length
1756
+ ]
1757
+ }),
1758
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1759
+ type: "button",
1760
+ "data-demo-star": true,
1761
+ "aria-pressed": favOnly,
1762
+ "aria-label": t("bookmark.filter"),
1763
+ title: t("bookmark.filter"),
1764
+ onClick: () => setFavOnly((v) => !v),
1765
+ style: {
1766
+ width: 30,
1767
+ height: 30,
1768
+ flexShrink: 0,
1769
+ display: "flex",
1770
+ alignItems: "center",
1771
+ justifyContent: "center",
1772
+ background: favOnly ? "var(--ms-accent-bg)" : "transparent",
1773
+ border: `1px solid ${MODAL_BORDER}`,
1774
+ borderRadius: 8,
1775
+ padding: 0,
1776
+ cursor: "pointer",
1777
+ color: favOnly ? "var(--ms-accent-soft)" : MODAL_HINT
1778
+ },
1779
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1780
+ width: "14",
1781
+ height: "14",
1782
+ viewBox: "0 0 24 24",
1783
+ fill: favOnly ? "currentColor" : "none",
1784
+ stroke: "currentColor",
1785
+ strokeWidth: "2",
1786
+ strokeLinejoin: "round",
1787
+ "aria-hidden": "true",
1788
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m12 2 3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" })
1789
+ })
1790
+ })
1791
+ ]
1792
+ }),
1793
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1794
+ "data-demo-search-rows": true,
1795
+ style: {
1796
+ display: "flex",
1797
+ flexDirection: "column",
1798
+ gap: 6,
1799
+ marginTop: 10
1800
+ },
1801
+ children: visible.map((msg, i) => {
1802
+ const realIndex = favOnly ? starIndex : i;
1803
+ const lit = lower === "" || msg.toLowerCase().includes(lower);
1804
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1805
+ "data-demo-search-row": true,
1806
+ "data-index": realIndex,
1807
+ "data-lit": lit ? "true" : "false",
1808
+ style: {
1809
+ display: "flex",
1810
+ alignItems: "center",
1811
+ gap: 8,
1812
+ fontSize: 12,
1813
+ color: lit ? MODAL_FG : MODAL_HINT,
1814
+ opacity: lit ? 1 : .45,
1815
+ transition: "opacity 120ms ease"
1816
+ },
1817
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1818
+ "aria-hidden": "true",
1819
+ style: {
1820
+ width: 8,
1821
+ height: 8,
1822
+ flexShrink: 0,
1823
+ borderRadius: "50%",
1824
+ background: dotColor(realIndex, messages.length, accent)
1825
+ }
1826
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: msg })]
1827
+ }, msg);
1828
+ })
1829
+ }),
1830
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1831
+ "data-demo-search-hint": true,
1832
+ style: {
1833
+ marginTop: 8,
1834
+ textAlign: "center",
1835
+ fontSize: 12,
1836
+ color: MODAL_HINT
1837
+ },
1838
+ children: t("onboarding.demo.searchHint")
1839
+ })
1840
+ ]
1841
+ });
1842
+ }
1843
+ /**
1844
+ * Step-3 demo: a static legend of the personalization controls (accent / size /
1845
+ * distance / side / language / focus mix / pin), each with a tiny aria-hidden
1846
+ * visual, plus the 展开箭头 → 齿轮 → 设置 path hint.
1847
+ */
1848
+ function DemoSettings({ t, accent }) {
1849
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1850
+ "data-demo-settings": true,
1851
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1852
+ style: {
1853
+ display: "flex",
1854
+ flexDirection: "column",
1855
+ gap: 6
1856
+ },
1857
+ children: [
1858
+ {
1859
+ label: t("settings.accent"),
1860
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1861
+ "aria-hidden": "true",
1862
+ style: {
1863
+ width: 10,
1864
+ height: 10,
1865
+ borderRadius: "50%",
1866
+ background: accent
1867
+ }
1868
+ })
1869
+ },
1870
+ {
1871
+ label: t("settings.iconSize"),
1872
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1873
+ "aria-hidden": "true",
1874
+ style: {
1875
+ display: "flex",
1876
+ alignItems: "flex-end",
1877
+ gap: 2
1878
+ },
1879
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
1880
+ width: 7,
1881
+ height: 7,
1882
+ borderRadius: "50%",
1883
+ background: MODAL_HINT
1884
+ } }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
1885
+ width: 12,
1886
+ height: 12,
1887
+ borderRadius: "50%",
1888
+ background: MODAL_TEXT
1889
+ } })]
1890
+ })
1891
+ },
1892
+ {
1893
+ label: t("settings.inset"),
1894
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1895
+ "aria-hidden": "true",
1896
+ style: {
1897
+ width: 12,
1898
+ height: 12,
1899
+ border: `1px solid ${MODAL_BORDER}`,
1900
+ borderRadius: 2
1901
+ }
1902
+ })
1903
+ },
1904
+ {
1905
+ label: t("settings.side"),
1906
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1907
+ "aria-hidden": "true",
1908
+ style: {
1909
+ fontSize: 14,
1910
+ color: MODAL_TEXT
1911
+ },
1912
+ children: "⇄"
1913
+ })
1914
+ },
1915
+ {
1916
+ label: t("settings.language"),
1917
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1918
+ "aria-hidden": "true",
1919
+ style: {
1920
+ fontSize: 11,
1921
+ color: MODAL_TEXT
1922
+ },
1923
+ children: "中 / EN"
1924
+ })
1925
+ },
1926
+ {
1927
+ label: t("onboarding.demo.focusMix"),
1928
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1929
+ "aria-hidden": "true",
1930
+ width: "14",
1931
+ height: "10",
1932
+ viewBox: "0 0 24 24",
1933
+ fill: "none",
1934
+ stroke: "currentColor",
1935
+ strokeWidth: "2.5",
1936
+ strokeLinecap: "round",
1937
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1938
+ cx: "12",
1939
+ cy: "12",
1940
+ r: "3"
1941
+ })]
1942
+ })
1943
+ },
1944
+ {
1945
+ label: t("onboarding.demo.pin"),
1946
+ visual: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1947
+ "aria-hidden": "true",
1948
+ width: "12",
1949
+ height: "14",
1950
+ viewBox: "0 0 24 24",
1951
+ fill: "none",
1952
+ stroke: "currentColor",
1953
+ strokeWidth: "2",
1954
+ strokeLinecap: "round",
1955
+ strokeLinejoin: "round",
1956
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 21v-4" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M7 4h10l-1.2 6.5a4.6 4.6 0 0 1-7.6 0z" })]
1957
+ })
1958
+ }
1959
+ ].map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1960
+ "data-demo-legend-row": true,
1961
+ style: {
1962
+ display: "flex",
1963
+ alignItems: "center",
1964
+ gap: 10,
1965
+ fontSize: 12.5,
1966
+ color: MODAL_TEXT
1967
+ },
1968
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1969
+ style: {
1970
+ width: 56,
1971
+ flexShrink: 0,
1972
+ display: "flex",
1973
+ justifyContent: "center"
1974
+ },
1975
+ children: row.visual
1976
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: row.label })]
1977
+ }, row.label))
1978
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1979
+ "data-demo-settings-path": true,
1980
+ style: {
1981
+ marginTop: 10,
1982
+ textAlign: "center",
1983
+ fontSize: 12,
1984
+ color: MODAL_HINT
1985
+ },
1986
+ children: t("onboarding.demo.settingsPath")
1987
+ })]
1988
+ });
1989
+ }
1990
+ /** Step-4 demo: update-check pill + the four support links (repo/star/issues/npm). */
1991
+ function DemoSupport({ t }) {
1992
+ const linkStyle = {
1993
+ display: "flex",
1994
+ alignItems: "center",
1995
+ justifyContent: "center",
1996
+ padding: "7px 6px",
1997
+ borderRadius: 8,
1998
+ background: "rgba(255, 255, 255, 0.05)",
1999
+ border: `1px solid ${MODAL_BORDER}`,
2000
+ color: MODAL_TITLE,
2001
+ fontSize: 11.5,
2002
+ textDecoration: "none",
2003
+ textAlign: "center",
2004
+ lineHeight: 1.35
2005
+ };
2006
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2007
+ "data-demo-support": true,
2008
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2009
+ "data-demo-update-pill": true,
2010
+ style: {
2011
+ display: "inline-flex",
2012
+ alignItems: "center",
2013
+ gap: 6,
2014
+ padding: "4px 10px",
2015
+ borderRadius: 999,
2016
+ background: "rgba(255, 255, 255, 0.06)",
2017
+ border: `1px solid ${MODAL_BORDER}`,
2018
+ color: MODAL_TEXT,
2019
+ fontSize: 12
2020
+ },
2021
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2022
+ "aria-hidden": "true",
2023
+ style: {
2024
+ width: 6,
2025
+ height: 6,
2026
+ borderRadius: "50%",
2027
+ background: "var(--ms-accent)"
2028
+ }
2029
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2030
+ t("update.title"),
2031
+ " · v",
2032
+ PLUGIN_VERSION
2033
+ ] })]
2034
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2035
+ "data-demo-links": true,
2036
+ style: {
2037
+ display: "grid",
2038
+ gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
2039
+ gap: 8,
2040
+ marginTop: 12
2041
+ },
2042
+ children: [
2043
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2044
+ href: PLUGIN_REPO_URL,
2045
+ target: "_blank",
2046
+ rel: "noreferrer",
2047
+ "data-demo-link": true,
2048
+ "data-link": "repo",
2049
+ style: linkStyle,
2050
+ children: t("settings.repo")
2051
+ }),
2052
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2053
+ href: PLUGIN_REPO_URL,
2054
+ target: "_blank",
2055
+ rel: "noreferrer",
2056
+ "data-demo-link": true,
2057
+ "data-link": "star",
2058
+ style: linkStyle,
2059
+ children: t("settings.star")
2060
+ }),
2061
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2062
+ href: `${PLUGIN_REPO_URL}/issues`,
2063
+ target: "_blank",
2064
+ rel: "noreferrer",
2065
+ "data-demo-link": true,
2066
+ "data-link": "issues",
2067
+ style: linkStyle,
2068
+ children: t("settings.issues")
2069
+ }),
2070
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2071
+ href: PLUGIN_NPM_URL,
2072
+ target: "_blank",
2073
+ rel: "noreferrer",
2074
+ "data-demo-link": true,
2075
+ "data-link": "npm",
2076
+ style: linkStyle,
2077
+ children: t("settings.npm")
2078
+ })
2079
+ ]
2080
+ })]
2081
+ });
2082
+ }
2083
+ /**
2084
+ * The tutorial dialog. `step` 0 = welcome; 1–4 = the step pages.
2085
+ *
2086
+ * Impressions persist: the moment the dialog mounts (welcome shown), the
2087
+ * onboarded flag is written — closing mid-tour via refresh/crash/navigation
2088
+ * never re-pops (ROADMAP 0.6.4: 印象即持久化). Every explicit close path
2089
+ * (skip anywhere, finish, Escape) re-asserts the same `'1'` and then lets the
2090
+ * parent unmount the modal.
2091
+ */
2092
+ function MilestoneOnboarding({ t, accent, onClose }) {
2093
+ const [step, setStep] = (0, react.useState)(0);
2094
+ const panelRef = (0, react.useRef)(null);
2095
+ (0, react.useEffect)(() => {
2096
+ writeOnboardedFlag();
2097
+ }, []);
2098
+ /** Skip / finish / Escape converge here: persist, then close. */
2099
+ const finish = (0, react.useCallback)(() => {
2100
+ writeOnboardedFlag();
2101
+ onClose();
2102
+ }, [onClose]);
2103
+ (0, react.useEffect)(() => {
2104
+ const onKey = (e) => {
2105
+ if (e.key !== "Escape") return;
2106
+ finish();
2107
+ };
2108
+ window.addEventListener("keydown", onKey);
2109
+ return () => window.removeEventListener("keydown", onKey);
2110
+ }, [finish]);
2111
+ (0, react.useEffect)(() => {
2112
+ panelRef.current?.querySelector("[data-onboarding-start], [data-onboarding-next], [data-onboarding-finish]")?.focus();
2113
+ }, [step]);
2114
+ const goNext = () => setStep((s) => Math.min(4, s + 1));
2115
+ const goPrev = () => setStep((s) => Math.max(1, s - 1));
2116
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2117
+ "data-onboarding-overlay": true,
2118
+ style: {
2119
+ position: "fixed",
2120
+ inset: 0,
2121
+ background: "rgba(8, 10, 15, 0.55)",
2122
+ zIndex: ONBOARDING_Z,
2123
+ display: "flex",
2124
+ alignItems: "center",
2125
+ justifyContent: "center",
2126
+ padding: 16
2127
+ },
2128
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2129
+ ref: panelRef,
2130
+ "data-onboarding-panel": true,
2131
+ role: "dialog",
2132
+ "aria-modal": "true",
2133
+ "aria-label": t("onboarding.welcome.title"),
2134
+ onClick: (e) => e.stopPropagation(),
2135
+ style: {
2136
+ width: "min(560px, 92vw)",
2137
+ maxHeight: "80vh",
2138
+ overflowY: "auto",
2139
+ padding: 20,
2140
+ background: MODAL_BG,
2141
+ color: MODAL_FG,
2142
+ borderRadius: 12,
2143
+ boxShadow: "0 24px 64px rgba(0, 0, 0, 0.55)",
2144
+ scrollbarWidth: "thin",
2145
+ scrollbarColor: "rgba(255, 255, 255, 0.2) transparent"
2146
+ },
2147
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: ONBOARDING_CSS }), step === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2148
+ "data-onboarding-welcome": true,
2149
+ children: [
2150
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2151
+ "data-onboarding-welcome-title": true,
2152
+ style: {
2153
+ fontSize: 17,
2154
+ fontWeight: 700,
2155
+ color: MODAL_FG
2156
+ },
2157
+ children: t("onboarding.welcome.title")
2158
+ }),
2159
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2160
+ "data-onboarding-welcome-subtitle": true,
2161
+ style: {
2162
+ marginTop: 8,
2163
+ fontSize: 13,
2164
+ lineHeight: 1.65,
2165
+ color: MODAL_TEXT
2166
+ },
2167
+ children: t("onboarding.welcome.subtitle")
2168
+ }),
2169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2170
+ "data-onboarding-welcome-actions": true,
2171
+ style: {
2172
+ display: "flex",
2173
+ justifyContent: "center",
2174
+ gap: 10,
2175
+ marginTop: 18
2176
+ },
2177
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2178
+ type: "button",
2179
+ "data-onboarding-start": true,
2180
+ onClick: () => setStep(1),
2181
+ style: PRIMARY_BUTTON,
2182
+ children: t("onboarding.start")
2183
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2184
+ type: "button",
2185
+ "data-onboarding-skip": true,
2186
+ onClick: finish,
2187
+ style: GHOST_BUTTON,
2188
+ children: t("onboarding.skip")
2189
+ })]
2190
+ })
2191
+ ]
2192
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2193
+ "data-onboarding-step": true,
2194
+ "data-step": step,
2195
+ children: [
2196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2197
+ style: {
2198
+ display: "flex",
2199
+ alignItems: "flex-start",
2200
+ justifyContent: "space-between",
2201
+ gap: 10
2202
+ },
2203
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2204
+ "data-onboarding-step-title": true,
2205
+ style: {
2206
+ fontSize: 15,
2207
+ fontWeight: 600,
2208
+ color: MODAL_FG
2209
+ },
2210
+ children: [
2211
+ step === 1 && t("onboarding.step1.title"),
2212
+ step === 2 && t("onboarding.step2.title"),
2213
+ step === 3 && t("onboarding.step3.title"),
2214
+ step === 4 && t("onboarding.step4.title")
2215
+ ]
2216
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2217
+ type: "button",
2218
+ "data-onboarding-skip": true,
2219
+ onClick: finish,
2220
+ style: SKIP_BUTTON,
2221
+ children: t("onboarding.skip")
2222
+ })]
2223
+ }),
2224
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2225
+ style: {
2226
+ display: "flex",
2227
+ flexDirection: "column",
2228
+ gap: 6,
2229
+ marginTop: 10
2230
+ },
2231
+ children: [
2232
+ step === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2233
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2234
+ "data-onboarding-step-desc": true,
2235
+ "data-desc": "1",
2236
+ children: t("onboarding.step1.desc1")
2237
+ }),
2238
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2239
+ "data-onboarding-step-desc": true,
2240
+ "data-desc": "2",
2241
+ children: t("onboarding.step1.desc2")
2242
+ }),
2243
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2244
+ "data-onboarding-step-desc": true,
2245
+ "data-desc": "3",
2246
+ children: t("onboarding.step1.desc3")
2247
+ })
2248
+ ] }),
2249
+ step === 2 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2250
+ "data-onboarding-step-desc": true,
2251
+ "data-desc": "1",
2252
+ children: t("onboarding.step2.desc1")
2253
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2254
+ "data-onboarding-step-desc": true,
2255
+ "data-desc": "2",
2256
+ children: t("onboarding.step2.desc2")
2257
+ })] }),
2258
+ step === 3 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2259
+ "data-onboarding-step-desc": true,
2260
+ "data-desc": "1",
2261
+ children: t("onboarding.step3.desc1")
2262
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2263
+ "data-onboarding-step-desc": true,
2264
+ "data-desc": "2",
2265
+ children: t("onboarding.step3.desc2")
2266
+ })] }),
2267
+ step === 4 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2268
+ "data-onboarding-step-desc": true,
2269
+ "data-desc": "1",
2270
+ children: t("onboarding.step4.desc1")
2271
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2272
+ "data-onboarding-step-desc": true,
2273
+ "data-desc": "2",
2274
+ children: t("onboarding.step4.desc2")
2275
+ })] })
2276
+ ]
2277
+ }),
2278
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2279
+ "data-onboarding-demo": true,
2280
+ style: {
2281
+ marginTop: 14,
2282
+ padding: 12,
2283
+ borderRadius: 8,
2284
+ background: MODAL_TIP_BG,
2285
+ border: `1px solid ${MODAL_BORDER}`
2286
+ },
2287
+ children: [
2288
+ step === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DemoDotRail, {
2289
+ t,
2290
+ accent
2291
+ }),
2292
+ step === 2 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DemoSearch, {
2293
+ t,
2294
+ accent
2295
+ }),
2296
+ step === 3 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DemoSettings, {
2297
+ t,
2298
+ accent
2299
+ }),
2300
+ step === 4 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DemoSupport, { t })
2301
+ ]
2302
+ }),
2303
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
2304
+ style: {
2305
+ display: "flex",
2306
+ alignItems: "center",
2307
+ justifyContent: "space-between",
2308
+ gap: 12,
2309
+ marginTop: 16
2310
+ },
2311
+ children: [
2312
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2313
+ type: "button",
2314
+ "data-onboarding-prev": true,
2315
+ onClick: goPrev,
2316
+ disabled: step === 1,
2317
+ style: GHOST_BUTTON,
2318
+ children: t("onboarding.prev")
2319
+ }),
2320
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2321
+ style: {
2322
+ display: "flex",
2323
+ flexDirection: "column",
2324
+ alignItems: "center",
2325
+ gap: 6
2326
+ },
2327
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2328
+ "data-onboarding-progress": true,
2329
+ style: {
2330
+ fontSize: 12,
2331
+ color: MODAL_HINT
2332
+ },
2333
+ children: t("onboarding.step.label", { n: step })
2334
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2335
+ style: {
2336
+ display: "flex",
2337
+ gap: 5
2338
+ },
2339
+ children: STEP_COUNT.map((n) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2340
+ "data-onboarding-progress-dot": true,
2341
+ "data-active": step === n ? "true" : void 0,
2342
+ "aria-label": t("onboarding.step.short", { n }),
2343
+ "aria-current": step === n ? "step" : void 0,
2344
+ style: {
2345
+ width: 16,
2346
+ height: 4,
2347
+ borderRadius: 2,
2348
+ background: step === n ? "var(--ms-accent)" : "rgba(255, 255, 255, 0.18)",
2349
+ transition: "background 120ms ease, width 120ms ease"
2350
+ }
2351
+ }, n))
2352
+ })]
2353
+ }),
2354
+ step < 4 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2355
+ type: "button",
2356
+ "data-onboarding-next": true,
2357
+ onClick: goNext,
2358
+ style: PRIMARY_BUTTON,
2359
+ children: t("onboarding.next")
2360
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2361
+ type: "button",
2362
+ "data-onboarding-finish": true,
2363
+ onClick: finish,
2364
+ style: PRIMARY_BUTTON,
2365
+ children: t("onboarding.finish")
2366
+ })
2367
+ ]
2368
+ })
2369
+ ]
2370
+ })]
2371
+ })
2372
+ });
2373
+ }
2374
+ //#endregion
1332
2375
  //#region src/client/MilestoneRailTooltip.tsx
1333
2376
  /**
1334
2377
  * @param props - the hovered mark + bookmark wiring (see {@link MilestoneRailTooltipProps}).
@@ -2274,13 +3317,6 @@ window.__ModuleLoader__.load({
2274
3317
  return fresh;
2275
3318
  }
2276
3319
  //#endregion
2277
- //#region src/client/version-meta.ts
2278
- /**
2279
- * Installed plugin version. Injected at build time as
2280
- * `__DSH_MILESTONE_VERSION__`; falls back to `0.0.0-dev` when unbuilt.
2281
- */
2282
- const PLUGIN_VERSION = "0.6.3";
2283
- //#endregion
2284
3320
  //#region src/client/MilestoneRail.tsx
2285
3321
  /**
2286
3322
  * MilestoneRail: the milestone.rail entry (session scope). Renders a fixed
@@ -2324,6 +3360,13 @@ window.__ModuleLoader__.load({
2324
3360
  * hover descriptions, the personalization controls, and the support-us card
2325
3361
  * grid); everything the modal changes persists under `dsh-milestone.toolbar`.
2326
3362
  */
3363
+ /**
3364
+ * Settings modal shared palette + geometry — ONE source in modal-tokens.ts,
3365
+ * also consumed by the 0.6.4 onboarding tutorial modal so the two dialogs
3366
+ * cannot drift. Dark panel on a dark host, three text tiers (primary /
3367
+ * section title / hint + muted), one border tone, a 12px panel / 8px control
3368
+ * radius scale and a 4-unit spacing scale (4 / 8 / 12 / 16 / 20).
3369
+ */
2327
3370
  /** Minimum user messages before the rail adds value. */
2328
3371
  const MIN_MARKS = 2;
2329
3372
  const PREVIEW_LENGTH = 80;
@@ -2422,22 +3465,6 @@ window.__ModuleLoader__.load({
2422
3465
  }
2423
3466
  return rules.join("\n");
2424
3467
  }
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
3468
  /** Near-row description tip: how far its right edge sits from the row's right
2442
3469
  * edge — clears the 32px switch + its 10px padding. */
2443
3470
  const MODAL_TIP_RIGHT = 54;
@@ -2470,12 +3497,13 @@ window.__ModuleLoader__.load({
2470
3497
  [data-personal-toggle]:hover, [data-focus-toggle-settings]:hover { background: rgba(255, 255, 255, 0.05); }
2471
3498
  [data-focus-option]:hover { background: rgba(255, 255, 255, 0.04); }
2472
3499
  [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); }
3500
+ [data-toolbar-settings-reset], [data-onboarding-reopen] { background: rgba(255, 255, 255, 0.06); }
3501
+ [data-toolbar-settings-reset]:hover, [data-onboarding-reopen]:hover { background: rgba(255, 255, 255, 0.1); }
2475
3502
  /* ONE accent ring for keyboard focus on every modal control. */
2476
3503
  [data-toolbar-pin-toggle]:focus-visible, [data-personal-toggle]:focus-visible,
2477
3504
  [data-focus-toggle-settings]:focus-visible,
2478
- [data-toolbar-settings-close]:focus-visible, [data-toolbar-settings-reset]:focus-visible {
3505
+ [data-toolbar-settings-close]:focus-visible, [data-toolbar-settings-reset]:focus-visible,
3506
+ [data-onboarding-reopen]:focus-visible {
2479
3507
  box-shadow: 0 0 0 2px var(--ms-accent-soft);
2480
3508
  }
2481
3509
  /* Near-row description tip: a rotated square peeks out of the LEFT edge so
@@ -2518,7 +3546,7 @@ window.__ModuleLoader__.load({
2518
3546
  width: "100%",
2519
3547
  padding: "8px 10px",
2520
3548
  border: "none",
2521
- borderRadius: MODAL_RADIUS_CONTROL,
3549
+ borderRadius: 8,
2522
3550
  cursor: "pointer",
2523
3551
  color: MODAL_TITLE,
2524
3552
  fontSize: 13,
@@ -2551,6 +3579,9 @@ window.__ModuleLoader__.load({
2551
3579
  /** B4 update-check: mount-time silent check delay (ms) — give the harness
2552
3580
  * time to settle before hitting the registry. */
2553
3581
  const UPDATE_CHECK_MOUNT_DELAY = 1500;
3582
+ /** 0.6.4 first-run tutorial: mount-time show delay (ms) — let the rail settle
3583
+ * before the onboarding modal pops. */
3584
+ const ONBOARDING_MOUNT_DELAY = 800;
2554
3585
  /** Initial state: no check has completed yet, nothing to show. */
2555
3586
  const NO_UPDATE_CHECK = {
2556
3587
  phase: "idle",
@@ -2778,6 +3809,7 @@ window.__ModuleLoader__.load({
2778
3809
  const [expandHovered, setExpandHovered] = (0, react.useState)(false);
2779
3810
  const [settingsHovered, setSettingsHovered] = (0, react.useState)(false);
2780
3811
  const [settingsOpen, setSettingsOpen] = (0, react.useState)(false);
3812
+ const [onboardingOpen, setOnboardingOpen] = (0, react.useState)(false);
2781
3813
  /** The feature whose near-row description tip is currently visible
2782
3814
  * (`null` = none — tips only appear on hover/focus of their own row). */
2783
3815
  const [descFeature, setDescFeature] = (0, react.useState)(null);
@@ -2857,6 +3889,12 @@ window.__ModuleLoader__.load({
2857
3889
  const timer = window.setTimeout(runUpdateCheck, UPDATE_CHECK_MOUNT_DELAY);
2858
3890
  return () => window.clearTimeout(timer);
2859
3891
  }, []);
3892
+ (0, react.useEffect)(() => {
3893
+ const timer = window.setTimeout(() => {
3894
+ if (!readOnboardedFlag()) setOnboardingOpen(true);
3895
+ }, ONBOARDING_MOUNT_DELAY);
3896
+ return () => window.clearTimeout(timer);
3897
+ }, []);
2860
3898
  useOutsideDismiss(updatePanelRef, updateOpen, () => {
2861
3899
  setUpdateOpen(false);
2862
3900
  updateBtnRef.current?.focus();
@@ -3020,6 +4058,13 @@ window.__ModuleLoader__.load({
3020
4058
  setSettingsOpen(false);
3021
4059
  settingsBtnRef.current?.focus();
3022
4060
  };
4061
+ /** 0.6.4: settings → 重新查看教程 — close settings and replay the tutorial
4062
+ * immediately (the flag may or may not be set; skipping/completing it
4063
+ * re-persists the flag anyway). */
4064
+ const reopenOnboarding = () => {
4065
+ setSettingsOpen(false);
4066
+ setOnboardingOpen(true);
4067
+ };
3023
4068
  /** B1: a feature renders while the toolbar is EXPANDED or while it is pinned. */
3024
4069
  const featureVisible = (id) => toolbarExpanded || pinned.includes(id);
3025
4070
  /** Base chrome-button style: accent-defined active tint, scaled hit area. */
@@ -3503,9 +4548,9 @@ window.__ModuleLoader__.load({
3503
4548
  maxHeight: "78vh",
3504
4549
  overflowY: "auto",
3505
4550
  padding: 20,
3506
- background: MODAL_BG,
3507
- color: MODAL_FG,
3508
- borderRadius: MODAL_RADIUS_PANEL,
4551
+ background: "rgba(20, 24, 32, 0.98)",
4552
+ color: "#e6e8ee",
4553
+ borderRadius: 12,
3509
4554
  boxShadow: "0 24px 64px rgba(0, 0, 0, 0.55)",
3510
4555
  scrollbarWidth: "thin",
3511
4556
  scrollbarColor: "rgba(255, 255, 255, 0.2) transparent"
@@ -3524,7 +4569,7 @@ window.__ModuleLoader__.load({
3524
4569
  style: {
3525
4570
  fontSize: 15,
3526
4571
  fontWeight: 600,
3527
- color: MODAL_FG
4572
+ color: "#e6e8ee"
3528
4573
  },
3529
4574
  children: t("settings.title")
3530
4575
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -3543,8 +4588,8 @@ window.__ModuleLoader__.load({
3543
4588
  border: "none",
3544
4589
  padding: 0,
3545
4590
  cursor: "pointer",
3546
- color: MODAL_HINT,
3547
- borderRadius: MODAL_RADIUS_CONTROL,
4591
+ color: "#8b96ab",
4592
+ borderRadius: 8,
3548
4593
  lineHeight: 1
3549
4594
  },
3550
4595
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
@@ -3569,7 +4614,7 @@ window.__ModuleLoader__.load({
3569
4614
  style: {
3570
4615
  fontSize: 13,
3571
4616
  fontWeight: 600,
3572
- color: MODAL_TITLE,
4617
+ color: "#c7cede",
3573
4618
  marginBottom: 4
3574
4619
  },
3575
4620
  children: t("settings.section.features")
@@ -3578,7 +4623,7 @@ window.__ModuleLoader__.load({
3578
4623
  "data-settings-pin-hint": true,
3579
4624
  style: {
3580
4625
  fontSize: 12,
3581
- color: MODAL_HINT,
4626
+ color: "#8b96ab",
3582
4627
  lineHeight: 1.5,
3583
4628
  marginBottom: 10
3584
4629
  },
@@ -3619,9 +4664,9 @@ window.__ModuleLoader__.load({
3619
4664
  width: "100%",
3620
4665
  padding: "8px 10px",
3621
4666
  border: "none",
3622
- borderRadius: MODAL_RADIUS_CONTROL,
4667
+ borderRadius: 8,
3623
4668
  cursor: "pointer",
3624
- color: MODAL_FG,
4669
+ color: "#e6e8ee",
3625
4670
  fontSize: 13,
3626
4671
  textAlign: "left"
3627
4672
  },
@@ -3667,11 +4712,11 @@ window.__ModuleLoader__.load({
3667
4712
  maxWidth: "55%",
3668
4713
  transform: `translateY(-50%) translateX(${active ? 0 : 4}px)`,
3669
4714
  padding: "5px 10px",
3670
- borderRadius: MODAL_RADIUS_CONTROL,
3671
- background: MODAL_TIP_BG,
3672
- border: `1px solid ${MODAL_BORDER}`,
4715
+ borderRadius: 8,
4716
+ background: "#222834",
4717
+ border: `1px solid rgba(255, 255, 255, 0.14)`,
3673
4718
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.35)",
3674
- color: MODAL_TEXT,
4719
+ color: "#b9c2d4",
3675
4720
  fontSize: 12,
3676
4721
  lineHeight: 1.45,
3677
4722
  opacity: active ? 1 : 0,
@@ -3743,7 +4788,7 @@ window.__ModuleLoader__.load({
3743
4788
  "data-settings-personal-hint": true,
3744
4789
  style: {
3745
4790
  fontSize: 12,
3746
- color: MODAL_HINT,
4791
+ color: "#8b96ab",
3747
4792
  lineHeight: 1.5,
3748
4793
  padding: "0 6px"
3749
4794
  },
@@ -3759,7 +4804,7 @@ window.__ModuleLoader__.load({
3759
4804
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3760
4805
  style: {
3761
4806
  fontSize: 12.5,
3762
- color: MODAL_HINT,
4807
+ color: "#8b96ab",
3763
4808
  width: 90,
3764
4809
  flexShrink: 0
3765
4810
  },
@@ -3797,7 +4842,7 @@ window.__ModuleLoader__.load({
3797
4842
  alignItems: "center",
3798
4843
  gap: 6,
3799
4844
  fontSize: 12.5,
3800
- color: MODAL_TEXT,
4845
+ color: "#b9c2d4",
3801
4846
  cursor: "pointer"
3802
4847
  },
3803
4848
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -3828,7 +4873,7 @@ window.__ModuleLoader__.load({
3828
4873
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3829
4874
  style: {
3830
4875
  fontSize: 12.5,
3831
- color: MODAL_HINT,
4876
+ color: "#8b96ab",
3832
4877
  width: 90,
3833
4878
  flexShrink: 0
3834
4879
  },
@@ -3852,7 +4897,7 @@ window.__ModuleLoader__.load({
3852
4897
  "data-icon-size-value": true,
3853
4898
  style: {
3854
4899
  fontSize: 12.5,
3855
- color: MODAL_TEXT,
4900
+ color: "#b9c2d4",
3856
4901
  width: 40
3857
4902
  },
3858
4903
  children: [iconSize, "px"]
@@ -3870,7 +4915,7 @@ window.__ModuleLoader__.load({
3870
4915
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3871
4916
  style: {
3872
4917
  fontSize: 12.5,
3873
- color: MODAL_HINT,
4918
+ color: "#8b96ab",
3874
4919
  width: 90,
3875
4920
  flexShrink: 0
3876
4921
  },
@@ -3894,7 +4939,7 @@ window.__ModuleLoader__.load({
3894
4939
  "data-inset-value": true,
3895
4940
  style: {
3896
4941
  fontSize: 12.5,
3897
- color: MODAL_TEXT,
4942
+ color: "#b9c2d4",
3898
4943
  width: 40
3899
4944
  },
3900
4945
  children: [inset, "px"]
@@ -3914,7 +4959,7 @@ window.__ModuleLoader__.load({
3914
4959
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3915
4960
  style: {
3916
4961
  fontSize: 12.5,
3917
- color: MODAL_HINT,
4962
+ color: "#8b96ab",
3918
4963
  width: 90,
3919
4964
  flexShrink: 0
3920
4965
  },
@@ -3926,7 +4971,7 @@ window.__ModuleLoader__.load({
3926
4971
  alignItems: "center",
3927
4972
  gap: 5,
3928
4973
  fontSize: 13,
3929
- color: MODAL_FG,
4974
+ color: "#e6e8ee",
3930
4975
  cursor: "pointer"
3931
4976
  },
3932
4977
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -3944,7 +4989,7 @@ window.__ModuleLoader__.load({
3944
4989
  alignItems: "center",
3945
4990
  gap: 5,
3946
4991
  fontSize: 13,
3947
- color: MODAL_FG,
4992
+ color: "#e6e8ee",
3948
4993
  cursor: "pointer"
3949
4994
  },
3950
4995
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4014,7 +5059,7 @@ window.__ModuleLoader__.load({
4014
5059
  "data-settings-focus-hint": true,
4015
5060
  style: {
4016
5061
  fontSize: 12,
4017
- color: MODAL_HINT,
5062
+ color: "#8b96ab",
4018
5063
  lineHeight: 1.5,
4019
5064
  padding: "0 6px"
4020
5065
  },
@@ -4027,9 +5072,9 @@ window.__ModuleLoader__.load({
4027
5072
  alignItems: "center",
4028
5073
  gap: 8,
4029
5074
  padding: "6px 8px",
4030
- borderRadius: MODAL_RADIUS_CONTROL,
5075
+ borderRadius: 8,
4031
5076
  fontSize: 13,
4032
- color: MODAL_FG,
5077
+ color: "#e6e8ee",
4033
5078
  cursor: "pointer"
4034
5079
  },
4035
5080
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4046,9 +5091,9 @@ window.__ModuleLoader__.load({
4046
5091
  alignItems: "center",
4047
5092
  gap: 8,
4048
5093
  padding: "6px 8px",
4049
- borderRadius: MODAL_RADIUS_CONTROL,
5094
+ borderRadius: 8,
4050
5095
  fontSize: 13,
4051
- color: MODAL_FG,
5096
+ color: "#e6e8ee",
4052
5097
  cursor: "pointer"
4053
5098
  },
4054
5099
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4065,9 +5110,9 @@ window.__ModuleLoader__.load({
4065
5110
  alignItems: "center",
4066
5111
  gap: 8,
4067
5112
  padding: "6px 8px",
4068
- borderRadius: MODAL_RADIUS_CONTROL,
5113
+ borderRadius: 8,
4069
5114
  fontSize: 13,
4070
- color: MODAL_FG,
5115
+ color: "#e6e8ee",
4071
5116
  cursor: "pointer"
4072
5117
  },
4073
5118
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4088,7 +5133,7 @@ window.__ModuleLoader__.load({
4088
5133
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4089
5134
  style: {
4090
5135
  fontSize: 12.5,
4091
- color: MODAL_HINT,
5136
+ color: "#8b96ab",
4092
5137
  width: 90,
4093
5138
  flexShrink: 0
4094
5139
  },
@@ -4112,7 +5157,7 @@ window.__ModuleLoader__.load({
4112
5157
  "data-focus-opacity-value": true,
4113
5158
  style: {
4114
5159
  fontSize: 12.5,
4115
- color: MODAL_TEXT,
5160
+ color: "#b9c2d4",
4116
5161
  width: 44
4117
5162
  },
4118
5163
  children: [Math.round(prefs.focus.opacity * 100), "%"]
@@ -4131,7 +5176,7 @@ window.__ModuleLoader__.load({
4131
5176
  style: {
4132
5177
  fontSize: 13,
4133
5178
  fontWeight: 600,
4134
- color: MODAL_TITLE,
5179
+ color: "#c7cede",
4135
5180
  marginBottom: 8
4136
5181
  },
4137
5182
  children: t("settings.language")
@@ -4154,7 +5199,7 @@ window.__ModuleLoader__.load({
4154
5199
  alignItems: "center",
4155
5200
  gap: 5,
4156
5201
  fontSize: 13,
4157
- color: MODAL_FG,
5202
+ color: "#e6e8ee",
4158
5203
  cursor: "pointer"
4159
5204
  },
4160
5205
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -4174,7 +5219,7 @@ window.__ModuleLoader__.load({
4174
5219
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4175
5220
  style: {
4176
5221
  fontSize: 12,
4177
- color: MODAL_HINT,
5222
+ color: "#8b96ab",
4178
5223
  marginBottom: 10
4179
5224
  },
4180
5225
  children: t("settings.support")
@@ -4275,25 +5320,51 @@ window.__ModuleLoader__.load({
4275
5320
  ]
4276
5321
  })]
4277
5322
  }),
4278
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4279
- type: "button",
4280
- "data-toolbar-settings-reset": true,
4281
- onClick: onResetAll,
5323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5324
+ "data-toolbar-settings-actions": true,
4282
5325
  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
5326
+ display: "flex",
5327
+ alignItems: "center",
5328
+ justifyContent: "center",
5329
+ gap: 10,
5330
+ margin: "16px auto 2px"
4291
5331
  },
4292
- children: t("settings.reset")
5332
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5333
+ type: "button",
5334
+ "data-toolbar-settings-reset": true,
5335
+ onClick: onResetAll,
5336
+ style: {
5337
+ padding: "7px 16px",
5338
+ border: `1px solid rgba(255, 255, 255, 0.14)`,
5339
+ borderRadius: 8,
5340
+ cursor: "pointer",
5341
+ color: "#b9c2d4",
5342
+ fontSize: 12.5
5343
+ },
5344
+ children: t("settings.reset")
5345
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5346
+ type: "button",
5347
+ "data-onboarding-reopen": true,
5348
+ onClick: reopenOnboarding,
5349
+ style: {
5350
+ padding: "7px 16px",
5351
+ border: `1px solid rgba(255, 255, 255, 0.14)`,
5352
+ borderRadius: 8,
5353
+ cursor: "pointer",
5354
+ color: "#b9c2d4",
5355
+ fontSize: 12.5
5356
+ },
5357
+ children: t("onboarding.reopen")
5358
+ })]
4293
5359
  })
4294
5360
  ]
4295
5361
  })
4296
5362
  }),
5363
+ onboardingOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MilestoneOnboarding, {
5364
+ t,
5365
+ accent,
5366
+ onClose: () => setOnboardingOpen(false)
5367
+ }),
4297
5368
  updateOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4298
5369
  ref: updatePanelRef,
4299
5370
  "data-update-panel": true,
@@ -4330,7 +5401,7 @@ window.__ModuleLoader__.load({
4330
5401
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4331
5402
  style: { color: "#8b96ab" },
4332
5403
  children: [t("update.current"), ": "]
4333
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "0.6.3" })] }),
5404
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "0.6.4" })] }),
4334
5405
  updateCheck.phase === "ok" && updateCheck.latest !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4335
5406
  "data-update-latest": true,
4336
5407
  children: [