duaer-spec 0.27.2 → 0.27.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 (55) hide show
  1. package/.duaer/active-job.json +3 -3
  2. package/.duaer/specs/281-release-0272/delivery.json +8 -0
  3. package/.duaer/specs/281-release-0272/tasks.md +1 -1
  4. package/.duaer/specs/282-dispatch-confirm-lock/delivery.json +12 -0
  5. package/.duaer/specs/282-dispatch-confirm-lock/spec.md +26 -0
  6. package/.duaer/specs/282-dispatch-confirm-lock/tasks.md +5 -0
  7. package/.duaer/specs/283-desk-theme-compact/delivery.json +12 -0
  8. package/.duaer/specs/283-desk-theme-compact/spec.md +26 -0
  9. package/.duaer/specs/283-desk-theme-compact/tasks.md +5 -0
  10. package/.duaer/specs/284-dispatch-graph-regen/delivery.json +12 -0
  11. package/.duaer/specs/284-dispatch-graph-regen/spec.md +33 -0
  12. package/.duaer/specs/284-dispatch-graph-regen/tasks.md +5 -0
  13. package/.duaer/specs/285-desk-light-compact/delivery.json +11 -0
  14. package/.duaer/specs/285-desk-light-compact/spec.md +13 -0
  15. package/.duaer/specs/285-desk-light-compact/tasks.md +5 -0
  16. package/.duaer/specs/286-modules-bug-theme/delivery.json +10 -0
  17. package/.duaer/specs/286-modules-bug-theme/spec.md +26 -0
  18. package/.duaer/specs/286-modules-bug-theme/tasks.md +5 -0
  19. package/.duaer/specs/287-progress-modules-ux/delivery.json +10 -0
  20. package/.duaer/specs/287-progress-modules-ux/spec.md +31 -0
  21. package/.duaer/specs/287-progress-modules-ux/tasks.md +5 -0
  22. package/.duaer/specs/288-settings-close-compact/delivery.json +10 -0
  23. package/.duaer/specs/288-settings-close-compact/spec.md +17 -0
  24. package/.duaer/specs/288-settings-close-compact/tasks.md +5 -0
  25. package/.duaer/specs/289-settings-close-click/delivery.json +10 -0
  26. package/.duaer/specs/289-settings-close-click/spec.md +16 -0
  27. package/.duaer/specs/289-settings-close-click/tasks.md +4 -0
  28. package/.duaer/specs/290-remove-quicknav/delivery.json +10 -0
  29. package/.duaer/specs/290-remove-quicknav/spec.md +11 -0
  30. package/.duaer/specs/290-remove-quicknav/tasks.md +4 -0
  31. package/.duaer/specs/291-release-0273/spec.md +12 -0
  32. package/.duaer/specs/291-release-0273/tasks.md +4 -0
  33. package/CHANGELOG.md +56 -0
  34. package/bin/duaer-live.mjs +11 -20
  35. package/bin/live-modules.mjs +23 -3
  36. package/docs/agent/e2e-test-plan.md +16 -5
  37. package/docs/agent/live-desk.md +24 -11
  38. package/package.json +1 -1
  39. package/web/live-dev/app.js +329 -167
  40. package/web/live-dev/dispatch-center.html +29 -1
  41. package/web/live-dev/dispatch-center.js +25 -1
  42. package/web/live-dev/i18n-de.js +5 -0
  43. package/web/live-dev/i18n-es.js +5 -0
  44. package/web/live-dev/i18n-fr.js +5 -0
  45. package/web/live-dev/i18n-ja.js +5 -0
  46. package/web/live-dev/i18n-ko.js +5 -0
  47. package/web/live-dev/i18n-pt-BR.js +5 -0
  48. package/web/live-dev/i18n-ru.js +5 -0
  49. package/web/live-dev/i18n-vi.js +5 -0
  50. package/web/live-dev/i18n-zh-TW.js +5 -0
  51. package/web/live-dev/i18n.js +10 -0
  52. package/web/live-dev/index.html +31 -32
  53. package/web/live-dev/styles.css +296 -315
  54. package/web/live-dev/task-graph.mjs +4 -1
  55. package/web/live-dev/theme.mjs +63 -0
@@ -4,13 +4,28 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>调度中心</title>
7
+ <script>
8
+ (function () {
9
+ try {
10
+ var t = localStorage.getItem("duaer.live.theme");
11
+ if (t !== "light" && t !== "dark") {
12
+ t = window.matchMedia("(prefers-color-scheme: light)").matches
13
+ ? "light"
14
+ : "dark";
15
+ }
16
+ document.documentElement.setAttribute("data-theme", t);
17
+ } catch (e) {
18
+ document.documentElement.setAttribute("data-theme", "dark");
19
+ }
20
+ })();
21
+ </script>
7
22
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
23
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
24
  <link
10
25
  href="https://fonts.googleapis.com/css2?family=Chivo+Mono:wght@400;700&family=Outfit:wght@500;700&display=swap"
11
26
  rel="stylesheet"
12
27
  />
13
- <link rel="stylesheet" href="/styles.css?v=preview-opaque-1" />
28
+ <link rel="stylesheet" href="/styles.css?v=remove-quicknav-1" />
14
29
  </head>
15
30
  <body class="dispatch-center-page">
16
31
  <header class="top">
@@ -72,6 +87,19 @@
72
87
  <option value="vi">Tiếng Việt</option>
73
88
  </select>
74
89
  </label>
90
+ <button
91
+ type="button"
92
+ class="top-btn"
93
+ id="themeToggle"
94
+ data-theme="dark"
95
+ aria-pressed="true"
96
+ data-i18n-aria="theme.aria"
97
+ aria-label="切换浅色或深色"
98
+ >
99
+ <span class="theme-icon theme-icon-moon" aria-hidden="true">☾</span>
100
+ <span class="theme-icon theme-icon-sun" aria-hidden="true">☀</span>
101
+ <span id="themeToggleLabel" data-i18n="theme.toLight">浅色</span>
102
+ </button>
75
103
  <a
76
104
  id="githubStars"
77
105
  class="top-btn github-btn"
@@ -4,7 +4,8 @@
4
4
  * Same top nav as the console; project / employee / settings open on `/`.
5
5
  * Graph rebuilds from live job progress so node status stays current.
6
6
  */
7
- import { t, getLocale, initI18n, onLocaleChange, setLocale } from "./i18n.js";
7
+ import { t, getLocale, initI18n, onLocaleChange, setLocale, applyDomI18n } from "./i18n.js";
8
+ import { getTheme, initTheme, toggleTheme } from "./theme.mjs";
8
9
  import {
9
10
  mountArchitectureDiagram,
10
11
  clearArchitectureMount,
@@ -126,6 +127,20 @@ async function refreshGithubStars() {
126
127
  }
127
128
  }
128
129
 
130
+ function syncThemeToggleUi() {
131
+ const btn = document.getElementById("themeToggle");
132
+ const label = document.getElementById("themeToggleLabel");
133
+ const theme = getTheme();
134
+ if (btn) {
135
+ btn.dataset.theme = theme;
136
+ btn.setAttribute("aria-pressed", theme === "dark" ? "true" : "false");
137
+ btn.setAttribute("aria-label", t("theme.aria"));
138
+ }
139
+ if (label) {
140
+ label.textContent = theme === "dark" ? t("theme.toLight") : t("theme.toDark");
141
+ }
142
+ }
143
+
129
144
  function wireTopNav() {
130
145
  projectToggle?.addEventListener("click", () => {
131
146
  goDesk("projects");
@@ -142,6 +157,11 @@ function wireTopNav() {
142
157
  setLocale(langSelect.value);
143
158
  });
144
159
  }
160
+ const themeToggle = document.getElementById("themeToggle");
161
+ themeToggle?.addEventListener("click", () => {
162
+ toggleTheme();
163
+ syncThemeToggleUi();
164
+ });
145
165
  viewGraphBtn?.addEventListener("click", () => setViewMode("graph"));
146
166
  viewArchBtn?.addEventListener("click", () => setViewMode("architecture"));
147
167
  void refreshGithubStars();
@@ -434,11 +454,15 @@ async function load() {
434
454
  }
435
455
 
436
456
  initI18n();
457
+ initTheme();
458
+ applyDomI18n();
459
+ syncThemeToggleUi();
437
460
  wireTopNav();
438
461
  onLocaleChange(() => {
439
462
  if (langSelect) langSelect.value = getLocale();
440
463
  if (viewGraphBtn) viewGraphBtn.textContent = t("dispatch.viewGraph");
441
464
  if (viewArchBtn) viewArchBtn.textContent = t("dispatch.viewArchitecture");
465
+ syncThemeToggleUi();
442
466
  renderRail();
443
467
  void renderStage(currentPath());
444
468
  });
@@ -7,6 +7,9 @@ export const de = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "Normen → prüfbare Abnahme → Dispatch → zufriedenstellende Vorschau → Überarbeitung",
9
9
  "lang.label": "Sprache",
10
+ "theme.toLight": "Hell",
11
+ "theme.toDark": "Dunkel",
12
+ "theme.aria": "Hell-/Dunkelmodus umschalten",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "GitHub-Projekt (Repo öffnen, Live-Sternzahl)",
12
15
  "history.toggle": "Projekte",
@@ -285,6 +288,8 @@ export const de = {
285
288
  "dispatch.decomposeEmpty": "Noch keine Aufgaben",
286
289
  "dispatch.parallelChip": "Parallel",
287
290
  "dispatch.confirmWorkersGraph": "Anzahl bestätigen und Graph erzeugen",
291
+ "dispatch.regenWorkersGraph": "Erneut bestätigen und Graph erzeugen",
292
+ "dispatch.confirmWorkersLocked": "Bestätigt — Graph bereit",
288
293
  "dispatch.graphBuilding": "Graph wird erzeugt…",
289
294
  "dispatch.graphBuildFail": "Graph konnte nicht erzeugt werden",
290
295
  "dispatch.graphBuildFailDetail": "Graph fehlgeschlagen: {msg}",
@@ -7,6 +7,9 @@ export const es = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "Normas → aceptación verificable → despacho → vista previa satisfactoria → revisar",
9
9
  "lang.label": "Idioma",
10
+ "theme.toLight": "Claro",
11
+ "theme.toDark": "Oscuro",
12
+ "theme.aria": "Cambiar tema claro u oscuro",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "Proyecto en GitHub (abrir repositorio, contador de estrellas en vivo)",
12
15
  "history.toggle": "Proyectos",
@@ -285,6 +288,8 @@ export const es = {
285
288
  "dispatch.decomposeEmpty": "Aún no hay tareas",
286
289
  "dispatch.parallelChip": "Paralelo",
287
290
  "dispatch.confirmWorkersGraph": "Confirmar número y generar grafo",
291
+ "dispatch.regenWorkersGraph": "Reconfirmar y regenerar el grafo",
292
+ "dispatch.confirmWorkersLocked": "Confirmado — grafo listo",
288
293
  "dispatch.graphBuilding": "Generando el grafo…",
289
294
  "dispatch.graphBuildFail": "Error al generar el grafo",
290
295
  "dispatch.graphBuildFailDetail": "Error al generar el grafo: {msg}",
@@ -7,6 +7,9 @@ export const fr = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "Normes → acceptation vérifiable → dispatch → aperçu satisfaisant → révision",
9
9
  "lang.label": "Langue",
10
+ "theme.toLight": "Clair",
11
+ "theme.toDark": "Sombre",
12
+ "theme.aria": "Basculer clair / sombre",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "Projet GitHub (ouvrir le dépôt, nombre d’étoiles en direct)",
12
15
  "history.toggle": "Projets",
@@ -285,6 +288,8 @@ export const fr = {
285
288
  "dispatch.decomposeEmpty": "Pas encore de tâches",
286
289
  "dispatch.parallelChip": "Parallèle",
287
290
  "dispatch.confirmWorkersGraph": "Confirmer le nombre et générer le graphe",
291
+ "dispatch.regenWorkersGraph": "Reconfirmer et régénérer le graphe",
292
+ "dispatch.confirmWorkersLocked": "Confirmé — graphe prêt",
288
293
  "dispatch.graphBuilding": "Génération du graphe…",
289
294
  "dispatch.graphBuildFail": "Échec de génération du graphe",
290
295
  "dispatch.graphBuildFailDetail": "Échec de génération du graphe : {msg}",
@@ -7,6 +7,9 @@ export const ja = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "規範 → 検証可能な受入 → 派遣 → 満足できるプレビュー → 改訂",
9
9
  "lang.label": "言語",
10
+ "theme.toLight": "ライト",
11
+ "theme.toDark": "ダーク",
12
+ "theme.aria": "ライト / ダーク切替",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "GitHub プロジェクト(リポジトリを開く、スター数を表示)",
12
15
  "history.toggle": "プロジェクト",
@@ -285,6 +288,8 @@ export const ja = {
285
288
  "dispatch.decomposeEmpty": "まだタスクがありません",
286
289
  "dispatch.parallelChip": "並列可",
287
290
  "dispatch.confirmWorkersGraph": "人数を確定して派工図を生成",
291
+ "dispatch.regenWorkersGraph": "人数を再確定して派工図を生成",
292
+ "dispatch.confirmWorkersLocked": "確定済み — 派工図を生成済み",
288
293
  "dispatch.graphBuilding": "派工図を生成中…",
289
294
  "dispatch.graphBuildFail": "派工図の生成に失敗しました",
290
295
  "dispatch.graphBuildFailDetail": "派工図の生成に失敗しました:{msg}",
@@ -7,6 +7,9 @@ export const ko = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "규범 → 검증 가능한 수락 → 파견 → 만족스러운 미리보기 → 개정",
9
9
  "lang.label": "언어",
10
+ "theme.toLight": "라이트",
11
+ "theme.toDark": "다크",
12
+ "theme.aria": "라이트/다크 전환",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "GitHub 프로젝트(저장소 열기, 별표 수 표시)",
12
15
  "history.toggle": "프로젝트",
@@ -285,6 +288,8 @@ export const ko = {
285
288
  "dispatch.decomposeEmpty": "아직 작업 없음",
286
289
  "dispatch.parallelChip": "병렬",
287
290
  "dispatch.confirmWorkersGraph": "인원 확정 후 배정 그래프 생성",
291
+ "dispatch.regenWorkersGraph": "인원 재확정 후 배정 그래프 생성",
292
+ "dispatch.confirmWorkersLocked": "확정됨 — 배정 그래프 준비됨",
288
293
  "dispatch.graphBuilding": "배정 그래프 생성 중…",
289
294
  "dispatch.graphBuildFail": "배정 그래프 생성 실패",
290
295
  "dispatch.graphBuildFailDetail": "배정 그래프 생성 실패: {msg}",
@@ -7,6 +7,9 @@ export const ptBR = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "Normas → aceitação verificável → despacho → prévia satisfatória → revisar",
9
9
  "lang.label": "Idioma",
10
+ "theme.toLight": "Claro",
11
+ "theme.toDark": "Escuro",
12
+ "theme.aria": "Alternar tema claro ou escuro",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "Projeto no GitHub (abrir repositório, contagem de estrelas ao vivo)",
12
15
  "history.toggle": "Projetos",
@@ -285,6 +288,8 @@ export const ptBR = {
285
288
  "dispatch.decomposeEmpty": "Ainda sem tarefas",
286
289
  "dispatch.parallelChip": "Paralelo",
287
290
  "dispatch.confirmWorkersGraph": "Confirmar quantidade e gerar grafo",
291
+ "dispatch.regenWorkersGraph": "Reconfirmar e regenerar o grafo",
292
+ "dispatch.confirmWorkersLocked": "Confirmado — grafo pronto",
288
293
  "dispatch.graphBuilding": "Gerando o grafo…",
289
294
  "dispatch.graphBuildFail": "Falha ao gerar o grafo",
290
295
  "dispatch.graphBuildFailDetail": "Falha ao gerar o grafo: {msg}",
@@ -7,6 +7,9 @@ export const ru = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "Нормы → проверяемая приёмка → назначение → удовлетворительный превью → доработка",
9
9
  "lang.label": "Язык",
10
+ "theme.toLight": "Светлая",
11
+ "theme.toDark": "Тёмная",
12
+ "theme.aria": "Переключить светлую или тёмную тему",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "Проект GitHub (открыть репозиторий, число звёзд)",
12
15
  "history.toggle": "Проекты",
@@ -285,6 +288,8 @@ export const ru = {
285
288
  "dispatch.decomposeEmpty": "Задач ещё нет",
286
289
  "dispatch.parallelChip": "Параллельно",
287
290
  "dispatch.confirmWorkersGraph": "Подтвердить число и построить граф",
291
+ "dispatch.regenWorkersGraph": "Подтвердить снова и перестроить граф",
292
+ "dispatch.confirmWorkersLocked": "Подтверждено — граф готов",
288
293
  "dispatch.graphBuilding": "Строим граф…",
289
294
  "dispatch.graphBuildFail": "Не удалось построить граф",
290
295
  "dispatch.graphBuildFailDetail": "Не удалось построить граф: {msg}",
@@ -7,6 +7,9 @@ export const vi = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "Chuẩn mực → nghiệm thu kiểm chứng được → giao việc → bản xem trước đạt → chỉnh sửa",
9
9
  "lang.label": "Ngôn ngữ",
10
+ "theme.toLight": "Sáng",
11
+ "theme.toDark": "Tối",
12
+ "theme.aria": "Chuyển sáng / tối",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "Dự án GitHub (mở repo, số sao trực tiếp)",
12
15
  "history.toggle": "Dự án",
@@ -285,6 +288,8 @@ export const vi = {
285
288
  "dispatch.decomposeEmpty": "Chưa có nhiệm vụ",
286
289
  "dispatch.parallelChip": "Song song",
287
290
  "dispatch.confirmWorkersGraph": "Xác nhận số lượng và tạo đồ thị",
291
+ "dispatch.regenWorkersGraph": "Xác nhận lại và tạo lại đồ thị",
292
+ "dispatch.confirmWorkersLocked": "Đã xác nhận — đồ thị sẵn sàng",
288
293
  "dispatch.graphBuilding": "Đang tạo đồ thị…",
289
294
  "dispatch.graphBuildFail": "Tạo đồ thị thất bại",
290
295
  "dispatch.graphBuildFailDetail": "Tạo đồ thị thất bại: {msg}",
@@ -7,6 +7,9 @@ export const zhTW = {
7
7
  "header.brandFde": "FDE",
8
8
  "header.tag": "規範 → 可檢查驗收 → 派工 → 滿意預覽 → 改版",
9
9
  "lang.label": "語言",
10
+ "theme.toLight": "淺色",
11
+ "theme.toDark": "深色",
12
+ "theme.aria": "切換淺色或深色",
10
13
  "github.label": "GitHub",
11
14
  "github.aria": "GitHub 專案(開啟倉庫,顯示星標數)",
12
15
  "history.toggle": "專案",
@@ -285,6 +288,8 @@ export const zhTW = {
285
288
  "dispatch.decomposeEmpty": "尚未拆解任務",
286
289
  "dispatch.parallelChip": "可並行",
287
290
  "dispatch.confirmWorkersGraph": "確認人數並產生派工圖",
291
+ "dispatch.regenWorkersGraph": "重新確認並產生派工圖",
292
+ "dispatch.confirmWorkersLocked": "已確認並產生派工圖",
288
293
  "dispatch.graphBuilding": "正在產生派工圖…",
289
294
  "dispatch.graphBuildFail": "派工圖產生失敗",
290
295
  "dispatch.graphBuildFailDetail": "派工圖產生失敗:{msg}",
@@ -37,6 +37,9 @@ const zhCN = {
37
37
  "header.brandFde": "FDE",
38
38
  "header.tag": "规范需求 → 可检查验收 → 派工 → 满意成品 → 可继续改进",
39
39
  "lang.label": "语言",
40
+ "theme.toLight": "浅色",
41
+ "theme.toDark": "深色",
42
+ "theme.aria": "切换浅色或深色",
40
43
  "github.label": "GitHub",
41
44
  "github.aria": "GitHub 项目(打开仓库,显示星标数)",
42
45
  "history.toggle": "项目",
@@ -332,6 +335,8 @@ const zhCN = {
332
335
  "dispatch.decomposeEmpty": "尚未拆解任务",
333
336
  "dispatch.parallelChip": "可并行",
334
337
  "dispatch.confirmWorkersGraph": "确认人数并生成派工图",
338
+ "dispatch.regenWorkersGraph": "重新确认并生成派工图",
339
+ "dispatch.confirmWorkersLocked": "已确认并生成派工图",
335
340
  "dispatch.graphBuilding": "正在生成派工图…",
336
341
  "dispatch.graphBuildFail": "派工图生成失败",
337
342
  "dispatch.graphBuildFailDetail": "派工图生成失败:{msg}",
@@ -680,6 +685,9 @@ const en = {
680
685
  "header.brandFde": "FDE",
681
686
  "header.tag": "Norms → checkable acceptance → dispatch → satisfactory preview → revise",
682
687
  "lang.label": "Language",
688
+ "theme.toLight": "Light",
689
+ "theme.toDark": "Dark",
690
+ "theme.aria": "Switch light or dark theme",
683
691
  "github.label": "GitHub",
684
692
  "github.aria": "GitHub project (open repo, live star count)",
685
693
  "history.toggle": "Projects",
@@ -983,6 +991,8 @@ const en = {
983
991
  "dispatch.decomposeEmpty": "No tasks yet",
984
992
  "dispatch.parallelChip": "Parallel",
985
993
  "dispatch.confirmWorkersGraph": "Confirm count and build dispatch graph",
994
+ "dispatch.regenWorkersGraph": "Reconfirm and rebuild dispatch graph",
995
+ "dispatch.confirmWorkersLocked": "Confirmed — dispatch graph ready",
986
996
  "dispatch.graphBuilding": "Building dispatch graph…",
987
997
  "dispatch.graphBuildFail": "Failed to build dispatch graph",
988
998
  "dispatch.graphBuildFailDetail": "Dispatch graph failed: {msg}",
@@ -4,13 +4,28 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Duaer-spec FDE</title>
7
+ <script>
8
+ (function () {
9
+ try {
10
+ var t = localStorage.getItem("duaer.live.theme");
11
+ if (t !== "light" && t !== "dark") {
12
+ t = window.matchMedia("(prefers-color-scheme: light)").matches
13
+ ? "light"
14
+ : "dark";
15
+ }
16
+ document.documentElement.setAttribute("data-theme", t);
17
+ } catch (e) {
18
+ document.documentElement.setAttribute("data-theme", "dark");
19
+ }
20
+ })();
21
+ </script>
7
22
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
23
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
24
  <link
10
25
  href="https://fonts.googleapis.com/css2?family=Chivo+Mono:wght@400;700&family=Outfit:wght@500;700&display=swap"
11
26
  rel="stylesheet"
12
27
  />
13
- <link rel="stylesheet" href="/styles.css?v=quicknav-visible-1" />
28
+ <link rel="stylesheet" href="/styles.css?v=remove-quicknav-1" />
14
29
  </head>
15
30
  <body>
16
31
  <div class="shell">
@@ -74,6 +89,19 @@
74
89
  <option value="vi">Tiếng Việt</option>
75
90
  </select>
76
91
  </label>
92
+ <button
93
+ type="button"
94
+ class="top-btn"
95
+ id="themeToggle"
96
+ data-theme="dark"
97
+ aria-pressed="true"
98
+ data-i18n-aria="theme.aria"
99
+ aria-label="切换浅色或深色"
100
+ >
101
+ <span class="theme-icon theme-icon-moon" aria-hidden="true">☾</span>
102
+ <span class="theme-icon theme-icon-sun" aria-hidden="true">☀</span>
103
+ <span id="themeToggleLabel" data-i18n="theme.toLight">浅色</span>
104
+ </button>
77
105
  <a
78
106
  id="githubStars"
79
107
  class="top-btn github-btn"
@@ -95,35 +123,6 @@
95
123
 
96
124
  <main id="desk" class="layout" hidden>
97
125
  <section class="panel chat-panel" data-i18n-aria="chat.aria" aria-label="对话">
98
- <div class="chat-quicknav" id="chatQuickNavWrap">
99
- <button
100
- type="button"
101
- class="chat-quicknav-btn"
102
- id="chatQuickNav"
103
- aria-expanded="false"
104
- aria-haspopup="true"
105
- aria-controls="chatQuickNavMenu"
106
- data-i18n="chat.quickNav"
107
- data-i18n-title="chat.quickNavHint"
108
- title="快速导航"
109
- >
110
- 导航
111
- </button>
112
- <div id="chatQuickNavMenu" class="chat-quicknav-menu" hidden role="menu">
113
- <button type="button" role="menuitem" data-nav="chat" data-i18n="chat.navChat">
114
- 对话底部
115
- </button>
116
- <button type="button" role="menuitem" data-nav="card" data-i18n="chat.navCard">
117
- 确认卡
118
- </button>
119
- <button type="button" role="menuitem" data-nav="result" data-i18n="chat.navResult">
120
- 结果
121
- </button>
122
- <button type="button" role="menuitem" data-nav="progress" data-i18n="chat.navProgress">
123
- 进度
124
- </button>
125
- </div>
126
- </div>
127
126
  <div id="log" class="log">
128
127
  <div id="chatEmpty" class="chat-empty">
129
128
  <ol class="chat-empty-steps" data-i18n-aria="chat.emptyStepsAria" aria-label="怎么用">
@@ -580,7 +579,7 @@
580
579
  <p class="mark" data-i18n="setup.mark">Duaer-spec FDE · model</p>
581
580
  <h2 class="history-title" data-i18n="setup.title">配置模型</h2>
582
581
  </div>
583
- <button type="button" class="btn history-close" id="settingsClose" data-i18n="setup.close" hidden>
582
+ <button type="button" class="btn history-close" id="settingsClose" data-i18n="setup.close">
584
583
  关闭
585
584
  </button>
586
585
  </div>
@@ -776,6 +775,6 @@
776
775
  </div>
777
776
  </div>
778
777
 
779
- <script type="module" src="/app.js?v=perf-budget-1"></script>
778
+ <script type="module" src="/app.js?v=remove-quicknav-1"></script>
780
779
  </body>
781
780
  </html>