mirror of
https://github.com/stackblitz/bolt.new
synced 2025-06-26 18:17:50 +00:00
commit
f25a3e469d
@ -16,6 +16,7 @@ import { cubicEasingFn } from '~/utils/easings';
|
||||
import { renderLogger } from '~/utils/logger';
|
||||
import { EditorPanel } from './EditorPanel';
|
||||
import { Preview } from './Preview';
|
||||
import JSZip from 'jszip';
|
||||
|
||||
interface WorkspaceProps {
|
||||
chatStarted?: boolean;
|
||||
@ -52,6 +53,53 @@ const workbenchVariants = {
|
||||
},
|
||||
} satisfies Variants;
|
||||
|
||||
async function downloadAsZip(files: Record<string, any>) {
|
||||
const zip = new JSZip();
|
||||
|
||||
// add files to zip
|
||||
for (const [path, dirent] of Object.entries(files)) {
|
||||
if (dirent?.type === 'file' && dirent.content) {
|
||||
zip.file(path.startsWith('/') ? path.slice(1) : path, dirent.content);
|
||||
}
|
||||
}
|
||||
|
||||
// generate and download zip
|
||||
const blob = await zip.generateAsync({ type: 'blob' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'files.zip';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
async function copyFilesToDirectory(files: Record<string, any>) {
|
||||
try {
|
||||
// using the Fetch API to send files to your backend
|
||||
const response = await fetch('/api/copy-files', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
files,
|
||||
targetDirectory: '/Users/yaqub.mahmoud/github/ai-website-microservice/web-projects/project_name',
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to copy files');
|
||||
}
|
||||
|
||||
toast.success('Files copied successfully');
|
||||
} catch (error) {
|
||||
console.error('Error copying files:', error);
|
||||
toast.error('Failed to copy files');
|
||||
}
|
||||
}
|
||||
|
||||
export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) => {
|
||||
renderLogger.trace('Workbench');
|
||||
|
||||
@ -132,6 +180,14 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
||||
Toggle Terminal
|
||||
</PanelHeaderButton>
|
||||
)}
|
||||
<PanelHeaderButton className="mr-1 text-sm" onClick={() => downloadAsZip(files)}>
|
||||
<div className="i-ph:download mr-1" />
|
||||
Download ZIP
|
||||
</PanelHeaderButton>
|
||||
<PanelHeaderButton className="mr-1 text-sm" onClick={() => copyFilesToDirectory(files)}>
|
||||
<div className="i-ph:rocket mr-1" />
|
||||
Deploy
|
||||
</PanelHeaderButton>
|
||||
<IconButton
|
||||
icon="i-ph:x-circle"
|
||||
className="-mr-1"
|
||||
|
@ -62,6 +62,7 @@
|
||||
"isbot": "^4.1.0",
|
||||
"istextorbinary": "^9.5.0",
|
||||
"jose": "^5.6.3",
|
||||
"jszip": "^3.10.1",
|
||||
"nanostores": "^0.10.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@ -90,7 +91,7 @@
|
||||
"node-fetch": "^3.3.2",
|
||||
"prettier": "^3.3.2",
|
||||
"sass-embedded": "^1.83.4",
|
||||
"typescript": "^5.5.2",
|
||||
"typescript": "^5.7.3",
|
||||
"unified": "^11.0.5",
|
||||
"unocss": "^0.61.3",
|
||||
"vite": "^5.3.1",
|
||||
|
@ -128,6 +128,9 @@ importers:
|
||||
jose:
|
||||
specifier: ^5.6.3
|
||||
version: 5.9.6
|
||||
jszip:
|
||||
specifier: ^3.10.1
|
||||
version: 3.10.1
|
||||
nanostores:
|
||||
specifier: ^0.10.3
|
||||
version: 0.10.3
|
||||
@ -208,7 +211,7 @@ importers:
|
||||
specifier: ^1.83.4
|
||||
version: 1.83.4
|
||||
typescript:
|
||||
specifier: ^5.5.2
|
||||
specifier: ^5.7.3
|
||||
version: 5.7.3
|
||||
unified:
|
||||
specifier: ^11.0.5
|
||||
@ -3258,6 +3261,9 @@ packages:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
immediate@3.0.6:
|
||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||
|
||||
immutable@5.0.3:
|
||||
resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
|
||||
|
||||
@ -3467,6 +3473,9 @@ packages:
|
||||
jsonfile@6.1.0:
|
||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
||||
|
||||
jszip@3.10.1:
|
||||
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||
|
||||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
@ -3481,6 +3490,9 @@ packages:
|
||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
lie@3.3.0:
|
||||
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||
|
||||
lilconfig@3.1.3:
|
||||
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
||||
engines: {node: '>=14'}
|
||||
@ -8878,6 +8890,8 @@ snapshots:
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
immediate@3.0.6: {}
|
||||
|
||||
immutable@5.0.3: {}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
@ -9059,6 +9073,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jszip@3.10.1:
|
||||
dependencies:
|
||||
lie: 3.3.0
|
||||
pako: 1.0.11
|
||||
readable-stream: 2.3.8
|
||||
setimmediate: 1.0.5
|
||||
|
||||
keyv@4.5.4:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
@ -9072,6 +9093,10 @@ snapshots:
|
||||
prelude-ls: 1.2.1
|
||||
type-check: 0.4.0
|
||||
|
||||
lie@3.3.0:
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
|
||||
lilconfig@3.1.3: {}
|
||||
|
||||
load-tsconfig@0.2.5: {}
|
||||
|
Loading…
Reference in New Issue
Block a user