🗑️ 刪除舊版相關檔案

This commit is contained in:
Minidoracat 2025-06-03 15:08:43 +08:00
parent a4dd076038
commit 4e1f6c8bb3
4 changed files with 0 additions and 2402 deletions

View File

@ -1,322 +0,0 @@
/**
* 前端國際化支援 - 新架構版本
* =============================
*
* 提供 Web UI 的多語系支援支援繁體中文英文簡體中文
* 新特性
* - 支援從 API 動態載入翻譯檔案
* - 巢狀翻譯鍵值支援
* - 舊格式兼容
* - 自動偵測瀏覽器語言
*/
class I18nManager {
constructor() {
this.currentLanguage = null;
this.translations = {};
this.supportedLanguages = ['zh-TW', 'en', 'zh-CN'];
this.fallbackLanguage = 'en';
this.isLoaded = false;
// 內嵌的備用翻譯(防止 API 載入失敗)
this.fallbackTranslations = this._getEmbeddedTranslations();
// 初始化語言設定
this.currentLanguage = this.detectLanguage();
}
/**
* 獲取內嵌的備用翻譯僅保留基本錯誤訊息
*/
_getEmbeddedTranslations() {
return {
'zh-TW': {
app: { title: 'Interactive Feedback MCP' },
loading: '載入中...',
error: '載入失敗',
retry: '重試'
},
'en': {
app: { title: 'Interactive Feedback MCP' },
loading: 'Loading...',
error: 'Loading failed',
retry: 'Retry'
},
'zh-CN': {
app: { title: 'Interactive Feedback MCP' },
loading: '加载中...',
error: '加载失败',
retry: '重试'
}
};
}
/**
* API 載入翻譯檔案
*/
async loadTranslations() {
try {
// 嘗試從 API 載入翻譯
const response = await fetch('/api/translations');
if (response.ok) {
const data = await response.json();
this.translations = data;
this.isLoaded = true;
console.log('[I18N] 成功從 API 載入翻譯');
return true;
}
} catch (error) {
console.warn('[I18N] 無法從 API 載入翻譯,使用內嵌翻譯:', error);
}
// 使用內嵌翻譯作為備用
this.translations = this.fallbackTranslations;
this.isLoaded = true;
console.log('[I18N] 使用內嵌翻譯');
return false;
}
/**
* 自動偵測語言
*/
detectLanguage() {
// 1. 先檢查 localStorage
const savedLang = localStorage.getItem('mcp-feedback-language');
if (savedLang && this.supportedLanguages.includes(savedLang)) {
return savedLang;
}
// 2. 檢查瀏覽器語言設定
const browserLang = navigator.language || navigator.userLanguage;
// 映射常見的語言代碼
const langMap = {
'zh-TW': 'zh-TW',
'zh-HK': 'zh-TW',
'zh-MO': 'zh-TW',
'zh-CN': 'zh-CN',
'zh-SG': 'zh-CN',
'zh': 'zh-TW', // 默認繁體中文
'en': 'en',
'en-US': 'en',
'en-GB': 'en',
'en-AU': 'en',
'en-CA': 'en'
};
if (langMap[browserLang]) {
return langMap[browserLang];
}
// 3. 檢查語言前綴
const prefix = browserLang.split('-')[0];
if (langMap[prefix]) {
return langMap[prefix];
}
// 4. 回退到默認語言
return this.fallbackLanguage;
}
/**
* 設定語言
*/
setLanguage(language) {
if (!this.supportedLanguages.includes(language)) {
console.warn(`Unsupported language: ${language}`);
return false;
}
this.currentLanguage = language;
localStorage.setItem('mcp-feedback-language', language);
// 觸發語言變更事件
document.dispatchEvent(new CustomEvent('languageChanged', {
detail: { language: language }
}));
return true;
}
/**
* 從巢狀物件中獲取值
*/
_getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : null;
}, obj);
}
/**
* 舊鍵到新鍵的映射
*/
_getLegacyMapping() {
return {
// 應用程式標題
'app_title': 'app.title',
'project_directory': 'app.projectDirectory',
'language_selector': 'languageSelector',
// 語言名稱
'lang_zh_tw': 'languageNames.zhTw',
'lang_en': 'languageNames.en',
'lang_zh_cn': 'languageNames.zhCn',
// AI 摘要區域
'ai_summary': 'aiSummary',
// 分頁標籤
'feedback_tab': 'tabs.feedback',
'command_tab': 'tabs.command',
// 回饋區域
'feedback_title': 'feedback.title',
'feedback_description': 'feedback.description',
'feedback_placeholder': 'feedback.placeholder',
// 命令區域
'command_title': 'command.title',
'command_description': 'command.description',
'command_placeholder': 'command.placeholder',
'command_output': 'command.output',
// 圖片區域
'images_title': 'images.title',
'images_select': 'images.select',
'images_paste': 'images.paste',
'images_clear': 'images.clear',
'images_status': 'images.status',
'images_status_with_size': 'images.statusWithSize',
'images_drag_hint': 'images.dragHint',
'images_delete_confirm': 'images.deleteConfirm',
'images_delete_title': 'images.deleteTitle',
'images_size_warning': 'images.sizeWarning',
'images_format_error': 'images.formatError',
// 按鈕
'btn_select_files': 'buttons.selectFiles',
'btn_paste_clipboard': 'buttons.pasteClipboard',
'btn_clear_all': 'buttons.clearAll',
'btn_run_command': 'buttons.runCommand',
'btn_submit_feedback': 'buttons.submitFeedback',
'btn_cancel': 'buttons.cancel',
// 狀態消息
'uploading': 'status.uploading',
'upload_success': 'status.uploadSuccess',
'upload_failed': 'status.uploadFailed',
'command_running': 'status.commandRunning',
'command_finished': 'status.commandFinished',
'paste_success': 'status.pasteSuccess',
'paste_failed': 'status.pasteFailed',
'paste_no_image': 'status.paste_no_image',
'paste_image_from_textarea': 'status.paste_image_from_textarea',
'invalid_file_type': 'status.invalidFileType',
'file_too_large': 'status.fileTooLarge'
};
}
/**
* 獲取翻譯文字
*/
t(key, params = {}) {
// 確保翻譯已載入
if (!this.isLoaded) {
// 如果還沒載入,先嘗試從備用翻譯獲取
this.translations = this.fallbackTranslations;
}
const currentTranslations = this.translations[this.currentLanguage] || {};
// 嘗試新格式(巢狀鍵)
let translation = this._getNestedValue(currentTranslations, key);
// 如果沒有找到,嘗試舊格式映射
if (translation === null) {
const legacyMapping = this._getLegacyMapping();
const newKey = legacyMapping[key];
if (newKey) {
translation = this._getNestedValue(currentTranslations, newKey);
}
}
// 如果還是沒有找到,嘗試回退語言
if (translation === null) {
const fallbackTranslations = this.translations[this.fallbackLanguage] || {};
translation = this._getNestedValue(fallbackTranslations, key);
if (translation === null) {
const legacyMapping = this._getLegacyMapping();
const newKey = legacyMapping[key];
if (newKey) {
translation = this._getNestedValue(fallbackTranslations, newKey);
}
}
}
// 最後回退到鍵本身
if (translation === null) {
translation = key;
}
// 替換參數
if (typeof translation === 'string') {
translation = translation.replace(/{(\w+)}/g, (match, param) => {
return params[param] !== undefined ? params[param] : match;
});
}
return translation;
}
/**
* 獲取語言顯示名稱
*/
getLanguageDisplayName(languageCode) {
const key = `languageNames.${languageCode.toLowerCase().replace('-', '')}`;
if (languageCode === 'zh-TW') {
return this.t('languageNames.zhTw');
} else if (languageCode === 'zh-CN') {
return this.t('languageNames.zhCn');
} else if (languageCode === 'en') {
return this.t('languageNames.en');
}
return this.t(key);
}
/**
* 獲取當前語言
*/
getCurrentLanguage() {
return this.currentLanguage;
}
/**
* 獲取支援的語言列表
*/
getSupportedLanguages() {
return [...this.supportedLanguages];
}
/**
* 初始化載入翻譯
*/
async init() {
await this.loadTranslations();
return this.isLoaded;
}
}
// 創建全域實例
window.i18n = new I18nManager();
// 翻譯函數的全域快捷方式
window.t = function(key, params = {}) {
return window.i18n.t(key, params);
};
// 初始化函數
window.initI18n = async function() {
await window.i18n.init();
return window.i18n.isLoaded;
};

View File

@ -1,447 +0,0 @@
/* Interactive Feedback MCP - Modern Dark Theme */
:root {
--primary-color: #007acc;
--primary-hover: #005999;
--background-color: #1e1e1e;
--surface-color: #2d2d30;
--surface-hover: #383838;
--text-primary: #cccccc;
--text-secondary: #9e9e9e;
--text-accent: #007acc;
--border-color: #464647;
--success-color: #4caf50;
--warning-color: #ff9800;
--error-color: #f44336;
--console-bg: #1a1a1a;
--input-bg: #2d2d30;
--button-bg: #0e639c;
--button-hover-bg: #1177bb;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--background-color);
color: var(--text-primary);
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
min-height: 100vh;
display: flex;
flex-direction: column;
}
h1 {
text-align: center;
color: var(--text-accent);
margin-bottom: 30px;
font-size: 2.5em;
font-weight: 300;
}
h2, h3 {
color: var(--text-primary);
margin-bottom: 15px;
}
h3 {
font-size: 1.3em;
font-weight: 500;
}
.section {
background-color: var(--surface-color);
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
border: 1px solid var(--border-color);
transition: all 0.3s ease;
}
.section:hover {
background-color: var(--surface-hover);
}
.session-info {
background: linear-gradient(135deg, var(--surface-color), var(--surface-hover));
border-left: 4px solid var(--primary-color);
}
.session-info p {
margin-bottom: 8px;
font-size: 1.1em;
}
.session-info strong {
color: var(--text-accent);
}
.toggle-btn {
width: 100%;
background-color: var(--button-bg);
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
font-size: 1.1em;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 10px;
}
.toggle-btn:hover {
background-color: var(--button-hover-bg);
transform: translateY(-1px);
}
.command-section {
animation: slideDown 0.3s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.input-group {
display: flex;
gap: 10px;
margin-bottom: 15px;
align-items: center;
}
.input-group input {
flex: 1;
background-color: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px 15px;
color: var(--text-primary);
font-size: 14px;
transition: all 0.3s ease;
}
.input-group input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(0, 122, 204, 0.1);
}
.input-group button {
background-color: var(--button-bg);
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
min-width: 80px;
}
.input-group button:hover {
background-color: var(--button-hover-bg);
transform: translateY(-1px);
}
#stop-btn {
background-color: var(--error-color);
}
#stop-btn:hover {
background-color: #d32f2f;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 20px;
padding: 10px 0;
}
.checkbox-group label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 14px;
}
.checkbox-group input[type="checkbox"] {
width: 18px;
height: 18px;
accent-color: var(--primary-color);
}
#save-config {
background-color: var(--success-color);
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
transition: all 0.3s ease;
}
#save-config:hover {
background-color: #45a049;
}
.console-section {
margin-top: 20px;
}
.console-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.console-header h4 {
margin: 0;
color: var(--text-secondary);
}
#clear-logs {
background-color: var(--warning-color);
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.3s ease;
}
#clear-logs:hover {
background-color: #f57c00;
}
.console {
background-color: var(--console-bg);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 15px;
height: 300px;
overflow-y: auto;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 13px;
line-height: 1.4;
white-space: pre-wrap;
word-wrap: break-word;
}
.console-line {
margin-bottom: 2px;
color: var(--text-primary);
}
.console::-webkit-scrollbar {
width: 8px;
}
.console::-webkit-scrollbar-track {
background: var(--surface-color);
border-radius: 4px;
}
.console::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
}
.console::-webkit-scrollbar-thumb:hover {
background: var(--text-secondary);
}
.feedback-section {
background: linear-gradient(135deg, var(--surface-color), var(--surface-hover));
border-left: 4px solid var(--success-color);
flex-grow: 1;
display: flex;
flex-direction: column;
}
.feedback-description {
background-color: var(--input-bg);
padding: 15px;
border-radius: 6px;
margin-bottom: 15px;
border-left: 3px solid var(--primary-color);
font-style: italic;
color: var(--text-secondary);
}
#feedback-input {
flex-grow: 1;
min-height: 150px;
background-color: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 15px;
color: var(--text-primary);
font-size: 14px;
font-family: inherit;
resize: vertical;
transition: all 0.3s ease;
margin-bottom: 15px;
}
#feedback-input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(0, 122, 204, 0.1);
}
#feedback-input::placeholder {
color: var(--text-secondary);
}
#submit-feedback {
background: linear-gradient(135deg, var(--success-color), #66bb6a);
color: white;
border: none;
padding: 15px 30px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 0.5px;
}
#submit-feedback:hover {
background: linear-gradient(135deg, #45a049, #4caf50);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
}
.footer {
text-align: center;
margin-top: 30px;
padding: 20px;
color: var(--text-secondary);
font-size: 13px;
border-top: 1px solid var(--border-color);
}
.footer a {
color: var(--text-accent);
text-decoration: none;
transition: color 0.3s ease;
}
.footer a:hover {
color: var(--primary-hover);
text-decoration: underline;
}
.loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1000;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid var(--border-color);
border-top: 4px solid var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading p {
color: var(--text-primary);
font-size: 18px;
font-weight: 500;
}
/* Responsive Design */
@media (max-width: 768px) {
.container {
padding: 15px;
}
h1 {
font-size: 2em;
margin-bottom: 20px;
}
.input-group {
flex-direction: column;
align-items: stretch;
}
.input-group button {
margin-top: 10px;
}
.checkbox-group {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.console {
height: 200px;
}
#feedback-input {
min-height: 120px;
}
}
/* Smooth transitions for all interactive elements */
* {
transition: color 0.3s ease, background-color 0.3s ease, border-color 0.3s ease;
}
/* Focus styles for accessibility */
button:focus,
input:focus,
textarea:focus {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
/* Custom selection colors */
::selection {
background-color: var(--primary-color);
color: white;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Feedback MCP Server</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
<h1>Interactive Feedback MCP</h1>
<div class="section">
<h2>服務器狀態</h2>
<p>🟢 MCP 服務器正在運行</p>
<p>等待來自 AI 助手的互動請求...</p>
</div>
<div class="section">
<h3>關於此服務</h3>
<p>這是一個 Model Context Protocol (MCP) 服務器,用於在 AI 輔助開發工具中提供人在回路的互動回饋功能。</p>
<p>當 AI 助手需要用戶回饋時,會自動在瀏覽器中開啟互動頁面。</p>
</div>
<div class="section">
<h3>功能特色</h3>
<ul style="color: var(--text-primary); margin-left: 20px;">
<li>🌐 Web UI 支援 SSH remote 開發</li>
<li>💻 即時命令執行和輸出顯示</li>
<li>💬 結構化回饋收集</li>
<li>⚙️ 專案特定的設定管理</li>
<li>🔄 WebSocket 即時通訊</li>
</ul>
</div>
<div class="footer">
<p>開發者: Fábio Ferreira | <a href="https://x.com/fabiomlferreira" target="_blank">X.com</a> | <a href="https://dotcursorrules.com/" target="_blank">dotcursorrules.com</a></p>
</div>
</div>
</body>
</html>