@hirohsu/user-web-feedback 2.8.2 → 2.8.9

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 (34) hide show
  1. package/README.md +953 -953
  2. package/dist/cli.cjs +35128 -22228
  3. package/dist/index.cjs +39895 -26993
  4. package/dist/static/app.js +385 -385
  5. package/dist/static/components/navbar.css +406 -406
  6. package/dist/static/components/navbar.html +49 -49
  7. package/dist/static/components/navbar.js +211 -211
  8. package/dist/static/dashboard.css +495 -495
  9. package/dist/static/dashboard.html +95 -95
  10. package/dist/static/dashboard.js +540 -540
  11. package/dist/static/favicon.svg +27 -27
  12. package/dist/static/index.html +541 -541
  13. package/dist/static/logs.html +376 -376
  14. package/dist/static/logs.js +442 -442
  15. package/dist/static/mcp-settings.html +797 -797
  16. package/dist/static/mcp-settings.js +884 -884
  17. package/dist/static/modules/app-core.js +124 -124
  18. package/dist/static/modules/conversation-panel.js +247 -247
  19. package/dist/static/modules/feedback-handler.js +1420 -1420
  20. package/dist/static/modules/image-handler.js +155 -155
  21. package/dist/static/modules/log-viewer.js +296 -296
  22. package/dist/static/modules/mcp-manager.js +474 -474
  23. package/dist/static/modules/prompt-manager.js +364 -364
  24. package/dist/static/modules/settings-manager.js +299 -299
  25. package/dist/static/modules/socket-manager.js +170 -170
  26. package/dist/static/modules/state-manager.js +352 -352
  27. package/dist/static/modules/timer-controller.js +243 -243
  28. package/dist/static/modules/ui-helpers.js +246 -246
  29. package/dist/static/settings.html +426 -417
  30. package/dist/static/settings.js +767 -705
  31. package/dist/static/style.css +2156 -2156
  32. package/dist/static/terminals.html +357 -357
  33. package/dist/static/terminals.js +321 -321
  34. package/package.json +95 -93
@@ -1,49 +1,49 @@
1
- <nav class="navbar" role="navigation" aria-label="主導覽">
2
- <div class="navbar-container">
3
- <div class="navbar-brand">
4
- <span class="navbar-logo">🎯</span>
5
- <span class="navbar-title">User Feedback</span>
6
- </div>
7
-
8
- <button class="navbar-toggle" aria-label="展開選單" aria-expanded="false">
9
- <span class="toggle-icon"></span>
10
- </button>
11
-
12
- <div class="navbar-menu">
13
- <div class="navbar-links">
14
- <a href="/dashboard" class="navbar-link" data-page="dashboard">
15
- <span class="link-icon">📊</span>
16
- <span class="link-text">Dashboard</span>
17
- </a>
18
- <a href="/" class="navbar-link" data-page="feedback">
19
- <span class="link-icon">💬</span>
20
- <span class="link-text">回覆</span>
21
- </a>
22
- <a href="/mcp-settings" class="navbar-link" data-page="mcp-settings">
23
- <span class="link-icon">🔧</span>
24
- <span class="link-text">MCP</span>
25
- </a>
26
- <a href="/logs" class="navbar-link" data-page="logs">
27
- <span class="link-icon">📋</span>
28
- <span class="link-text">日誌</span>
29
- </a>
30
- <a href="/terminals" class="navbar-link" data-page="terminals">
31
- <span class="link-icon">💻</span>
32
- <span class="link-text">終端機</span>
33
- </a>
34
- <a href="/settings" class="navbar-link" data-page="settings">
35
- <span class="link-icon">⚙️</span>
36
- <span class="link-text">設定</span>
37
- </a>
38
- </div>
39
-
40
- <div class="navbar-status">
41
- <div class="connection-status" id="navbar-connection-status">
42
- <span class="status-dot"></span>
43
- <span class="status-text">連接中...</span>
44
- </div>
45
- <span class="version-badge" id="navbar-version">v--</span>
46
- </div>
47
- </div>
48
- </div>
49
- </nav>
1
+ <nav class="navbar" role="navigation" aria-label="主導覽">
2
+ <div class="navbar-container">
3
+ <div class="navbar-brand">
4
+ <span class="navbar-logo">🎯</span>
5
+ <span class="navbar-title">User Feedback</span>
6
+ </div>
7
+
8
+ <button class="navbar-toggle" aria-label="展開選單" aria-expanded="false">
9
+ <span class="toggle-icon"></span>
10
+ </button>
11
+
12
+ <div class="navbar-menu">
13
+ <div class="navbar-links">
14
+ <a href="/dashboard" class="navbar-link" data-page="dashboard">
15
+ <span class="link-icon">📊</span>
16
+ <span class="link-text">Dashboard</span>
17
+ </a>
18
+ <a href="/" class="navbar-link" data-page="feedback">
19
+ <span class="link-icon">💬</span>
20
+ <span class="link-text">回覆</span>
21
+ </a>
22
+ <a href="/mcp-settings" class="navbar-link" data-page="mcp-settings">
23
+ <span class="link-icon">🔧</span>
24
+ <span class="link-text">MCP</span>
25
+ </a>
26
+ <a href="/logs" class="navbar-link" data-page="logs">
27
+ <span class="link-icon">📋</span>
28
+ <span class="link-text">日誌</span>
29
+ </a>
30
+ <a href="/terminals" class="navbar-link" data-page="terminals">
31
+ <span class="link-icon">💻</span>
32
+ <span class="link-text">終端機</span>
33
+ </a>
34
+ <a href="/settings" class="navbar-link" data-page="settings">
35
+ <span class="link-icon">⚙️</span>
36
+ <span class="link-text">設定</span>
37
+ </a>
38
+ </div>
39
+
40
+ <div class="navbar-status">
41
+ <div class="connection-status" id="navbar-connection-status">
42
+ <span class="status-dot"></span>
43
+ <span class="status-text">連接中...</span>
44
+ </div>
45
+ <span class="version-badge" id="navbar-version">v--</span>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </nav>
@@ -1,211 +1,211 @@
1
- /**
2
- * Unified Navigation Bar Component
3
- * 可重用的導覽列組件,注入到所有頁面
4
- */
5
-
6
- (function () {
7
- "use strict";
8
-
9
- const NAVBAR_HTML_PATH = "/components/navbar.html";
10
-
11
- class Navbar {
12
- constructor() {
13
- this.container = null;
14
- this.socket = null;
15
- this.currentPage = this.detectCurrentPage();
16
- }
17
-
18
- /**
19
- * 初始化導覽列
20
- */
21
- async init() {
22
- try {
23
- await this.loadAndInject();
24
- this.setupEventListeners();
25
- this.highlightActivePage();
26
- this.loadVersion();
27
-
28
- // 如果頁面有 Socket.IO,連接狀態同步
29
- if (window.io) {
30
- this.connectSocket();
31
- }
32
- } catch (error) {
33
- console.error("[Navbar] Initialization failed:", error);
34
- }
35
- }
36
-
37
- /**
38
- * 載入並注入 HTML
39
- */
40
- async loadAndInject() {
41
- const response = await fetch(NAVBAR_HTML_PATH);
42
- if (!response.ok) {
43
- throw new Error(`Failed to load navbar: ${response.status}`);
44
- }
45
-
46
- const html = await response.text();
47
- const tempContainer = document.createElement("div");
48
- tempContainer.innerHTML = html;
49
-
50
- const navbar = tempContainer.querySelector(".navbar");
51
- if (!navbar) {
52
- throw new Error("Navbar element not found in HTML");
53
- }
54
-
55
- // 注入到 body 的最前面
56
- document.body.insertBefore(navbar, document.body.firstChild);
57
- this.container = navbar;
58
- }
59
-
60
- /**
61
- * 偵測當前頁面
62
- */
63
- detectCurrentPage() {
64
- const path = window.location.pathname;
65
-
66
- if (path === "/" || path === "/index.html") {
67
- return "feedback";
68
- } else if (path.startsWith("/dashboard")) {
69
- return "dashboard";
70
- } else if (path.startsWith("/mcp-settings")) {
71
- return "mcp-settings";
72
- } else if (path.startsWith("/logs")) {
73
- return "logs";
74
- } else if (path.startsWith("/terminals")) {
75
- return "terminals";
76
- } else if (path.startsWith("/settings")) {
77
- return "settings";
78
- }
79
-
80
- return null;
81
- }
82
-
83
- /**
84
- * 高亮當前頁面連結
85
- */
86
- highlightActivePage() {
87
- if (!this.container || !this.currentPage) return;
88
-
89
- const links = this.container.querySelectorAll(".navbar-link");
90
- links.forEach((link) => {
91
- if (link.dataset.page === this.currentPage) {
92
- link.classList.add("active");
93
- link.setAttribute("aria-current", "page");
94
- } else {
95
- link.classList.remove("active");
96
- link.removeAttribute("aria-current");
97
- }
98
- });
99
- }
100
-
101
- /**
102
- * 設置事件監聽器
103
- */
104
- setupEventListeners() {
105
- if (!this.container) return;
106
-
107
- // 移動端選單切換
108
- const toggle = this.container.querySelector(".navbar-toggle");
109
- const menu = this.container.querySelector(".navbar-menu");
110
-
111
- if (toggle && menu) {
112
- toggle.addEventListener("click", () => {
113
- const isExpanded = menu.classList.toggle("active");
114
- toggle.setAttribute("aria-expanded", String(isExpanded));
115
- toggle.classList.toggle("active");
116
- });
117
- }
118
-
119
- // 點擊連結時關閉移動端選單
120
- const links = this.container.querySelectorAll(".navbar-link");
121
- links.forEach((link) => {
122
- link.addEventListener("click", () => {
123
- if (menu.classList.contains("active")) {
124
- menu.classList.remove("active");
125
- toggle.classList.remove("active");
126
- toggle.setAttribute("aria-expanded", "false");
127
- }
128
- });
129
- });
130
- }
131
-
132
- /**
133
- * 載入版本資訊
134
- */
135
- async loadVersion() {
136
- try {
137
- const response = await fetch("/api/version");
138
- const data = await response.json();
139
-
140
- const versionEl = this.container.querySelector("#navbar-version");
141
- if (versionEl && data.version) {
142
- versionEl.textContent = `v${data.version}`;
143
- }
144
- } catch (error) {
145
- console.warn("[Navbar] Failed to load version:", error);
146
- }
147
- }
148
-
149
- /**
150
- * 連接 Socket.IO 並同步狀態
151
- */
152
- connectSocket() {
153
- // 尋找全局的 socket 實例
154
- if (window.socket) {
155
- this.socket = window.socket;
156
- this.syncSocketStatus();
157
- return;
158
- }
159
-
160
- // 如果還沒有 socket,創建一個用於狀態監聽
161
- if (window.io) {
162
- this.socket = io();
163
- this.syncSocketStatus();
164
- }
165
- }
166
-
167
- /**
168
- * 同步 Socket.IO 連接狀態
169
- */
170
- syncSocketStatus() {
171
- if (!this.socket || !this.container) return;
172
-
173
- const statusEl = this.container.querySelector(
174
- "#navbar-connection-status"
175
- );
176
- if (!statusEl) return;
177
-
178
- // 更新狀態顯示
179
- const updateStatus = (connected) => {
180
- statusEl.classList.toggle("connected", connected);
181
- statusEl.classList.toggle("disconnected", !connected);
182
-
183
- const textEl = statusEl.querySelector(".status-text");
184
- if (textEl) {
185
- textEl.textContent = connected ? "已連接" : "已斷開";
186
- }
187
- };
188
-
189
- // 監聽連接事件
190
- this.socket.on("connect", () => updateStatus(true));
191
- this.socket.on("disconnect", () => updateStatus(false));
192
-
193
- // 初始狀態
194
- updateStatus(this.socket.connected);
195
- }
196
- }
197
-
198
- // 頁面載入時自動初始化
199
- if (document.readyState === "loading") {
200
- document.addEventListener("DOMContentLoaded", () => {
201
- const navbar = new Navbar();
202
- navbar.init();
203
- });
204
- } else {
205
- const navbar = new Navbar();
206
- navbar.init();
207
- }
208
-
209
- // 將 Navbar 暴露為全局對象(可選)
210
- window.Navbar = Navbar;
211
- })();
1
+ /**
2
+ * Unified Navigation Bar Component
3
+ * 可重用的導覽列組件,注入到所有頁面
4
+ */
5
+
6
+ (function () {
7
+ "use strict";
8
+
9
+ const NAVBAR_HTML_PATH = "/components/navbar.html";
10
+
11
+ class Navbar {
12
+ constructor() {
13
+ this.container = null;
14
+ this.socket = null;
15
+ this.currentPage = this.detectCurrentPage();
16
+ }
17
+
18
+ /**
19
+ * 初始化導覽列
20
+ */
21
+ async init() {
22
+ try {
23
+ await this.loadAndInject();
24
+ this.setupEventListeners();
25
+ this.highlightActivePage();
26
+ this.loadVersion();
27
+
28
+ // 如果頁面有 Socket.IO,連接狀態同步
29
+ if (window.io) {
30
+ this.connectSocket();
31
+ }
32
+ } catch (error) {
33
+ console.error("[Navbar] Initialization failed:", error);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * 載入並注入 HTML
39
+ */
40
+ async loadAndInject() {
41
+ const response = await fetch(NAVBAR_HTML_PATH);
42
+ if (!response.ok) {
43
+ throw new Error(`Failed to load navbar: ${response.status}`);
44
+ }
45
+
46
+ const html = await response.text();
47
+ const tempContainer = document.createElement("div");
48
+ tempContainer.innerHTML = html;
49
+
50
+ const navbar = tempContainer.querySelector(".navbar");
51
+ if (!navbar) {
52
+ throw new Error("Navbar element not found in HTML");
53
+ }
54
+
55
+ // 注入到 body 的最前面
56
+ document.body.insertBefore(navbar, document.body.firstChild);
57
+ this.container = navbar;
58
+ }
59
+
60
+ /**
61
+ * 偵測當前頁面
62
+ */
63
+ detectCurrentPage() {
64
+ const path = window.location.pathname;
65
+
66
+ if (path === "/" || path === "/index.html") {
67
+ return "feedback";
68
+ } else if (path.startsWith("/dashboard")) {
69
+ return "dashboard";
70
+ } else if (path.startsWith("/mcp-settings")) {
71
+ return "mcp-settings";
72
+ } else if (path.startsWith("/logs")) {
73
+ return "logs";
74
+ } else if (path.startsWith("/terminals")) {
75
+ return "terminals";
76
+ } else if (path.startsWith("/settings")) {
77
+ return "settings";
78
+ }
79
+
80
+ return null;
81
+ }
82
+
83
+ /**
84
+ * 高亮當前頁面連結
85
+ */
86
+ highlightActivePage() {
87
+ if (!this.container || !this.currentPage) return;
88
+
89
+ const links = this.container.querySelectorAll(".navbar-link");
90
+ links.forEach((link) => {
91
+ if (link.dataset.page === this.currentPage) {
92
+ link.classList.add("active");
93
+ link.setAttribute("aria-current", "page");
94
+ } else {
95
+ link.classList.remove("active");
96
+ link.removeAttribute("aria-current");
97
+ }
98
+ });
99
+ }
100
+
101
+ /**
102
+ * 設置事件監聽器
103
+ */
104
+ setupEventListeners() {
105
+ if (!this.container) return;
106
+
107
+ // 移動端選單切換
108
+ const toggle = this.container.querySelector(".navbar-toggle");
109
+ const menu = this.container.querySelector(".navbar-menu");
110
+
111
+ if (toggle && menu) {
112
+ toggle.addEventListener("click", () => {
113
+ const isExpanded = menu.classList.toggle("active");
114
+ toggle.setAttribute("aria-expanded", String(isExpanded));
115
+ toggle.classList.toggle("active");
116
+ });
117
+ }
118
+
119
+ // 點擊連結時關閉移動端選單
120
+ const links = this.container.querySelectorAll(".navbar-link");
121
+ links.forEach((link) => {
122
+ link.addEventListener("click", () => {
123
+ if (menu.classList.contains("active")) {
124
+ menu.classList.remove("active");
125
+ toggle.classList.remove("active");
126
+ toggle.setAttribute("aria-expanded", "false");
127
+ }
128
+ });
129
+ });
130
+ }
131
+
132
+ /**
133
+ * 載入版本資訊
134
+ */
135
+ async loadVersion() {
136
+ try {
137
+ const response = await fetch("/api/version");
138
+ const data = await response.json();
139
+
140
+ const versionEl = this.container.querySelector("#navbar-version");
141
+ if (versionEl && data.version) {
142
+ versionEl.textContent = `v${data.version}`;
143
+ }
144
+ } catch (error) {
145
+ console.warn("[Navbar] Failed to load version:", error);
146
+ }
147
+ }
148
+
149
+ /**
150
+ * 連接 Socket.IO 並同步狀態
151
+ */
152
+ connectSocket() {
153
+ // 尋找全局的 socket 實例
154
+ if (window.socket) {
155
+ this.socket = window.socket;
156
+ this.syncSocketStatus();
157
+ return;
158
+ }
159
+
160
+ // 如果還沒有 socket,創建一個用於狀態監聽
161
+ if (window.io) {
162
+ this.socket = io();
163
+ this.syncSocketStatus();
164
+ }
165
+ }
166
+
167
+ /**
168
+ * 同步 Socket.IO 連接狀態
169
+ */
170
+ syncSocketStatus() {
171
+ if (!this.socket || !this.container) return;
172
+
173
+ const statusEl = this.container.querySelector(
174
+ "#navbar-connection-status"
175
+ );
176
+ if (!statusEl) return;
177
+
178
+ // 更新狀態顯示
179
+ const updateStatus = (connected) => {
180
+ statusEl.classList.toggle("connected", connected);
181
+ statusEl.classList.toggle("disconnected", !connected);
182
+
183
+ const textEl = statusEl.querySelector(".status-text");
184
+ if (textEl) {
185
+ textEl.textContent = connected ? "已連接" : "已斷開";
186
+ }
187
+ };
188
+
189
+ // 監聽連接事件
190
+ this.socket.on("connect", () => updateStatus(true));
191
+ this.socket.on("disconnect", () => updateStatus(false));
192
+
193
+ // 初始狀態
194
+ updateStatus(this.socket.connected);
195
+ }
196
+ }
197
+
198
+ // 頁面載入時自動初始化
199
+ if (document.readyState === "loading") {
200
+ document.addEventListener("DOMContentLoaded", () => {
201
+ const navbar = new Navbar();
202
+ navbar.init();
203
+ });
204
+ } else {
205
+ const navbar = new Navbar();
206
+ navbar.init();
207
+ }
208
+
209
+ // 將 Navbar 暴露為全局對象(可選)
210
+ window.Navbar = Navbar;
211
+ })();