diff --git a/src/extension.ts b/src/extension.ts index 197a7893..1167f78f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1626,7 +1626,7 @@ class SuperdesignCanvasPanel { // Handle messages from the webview this._panel.webview.onDidReceiveMessage( - message => { + async message => { switch (message.command) { case 'loadDesignFiles': this._loadDesignFiles(); @@ -1648,6 +1648,9 @@ class SuperdesignCanvasPanel { data: message.data }); break; + case 'deleteDesignFile': + await this._deleteDesignFile(message.fileName); + break; } }, null, @@ -1876,6 +1879,48 @@ class SuperdesignCanvasPanel { } } + private async _deleteDesignFile(fileName: string) { + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; + if (!workspaceFolder) { + Logger.error('No workspace folder found for deleting file'); + return; + } + + try { + const filePath = vscode.Uri.joinPath( + workspaceFolder.uri, + '.superdesign', + 'design_iterations', + fileName + ); + + // Check if file exists + try { + await vscode.workspace.fs.stat(filePath); + } catch { + Logger.warn(`File not found for deletion: ${fileName}`); + return; + } + + // Delete the file + await vscode.workspace.fs.delete(filePath); + Logger.info(`Deleted design file: ${fileName}`); + + // Notify webview of successful deletion + this._panel.webview.postMessage({ + command: 'fileDeleted', + data: { fileName } + }); + + } catch (error) { + Logger.error(`Failed to delete file ${fileName}: ${error}`); + this._panel.webview.postMessage({ + command: 'error', + data: { error: `Failed to delete file: ${error}` } + }); + } + } + private async _inlineExternalCSS(htmlContent: string, designFolder: vscode.Uri): Promise { // Match link tags that reference CSS files const linkRegex = /]*rel=["']stylesheet["'][^>]*href=["']([^"']+)["'][^>]*>/gi; diff --git a/src/providers/claudeCodeProvider.ts b/src/providers/claudeCodeProvider.ts index f6a13e03..de0e695b 100644 --- a/src/providers/claudeCodeProvider.ts +++ b/src/providers/claudeCodeProvider.ts @@ -343,10 +343,12 @@ Whenever there are UI implementation task, think deeply of the design style firs let buffer = ''; const outputs: string[] = []; + let wasAborted = false; if (abortController) { abortController.signal.addEventListener('abort', () => { Logger.info('Aborting claude-code process'); + wasAborted = true; child.kill('SIGTERM'); }); } @@ -389,12 +391,19 @@ Whenever there are UI implementation task, think deeply of the design style firs child.on('close', (code) => { Logger.info(`Claude Code process closed with code: ${code}`); Logger.info(`Process outputs collected: ${outputs.length} items`); - + // Process any remaining buffer if (buffer.trim()) { outputs.push(buffer.trim()); } - + + // If aborted, always resolve successfully + if (wasAborted) { + Logger.info('Process was aborted by user, resolving successfully'); + resolve(outputs); + return; + } + if (code !== 0 && !abortController?.signal.aborted) { let errorMessage = `Claude Code process exited with code ${code}`; if (code === 2) { diff --git a/src/webview/App.css b/src/webview/App.css index a814f74a..7adb6f2e 100644 --- a/src/webview/App.css +++ b/src/webview/App.css @@ -1417,6 +1417,102 @@ } } +/* Delete Confirmation Modal */ +.delete-confirm-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + animation: fadeIn 0.2s ease; +} + +.delete-confirm-dialog { + background: var(--vscode-editorWidget-background); + border: 1px solid var(--vscode-editorWidget-border); + border-radius: 6px; + padding: 20px; + min-width: 300px; + max-width: 400px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + animation: slideUp 0.2s ease; +} + +.delete-confirm-dialog h3 { + margin: 0 0 12px 0; + font-size: 1rem; + font-weight: 600; + color: var(--vscode-foreground); +} + +.delete-confirm-dialog p { + margin: 0 0 20px 0; + font-size: 0.9rem; + color: var(--vscode-descriptionForeground); + line-height: 1.4; +} + +.delete-confirm-buttons { + display: flex; + gap: 8px; + justify-content: flex-end; +} + +.delete-confirm-cancel, +.delete-confirm-delete { + padding: 6px 16px; + border-radius: 4px; + border: none; + font-size: 0.85rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.delete-confirm-cancel { + background: var(--vscode-button-secondaryBackground); + color: var(--vscode-button-secondaryForeground); +} + +.delete-confirm-cancel:hover { + background: var(--vscode-button-secondaryHoverBackground); +} + +.delete-confirm-delete { + background: var(--vscode-errorForeground); + color: white; +} + +.delete-confirm-delete:hover { + opacity: 0.9; + transform: translateY(-1px); +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + /* Copied Notification */ .copied-notification { position: absolute; diff --git a/src/webview/components/CanvasView.tsx b/src/webview/components/CanvasView.tsx index 20607ffd..5c0254fb 100644 --- a/src/webview/components/CanvasView.tsx +++ b/src/webview/components/CanvasView.tsx @@ -543,6 +543,26 @@ const CanvasView: React.FC = ({ vscode, nonce }) => { }); }; + // Handle design file deletion + const handleDeleteDesign = (fileName: string) => { + // Send delete request to backend + vscode.postMessage({ + command: 'deleteDesignFile', + fileName: fileName + }); + + // Optimistically remove from UI + setDesignFiles(prev => prev.filter(file => file.name !== fileName)); + setSelectedFrames(prev => prev.filter(name => name !== fileName)); + + // Clean up custom positions + setCustomPositions(prev => { + const updated = { ...prev }; + delete updated[fileName]; + return updated; + }); + }; + // Keyboard shortcuts for zoom useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { @@ -847,6 +867,7 @@ const CanvasView: React.FC = ({ vscode, nonce }) => { isDragging={dragState.isDragging && dragState.draggedFrame === file.name} nonce={nonce} onSendToChat={handleSendToChat} + onDelete={handleDeleteDesign} /> ); })} diff --git a/src/webview/components/Chat/ChatInterface.tsx b/src/webview/components/Chat/ChatInterface.tsx index 1ede6e68..3de91e09 100644 --- a/src/webview/components/Chat/ChatInterface.tsx +++ b/src/webview/components/Chat/ChatInterface.tsx @@ -1481,10 +1481,12 @@ const ChatInterface: React.FC = ({ layout, vscode }) => { {isLoading ? ( - + + {/* Delete Button */} + {onDelete && ( + <> + + + {/* Delete Confirmation Modal */} + {showDeleteConfirm && ( +
{ + e.stopPropagation(); + setShowDeleteConfirm(false); + }} + > +
e.stopPropagation()} + > +

Delete Design?

+

Are you sure you want to delete "{file.name}"?

+
+ + +
+
+
+ )} + + )} )}