diff --git a/package-lock.json b/package-lock.json index b3d9d29..e862980 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,8 @@ "concurrently": "^8.2.2", "electron": "^28.0.0", "electron-builder": "^24.13.3", + "less": "^4.6.4", + "less-loader": "^12.3.2", "vite": "^8.0.8", "vue": "^3.4.0" } @@ -2080,6 +2082,22 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2717,6 +2735,20 @@ "dev": true, "license": "MIT" }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -3392,6 +3424,20 @@ ], "license": "BSD-3-Clause" }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3434,6 +3480,19 @@ "node": ">=8" } }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3621,6 +3680,73 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/less": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz", + "integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^3.0.5", + "parse-node-version": "^1.0.1" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.3.2.tgz", + "integrity": "sha512-uLV5c702ff2jBvO7qewpkLRzkh/I9QW07ur2NKkv8TVTrtX2lrKjEbEU/LLXAn7cgpCIBbkfyUm4qYXCQs5/+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -3961,6 +4087,32 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -4129,6 +4281,24 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/needle": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.5.0.tgz", + "integrity": "sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, "node_modules/node-addon-api": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", @@ -4199,6 +4369,16 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -4269,6 +4449,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/plist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", @@ -4344,6 +4535,14 @@ "node": ">=10" } }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/pump": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", diff --git a/package.json b/package.json index b6b3fab..8166142 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,8 @@ "concurrently": "^8.2.2", "electron": "^28.0.0", "electron-builder": "^24.13.3", + "less": "^4.6.4", + "less-loader": "^12.3.2", "vite": "^8.0.8", "vue": "^3.4.0" }, diff --git a/src/App.vue b/src/App.vue index 6ca3a6e..fe7bfbf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,400 +1,65 @@ + - diff --git a/src/components/ApiProfileDialog.vue b/src/components/ApiProfileDialog.vue new file mode 100644 index 0000000..5a9f354 --- /dev/null +++ b/src/components/ApiProfileDialog.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/src/components/Footer.vue b/src/components/Footer.vue new file mode 100644 index 0000000..e984dce --- /dev/null +++ b/src/components/Footer.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/components/InputDialog.vue b/src/components/InputDialog.vue new file mode 100644 index 0000000..3626f48 --- /dev/null +++ b/src/components/InputDialog.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/src/components/MessageDialog.vue b/src/components/MessageDialog.vue new file mode 100644 index 0000000..2ca3135 --- /dev/null +++ b/src/components/MessageDialog.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/components/ServerPanel.vue b/src/components/ServerPanel.vue new file mode 100644 index 0000000..eca693d --- /dev/null +++ b/src/components/ServerPanel.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/src/components/SideBar.vue b/src/components/SideBar.vue new file mode 100644 index 0000000..cf81164 --- /dev/null +++ b/src/components/SideBar.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/components/TitleBar.vue b/src/components/TitleBar.vue new file mode 100644 index 0000000..d2d5566 --- /dev/null +++ b/src/components/TitleBar.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/styles/global.less b/src/styles/global.less new file mode 100644 index 0000000..7839cb9 --- /dev/null +++ b/src/styles/global.less @@ -0,0 +1,702 @@ +// Global styles +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --bg-primary: #f8fafc; + --bg-secondary: #ffffff; + --bg-tertiary: #f1f5f9; + --bg-hover: #e2e8f0; + --text-primary: #0f172a; + --text-secondary: #475569; + --text-tertiary: #94a3b8; + --accent: #3b82f6; + --accent-hover: #2563eb; + --accent-light: #eff6ff; + --border: #e2e8f0; + --border-light: #f1f5f9; + --success: #10b981; + --danger: #ef4444; + --radius: 6px; + --radius-lg: 10px; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.04); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.04); +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateX(-10px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.6; + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInRight { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + background: var(--bg-primary); + color: var(--text-primary); + height: 100vh; + overflow: hidden; + user-select: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.dark, +.solarized-dark { + --bg-primary: #1a1a2e; + --bg-secondary: #16213e; + --bg-tertiary: #0f3460; + --bg-hover: #1f4068; + --text-primary: #e4e4e7; + --text-secondary: #a1a1aa; + --text-tertiary: #71717a; + --accent: #60a5fa; + --accent-hover: #3b82f6; + --accent-light: rgba(96, 165, 250, 0.15); + --border: #2d2d44; + --border-light: #232338; + --success: #34d399; + --danger: #f87171; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -4px rgba(0, 0, 0, 0.4); +} + +.solarized-dark { + --bg-primary: #002b36; + --bg-secondary: #073642; + --bg-tertiary: #094856; + --bg-hover: #0a5a6f; + --text-primary: #839496; + --text-secondary: #93a1a1; + --text-tertiary: #586e75; + --accent: #268bd2; + --accent-hover: #1a73c0; + --accent-light: rgba(38, 139, 210, 0.15); + --border: #1d3a47; + --border-light: #0d3a47; + --success: #2aa198; + --danger: #dc322f; +} + +// Scrollbar styles +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: transparent; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; + transition: background 0.2s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); +} + +::-webkit-scrollbar-corner { + background: transparent; +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--border) transparent; +} + +// Shared layout styles +.app { + display: flex; + flex-direction: column; + height: 100vh; +} + +.main { + display: flex; + flex: 1; + overflow: hidden; +} + +.content { + flex: 1; + padding: 28px 32px; + overflow-y: auto; + background: var(--bg-primary); +} + +.content section { + animation: fadeIn 0.35s ease; +} + +// Content header (shared across all views) +.content-header { + margin-bottom: 24px; +} + +.content-title { + font-size: 22px; + font-weight: 600; + margin-bottom: 6px; + letter-spacing: -0.03em; + animation: slideIn 0.3s ease; + color: var(--text-primary); +} + +.content-desc { + font-size: 14px; + color: var(--text-tertiary); + animation: fadeIn 0.4s ease 0.1s backwards; + margin-top: 6px; + line-height: 1.5; +} +.content-header { + margin-bottom: 28px; +} + +// Card (shared across GeneralSettings and ApiConfig) +.card { + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); + padding: 20px 24px; + margin-bottom: 20px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + animation: fadeIn 0.4s ease backwards; +} + +.card:last-child { + margin-bottom: 0; +} + +.card-title { + font-size: 14px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text-primary); + margin-bottom: 14px; + padding-bottom: 12px; + border-bottom: 1px solid var(--border-light); + display: flex; + gap: 5px; +} +.card-title .iconpark-icon { + color: var(--accent); +} + +.card:nth-child(1) { + animation-delay: 0.05s; +} +.card:nth-child(2) { + animation-delay: 0.1s; +} +.card:hover { + box-shadow: var(--shadow); + transform: translateY(-1px); +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateX(-10px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +// Form styles +.form-group { + margin-bottom: 18px; +} + +.form-group:last-child { + margin-bottom: 0; +} + +.form-label { + display: block; + font-size: 13px; + font-weight: 500; + margin-bottom: 8px; + color: var(--text-secondary); + letter-spacing: -0.01em; +} + +.form-input { + width: 100%; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius); + font-family: 'SF Mono', 'Cascadia Code', 'Consolas', monospace; + font-size: 13px; + background: var(--bg-secondary); + color: var(--text-primary); + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + letter-spacing: -0.01em; +} + +.form-input:hover { + border-color: var(--text-tertiary); +} + +.form-input:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-light); + transform: translateY(-1px); +} + +.form-input::placeholder { + color: var(--text-tertiary); +} + +.form-row { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20px; +} + +.form-select { + width: 100%; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius); + font-family: inherit; + font-size: 13px; + font-weight: 400; + background: var(--bg-secondary); + color: var(--text-primary); + cursor: pointer; + appearance: none; + letter-spacing: -0.01em; + background-repeat: no-repeat; + background-position: right 12px center; + padding-right: 40px; + transition: all 0.2s ease; + position: relative; +} + +.form-select:hover { + border-color: var(--text-tertiary); + background-color: var(--bg-tertiary); +} + +.form-select:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-light); +} + +.form-textarea { + width: 100%; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius); + font-family: 'SF Mono', 'Cascadia Code', 'Consolas', monospace; + font-size: 13px; + background: var(--bg-secondary); + color: var(--text-primary); + resize: vertical; + min-height: 80px; + line-height: 1.5; + transition: all 0.2s ease; +} + +.form-textarea:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-light); +} + +// Icon styles +.iconpark-icon { + display: inline-flex; + align-items: center; + justify-content: center; + vertical-align: -0.125em; + flex-shrink: 0; +} + +.iconpark-icon svg { + display: block; +} + +// Button styles +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 7px; + padding: 9px 18px; + border: none; + border-radius: var(--radius); + font-family: inherit; + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + letter-spacing: -0.01em; + position: relative; + overflow: hidden; +} + +.btn::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + transform: translate(-50%, -50%); + transition: + width 0.4s ease, + height 0.4s ease; +} + +.btn:active::after { + width: 200px; + height: 200px; +} + +.btn-primary { + background: var(--accent); + color: white; + box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3); +} + +.btn-primary:hover { + background: var(--accent-hover); + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(59, 130, 246, 0.4); +} + +.btn-primary:active { + transform: translateY(0) scale(0.98); +} + +.btn-secondary:hover { + background: var(--bg-tertiary); + color: var(--text-primary); + border-color: var(--text-tertiary); +} + +.btn-secondary:active { + transform: scale(0.98); +} + +.btn-danger { + background: var(--danger); + color: white; + box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3); +} + +.btn-danger:hover { + background: #dc2626; + transform: translateY(-1px); +} + +.btn-danger:active { + transform: translateY(0) scale(0.98); +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none !important; +} + +.btn-sm { + padding: 6px 12px; + font-size: 12px; +} + +// Empty state +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 48px 24px; + text-align: center; + background: var(--bg-tertiary); + border-radius: var(--radius-lg); +} + +.empty-state-icon { + font-size: 48px; + margin-bottom: 16px; + opacity: 0.3; + color: var(--text-tertiary); +} + +.empty-state-title { + font-size: 15px; + font-weight: 500; + margin-bottom: 6px; + color: var(--text-secondary); +} + +.empty-state-desc { + font-size: 13px; + color: var(--text-tertiary); + margin-bottom: 20px; +} + +// Dialog overlay +.dialog-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.6); + backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + z-index: 1300; + animation: fadeIn 0.15s ease; +} + +.dialog { + background: var(--bg-secondary); + border-radius: var(--radius-lg); + padding: 24px; + min-width: 360px; + max-width: 480px; + box-shadow: var(--shadow-lg); + animation: slideUp 0.2s ease; +} + +.dialog-title { + font-size: 15px; + font-weight: 600; + margin-bottom: 18px; + letter-spacing: -0.01em; +} + +.dialog-confirm-text { + font-size: 14px; + color: var(--text-secondary); + margin-bottom: 8px; + line-height: 1.5; +} + +.dialog-actions { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 22px; +} + +// Message dialog +.message-dialog { + position: relative; + text-align: center; + padding: 32px 24px; + z-index: 1400; +} + +.message-dialog-icon { + width: 48px; + height: 48px; + margin: 0 auto 16px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +.message-dialog-icon svg { + width: 24px; + height: 24px; +} + +.message-dialog-icon-info { + background: rgba(59, 130, 246, 0.1); + color: var(--accent); +} + +.message-dialog-icon-success { + background: rgba(16, 185, 129, 0.1); + color: var(--success); +} + +.message-dialog-icon-warning { + background: rgba(245, 158, 11, 0.1); + color: #f59e0b; +} + +.message-dialog-icon-error { + background: rgba(239, 68, 68, 0.1); + color: var(--danger); +} + +.message-dialog-title { + font-size: 16px; + font-weight: 600; + margin-bottom: 8px; + color: var(--text-primary); +} + +.message-dialog-message { + font-size: 14px; + color: var(--text-secondary); + line-height: 1.5; +} + +.message-dialog .dialog-actions { + justify-content: center; + margin-top: 24px; +} + +.message-dialog .dialog-actions .btn { + min-width: 100px; +} + +// Server list (used by ApiConfig too) +.server-list { + border: 1px solid var(--border); + border-radius: var(--radius-lg); + overflow: hidden; + background: var(--bg-secondary); +} + +.server-item { + display: flex; + align-items: center; + padding: 14px 18px; + border-bottom: 1px solid var(--border-light); + cursor: pointer; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + animation: fadeIn 0.3s ease backwards; +} + +.server-item:nth-child(1) { + animation-delay: 0.02s; +} +.server-item:nth-child(2) { + animation-delay: 0.04s; +} +.server-item:nth-child(3) { + animation-delay: 0.06s; +} +.server-item:nth-child(4) { + animation-delay: 0.08s; +} +.server-item:nth-child(5) { + animation-delay: 0.1s; +} +.server-item:nth-child(6) { + animation-delay: 0.12s; +} +.server-item:nth-child(7) { + animation-delay: 0.14s; +} +.server-item:nth-child(8) { + animation-delay: 0.16s; +} + +.server-item:last-child { + border-bottom: none; +} + +.server-item:hover { + background: var(--bg-tertiary); + transform: translateX(4px); +} + +.server-item.selected { + background: var(--accent-light); + border-left: 3px solid var(--accent); + padding-left: 15px; +} + +.server-info { + flex: 1; + min-width: 0; +} + +.server-name { + font-size: 13px; + font-weight: 500; + letter-spacing: -0.01em; +} + +.server-desc { + font-size: 12px; + color: var(--text-tertiary); + margin-top: 3px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.server-status { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--success); + box-shadow: 0 0 6px rgba(16, 185, 129, 0.5); + animation: pulse 2s ease-in-out infinite; +} diff --git a/src/views/ApiConfig.vue b/src/views/ApiConfig.vue new file mode 100644 index 0000000..45bccec --- /dev/null +++ b/src/views/ApiConfig.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/src/views/GeneralSettings.vue b/src/views/GeneralSettings.vue new file mode 100644 index 0000000..714a676 --- /dev/null +++ b/src/views/GeneralSettings.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/src/views/McpServers.vue b/src/views/McpServers.vue new file mode 100644 index 0000000..be6091e --- /dev/null +++ b/src/views/McpServers.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/vite.config.js b/vite.config.js index 1a84e5b..11708c5 100644 --- a/vite.config.js +++ b/vite.config.js @@ -13,5 +13,12 @@ export default defineConfig({ alias: { '@': path.resolve(__dirname, 'src') } + }, + css: { + preprocessorOptions: { + less: { + javascriptEnabled: true + } + } } }); \ No newline at end of file