dsh-life-pack 0.3.13 → 0.3.15

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/dist/client.js CHANGED
@@ -100,7 +100,7 @@ window.__ModuleLoader__.load({
100
100
  const PANEL_LINKS = [{
101
101
  key: "star",
102
102
  glyph: "⭐",
103
- tip: "去 GitHub 点 Star",
103
+ tip: "你的🌟是我夜空中最亮的星。",
104
104
  url: "https://github.com/FeatherHunter/ilife"
105
105
  }, {
106
106
  key: "feedback",
@@ -668,7 +668,7 @@ window.__ModuleLoader__.load({
668
668
  marginBottom: 10
669
669
  },
670
670
  tab: {
671
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.35))",
671
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35))",
672
672
  background: "transparent",
673
673
  color: "var(--dsw-alias-label-primary, inherit)",
674
674
  borderRadius: 999,
@@ -679,13 +679,13 @@ window.__ModuleLoader__.load({
679
679
  tabActive: {
680
680
  background: "var(--dsw-alias-brand-primary, #0a84ff)",
681
681
  borderColor: "transparent",
682
- color: "#fff",
682
+ color: "var(--dsw-alias-label-primary-foreground, #0f1115)",
683
683
  fontWeight: 700
684
684
  },
685
685
  reco: {
686
686
  padding: "12px 14px",
687
687
  borderRadius: 10,
688
- border: "1px dashed var(--dsw-alias-border, rgba(128,128,128,.45))",
688
+ border: "1px dashed var(--dsw-alias-border-l1, rgba(128,128,128,.45))",
689
689
  color: "var(--dsw-alias-label-secondary, #9a9a9a)",
690
690
  fontSize: 13,
691
691
  lineHeight: 1.7
@@ -702,7 +702,7 @@ window.__ModuleLoader__.load({
702
702
  userSelect: "all"
703
703
  },
704
704
  btn: {
705
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.35))",
705
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35))",
706
706
  background: "transparent",
707
707
  color: "var(--dsw-alias-label-primary, inherit)",
708
708
  borderRadius: 8,
@@ -714,7 +714,7 @@ window.__ModuleLoader__.load({
714
714
  padding: "10px 12px",
715
715
  marginBottom: 10,
716
716
  borderRadius: 8,
717
- border: "1px solid var(--dsw-alias-state-warning-primary, #d8a300)",
717
+ border: "1px solid var(--dsw-alias-state-warn-primary, #d8a300)",
718
718
  background: "var(--dsw-alias-bg-base, rgba(216,163,0,.12))",
719
719
  color: "var(--dsw-alias-label-primary, inherit)",
720
720
  fontSize: 13,
@@ -724,7 +724,7 @@ window.__ModuleLoader__.load({
724
724
  padding: "10px 12px",
725
725
  marginBottom: 8,
726
726
  borderRadius: 10,
727
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.3))",
727
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.3))",
728
728
  borderLeftWidth: 3,
729
729
  fontSize: 13,
730
730
  lineHeight: 1.7
@@ -774,7 +774,7 @@ window.__ModuleLoader__.load({
774
774
  btnPrimary: {
775
775
  border: "1px solid transparent",
776
776
  background: "var(--dsw-alias-brand-primary, #0a84ff)",
777
- color: "#fff",
777
+ color: "var(--dsw-alias-label-primary-foreground, #0f1115)",
778
778
  borderRadius: 8,
779
779
  padding: "5px 14px",
780
780
  fontSize: 13,
@@ -807,8 +807,8 @@ window.__ModuleLoader__.load({
807
807
  flexDirection: "column",
808
808
  overflow: "hidden",
809
809
  borderRadius: 12,
810
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.4))",
811
- background: "var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #222))",
810
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.4))",
811
+ background: "var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-base, #222))",
812
812
  color: "var(--dsw-alias-label-primary, inherit)",
813
813
  boxShadow: "0 12px 32px rgba(0,0,0,.35)"
814
814
  },
@@ -819,7 +819,7 @@ window.__ModuleLoader__.load({
819
819
  gap: 8,
820
820
  flex: "0 0 auto",
821
821
  padding: "12px 14px",
822
- borderBottom: "1px solid var(--dsw-alias-border, rgba(128,128,128,.3))"
822
+ borderBottom: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.3))"
823
823
  },
824
824
  dialogTitle: {
825
825
  fontSize: 14,
@@ -833,7 +833,7 @@ window.__ModuleLoader__.load({
833
833
  padding: "12px 14px"
834
834
  },
835
835
  close: {
836
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.35))",
836
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35))",
837
837
  background: "transparent",
838
838
  color: "var(--dsw-alias-label-primary, inherit)",
839
839
  borderRadius: 8,
@@ -857,7 +857,7 @@ window.__ModuleLoader__.load({
857
857
  },
858
858
  blocked: {
859
859
  mark: "!",
860
- color: "var(--dsw-alias-state-warning-primary, #d8a300)",
860
+ color: "var(--dsw-alias-state-warn-primary, #d8a300)",
861
861
  tint: "rgba(216,163,0,.10)"
862
862
  },
863
863
  failed: {
@@ -1556,7 +1556,7 @@ window.__ModuleLoader__.load({
1556
1556
  /** 面板上的文字色与分隔线(与 `client.ts` 同一套别名)。 */
1557
1557
  const INK = "var(--dsw-alias-label-primary, inherit)";
1558
1558
  const INK_DIM = "var(--dsw-alias-label-secondary, #9a9a9a)";
1559
- const BORDER = "var(--dsw-alias-border, rgba(128,128,128,.35))";
1559
+ const BORDER = "var(--dsw-alias-border-l1, rgba(128,128,128,.35))";
1560
1560
  const HEALTH_STYLE = {
1561
1561
  box: {
1562
1562
  padding: "10px 12px",
@@ -1698,16 +1698,8 @@ window.__ModuleLoader__.load({
1698
1698
  };
1699
1699
  });
1700
1700
  }
1701
- /** 一家的一句话读数:「红 1 黄 2」,全绿就是「绿」。面板侧要**上色**的那几处不用它(见 `countSegments`)。 */
1702
- function countsText(counts) {
1703
- const parts = [];
1704
- if (counts.red > 0) parts.push("红 " + String(counts.red));
1705
- if (counts.yellow > 0) parts.push("黄 " + String(counts.yellow));
1706
- if (parts.length === 0) return "绿";
1707
- return parts.join(" · ");
1708
- }
1709
1701
  /** 把一份计数拆成**按档分色**的几截。红黄各自一截、各自上色,互不串色;
1710
- * 「黄 3」这一截为什么不能被染成红——见 `countSegments` 的注释(出图复评逮到的真缺陷)。 */
1702
+ * 数字本身不带档位字(#951):颜色即档位,胶囊形状由调用方配 `COUNT_CAPSULE`/`TAB_NOTE_STYLE`。 */
1711
1703
  function countSegsOf(light) {
1712
1704
  if (light.status === null) return [{
1713
1705
  status: null,
@@ -1718,16 +1710,26 @@ window.__ModuleLoader__.load({
1718
1710
  const count = light.counts[status];
1719
1711
  if (count > 0) segs.push({
1720
1712
  status,
1721
- text: STATUS_LABEL[status] + " " + String(count)
1713
+ text: String(count)
1722
1714
  });
1723
1715
  }
1724
1716
  return segs.length > 0 ? segs : [{
1725
1717
  status: "green",
1726
- text: "绿"
1718
+ text: String(light.counts.green)
1727
1719
  }];
1728
1720
  }
1729
1721
  /** 几截读数之间那个分隔符:不许染档位色(它不属于任何一档)。 */
1730
1722
  const SEG_SEP = " · ";
1723
+ /** 数字胶囊的形状(#951):页签那枚 `TAB_NOTE_STYLE` 的同形,汇总与表头共用。
1724
+ * 颜色不进这一格,调用方按档配 `STATUS_TEXT[status]`——颜色即档位,字上不再写档位名。 */
1725
+ const COUNT_CAPSULE_STYLE = {
1726
+ border: "1px solid " + BORDER,
1727
+ borderRadius: 999,
1728
+ padding: "0 6px",
1729
+ margin: "0 2px",
1730
+ fontSize: 11,
1731
+ fontWeight: 700
1732
+ };
1731
1733
  /** 汇总行那一句:绿要显眼(它是「正常」这件事本身),没通道的那几家不冒充绿。
1732
1734
  *
1733
1735
  * 「没有体检出口」与「还没跑过体检」是**两件事**(票 #735):前者那颗「体检一次」按下去不会有任何反应,
@@ -1760,10 +1762,10 @@ window.__ModuleLoader__.load({
1760
1762
  parts.push(react.createElement("span", {
1761
1763
  key: status,
1762
1764
  style: {
1763
- color: STATUS_TEXT[status],
1764
- fontWeight: 700
1765
+ ...COUNT_CAPSULE_STYLE,
1766
+ color: STATUS_TEXT[status]
1765
1767
  }
1766
- }, STATUS_LABEL[status] + " " + String(count)));
1768
+ }, String(count)));
1767
1769
  }
1768
1770
  if (parts.length === 0) return react.createElement("span", { style: { color: INK_DIM } }, (allGreen ? "有出口的都正常" : "还没体检") + tail);
1769
1771
  parts.push(react.createElement("span", {
@@ -1828,6 +1830,32 @@ window.__ModuleLoader__.load({
1828
1830
  function isAttentionItem(item) {
1829
1831
  return isAttention(item.status);
1830
1832
  }
1833
+ /** 表头那组数字(#951):与页签/汇总同口径——只印数字胶囊,颜色即档位,不印档位字。 */
1834
+ function headerCounts(report) {
1835
+ const counts = countByStatus(report.items);
1836
+ const segs = countSegsOf({
1837
+ id: "header",
1838
+ title: "",
1839
+ status: worstStatus(report.items),
1840
+ counts,
1841
+ hasChannel: true
1842
+ });
1843
+ return react.createElement("div", { style: {
1844
+ display: "flex",
1845
+ alignItems: "center",
1846
+ gap: 4,
1847
+ fontSize: 12
1848
+ } }, segs.map((seg, index) => seg.status === null ? react.createElement("span", {
1849
+ key: index,
1850
+ style: { color: INK_DIM }
1851
+ }, seg.text) : react.createElement("span", {
1852
+ key: index,
1853
+ style: {
1854
+ ...COUNT_CAPSULE_STYLE,
1855
+ color: STATUS_TEXT[seg.status]
1856
+ }
1857
+ }, seg.text)));
1858
+ }
1831
1859
  /** 一家那张表:**要处理的**(红黄)一条一块、整行上底带一句话与「去哪修」;
1832
1860
  * **正常的**(绿)收成一行并列的小字,点得到、扫得完(票面验收第一条:正常的收成一行,有问题的才展开)。 */
1833
1861
  function HealthTable(props) {
@@ -1836,10 +1864,7 @@ window.__ModuleLoader__.load({
1836
1864
  return react.createElement("div", {
1837
1865
  style: HEALTH_STYLE.box,
1838
1866
  "data-ilife-health": "table"
1839
- }, react.createElement("div", { style: HEALTH_STYLE.headRow }, react.createElement("div", { style: HEALTH_STYLE.head }, props.title + " · 体检"), report ? react.createElement("div", { style: {
1840
- color: INK_DIM,
1841
- fontSize: 12
1842
- } }, countsText(countByStatus(report.items))) : null), props.phase === "idle" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "还没体检:点上面那个「体检一次」。") : null, props.phase === "running" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "正在体检…") : null, props.error !== null ? react.createElement("div", { style: HEALTH_STYLE.error }, props.error) : null, report ? react.createElement("div", null, report.dataDir !== "" ? react.createElement("div", { style: {
1867
+ }, react.createElement("div", { style: HEALTH_STYLE.headRow }, react.createElement("div", { style: HEALTH_STYLE.head }, props.title + " · 体检"), report ? headerCounts(report) : null), props.phase === "idle" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "还没体检:点上面那个「体检一次」。") : null, props.phase === "running" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "正在体检…") : null, props.error !== null ? react.createElement("div", { style: HEALTH_STYLE.error }, props.error) : null, report ? react.createElement("div", null, report.dataDir !== "" ? react.createElement("div", { style: {
1843
1868
  color: INK_DIM,
1844
1869
  fontSize: 11.5,
1845
1870
  marginTop: 2
@@ -2432,7 +2457,7 @@ window.__ModuleLoader__.load({
2432
2457
  textOverflow: "ellipsis",
2433
2458
  whiteSpace: "nowrap"
2434
2459
  },
2435
- error: { color: "var(--dsw-alias-label-error, #e66)" }
2460
+ error: { color: "var(--dsw-alias-state-error-primary, #e66)" }
2436
2461
  };
2437
2462
  /** 面包屑:从文件系统根到当前层,每一格都是跳转目标(`listing.crumbs` 由取数方给)。 */
2438
2463
  function crumbRow(state, onEnter) {
@@ -2742,11 +2767,23 @@ window.__ModuleLoader__.load({
2742
2767
  fontSize: 14,
2743
2768
  lineHeight: 1
2744
2769
  },
2745
- meta: {
2746
- color: "var(--dsw-alias-label-secondary, #9a9a9a)",
2747
- fontSize: 12,
2748
- lineHeight: 1.7,
2749
- marginBottom: 10
2770
+ /** #933:页签格里「配置卡 + 体检卡」这一列的堆叠间距(唯一口径,别再给某一张卡加 margin)。 */
2771
+ tabStack: {
2772
+ display: "flex",
2773
+ flexDirection: "column",
2774
+ gap: 10
2775
+ },
2776
+ /** #937:标题行里那枚版本胶囊(形状照真源 v3.1 的 `.ic-ver`:10px 字、1px 描边、999 圆角)。 */
2777
+ versionCapsule: {
2778
+ fontSize: 10.5,
2779
+ lineHeight: 1.6,
2780
+ color: "var(--dsw-alias-label-tertiary, #adb2b8)",
2781
+ border: "1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.12))",
2782
+ borderRadius: 999,
2783
+ padding: "0 7px",
2784
+ whiteSpace: "nowrap",
2785
+ flex: "0 0 auto",
2786
+ fontWeight: 400
2750
2787
  },
2751
2788
  tablist: {
2752
2789
  display: "flex",
@@ -2755,7 +2792,7 @@ window.__ModuleLoader__.load({
2755
2792
  marginBottom: 10
2756
2793
  },
2757
2794
  tab: {
2758
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.35))",
2795
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35))",
2759
2796
  background: "transparent",
2760
2797
  color: "var(--dsw-alias-label-primary, inherit)",
2761
2798
  borderRadius: 999,
@@ -2766,13 +2803,13 @@ window.__ModuleLoader__.load({
2766
2803
  tabActive: {
2767
2804
  background: "var(--dsw-alias-brand-primary, #0a84ff)",
2768
2805
  borderColor: "transparent",
2769
- color: "#fff",
2806
+ color: "var(--dsw-alias-label-primary-foreground, #0f1115)",
2770
2807
  fontWeight: 700
2771
2808
  },
2772
2809
  reco: {
2773
2810
  padding: "12px 14px",
2774
2811
  borderRadius: 10,
2775
- border: "1px dashed var(--dsw-alias-border, rgba(128,128,128,.45))",
2812
+ border: "1px dashed var(--dsw-alias-border-l1, rgba(128,128,128,.45))",
2776
2813
  color: "var(--dsw-alias-label-secondary, #9a9a9a)",
2777
2814
  fontSize: 13,
2778
2815
  lineHeight: 1.7
@@ -2792,7 +2829,7 @@ window.__ModuleLoader__.load({
2792
2829
  marginTop: 16,
2793
2830
  padding: "10px 12px",
2794
2831
  borderRadius: 10,
2795
- border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.35))"
2832
+ border: "1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35))"
2796
2833
  },
2797
2834
  moreTitle: {
2798
2835
  fontSize: 13,
@@ -2884,22 +2921,47 @@ window.__ModuleLoader__.load({
2884
2921
  style: S.moreRow
2885
2922
  }, react.createElement("span", { style: S.morePkg }, row.pkg), react.createElement("span", { style: S.moreDesc }, row.desc), react.createElement("span", { style: S.moreIcon }, react.createElement(ExternalIcon, null)))));
2886
2923
  }
2887
- /** 总管自述版本(票 #737):**不手写**,问宿主——宿主读自己这份已安装包的 `package.json`。
2924
+ /** 总管自述版本(票 #737;#937 改口):**不手写**,问宿主——宿主读自己这份已安装包的 `package.json`。
2888
2925
  *
2889
- * 单次取数(`loadManagerVersion`),无轮询;初值 `unknown`,读不到也停在 `unknown`。
2926
+ * 三态(#937):`loading`(首帧就画胶囊占位 `…`)/`ready`(读到,画包名 · 版本)/`missing`(读不到,画「版本未知」)。
2927
+ * **失败要重试**:原先只取一次、一失败就永远停在未知(#937 查出来的真缺陷);这里按 1s/3s/8s 退避重试三次。
2890
2928
  * 与卡路里 #130 同一条路:面板是浏览器产物、禁 node 内建,读盘只许在宿主半。 */
2929
+ /** 读中 / 读不到 两种胶囊文案(#937:占位符用 `…`,读不到给人话,不把 `unknown` 印给人看)。 */
2930
+ const VERSION_PENDING_TEXT = "…";
2931
+ const VERSION_MISSING_TEXT = "版本未知";
2932
+ /** 重试间隔(#937):三次退避,之后不再打扰宿主。 */
2933
+ const VERSION_RETRY_MS = [
2934
+ 1e3,
2935
+ 3e3,
2936
+ 8e3
2937
+ ];
2891
2938
  function useManagerVersion(getCall) {
2892
- const [version, setVersion] = react.useState(VERSION_UNKNOWN);
2939
+ const [state, setState] = react.useState({ kind: "loading" });
2893
2940
  react.useEffect(() => {
2894
2941
  let alive = true;
2895
- loadManagerVersion(getCall()).then((next) => {
2896
- if (alive) setVersion(next);
2897
- });
2942
+ const timers = [];
2943
+ const attempt = (index) => {
2944
+ loadManagerVersion(getCall()).then((next) => {
2945
+ if (!alive) return;
2946
+ if (next !== "unknown") {
2947
+ setState({
2948
+ kind: "ready",
2949
+ version: next
2950
+ });
2951
+ return;
2952
+ }
2953
+ setState({ kind: "missing" });
2954
+ const wait = VERSION_RETRY_MS[index];
2955
+ if (wait !== void 0) timers.push(setTimeout(() => attempt(index + 1), wait));
2956
+ });
2957
+ };
2958
+ attempt(0);
2898
2959
  return () => {
2899
2960
  alive = false;
2961
+ for (const id of timers) clearTimeout(id);
2900
2962
  };
2901
2963
  }, [getCall]);
2902
- return version;
2964
+ return state;
2903
2965
  }
2904
2966
  /** 爱生活面板:总设置区 + 检查更新(七家)+ 爱生活页签条(slot 驱动)+ 技能设置页投影/缺席卡。 */
2905
2967
  function LifePackSection(props) {
@@ -2979,7 +3041,10 @@ window.__ModuleLoader__.load({
2979
3041
  setActiveId(next.plugin);
2980
3042
  tabRefs.current[nextIndex]?.focus();
2981
3043
  }
2982
- return react.createElement("div", null, react.createElement("div", { style: S.headRow }, react.createElement("div", { style: S.head }, "爱生活"), react.createElement("div", { style: S.headActions }, react.createElement(CheckUpdateButton, { face }), react.createElement(PanelActions, null))), react.createElement("div", { style: S.meta }, react.createElement("div", null, "总管 dsh-life-pack · " + managerVersion)), react.createElement(UpdateResults, { face }), react.createElement(HealthSummaryLine, {
3044
+ return react.createElement("div", null, react.createElement("div", { style: S.headRow }, react.createElement("div", { style: S.head }, "爱生活"), react.createElement("span", {
3045
+ style: S.versionCapsule,
3046
+ "data-ilife-version": "capsule"
3047
+ }, managerVersion.kind === "ready" ? "dsh-life-pack · " + managerVersion.version : managerVersion.kind === "missing" ? VERSION_MISSING_TEXT : VERSION_PENDING_TEXT), react.createElement("div", { style: S.headActions }, react.createElement(CheckUpdateButton, { face }), react.createElement(PanelActions, null))), react.createElement(UpdateResults, { face }), react.createElement(HealthSummaryLine, {
2983
3048
  lights,
2984
3049
  running: health.running,
2985
3050
  error: summaryErrorOf(health),
@@ -3039,8 +3104,8 @@ window.__ModuleLoader__.load({
3039
3104
  id: tabsId + "-panel-" + tab.plugin,
3040
3105
  role: "tabpanel",
3041
3106
  "aria-labelledby": tabsId + "-tab-" + tab.plugin,
3042
- hidden: !selected
3043
- }, present.has(tab.plugin) ? react.createElement("div", null, props.renderSlot(CONFIG_TAB_SLOT, {}, { only: tab.plugin }), react.createElement(HealthTable, {
3107
+ style: selected ? void 0 : { display: "none" }
3108
+ }, present.has(tab.plugin) ? react.createElement("div", { style: S.tabStack }, props.renderSlot(CONFIG_TAB_SLOT, {}, { only: tab.plugin }), react.createElement(HealthTable, {
3044
3109
  title: labelFor(tab),
3045
3110
  phase: health.rows[tab.plugin]?.phase ?? "idle",
3046
3111
  report: health.rows[tab.plugin]?.report ?? null,