dsh-cool-theme 0.2.0 → 0.3.0

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/lib/client.js CHANGED
@@ -1331,7 +1331,10 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
1331
1331
  "presets.desc": "一键套用主流配色方案",
1332
1332
  "scheme.light": "浅色",
1333
1333
  "scheme.dark": "深色",
1334
- "scheme.system": "跟随系统"
1334
+ "scheme.system": "跟随系统",
1335
+ "command.desc": "打开主题设置",
1336
+ "command.open": "打开主题设置",
1337
+ "command.detail": "快速打开主题面板"
1335
1338
  };
1336
1339
  /** English dictionary, checked complete against the zh key set. */
1337
1340
  const en = {
@@ -1342,7 +1345,10 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
1342
1345
  "presets.desc": "Apply popular color schemes in one click",
1343
1346
  "scheme.light": "Light",
1344
1347
  "scheme.dark": "Dark",
1345
- "scheme.system": "System"
1348
+ "scheme.system": "System",
1349
+ "command.desc": "Open theme settings",
1350
+ "command.open": "Open theme settings",
1351
+ "command.detail": "Quickly open theme panel"
1346
1352
  };
1347
1353
  //#endregion
1348
1354
  //#region src/client/theme.tsx
@@ -1590,6 +1596,168 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
1590
1596
  }
1591
1597
  };
1592
1598
  });
1599
+ function collectThemeLabels() {
1600
+ const s = /* @__PURE__ */ new Set();
1601
+ try {
1602
+ const cur = t("nav");
1603
+ if (cur) s.add(cur);
1604
+ } catch {}
1605
+ if (zh.nav) s.add(zh.nav);
1606
+ if (en.nav) s.add(en.nav);
1607
+ return s;
1608
+ }
1609
+ function isSettingsPanelOpen() {
1610
+ if (typeof document === "undefined") return false;
1611
+ return document.querySelector("[role=\"dialog\"][aria-modal=\"true\"]") !== null;
1612
+ }
1613
+ function findSettingsTrigger() {
1614
+ if (typeof document === "undefined") return null;
1615
+ const btn = document.querySelector("button[aria-haspopup=\"dialog\"]");
1616
+ if (btn) return btn;
1617
+ for (const b of Array.from(document.querySelectorAll("button"))) {
1618
+ const txt = (b.textContent || "").trim();
1619
+ if (txt.includes("设置") || txt.toLowerCase().includes("settings")) {
1620
+ if (b.getAttribute("aria-haspopup") === "dialog" || b.getAttribute("aria-expanded") !== null) return b;
1621
+ }
1622
+ }
1623
+ return null;
1624
+ }
1625
+ function findThemeNavCell(labels) {
1626
+ if (typeof document === "undefined") return null;
1627
+ const cells = document.querySelectorAll("[class*=\"navCell\"]");
1628
+ if (cells.length > 0) for (const c of Array.from(cells)) {
1629
+ const text = ((c.querySelector("[class*=\"navLabel\"]") || c).textContent || c.textContent || "").trim();
1630
+ for (const lbl of labels) if (text === lbl || text.includes(lbl)) return c;
1631
+ }
1632
+ const navButtons = document.querySelectorAll("[class*=\"nav\"] button, nav button");
1633
+ for (const b of Array.from(navButtons)) {
1634
+ const text = (b.textContent || "").trim();
1635
+ for (const lbl of labels) if (text === lbl || text.includes(lbl)) return b;
1636
+ }
1637
+ return null;
1638
+ }
1639
+ function openCoolThemeSettings() {
1640
+ if (typeof document === "undefined") return false;
1641
+ const labels = collectThemeLabels();
1642
+ if (isSettingsPanelOpen()) {
1643
+ const cell = findThemeNavCell(labels);
1644
+ if (cell) {
1645
+ try {
1646
+ cell.click();
1647
+ } catch {}
1648
+ return true;
1649
+ }
1650
+ return false;
1651
+ }
1652
+ const trigger = findSettingsTrigger();
1653
+ if (!trigger) return false;
1654
+ try {
1655
+ trigger.click();
1656
+ } catch {
1657
+ return false;
1658
+ }
1659
+ let attempts = 0;
1660
+ const maxAttempts = 40;
1661
+ const timer = setInterval(() => {
1662
+ attempts++;
1663
+ try {
1664
+ patchThemeNavIcon();
1665
+ } catch {}
1666
+ const cell = findThemeNavCell(labels);
1667
+ if (cell) {
1668
+ clearInterval(timer);
1669
+ setTimeout(() => {
1670
+ try {
1671
+ cell.click();
1672
+ } catch {}
1673
+ }, 30);
1674
+ return;
1675
+ }
1676
+ if (attempts >= maxAttempts) clearInterval(timer);
1677
+ }, 50);
1678
+ setTimeout(() => {
1679
+ try {
1680
+ patchThemeNavIcon();
1681
+ } catch {}
1682
+ }, 120);
1683
+ return true;
1684
+ }
1685
+ try {
1686
+ ctx.inject(["commandUi", "locale"], (scope) => {
1687
+ const commandUi = scope.get("commandUi");
1688
+ const loc = scope.get("locale");
1689
+ if (!commandUi || !loc) return;
1690
+ let dispose = null;
1691
+ const sync = () => {
1692
+ if (dispose) {
1693
+ try {
1694
+ dispose();
1695
+ } catch {}
1696
+ dispose = null;
1697
+ }
1698
+ try {
1699
+ dispose = commandUi.register({
1700
+ name: "cool-theme",
1701
+ description: t("command.desc"),
1702
+ available: () => true,
1703
+ ui: {
1704
+ kind: "popupSelect",
1705
+ options: async () => [{
1706
+ id: "open",
1707
+ label: t("command.open"),
1708
+ detail: t("command.detail")
1709
+ }],
1710
+ onSelect: async () => {
1711
+ openCoolThemeSettings();
1712
+ }
1713
+ }
1714
+ });
1715
+ } catch {}
1716
+ };
1717
+ sync();
1718
+ let off = null;
1719
+ try {
1720
+ off = loc.subscribe(sync);
1721
+ } catch {}
1722
+ scope.effect(() => () => {
1723
+ if (off) {
1724
+ try {
1725
+ off();
1726
+ } catch {}
1727
+ off = null;
1728
+ }
1729
+ if (dispose) {
1730
+ try {
1731
+ dispose();
1732
+ } catch {}
1733
+ dispose = null;
1734
+ }
1735
+ }, "dsh-cool-theme: /cool-theme contribution");
1736
+ });
1737
+ } catch {}
1738
+ if (typeof document !== "undefined") {
1739
+ const onKey = (e) => {
1740
+ if (!(e.ctrlKey || e.metaKey) || !e.shiftKey) return;
1741
+ if (e.key.toLowerCase() !== "t") return;
1742
+ const target = e.target;
1743
+ if (target) {
1744
+ const tag = target.tagName?.toLowerCase();
1745
+ if (tag === "input" || tag === "textarea" || target.isContentEditable) return;
1746
+ }
1747
+ e.preventDefault();
1748
+ try {
1749
+ openCoolThemeSettings();
1750
+ } catch {}
1751
+ };
1752
+ try {
1753
+ document.addEventListener("keydown", onKey);
1754
+ ctx.effect(() => () => {
1755
+ try {
1756
+ document.removeEventListener("keydown", onKey);
1757
+ } catch {}
1758
+ });
1759
+ } catch {}
1760
+ }
1593
1761
  }
1594
1762
  //#endregion
1595
1763
  //#region src/client/index.ts
package/lib/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  //#region src/host/index.ts
2
2
  /**
3
3
  * Host entry for dsh-cool-theme.
4
- * No host routes needed — theme is purely client-side (localStorage + overrideTokens).
4
+ * Theme is purely client-side (localStorage + overrideTokens).
5
+ * The `/cool-theme` slash command is registered on the client via
6
+ * `ctx.commandUi` so its description can follow `ctx.locale`
7
+ * (zh: “打开主题设置”, en: “Open theme settings”).
5
8
  * Keep a minimal apply so the cordis patch has a mount point.
6
9
  */
7
10
  const name = "dsh-cool-theme";
@@ -13,6 +13,9 @@ export declare const zh: {
13
13
  'scheme.light': string;
14
14
  'scheme.dark': string;
15
15
  'scheme.system': string;
16
+ 'command.desc': string;
17
+ 'command.open': string;
18
+ 'command.detail': string;
16
19
  };
17
20
  /** The theme settings namespace key union. */
18
21
  export type ThemeKey = keyof typeof zh;
@@ -26,5 +29,8 @@ export declare const en: {
26
29
  'scheme.light': string;
27
30
  'scheme.dark': string;
28
31
  'scheme.system': string;
32
+ 'command.desc': string;
33
+ 'command.open': string;
34
+ 'command.detail': string;
29
35
  };
30
36
  //# sourceMappingURL=locales.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;CASmB,CAAA;AAElC,8CAA8C;AAC9C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,EAAE,CAAA;AAEtC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;CASqB,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;CAYmB,CAAA;AAElC,8CAA8C;AAC9C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,EAAE,CAAA;AAEtC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;CAYqB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/client/theme.tsx"],"names":[],"mappings":"AAiCA,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,QAsQrC"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/client/theme.tsx"],"names":[],"mappings":"AAiCA,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,QAicrC"}
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Host entry for dsh-cool-theme.
3
- * No host routes needed — theme is purely client-side (localStorage + overrideTokens).
3
+ * Theme is purely client-side (localStorage + overrideTokens).
4
+ * The `/cool-theme` slash command is registered on the client via
5
+ * `ctx.commandUi` so its description can follow `ctx.locale`
6
+ * (zh: “打开主题设置”, en: “Open theme settings”).
4
7
  * Keep a minimal apply so the cordis patch has a mount point.
5
8
  */
6
9
  export declare const name = "dsh-cool-theme";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/host/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAA;AAElC,wBAAgB,KAAK,CAAC,IAAI,EAAE,GAAG,QAAI"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAA;AAElC,wBAAgB,KAAK,CAAC,IAAI,EAAE,GAAG,QAAI"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-cool-theme",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A plugin for changing themes for DSH, with a number of popular default themes built in.",
5
5
  "type": "module",
6
6
  "license": "MIT",