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.
- package/README.md +10 -1
- package/lib/client.js +1150 -79
- 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:
|
|
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:
|
|
3507
|
-
color:
|
|
3508
|
-
borderRadius:
|
|
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:
|
|
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:
|
|
3547
|
-
borderRadius:
|
|
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:
|
|
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:
|
|
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:
|
|
4667
|
+
borderRadius: 8,
|
|
3623
4668
|
cursor: "pointer",
|
|
3624
|
-
color:
|
|
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:
|
|
3671
|
-
background:
|
|
3672
|
-
border: `1px solid
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
5075
|
+
borderRadius: 8,
|
|
4031
5076
|
fontSize: 13,
|
|
4032
|
-
color:
|
|
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:
|
|
5094
|
+
borderRadius: 8,
|
|
4050
5095
|
fontSize: 13,
|
|
4051
|
-
color:
|
|
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:
|
|
5113
|
+
borderRadius: 8,
|
|
4069
5114
|
fontSize: 13,
|
|
4070
|
-
color:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
4279
|
-
|
|
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: "
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
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:
|
|
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.
|
|
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: [
|