@ohmykreee/dsh-remote-control 0.0.0-stage → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/AGENTS.md +556 -0
  2. package/INSTALLATION.md +310 -0
  3. package/LICENSE +21 -0
  4. package/README.md +195 -2
  5. package/client.js +3 -0
  6. package/components.json +20 -0
  7. package/cordis.patch.yml +3 -0
  8. package/docs/README.en.md +196 -0
  9. package/docs/screenshots/en/overview.png +0 -0
  10. package/docs/screenshots/en/question.png +0 -0
  11. package/docs/screenshots/zh/overview.png +0 -0
  12. package/docs/screenshots/zh/question.png +0 -0
  13. package/icon.svg +24 -0
  14. package/index.js +2 -0
  15. package/lib/account.js +1 -0
  16. package/lib/app-mapping.js +1 -0
  17. package/lib/i18n.js +1 -0
  18. package/lib/media-enrich.js +1 -0
  19. package/lib/notifications.js +1 -0
  20. package/lib/performance.js +1 -0
  21. package/lib/platform/index.js +1 -0
  22. package/lib/probe-adapter.js +1 -0
  23. package/lib/probe-daemon.js +1 -0
  24. package/lib/probe.js +1 -0
  25. package/lib/qr.js +1 -0
  26. package/lib/runtime.js +1 -0
  27. package/lib/service.js +1 -0
  28. package/lib/sessions.js +1 -0
  29. package/lib/settings.js +1 -0
  30. package/lib/types.js +1 -0
  31. package/lib/util.js +1 -0
  32. package/lib/weather.js +1 -0
  33. package/lib/ws.js +1 -0
  34. package/locale/en.json +6 -0
  35. package/locale/zh.json +6 -0
  36. package/package.json +118 -4
  37. package/scripts/browser-shot.mjs +217 -0
  38. package/scripts/build-dsh.mjs +228 -0
  39. package/scripts/build-rust.mjs +319 -0
  40. package/scripts/build-web.mjs +17 -0
  41. package/scripts/check-npm-package.mjs +322 -0
  42. package/scripts/mock-preview.py +574 -0
  43. package/scripts/screenshot-compose.py +89 -0
  44. package/scripts/screenshot-device.sh +75 -0
  45. package/src/dsh/client/api.ts +68 -0
  46. package/src/dsh/client/i18n.ts +573 -0
  47. package/src/dsh/client/icons.ts +56 -0
  48. package/src/dsh/client/index.ts +95 -0
  49. package/src/dsh/client/logic.ts +310 -0
  50. package/src/dsh/client/panel.ts +483 -0
  51. package/src/dsh/client/sections/apps.ts +40 -0
  52. package/src/dsh/client/sections/balance.ts +38 -0
  53. package/src/dsh/client/sections/connection.ts +97 -0
  54. package/src/dsh/client/sections/notifications.ts +43 -0
  55. package/src/dsh/client/sections/pomodoro.ts +184 -0
  56. package/src/dsh/client/sections/preferences.ts +138 -0
  57. package/src/dsh/client/sections/system.ts +120 -0
  58. package/src/dsh/client/sections/weather.ts +276 -0
  59. package/src/dsh/client/styles.ts +1119 -0
  60. package/src/dsh/client/types.ts +366 -0
  61. package/src/dsh/client/ui.ts +142 -0
  62. package/src/dsh/index.ts +108 -0
  63. package/src/dsh/lib/account.ts +520 -0
  64. package/src/dsh/lib/app-mapping.ts +366 -0
  65. package/src/dsh/lib/i18n.ts +82 -0
  66. package/src/dsh/lib/media-enrich.ts +202 -0
  67. package/src/dsh/lib/notifications.ts +322 -0
  68. package/src/dsh/lib/performance.ts +279 -0
  69. package/src/dsh/lib/platform/index.ts +43 -0
  70. package/src/dsh/lib/probe-adapter.ts +275 -0
  71. package/src/dsh/lib/probe-daemon.ts +359 -0
  72. package/src/dsh/lib/probe.ts +395 -0
  73. package/src/dsh/lib/qr.ts +42 -0
  74. package/src/dsh/lib/runtime.ts +126 -0
  75. package/src/dsh/lib/service.ts +1645 -0
  76. package/src/dsh/lib/sessions.ts +907 -0
  77. package/src/dsh/lib/settings.ts +468 -0
  78. package/src/dsh/lib/types.ts +231 -0
  79. package/src/dsh/lib/util.ts +115 -0
  80. package/src/dsh/lib/weather.ts +532 -0
  81. package/src/dsh/lib/ws.ts +328 -0
  82. package/src/dsh/types/qrcode-generator.d.ts +16 -0
  83. package/src/rust/Cargo.lock +1431 -0
  84. package/src/rust/Cargo.toml +68 -0
  85. package/src/rust/src/cli.rs +233 -0
  86. package/src/rust/src/daemon.rs +140 -0
  87. package/src/rust/src/location/linux.rs +118 -0
  88. package/src/rust/src/location/macos.rs +26 -0
  89. package/src/rust/src/location/mod.rs +170 -0
  90. package/src/rust/src/location/windows.rs +205 -0
  91. package/src/rust/src/main.rs +42 -0
  92. package/src/rust/src/media/catalog.rs +454 -0
  93. package/src/rust/src/media/linux.rs +350 -0
  94. package/src/rust/src/media/macos/accessibility.rs +59 -0
  95. package/src/rust/src/media/macos.rs +366 -0
  96. package/src/rust/src/media/mod.rs +298 -0
  97. package/src/rust/src/media/vendor/apple_music.rs +90 -0
  98. package/src/rust/src/media/vendor/common.rs +186 -0
  99. package/src/rust/src/media/vendor/kugou.rs +52 -0
  100. package/src/rust/src/media/vendor/kuwo.rs +49 -0
  101. package/src/rust/src/media/vendor/mod.rs +75 -0
  102. package/src/rust/src/media/vendor/netease.rs +1715 -0
  103. package/src/rust/src/media/vendor/qishui.rs +36 -0
  104. package/src/rust/src/media/vendor/qqmusic.rs +33 -0
  105. package/src/rust/src/media/vendor/spotify.rs +46 -0
  106. package/src/rust/src/media/vendor/wesing.rs +39 -0
  107. package/src/rust/src/media/vendor/youtube_music.rs +49 -0
  108. package/src/rust/src/media/windows/accessibility.rs +85 -0
  109. package/src/rust/src/media/windows/audio.rs +116 -0
  110. package/src/rust/src/media/windows/private.rs +291 -0
  111. package/src/rust/src/media/windows.rs +775 -0
  112. package/src/rust/src/notifications/linux.rs +276 -0
  113. package/src/rust/src/notifications/macos.rs +382 -0
  114. package/src/rust/src/notifications/mod.rs +244 -0
  115. package/src/rust/src/notifications/windows.rs +565 -0
  116. package/src/rust/src/perf/common.rs +109 -0
  117. package/src/rust/src/perf/linux.rs +282 -0
  118. package/src/rust/src/perf/macos.rs +28 -0
  119. package/src/rust/src/perf/mod.rs +157 -0
  120. package/src/rust/src/perf/windows.rs +981 -0
  121. package/src/rust/src/util.rs +360 -0
  122. package/src/rust/src/volume/linux.rs +195 -0
  123. package/src/rust/src/volume/macos.rs +54 -0
  124. package/src/rust/src/volume/mod.rs +116 -0
  125. package/src/rust/src/volume/windows.rs +75 -0
  126. package/src/rust/tests/cli.rs +79 -0
  127. package/src/rust/tests/daemon.rs +107 -0
  128. package/src/svelte/App.svelte +385 -0
  129. package/src/svelte/index.html +18 -0
  130. package/src/svelte/lib/billing.svelte.ts +228 -0
  131. package/src/svelte/lib/components/BalanceCard.svelte +173 -0
  132. package/src/svelte/lib/components/ClockCard.svelte +183 -0
  133. package/src/svelte/lib/components/CountdownCard.svelte +261 -0
  134. package/src/svelte/lib/components/CpuMemoryCard.svelte +238 -0
  135. package/src/svelte/lib/components/EmptyState.svelte +34 -0
  136. package/src/svelte/lib/components/GpuCard.svelte +245 -0
  137. package/src/svelte/lib/components/HomePage.svelte +34 -0
  138. package/src/svelte/lib/components/MusicControls.svelte +256 -0
  139. package/src/svelte/lib/components/MusicCover.svelte +88 -0
  140. package/src/svelte/lib/components/MusicPage.svelte +116 -0
  141. package/src/svelte/lib/components/NotificationsCard.svelte +109 -0
  142. package/src/svelte/lib/components/Panel.svelte +22 -0
  143. package/src/svelte/lib/components/PerformancePage.svelte +55 -0
  144. package/src/svelte/lib/components/PomodoroCard.svelte +250 -0
  145. package/src/svelte/lib/components/QuestionSheet.svelte +354 -0
  146. package/src/svelte/lib/components/RadialGauge.svelte +99 -0
  147. package/src/svelte/lib/components/Rail.svelte +217 -0
  148. package/src/svelte/lib/components/SectionHeader.svelte +40 -0
  149. package/src/svelte/lib/components/SeekBar.svelte +421 -0
  150. package/src/svelte/lib/components/SessionList.svelte +364 -0
  151. package/src/svelte/lib/components/SessionStats.svelte +98 -0
  152. package/src/svelte/lib/components/SessionsPage.svelte +61 -0
  153. package/src/svelte/lib/components/SpendCard.svelte +105 -0
  154. package/src/svelte/lib/components/ThermalCard.svelte +249 -0
  155. package/src/svelte/lib/components/Toast.svelte +32 -0
  156. package/src/svelte/lib/components/WeatherIcon.svelte +40 -0
  157. package/src/svelte/lib/components/WeatherPanel.svelte +420 -0
  158. package/src/svelte/lib/components/ui/alert/alert-action.svelte +20 -0
  159. package/src/svelte/lib/components/ui/alert/alert-description.svelte +23 -0
  160. package/src/svelte/lib/components/ui/alert/alert-title.svelte +23 -0
  161. package/src/svelte/lib/components/ui/alert/alert.svelte +43 -0
  162. package/src/svelte/lib/components/ui/alert/index.ts +17 -0
  163. package/src/svelte/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  164. package/src/svelte/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  165. package/src/svelte/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  166. package/src/svelte/lib/components/ui/avatar/avatar-group.svelte +23 -0
  167. package/src/svelte/lib/components/ui/avatar/avatar-image.svelte +17 -0
  168. package/src/svelte/lib/components/ui/avatar/avatar.svelte +26 -0
  169. package/src/svelte/lib/components/ui/avatar/index.ts +22 -0
  170. package/src/svelte/lib/components/ui/badge/badge.svelte +49 -0
  171. package/src/svelte/lib/components/ui/badge/index.ts +2 -0
  172. package/src/svelte/lib/components/ui/button/button.svelte +82 -0
  173. package/src/svelte/lib/components/ui/button/index.ts +17 -0
  174. package/src/svelte/lib/components/ui/card/card-action.svelte +23 -0
  175. package/src/svelte/lib/components/ui/card/card-content.svelte +20 -0
  176. package/src/svelte/lib/components/ui/card/card-description.svelte +20 -0
  177. package/src/svelte/lib/components/ui/card/card-footer.svelte +20 -0
  178. package/src/svelte/lib/components/ui/card/card-header.svelte +23 -0
  179. package/src/svelte/lib/components/ui/card/card-title.svelte +20 -0
  180. package/src/svelte/lib/components/ui/card/card.svelte +22 -0
  181. package/src/svelte/lib/components/ui/card/index.ts +25 -0
  182. package/src/svelte/lib/components/ui/dialog/dialog-close.svelte +11 -0
  183. package/src/svelte/lib/components/ui/dialog/dialog-content.svelte +48 -0
  184. package/src/svelte/lib/components/ui/dialog/dialog-description.svelte +17 -0
  185. package/src/svelte/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  186. package/src/svelte/lib/components/ui/dialog/dialog-header.svelte +20 -0
  187. package/src/svelte/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  188. package/src/svelte/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  189. package/src/svelte/lib/components/ui/dialog/dialog-title.svelte +17 -0
  190. package/src/svelte/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  191. package/src/svelte/lib/components/ui/dialog/dialog.svelte +7 -0
  192. package/src/svelte/lib/components/ui/dialog/index.ts +34 -0
  193. package/src/svelte/lib/components/ui/empty/empty-content.svelte +23 -0
  194. package/src/svelte/lib/components/ui/empty/empty-description.svelte +23 -0
  195. package/src/svelte/lib/components/ui/empty/empty-header.svelte +20 -0
  196. package/src/svelte/lib/components/ui/empty/empty-media.svelte +41 -0
  197. package/src/svelte/lib/components/ui/empty/empty-title.svelte +20 -0
  198. package/src/svelte/lib/components/ui/empty/empty.svelte +23 -0
  199. package/src/svelte/lib/components/ui/empty/index.ts +22 -0
  200. package/src/svelte/lib/components/ui/input/index.ts +7 -0
  201. package/src/svelte/lib/components/ui/input/input.svelte +48 -0
  202. package/src/svelte/lib/components/ui/progress/index.ts +7 -0
  203. package/src/svelte/lib/components/ui/progress/progress.svelte +27 -0
  204. package/src/svelte/lib/components/ui/scroll-area/index.ts +10 -0
  205. package/src/svelte/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte +30 -0
  206. package/src/svelte/lib/components/ui/scroll-area/scroll-area.svelte +43 -0
  207. package/src/svelte/lib/components/ui/separator/index.ts +7 -0
  208. package/src/svelte/lib/components/ui/separator/separator.svelte +21 -0
  209. package/src/svelte/lib/components/ui/sheet/index.ts +34 -0
  210. package/src/svelte/lib/components/ui/sheet/sheet-close.svelte +7 -0
  211. package/src/svelte/lib/components/ui/sheet/sheet-content.svelte +55 -0
  212. package/src/svelte/lib/components/ui/sheet/sheet-description.svelte +17 -0
  213. package/src/svelte/lib/components/ui/sheet/sheet-footer.svelte +20 -0
  214. package/src/svelte/lib/components/ui/sheet/sheet-header.svelte +20 -0
  215. package/src/svelte/lib/components/ui/sheet/sheet-overlay.svelte +20 -0
  216. package/src/svelte/lib/components/ui/sheet/sheet-portal.svelte +7 -0
  217. package/src/svelte/lib/components/ui/sheet/sheet-title.svelte +17 -0
  218. package/src/svelte/lib/components/ui/sheet/sheet-trigger.svelte +7 -0
  219. package/src/svelte/lib/components/ui/sheet/sheet.svelte +7 -0
  220. package/src/svelte/lib/components/ui/skeleton/index.ts +7 -0
  221. package/src/svelte/lib/components/ui/skeleton/skeleton.svelte +17 -0
  222. package/src/svelte/lib/components/ui/slider/index.ts +7 -0
  223. package/src/svelte/lib/components/ui/slider/slider.svelte +52 -0
  224. package/src/svelte/lib/components/ui/tooltip/index.ts +19 -0
  225. package/src/svelte/lib/components/ui/tooltip/tooltip-content.svelte +51 -0
  226. package/src/svelte/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  227. package/src/svelte/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  228. package/src/svelte/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  229. package/src/svelte/lib/components/ui/tooltip/tooltip.svelte +7 -0
  230. package/src/svelte/lib/countdown.svelte.ts +252 -0
  231. package/src/svelte/lib/format.ts +199 -0
  232. package/src/svelte/lib/i18n.svelte.ts +583 -0
  233. package/src/svelte/lib/media.ts +32 -0
  234. package/src/svelte/lib/pages.ts +18 -0
  235. package/src/svelte/lib/pomodoro.svelte.ts +223 -0
  236. package/src/svelte/lib/session-tree.ts +80 -0
  237. package/src/svelte/lib/state.svelte.ts +359 -0
  238. package/src/svelte/lib/timer-alarm.svelte.ts +319 -0
  239. package/src/svelte/lib/types.ts +306 -0
  240. package/src/svelte/lib/utils.ts +8 -0
  241. package/src/svelte/lib/weather.ts +84 -0
  242. package/src/svelte/lib/ws.ts +104 -0
  243. package/src/svelte/main.ts +13 -0
  244. package/src/svelte/styles/global.css +315 -0
  245. package/src/svelte/vite-env.d.ts +12 -0
  246. package/static/fonts/LICENSE.txt +287 -0
  247. package/static/icon.svg +24 -0
  248. package/static/manifest.webmanifest +18 -0
  249. package/svelte.config.js +5 -0
  250. package/tsconfig.dsh-client.json +18 -0
  251. package/tsconfig.dsh.json +21 -0
  252. package/tsconfig.json +20 -0
  253. package/vite.config.js +31 -0
  254. package/web/assets/index-DLdSfnJ3.css +1 -0
  255. package/web/assets/index-YNE8X0Uy.js +6 -0
  256. package/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  257. package/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  258. package/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  259. package/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  260. package/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  261. package/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  262. package/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  263. package/web/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
  264. package/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  265. package/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  266. package/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  267. package/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  268. package/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  269. package/web/assets/noto-sans-sc-100-wght-normal-DluiXYzi.woff2 +0 -0
  270. package/web/assets/noto-sans-sc-101-wght-normal-CPkZHnw0.woff2 +0 -0
  271. package/web/assets/noto-sans-sc-102-wght-normal-gzIulUH6.woff2 +0 -0
  272. package/web/assets/noto-sans-sc-103-wght-normal-CJfSBxFo.woff2 +0 -0
  273. package/web/assets/noto-sans-sc-104-wght-normal-B3QMglgE.woff2 +0 -0
  274. package/web/assets/noto-sans-sc-105-wght-normal-xXh_OMfk.woff2 +0 -0
  275. package/web/assets/noto-sans-sc-106-wght-normal-B9n3jMjP.woff2 +0 -0
  276. package/web/assets/noto-sans-sc-107-wght-normal-D7fvVprN.woff2 +0 -0
  277. package/web/assets/noto-sans-sc-108-wght-normal-J0_LhxVo.woff2 +0 -0
  278. package/web/assets/noto-sans-sc-109-wght-normal-Dsp-De_0.woff2 +0 -0
  279. package/web/assets/noto-sans-sc-110-wght-normal-DE_6NUrb.woff2 +0 -0
  280. package/web/assets/noto-sans-sc-111-wght-normal-C4S-TlTn.woff2 +0 -0
  281. package/web/assets/noto-sans-sc-112-wght-normal-BcFuP3w6.woff2 +0 -0
  282. package/web/assets/noto-sans-sc-113-wght-normal-Dk932kmj.woff2 +0 -0
  283. package/web/assets/noto-sans-sc-114-wght-normal-CO_5Xo-i.woff2 +0 -0
  284. package/web/assets/noto-sans-sc-115-wght-normal-BWy07H14.woff2 +0 -0
  285. package/web/assets/noto-sans-sc-116-wght-normal-B4HVAfHo.woff2 +0 -0
  286. package/web/assets/noto-sans-sc-117-wght-normal-siZzFqgK.woff2 +0 -0
  287. package/web/assets/noto-sans-sc-118-wght-normal-xhBB7f6V.woff2 +0 -0
  288. package/web/assets/noto-sans-sc-119-wght-normal-Ck_g2FGz.woff2 +0 -0
  289. package/web/assets/noto-sans-sc-21-wght-normal-D0x9-yBt.woff2 +0 -0
  290. package/web/assets/noto-sans-sc-22-wght-normal-BBUVTShg.woff2 +0 -0
  291. package/web/assets/noto-sans-sc-23-wght-normal-Du1oYWkE.woff2 +0 -0
  292. package/web/assets/noto-sans-sc-24-wght-normal-CmWjJ0gt.woff2 +0 -0
  293. package/web/assets/noto-sans-sc-25-wght-normal-BFHiqilg.woff2 +0 -0
  294. package/web/assets/noto-sans-sc-26-wght-normal-C0sF2Z2f.woff2 +0 -0
  295. package/web/assets/noto-sans-sc-27-wght-normal-COFdrquJ.woff2 +0 -0
  296. package/web/assets/noto-sans-sc-28-wght-normal-DMgdNu1o.woff2 +0 -0
  297. package/web/assets/noto-sans-sc-29-wght-normal-Cmq8em30.woff2 +0 -0
  298. package/web/assets/noto-sans-sc-30-wght-normal-CZWqZ3yU.woff2 +0 -0
  299. package/web/assets/noto-sans-sc-31-wght-normal-Wfi_lutW.woff2 +0 -0
  300. package/web/assets/noto-sans-sc-32-wght-normal-BRJQ4PY5.woff2 +0 -0
  301. package/web/assets/noto-sans-sc-33-wght-normal-CUVQXNAJ.woff2 +0 -0
  302. package/web/assets/noto-sans-sc-34-wght-normal-Bspba0wC.woff2 +0 -0
  303. package/web/assets/noto-sans-sc-35-wght-normal-K8fX_YPG.woff2 +0 -0
  304. package/web/assets/noto-sans-sc-36-wght-normal-CkITyjoT.woff2 +0 -0
  305. package/web/assets/noto-sans-sc-37-wght-normal-WCZ2zfEe.woff2 +0 -0
  306. package/web/assets/noto-sans-sc-38-wght-normal-DeM7CUce.woff2 +0 -0
  307. package/web/assets/noto-sans-sc-39-wght-normal-BMZNLWQU.woff2 +0 -0
  308. package/web/assets/noto-sans-sc-4-wght-normal-AR5bdDjz.woff2 +0 -0
  309. package/web/assets/noto-sans-sc-40-wght-normal-BQ5xpS5j.woff2 +0 -0
  310. package/web/assets/noto-sans-sc-41-wght-normal-Hthm7FFi.woff2 +0 -0
  311. package/web/assets/noto-sans-sc-42-wght-normal-eaS2gKds.woff2 +0 -0
  312. package/web/assets/noto-sans-sc-43-wght-normal-o-T53XXV.woff2 +0 -0
  313. package/web/assets/noto-sans-sc-44-wght-normal-BJH5J4Ez.woff2 +0 -0
  314. package/web/assets/noto-sans-sc-45-wght-normal-BKuxSCOJ.woff2 +0 -0
  315. package/web/assets/noto-sans-sc-46-wght-normal-BR_5Mu6e.woff2 +0 -0
  316. package/web/assets/noto-sans-sc-47-wght-normal-CyY7gKNX.woff2 +0 -0
  317. package/web/assets/noto-sans-sc-48-wght-normal-BNMfTR6k.woff2 +0 -0
  318. package/web/assets/noto-sans-sc-49-wght-normal-DX-0y7wg.woff2 +0 -0
  319. package/web/assets/noto-sans-sc-5-wght-normal-CfWugllB.woff2 +0 -0
  320. package/web/assets/noto-sans-sc-50-wght-normal-DAOGW-Dr.woff2 +0 -0
  321. package/web/assets/noto-sans-sc-51-wght-normal-BlFLOjcP.woff2 +0 -0
  322. package/web/assets/noto-sans-sc-52-wght-normal-OZjrybnw.woff2 +0 -0
  323. package/web/assets/noto-sans-sc-53-wght-normal-CwyWNT6x.woff2 +0 -0
  324. package/web/assets/noto-sans-sc-54-wght-normal-DM0nRe18.woff2 +0 -0
  325. package/web/assets/noto-sans-sc-55-wght-normal-DBK2wUOR.woff2 +0 -0
  326. package/web/assets/noto-sans-sc-56-wght-normal-C-VKK1LS.woff2 +0 -0
  327. package/web/assets/noto-sans-sc-57-wght-normal-Cdbfh5kq.woff2 +0 -0
  328. package/web/assets/noto-sans-sc-58-wght-normal-CflMKARZ.woff2 +0 -0
  329. package/web/assets/noto-sans-sc-59-wght-normal-BS4Kwzxx.woff2 +0 -0
  330. package/web/assets/noto-sans-sc-6-wght-normal-ChnZIQfQ.woff2 +0 -0
  331. package/web/assets/noto-sans-sc-60-wght-normal-B7QOYsXJ.woff2 +0 -0
  332. package/web/assets/noto-sans-sc-61-wght-normal-C8JjQS7w.woff2 +0 -0
  333. package/web/assets/noto-sans-sc-62-wght-normal-bS4wq1Gg.woff2 +0 -0
  334. package/web/assets/noto-sans-sc-63-wght-normal-BJr8P-OB.woff2 +0 -0
  335. package/web/assets/noto-sans-sc-64-wght-normal-DVB11t7j.woff2 +0 -0
  336. package/web/assets/noto-sans-sc-65-wght-normal-DMPCXBvK.woff2 +0 -0
  337. package/web/assets/noto-sans-sc-66-wght-normal-BobaG10V.woff2 +0 -0
  338. package/web/assets/noto-sans-sc-67-wght-normal-Dzk7WhCR.woff2 +0 -0
  339. package/web/assets/noto-sans-sc-68-wght-normal-DGbCD9xu.woff2 +0 -0
  340. package/web/assets/noto-sans-sc-69-wght-normal-Ctrv1EqA.woff2 +0 -0
  341. package/web/assets/noto-sans-sc-70-wght-normal-RgTO941D.woff2 +0 -0
  342. package/web/assets/noto-sans-sc-71-wght-normal-D9sG-CWv.woff2 +0 -0
  343. package/web/assets/noto-sans-sc-72-wght-normal-C4oWy3ul.woff2 +0 -0
  344. package/web/assets/noto-sans-sc-73-wght-normal-B1ZoOTgM.woff2 +0 -0
  345. package/web/assets/noto-sans-sc-74-wght-normal-F7dH_rZJ.woff2 +0 -0
  346. package/web/assets/noto-sans-sc-75-wght-normal-Cp2wp4si.woff2 +0 -0
  347. package/web/assets/noto-sans-sc-76-wght-normal-B494D7xS.woff2 +0 -0
  348. package/web/assets/noto-sans-sc-77-wght-normal-B3MVY9Ax.woff2 +0 -0
  349. package/web/assets/noto-sans-sc-78-wght-normal-5jX7iNMC.woff2 +0 -0
  350. package/web/assets/noto-sans-sc-79-wght-normal-BIoZy8fr.woff2 +0 -0
  351. package/web/assets/noto-sans-sc-80-wght-normal-Bje1Fxy1.woff2 +0 -0
  352. package/web/assets/noto-sans-sc-81-wght-normal-B2NN7Qi3.woff2 +0 -0
  353. package/web/assets/noto-sans-sc-82-wght-normal-CUggNZi4.woff2 +0 -0
  354. package/web/assets/noto-sans-sc-83-wght-normal-99rD8YO-.woff2 +0 -0
  355. package/web/assets/noto-sans-sc-84-wght-normal-zMBmUocm.woff2 +0 -0
  356. package/web/assets/noto-sans-sc-85-wght-normal-CjI3qdxG.woff2 +0 -0
  357. package/web/assets/noto-sans-sc-86-wght-normal-BHY8TVEH.woff2 +0 -0
  358. package/web/assets/noto-sans-sc-87-wght-normal-DioZSHnU.woff2 +0 -0
  359. package/web/assets/noto-sans-sc-88-wght-normal-BXYxwf2t.woff2 +0 -0
  360. package/web/assets/noto-sans-sc-89-wght-normal-ClMFrFaL.woff2 +0 -0
  361. package/web/assets/noto-sans-sc-90-wght-normal-BnOlPreP.woff2 +0 -0
  362. package/web/assets/noto-sans-sc-91-wght-normal-DTr9RQcS.woff2 +0 -0
  363. package/web/assets/noto-sans-sc-97-wght-normal-9u6Aiav-.woff2 +0 -0
  364. package/web/assets/noto-sans-sc-98-wght-normal-BR-H2C0V.woff2 +0 -0
  365. package/web/assets/noto-sans-sc-99-wght-normal-BI6XPoxp.woff2 +0 -0
  366. package/web/assets/noto-sans-sc-cyrillic-wght-normal-BGmsQlw-.woff2 +0 -0
  367. package/web/assets/noto-sans-sc-latin-ext-wght-normal-DuJTpTg_.woff2 +0 -0
  368. package/web/assets/noto-sans-sc-latin-wght-normal-DDW8mKAR.woff2 +0 -0
  369. package/web/assets/noto-sans-sc-vietnamese-wght-normal-Bi3ATJ76.woff2 +0 -0
  370. package/web/fonts/LICENSE.txt +287 -0
  371. package/web/icon.svg +24 -0
  372. package/web/index.html +19 -0
  373. package/web/manifest.webmanifest +18 -0
@@ -0,0 +1,583 @@
1
+ /**
2
+ * Console translations.
3
+ *
4
+ * Each shipped language is one flat key -> text object so adding a language
5
+ * later only means appending another object to {@link DICTS}. The `en` object
6
+ * is typed against the keys of `zh`, so a missing English translation is a
7
+ * compile error rather than a Chinese string leaking into the English UI.
8
+ */
9
+
10
+ import type { PageKey } from './types';
11
+
12
+ export type LocaleCode = 'zh' | 'en';
13
+
14
+ export const SUPPORTED_LOCALES: readonly LocaleCode[] = ['zh', 'en'];
15
+
16
+ export const zh = {
17
+ // Shell
18
+ offline: '正在重新连接…',
19
+ refreshing: '正在刷新',
20
+ fullscreenUnsupported: '当前浏览器不支持全屏',
21
+ fullscreenDenied: '当前浏览器不允许全屏',
22
+ navLabel: '页面导航',
23
+ pagesLabel: '页面',
24
+ refreshPage: '刷新页面状态',
25
+ fullscreenEnter: '进入全屏',
26
+ fullscreenExit: '退出全屏',
27
+ errorSessions: '有错误会话',
28
+ pendingQuestions: '有待回答问题',
29
+ timerAlert: '计时器已到时',
30
+
31
+ // Pages
32
+ pageHome: '首页',
33
+ pageSessions: '会话',
34
+ pageMusic: '音乐',
35
+ pagePerformance: '性能',
36
+
37
+ // Toasts and question actions
38
+ connecting: '正在连接,请稍候',
39
+ actionFailed: '操作失败',
40
+ serviceError: '服务异常',
41
+ pushQuestionsOff: '「推送问询」已关闭,请在 DSH 的通知设置中开启',
42
+ approvalPending: '该会话正在等待批准,请在 DSH 中处理',
43
+ answerInDsh: '这个问题需要在 DSH 中回答',
44
+ connectionLost: '连接已断开,请稍后重试',
45
+ answerReplaced: '答复已被新的回答替换',
46
+ answerTimeout: '回答超时,请重试',
47
+ answerFailed: '回答失败',
48
+
49
+ // Time and clock
50
+ greetingMorning: '早上好',
51
+ greetingNoon: '中午好',
52
+ greetingAfternoon: '下午好',
53
+ greetingEvening: '晚上好',
54
+ periodMorning: '早上',
55
+ periodNoon: '中午',
56
+ periodAfternoon: '下午',
57
+ periodEvening: '晚上',
58
+ justNow: '刚刚',
59
+ minutesAgo: '{count} 分钟前',
60
+ hoursAgo: '{count} 小时前',
61
+ daysAgo: '{count} 天前',
62
+ uptimeDays: '{days}天 {hours}小时',
63
+ uptimeHours: '{hours}小时 {minutes}分',
64
+ uptimeMinutes: '{minutes}分钟',
65
+
66
+ // Solar terms
67
+ termMinorCold: '小寒',
68
+ termMajorCold: '大寒',
69
+ termStartOfSpring: '立春',
70
+ termRainWater: '雨水',
71
+ termAwakening: '惊蛰',
72
+ termSpringEquinox: '春分',
73
+ termClearAndBright: '清明',
74
+ termGrainRain: '谷雨',
75
+ termStartOfSummer: '立夏',
76
+ termGrainFull: '小满',
77
+ termGrainInEar: '芒种',
78
+ termSummerSolstice: '夏至',
79
+ termMinorHeat: '小暑',
80
+ termMajorHeat: '大暑',
81
+ termStartOfAutumn: '立秋',
82
+ termEndOfHeat: '处暑',
83
+ termWhiteDew: '白露',
84
+ termAutumnEquinox: '秋分',
85
+ termColdDew: '寒露',
86
+ termFrostDescent: '霜降',
87
+ termStartOfWinter: '立冬',
88
+ termMinorSnow: '小雪',
89
+ termMajorSnow: '大雪',
90
+ termWinterSolstice: '冬至',
91
+
92
+ // Weather
93
+ weather: '天气',
94
+ weatherUnavailable: '天气暂不可用',
95
+ tryLater: '稍后再试',
96
+ currentLocation: '当前位置',
97
+ customLocation: '自定义位置',
98
+ highLow: '最高 / 最低',
99
+ feelsLike: '体感',
100
+ humidity: '湿度',
101
+ windSpeed: '风速',
102
+ today: '今天',
103
+ now: '现在',
104
+ hourLabel: '{hour}时',
105
+ sunrise: '日出',
106
+ sunset: '日落',
107
+ tomorrow: '明日',
108
+ weatherFallback: '天气',
109
+ weatherNight: '夜间',
110
+
111
+ // Weather codes (WMO)
112
+ wmoClear: '晴',
113
+ wmoMostlyClear: '大致晴朗',
114
+ wmoPartlyCloudy: '局部多云',
115
+ wmoOvercast: '阴天',
116
+ wmoFog: '有雾',
117
+ wmoRimeFog: '雾凇',
118
+ wmoDrizzle: '毛毛雨',
119
+ wmoDenseDrizzle: '较强毛毛雨',
120
+ wmoFreezingDrizzle: '冻毛毛雨',
121
+ wmoHeavyFreezingDrizzle: '强冻毛毛雨',
122
+ wmoLightRain: '小雨',
123
+ wmoRain: '中雨',
124
+ wmoHeavyRain: '大雨',
125
+ wmoFreezingRain: '冻雨',
126
+ wmoHeavyFreezingRain: '强冻雨',
127
+ wmoLightSnow: '小雪',
128
+ wmoSnow: '中雪',
129
+ wmoHeavySnow: '大雪',
130
+ wmoSnowGrains: '雪粒',
131
+ wmoRainShowers: '阵雨',
132
+ wmoHeavyRainShowers: '较强阵雨',
133
+ wmoViolentRainShowers: '强阵雨',
134
+ wmoSnowShowers: '阵雪',
135
+ wmoHeavySnowShowers: '强阵雪',
136
+ wmoThunderstorm: '雷雨',
137
+ wmoThunderstormHail: '雷雨伴冰雹',
138
+ wmoSevereThunderstorm: '强雷雨伴冰雹',
139
+
140
+ // Notifications
141
+ notifications: '通知',
142
+ notificationsUnavailable: '通知暂不可用',
143
+ noNotifications: '暂无通知',
144
+ noNotificationsHint: '新的通知会显示在这里',
145
+ notificationFallback: '通知',
146
+
147
+ // Sessions
148
+ conversations: '会话',
149
+ sessionLoading: '正在读取',
150
+ sessionCount: '{count} 个会话',
151
+ sessionCountOne: '1 个会话',
152
+ noActiveSessions: '暂无活动会话',
153
+ statusRunning: '运行中',
154
+ statusQuestion: '等待回答',
155
+ statusError: '错误',
156
+ statusDone: '已结束',
157
+ noMessage: '暂无消息',
158
+ turnLabel: '第 {turn} 轮',
159
+ subagent: '子代理',
160
+ needsAttention: '需要处理',
161
+ answer: '回答',
162
+ answerSession: '回答会话 {title}',
163
+ newSession: '新会话',
164
+ sessionLoadFailed: '会话暂时无法加载',
165
+ noSessions: '暂无会话',
166
+ noSessionsHint: '新的会话会显示在这里',
167
+
168
+ // Music
169
+ nothingPlaying: '没有播放内容',
170
+ unknownArtist: '未知艺术家',
171
+ chooseSong: '选择一首歌开始播放',
172
+ like: '喜欢',
173
+ unlike: '取消喜欢',
174
+ previousTrack: '上一首',
175
+ nextTrack: '下一首',
176
+ play: '播放',
177
+ pause: '暂停',
178
+ mute: '静音',
179
+ volume: '音量',
180
+ nowPlaying: '正在播放',
181
+ albumCover: '专辑封面',
182
+ mediaFallback: '媒体',
183
+ musicSource: '音乐',
184
+ sourceBilibili: '哔哩哔哩',
185
+
186
+ // Seek bar
187
+ playProgress: '播放进度',
188
+ progressUnavailable: '进度信息不可用',
189
+ progressReadOnly: '当前进度仅展示',
190
+
191
+ // Performance
192
+ cpuMemory: 'CPU / 内存',
193
+ gpuMemory: '显卡 / 显存',
194
+ currentStatus: '当前状态',
195
+ threadCount: '{count} 线程',
196
+ threadCountOne: '1 线程',
197
+ currentFrequency: '当前频率',
198
+ runningTime: '运行时间',
199
+ memoryUsed: '已用',
200
+ memoryFree: '可用',
201
+ unavailableShort: '暂不可用',
202
+ noDiscreteGpu: '未检测到独立显卡',
203
+ driverLabel: '驱动',
204
+ driverValue: '驱动 {name}',
205
+ driverUnknown: '驱动版本未知',
206
+ driverNone: '驱动 —',
207
+ coreClock: '核心频率',
208
+ memoryClock: '显存频率',
209
+ temperatures: '温度',
210
+ itemCount: '{count} 个',
211
+ noTemperature: '暂无温度读数',
212
+ maxTemperature: '最高温度',
213
+ notProvided: '未提供',
214
+ device: '设备',
215
+
216
+ // Balance and spending
217
+ accountBalance: '账户余额',
218
+ syncing: '正在同步',
219
+ signedOut: '未登录账号',
220
+ topUpBonus: '充值 {paid} · 赠送 {bonus}',
221
+ peakHours: '高峰时段',
222
+ offpeakHours: '低谷时段',
223
+ peak: '高峰',
224
+ offpeak: '低谷',
225
+ belowThreshold: '低于提醒线 {amount}',
226
+ usage: '消费',
227
+ todaySpend: '今日',
228
+ thisWeek: '本周',
229
+ last7Days: '最近 7 天',
230
+
231
+ // Pomodoro
232
+ pomodoro: '番茄钟',
233
+ focusDone: '专注完成',
234
+ breakDone: '休息结束',
235
+ focus: '专注',
236
+ rest: '休息',
237
+ stopAlarm: '停止响铃',
238
+ startBreak: '开始休息',
239
+ startFocus: '开始专注',
240
+ start: '开始',
241
+ switchPhase: '切换专注 / 休息',
242
+ roundCount: '{count} 个',
243
+ resetPomodoro: '重置番茄钟',
244
+ reset: '重置',
245
+
246
+ // Countdown
247
+ countdown: '倒计时',
248
+ countdownFinished: '时间到',
249
+ confirmEnd: '确认结束',
250
+ resetCountdown: '重置倒计时',
251
+ countdownPresets: '倒计时预设',
252
+
253
+ // Question sheet
254
+ sessionQuestion: '会话提问',
255
+ questionCount: '{count} 个问题',
256
+ questionCountOne: '1 个问题',
257
+ chooseOption: '选择一项,或填写自定义回复',
258
+ close: '关闭',
259
+ recommended: '推荐',
260
+ otherAnswer: '其他回答…',
261
+ typeAnswer: '输入回答…',
262
+ customReply: '自定义回复',
263
+ sendAnswer: '发送回答',
264
+ skipQuestion: '跳过此题',
265
+ skippedNote: '将作为未回答提交',
266
+ sendingEllipsis: '正在发送…',
267
+ canMultiAnswer: '可多选或填写自定义回复',
268
+ cancel: '取消',
269
+ sending: '发送中…',
270
+ answered: '已回复',
271
+ questionEnded: '当前问题已经结束',
272
+ answerEveryQuestion: '请先回答每一道问题,或选择跳过',
273
+ } as const;
274
+
275
+ export type MessageKey = keyof typeof zh;
276
+
277
+ export const en: Record<MessageKey, string> = {
278
+ // Shell
279
+ offline: 'Reconnecting…',
280
+ refreshing: 'Refreshing',
281
+ fullscreenUnsupported: 'This browser does not support fullscreen',
282
+ fullscreenDenied: 'Fullscreen is blocked in this browser',
283
+ navLabel: 'Page navigation',
284
+ pagesLabel: 'Pages',
285
+ refreshPage: 'Refresh page data',
286
+ fullscreenEnter: 'Enter fullscreen',
287
+ fullscreenExit: 'Exit fullscreen',
288
+ errorSessions: 'Sessions with errors',
289
+ pendingQuestions: 'Questions waiting',
290
+ timerAlert: 'Timer has finished',
291
+
292
+ // Pages
293
+ pageHome: 'Home',
294
+ pageSessions: 'Sessions',
295
+ pageMusic: 'Music',
296
+ pagePerformance: 'Performance',
297
+
298
+ // Toasts and question actions
299
+ connecting: 'Connecting, please wait',
300
+ actionFailed: 'Action failed',
301
+ serviceError: 'Service error',
302
+ pushQuestionsOff: 'Pushed inquiries are off; turn them on in DSH notification settings',
303
+ approvalPending: 'This session is waiting for approval; handle it in DSH',
304
+ answerInDsh: 'Answer this question in DSH',
305
+ connectionLost: 'Connection lost; try again shortly',
306
+ answerReplaced: 'This reply was replaced by a newer answer',
307
+ answerTimeout: 'The answer timed out; try again',
308
+ answerFailed: 'Answer failed',
309
+
310
+ // Time and clock
311
+ greetingMorning: 'Good morning',
312
+ greetingNoon: 'Good afternoon',
313
+ greetingAfternoon: 'Good afternoon',
314
+ greetingEvening: 'Good evening',
315
+ periodMorning: 'Morning',
316
+ periodNoon: 'Noon',
317
+ periodAfternoon: 'Afternoon',
318
+ periodEvening: 'Evening',
319
+ justNow: 'just now',
320
+ minutesAgo: '{count} min ago',
321
+ hoursAgo: '{count} h ago',
322
+ daysAgo: '{count} d ago',
323
+ uptimeDays: '{days}d {hours}h',
324
+ uptimeHours: '{hours}h {minutes}m',
325
+ uptimeMinutes: '{minutes} min',
326
+
327
+ // Solar terms
328
+ termMinorCold: 'Minor Cold',
329
+ termMajorCold: 'Major Cold',
330
+ termStartOfSpring: 'Start of Spring',
331
+ termRainWater: 'Rain Water',
332
+ termAwakening: 'Awakening of Insects',
333
+ termSpringEquinox: 'Spring Equinox',
334
+ termClearAndBright: 'Clear and Bright',
335
+ termGrainRain: 'Grain Rain',
336
+ termStartOfSummer: 'Start of Summer',
337
+ termGrainFull: 'Grain Full',
338
+ termGrainInEar: 'Grain in Ear',
339
+ termSummerSolstice: 'Summer Solstice',
340
+ termMinorHeat: 'Minor Heat',
341
+ termMajorHeat: 'Major Heat',
342
+ termStartOfAutumn: 'Start of Autumn',
343
+ termEndOfHeat: 'End of Heat',
344
+ termWhiteDew: 'White Dew',
345
+ termAutumnEquinox: 'Autumn Equinox',
346
+ termColdDew: 'Cold Dew',
347
+ termFrostDescent: 'Frost Descent',
348
+ termStartOfWinter: 'Start of Winter',
349
+ termMinorSnow: 'Minor Snow',
350
+ termMajorSnow: 'Major Snow',
351
+ termWinterSolstice: 'Winter Solstice',
352
+
353
+ // Weather
354
+ weather: 'Weather',
355
+ weatherUnavailable: 'Weather unavailable',
356
+ tryLater: 'Try again later',
357
+ currentLocation: 'Current location',
358
+ customLocation: 'Custom location',
359
+ highLow: 'High / Low',
360
+ feelsLike: 'Feels like',
361
+ humidity: 'Humidity',
362
+ windSpeed: 'Wind',
363
+ today: 'Today',
364
+ now: 'Now',
365
+ hourLabel: '{hour}:00',
366
+ sunrise: 'Sunrise',
367
+ sunset: 'Sunset',
368
+ tomorrow: 'Tomorrow',
369
+ weatherFallback: 'Weather',
370
+ weatherNight: 'Night',
371
+
372
+ // Weather codes (WMO)
373
+ wmoClear: 'Clear',
374
+ wmoMostlyClear: 'Mostly clear',
375
+ wmoPartlyCloudy: 'Partly cloudy',
376
+ wmoOvercast: 'Overcast',
377
+ wmoFog: 'Fog',
378
+ wmoRimeFog: 'Rime fog',
379
+ wmoDrizzle: 'Drizzle',
380
+ wmoDenseDrizzle: 'Dense drizzle',
381
+ wmoFreezingDrizzle: 'Freezing drizzle',
382
+ wmoHeavyFreezingDrizzle: 'Heavy freezing drizzle',
383
+ wmoLightRain: 'Light rain',
384
+ wmoRain: 'Rain',
385
+ wmoHeavyRain: 'Heavy rain',
386
+ wmoFreezingRain: 'Freezing rain',
387
+ wmoHeavyFreezingRain: 'Heavy freezing rain',
388
+ wmoLightSnow: 'Light snow',
389
+ wmoSnow: 'Snow',
390
+ wmoHeavySnow: 'Heavy snow',
391
+ wmoSnowGrains: 'Snow grains',
392
+ wmoRainShowers: 'Rain showers',
393
+ wmoHeavyRainShowers: 'Heavy rain showers',
394
+ wmoViolentRainShowers: 'Violent rain showers',
395
+ wmoSnowShowers: 'Snow showers',
396
+ wmoHeavySnowShowers: 'Heavy snow showers',
397
+ wmoThunderstorm: 'Thunderstorm',
398
+ wmoThunderstormHail: 'Thunderstorm with hail',
399
+ wmoSevereThunderstorm: 'Severe thunderstorm with hail',
400
+
401
+ // Notifications
402
+ notifications: 'Notifications',
403
+ notificationsUnavailable: 'Notifications unavailable',
404
+ noNotifications: 'No notifications',
405
+ noNotificationsHint: 'New notifications appear here',
406
+ notificationFallback: 'Notification',
407
+
408
+ // Sessions
409
+ conversations: 'Sessions',
410
+ sessionLoading: 'Loading',
411
+ sessionCount: '{count} sessions',
412
+ sessionCountOne: '1 session',
413
+ noActiveSessions: 'No active sessions',
414
+ statusRunning: 'Running',
415
+ statusQuestion: 'Waiting',
416
+ statusError: 'Error',
417
+ statusDone: 'Done',
418
+ noMessage: 'No messages yet',
419
+ turnLabel: 'Turn {turn}',
420
+ subagent: 'Subagent',
421
+ needsAttention: 'Needs attention',
422
+ answer: 'Answer',
423
+ answerSession: 'Answer session {title}',
424
+ newSession: 'New session',
425
+ sessionLoadFailed: 'Sessions cannot load right now',
426
+ noSessions: 'No sessions',
427
+ noSessionsHint: 'New sessions appear here',
428
+
429
+ // Music
430
+ nothingPlaying: 'Nothing playing',
431
+ unknownArtist: 'Unknown artist',
432
+ chooseSong: 'Pick a song to start playing',
433
+ like: 'Like',
434
+ unlike: 'Unlike',
435
+ previousTrack: 'Previous track',
436
+ nextTrack: 'Next track',
437
+ play: 'Play',
438
+ pause: 'Pause',
439
+ mute: 'Mute',
440
+ volume: 'Volume',
441
+ nowPlaying: 'Now playing',
442
+ albumCover: 'Album cover',
443
+ mediaFallback: 'Media',
444
+ musicSource: 'Music',
445
+ sourceBilibili: 'Bilibili',
446
+
447
+ // Seek bar
448
+ playProgress: 'Playback position',
449
+ progressUnavailable: 'Progress unavailable',
450
+ progressReadOnly: 'Position is display-only',
451
+
452
+ // Performance
453
+ cpuMemory: 'CPU / Memory',
454
+ gpuMemory: 'GPU / VRAM',
455
+ currentStatus: 'Current status',
456
+ threadCount: '{count} threads',
457
+ threadCountOne: '1 thread',
458
+ currentFrequency: 'Frequency',
459
+ runningTime: 'Uptime',
460
+ memoryUsed: 'Used',
461
+ memoryFree: 'Free',
462
+ unavailableShort: 'Unavailable',
463
+ noDiscreteGpu: 'No discrete GPU detected',
464
+ driverLabel: 'Driver',
465
+ driverValue: 'Driver {name}',
466
+ driverUnknown: 'Driver version unknown',
467
+ driverNone: 'Driver —',
468
+ coreClock: 'Core clock',
469
+ memoryClock: 'Memory clock',
470
+ temperatures: 'Temperatures',
471
+ itemCount: '{count}',
472
+ noTemperature: 'No temperature readings',
473
+ maxTemperature: 'Max temperature',
474
+ notProvided: 'Not provided',
475
+ device: 'Device',
476
+
477
+ // Balance and spending
478
+ accountBalance: 'Balance',
479
+ syncing: 'Syncing',
480
+ signedOut: 'Not signed in',
481
+ topUpBonus: 'Top-up {paid} · Bonus {bonus}',
482
+ peakHours: 'Peak hours',
483
+ offpeakHours: 'Off-peak hours',
484
+ peak: 'Peak',
485
+ offpeak: 'Off-peak',
486
+ belowThreshold: 'Below alert line {amount}',
487
+ usage: 'Usage',
488
+ todaySpend: 'Today',
489
+ thisWeek: 'This week',
490
+ last7Days: 'Last 7 days',
491
+
492
+ // Pomodoro
493
+ pomodoro: 'Pomodoro',
494
+ focusDone: 'Focus complete',
495
+ breakDone: 'Break over',
496
+ focus: 'Focus',
497
+ rest: 'Break',
498
+ stopAlarm: 'Stop ringing',
499
+ startBreak: 'Start break',
500
+ startFocus: 'Start focus',
501
+ start: 'Start',
502
+ switchPhase: 'Switch focus / break',
503
+ roundCount: '{count}',
504
+ resetPomodoro: 'Reset pomodoro',
505
+ reset: 'Reset',
506
+
507
+ // Countdown
508
+ countdown: 'Countdown',
509
+ countdownFinished: 'Time is up',
510
+ confirmEnd: 'Confirm end',
511
+ resetCountdown: 'Reset countdown',
512
+ countdownPresets: 'Countdown presets',
513
+
514
+ // Question sheet
515
+ sessionQuestion: 'Session question',
516
+ questionCount: '{count} questions',
517
+ questionCountOne: '1 question',
518
+ chooseOption: 'Choose an option or type a reply',
519
+ close: 'Close',
520
+ recommended: 'Recommended',
521
+ otherAnswer: 'Other answer…',
522
+ typeAnswer: 'Type an answer…',
523
+ customReply: 'Custom reply',
524
+ sendAnswer: 'Send answer',
525
+ skipQuestion: 'Skip this question',
526
+ skippedNote: 'Submitted as unanswered',
527
+ sendingEllipsis: 'Sending…',
528
+ canMultiAnswer: 'Select options or type a reply',
529
+ cancel: 'Cancel',
530
+ sending: 'Sending…',
531
+ answered: 'Answered',
532
+ questionEnded: 'This question has already ended',
533
+ answerEveryQuestion: 'Answer every question first, or skip it',
534
+ };
535
+
536
+ /** Every shipped dictionary, keyed by locale code. */
537
+ export const DICTS: Record<LocaleCode, Record<MessageKey, string>> = { zh, en };
538
+
539
+ /** Reactive console language; starts at the English fallback. */
540
+ export const i18n = $state<{ locale: LocaleCode }>({ locale: 'en' });
541
+
542
+ // The served HTML declares Chinese; point `<html lang>` at the actual
543
+ // fallback before the first settings snapshot can change it.
544
+ if (typeof document !== 'undefined') {
545
+ document.documentElement.lang = 'en-US';
546
+ }
547
+
548
+ /** Host locale tag used for Intl formatting. */
549
+ export function localeTag(): string {
550
+ return i18n.locale === 'zh' ? 'zh-CN' : 'en-US';
551
+ }
552
+
553
+ /** True when the console is rendering Chinese. */
554
+ export function isChinese(): boolean {
555
+ return i18n.locale === 'zh';
556
+ }
557
+
558
+ /** Apply a language pushed by the Host settings snapshot. */
559
+ export function setLocale(value: unknown): void {
560
+ const next: LocaleCode = value === 'zh' ? 'zh' : 'en';
561
+ if (next === i18n.locale) return;
562
+ i18n.locale = next;
563
+ if (typeof document !== 'undefined') {
564
+ document.documentElement.lang = localeTag();
565
+ }
566
+ }
567
+
568
+ /** Translate one key through the active dictionary, then English. */
569
+ export function t(key: MessageKey, params?: Record<string, string | number>): string {
570
+ const template = DICTS[i18n.locale][key] ?? en[key];
571
+ if (!params) return template;
572
+ return template.replace(/\{(\w+)\}/g, (match, name: string) =>
573
+ name in params ? String(params[name]) : match,
574
+ );
575
+ }
576
+
577
+ /** Page label shared by the rail, the pager and the accessibility tree. */
578
+ export function pageLabel(key: PageKey): string {
579
+ if (key === 'home') return t('pageHome');
580
+ if (key === 'sessions') return t('pageSessions');
581
+ if (key === 'music') return t('pageMusic');
582
+ return t('pagePerformance');
583
+ }
@@ -0,0 +1,32 @@
1
+ import type { MediaInfo } from './types';
2
+
3
+ export function isPlaying(media: MediaInfo | null | undefined): boolean {
4
+ return String(media?.playbackStatus).toLowerCase() === 'playing';
5
+ }
6
+
7
+ export function isSeekable(media: MediaInfo | null | undefined): boolean {
8
+ return Boolean(media?.canSeek) && media?.positionReported === true;
9
+ }
10
+
11
+ export function mediaDuration(media: MediaInfo | null | undefined): number {
12
+ if (!media) return 0;
13
+ return Math.max(0, Number(media.endTime) - Number(media.startTime || 0));
14
+ }
15
+
16
+ export function seekMaximum(media: MediaInfo | null | undefined): number {
17
+ if (!media) return 1;
18
+ return Math.max(1, Number(media.endTime) || 0);
19
+ }
20
+
21
+ /** Same linear projection the original `updateMediaProgress()` applied. */
22
+ export function projectedPosition(media: MediaInfo, receivedAt: number, now: number): number {
23
+ const duration = mediaDuration(media);
24
+ let position = Number(media.position) || 0;
25
+ if (isPlaying(media)) position += (now - receivedAt) / 1000;
26
+ position = duration > 0 ? Math.min(duration, Math.max(0, position)) : Math.max(0, position);
27
+ return position;
28
+ }
29
+
30
+ export function clampVolume(value: unknown): number {
31
+ return Math.max(0, Math.min(1, Number(value ?? 0.5)));
32
+ }
@@ -0,0 +1,18 @@
1
+ import type { PageKey } from './types';
2
+
3
+ export const DEFAULT_ORDER: readonly PageKey[] = ['home', 'sessions', 'music', 'performance'];
4
+
5
+ export function normalizeOrder(input: unknown): PageKey[] {
6
+ const keys = Array.isArray(input)
7
+ ? input.filter((key): key is PageKey => DEFAULT_ORDER.includes(key as PageKey))
8
+ : [];
9
+ const order = [...new Set(keys)];
10
+ for (const key of DEFAULT_ORDER) if (!order.includes(key)) order.push(key);
11
+ return order.slice(0, DEFAULT_ORDER.length);
12
+ }
13
+
14
+ export function enabledOrder(order: PageKey[], pageEnabled: Record<PageKey, boolean>): PageKey[] {
15
+ const enabled = order.filter((key) => pageEnabled[key] !== false);
16
+ if (enabled.length > 0) return enabled;
17
+ return ['home'];
18
+ }