From 018990b7f606d8812ad72d271037819d1f95063a Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Wed, 19 Nov 2025 23:34:05 +0800 Subject: [PATCH] =?UTF-8?q?build(vscode-ide-companion):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20SCSS=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 esbuild.js 中添加 SCSS 文件处理逻辑 - 在 package.json 中添加 sass 依赖 - 新增代码使用 sass 编译 SCSS 文件,并将其注入到页面中 --- package-lock.json | 407 ++++++++++++++++++ packages/vscode-ide-companion/esbuild.js | 18 + packages/vscode-ide-companion/package.json | 1 + .../src/webview/{App.css => App.scss} | 80 ++++ .../vscode-ide-companion/src/webview/App.tsx | 100 ++++- .../src/webview/index.tsx | 2 +- 6 files changed, 595 insertions(+), 13 deletions(-) rename packages/vscode-ide-companion/src/webview/{App.css => App.scss} (93%) diff --git a/package-lock.json b/package-lock.json index e0843ff3..2d8e825d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2642,6 +2642,354 @@ "node": ">=14" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -5824,6 +6172,22 @@ "entities": "^6.0.0" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -8971,6 +9335,13 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "dev": true, + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -12884,6 +13255,20 @@ "node": ">=10" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -13282,6 +13667,27 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sass": { + "version": "1.94.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.94.1.tgz", + "integrity": "sha512-/YVm5FRQaRlr3oNh2LLFYne1PdPlRZGyKnHh1sLleOqLcohTR4eUUvBjBIqkl1fEXd1MGOHgzJGJh+LgTtV4KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", @@ -16320,6 +16726,7 @@ "esbuild": "^0.25.3", "eslint": "^9.25.1", "npm-run-all2": "^8.0.2", + "sass": "^1.94.1", "typescript": "^5.8.3", "vitest": "^3.2.4" }, diff --git a/packages/vscode-ide-companion/esbuild.js b/packages/vscode-ide-companion/esbuild.js index c737ecc3..da53cd48 100644 --- a/packages/vscode-ide-companion/esbuild.js +++ b/packages/vscode-ide-companion/esbuild.js @@ -37,6 +37,7 @@ const esbuildProblemMatcherPlugin = { const cssInjectPlugin = { name: 'css-inject', setup(build) { + // Handle CSS files build.onLoad({ filter: /\.css$/ }, async (args) => { const fs = await import('fs'); const css = await fs.promises.readFile(args.path, 'utf8'); @@ -49,6 +50,23 @@ const cssInjectPlugin = { loader: 'js', }; }); + + // Handle SCSS files + build.onLoad({ filter: /\.scss$/ }, async (args) => { + const sass = await import('sass'); + const result = sass.compile(args.path, { + loadPaths: [args.path.substring(0, args.path.lastIndexOf('/'))], + }); + const css = result.css; + return { + contents: ` + const style = document.createElement('style'); + style.textContent = ${JSON.stringify(css)}; + document.head.appendChild(style); + `, + loader: 'js', + }; + }); }, }; diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index 5b83df42..0ab4d511 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -178,6 +178,7 @@ "esbuild": "^0.25.3", "eslint": "^9.25.1", "npm-run-all2": "^8.0.2", + "sass": "^1.94.1", "typescript": "^5.8.3", "vitest": "^3.2.4" }, diff --git a/packages/vscode-ide-companion/src/webview/App.css b/packages/vscode-ide-companion/src/webview/App.scss similarity index 93% rename from packages/vscode-ide-companion/src/webview/App.css rename to packages/vscode-ide-companion/src/webview/App.scss index 84c9e6e4..5ec1f226 100644 --- a/packages/vscode-ide-companion/src/webview/App.css +++ b/packages/vscode-ide-companion/src/webview/App.scss @@ -298,6 +298,22 @@ button { padding: var(--app-spacing-medium); } +.thinking-message { + background-color: var(--app-list-hover-background, rgba(100, 100, 255, 0.1)); + opacity: 0.8; + font-style: italic; + position: relative; + padding-left: 24px; +} + +.thinking-message::before { + content: "💭"; + position: absolute; + left: 6px; + top: 50%; + transform: translateY(-50%); +} + .thinking-label { font-size: 12px; font-weight: 600; @@ -314,6 +330,70 @@ button { color: rgba(200, 200, 255, 0.9); } +/* Waiting message styles - similar to Claude Code thinking state */ +.message.waiting-message { + opacity: 0.85; +} + +.waiting-message .message-content { + background-color: transparent; + border: none; + padding: 8px 0; + display: flex; + align-items: center; + gap: 8px; +} + +/* Typing indicator for loading messages */ +.typing-indicator { + display: inline-flex; + align-items: center; + margin-right: 0; + gap: 4px; +} + +.typing-dot, .thinking-dot { + width: 6px; + height: 6px; + background-color: var(--app-secondary-foreground); + border-radius: 50%; + margin-right: 0; + opacity: 0.6; + animation: typingPulse 1.4s infinite ease-in-out; +} + +.typing-dot:nth-child(1), +.thinking-dot:nth-child(1) { + animation-delay: 0s; +} + +.typing-dot:nth-child(2), +.thinking-dot:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-dot:nth-child(3), +.thinking-dot:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes typingPulse { + 0%, 60%, 100% { + transform: scale(0.7); + opacity: 0.6; + } + 30% { + transform: scale(1); + opacity: 1; + } +} + +.loading-text { + opacity: 0.7; + font-style: italic; + color: var(--app-secondary-foreground); +} + /* =========================== Scrollbar Styling =========================== */ diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index f820163f..ceb55f3b 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -190,13 +190,15 @@ export const App: React.FC = () => { const [messages, setMessages] = useState([]); const [inputText, setInputText] = useState(''); const [isStreaming, setIsStreaming] = useState(false); - const [_isWaitingForResponse, setIsWaitingForResponse] = useState(false); - const [_loadingMessage, setLoadingMessage] = useState(''); + const [isWaitingForResponse, setIsWaitingForResponse] = useState(false); + const [loadingMessage, setLoadingMessage] = useState(''); const [currentStreamContent, setCurrentStreamContent] = useState(''); const [qwenSessions, setQwenSessions] = useState< Array> >([]); const [currentSessionId, setCurrentSessionId] = useState(null); + const [currentSessionTitle, setCurrentSessionTitle] = + useState('Past Conversations'); const [showSessionSelector, setShowSessionSelector] = useState(false); const [sessionSearchQuery, setSessionSearchQuery] = useState(''); const [permissionRequest, setPermissionRequest] = useState<{ @@ -336,6 +338,18 @@ export const App: React.FC = () => { break; } + case 'thoughtChunk': { + const chunkData = message.data; + // Handle thought chunks for AI thinking display + const thinkingMessage: TextMessage = { + role: 'thinking', + content: chunkData.content || chunkData.chunk || '', + timestamp: Date.now(), + }; + setMessages((prev) => [...prev, thinkingMessage]); + break; + } + case 'streamEnd': // Finalize the streamed message if (currentStreamContentRef.current) { @@ -347,12 +361,14 @@ export const App: React.FC = () => { setMessages((prev) => [...prev, assistantMessage]); } setIsStreaming(false); + setIsWaitingForResponse(false); // Clear waiting state setCurrentStreamContent(''); currentStreamContentRef.current = ''; break; case 'error': setIsStreaming(false); + setIsWaitingForResponse(false); break; case 'permissionRequest': @@ -371,10 +387,30 @@ export const App: React.FC = () => { setQwenSessions(sessions); // If no current session is selected and there are sessions, select the first one if (!currentSessionId && sessions.length > 0) { + const firstSession = sessions[0]; const firstSessionId = - (sessions[0].id as string) || (sessions[0].sessionId as string); + (firstSession.id as string) || (firstSession.sessionId as string); + const firstSessionTitle = + (firstSession.title as string) || + (firstSession.name as string) || + 'Past Conversations'; if (firstSessionId) { setCurrentSessionId(firstSessionId); + setCurrentSessionTitle(firstSessionTitle); + } + } else if (currentSessionId && sessions.length > 0) { + // Update title for the current session if it exists in the list + const currentSession = sessions.find( + (s: Record) => + (s.id as string) === currentSessionId || + (s.sessionId as string) === currentSessionId, + ); + if (currentSession) { + const title = + (currentSession.title as string) || + (currentSession.name as string) || + 'Past Conversations'; + setCurrentSessionTitle(title); } } break; @@ -391,6 +427,14 @@ export const App: React.FC = () => { message.data.sessionId, ); } + // Update current session title + if (message.data.title || message.data.name) { + const title = + (message.data.title as string) || + (message.data.name as string) || + 'Past Conversations'; + setCurrentSessionTitle(title); + } // Load messages from the session if (message.data.messages) { console.log( @@ -463,6 +507,7 @@ export const App: React.FC = () => { vscode.postMessage({ type: 'newQwenSession', data: {} }); setShowSessionSelector(false); setCurrentSessionId(null); + setCurrentSessionTitle('Past Conversations'); // Reset title to default // Clear messages in UI setMessages([]); setCurrentStreamContent(''); @@ -694,7 +739,7 @@ export const App: React.FC = () => { title="Past conversations" > - Past Conversations + {currentSessionTitle} { ) : ( <> - {messages.map((msg, index) => ( -
-
{msg.content}
-
- {new Date(msg.timestamp).toLocaleTimeString()} + {messages.map((msg, index) => { + // Special styling for thinking messages (Claude Code style) + const messageClass = + msg.role === 'thinking' + ? 'message assistant thinking-message' + : `message ${msg.role}`; + + return ( +
+
+ {msg.role === 'thinking' && ( + + + + + + )} + {msg.content} +
+
+ {new Date(msg.timestamp).toLocaleTimeString()} +
-
- ))} + ); + })} {/* Tool Calls */} {Array.from(toolCalls.values()).map((toolCall) => ( @@ -757,6 +819,20 @@ export const App: React.FC = () => { /> )} + {/* Loading/Waiting Message - in message list */} + {isWaitingForResponse && loadingMessage && ( +
+
+ + + + + + {loadingMessage} +
+
+ )} + {isStreaming && currentStreamContent && (
{currentStreamContent}
@@ -830,7 +906,7 @@ export const App: React.FC = () => { role="textbox" aria-label="Message input" aria-multiline="true" - data-placeholder="Ask qwen to edit…" + data-placeholder="Ask Qwen Code …" onInput={(e) => { const target = e.target as HTMLDivElement; setInputText(target.textContent || ''); diff --git a/packages/vscode-ide-companion/src/webview/index.tsx b/packages/vscode-ide-companion/src/webview/index.tsx index 34e4a9fb..a8fce313 100644 --- a/packages/vscode-ide-companion/src/webview/index.tsx +++ b/packages/vscode-ide-companion/src/webview/index.tsx @@ -6,7 +6,7 @@ import ReactDOM from 'react-dom/client'; import { App } from './App.js'; -import './App.css'; +import './App.scss'; import './ClaudeCodeStyles.css'; const container = document.getElementById('root');