From 21dbd42184952d7f19df46d4f0844c05a190e09e Mon Sep 17 00:00:00 2001 From: Waseem Anjum Date: Sat, 19 Oct 2024 12:26:29 +0500 Subject: [PATCH] added download code button --- app/components/workbench/Workbench.client.tsx | 29 +++++++++---- app/lib/stores/workbench.ts | 32 +++++++++++++++ package.json | 3 ++ pnpm-lock.yaml | 41 +++++++++++++++++++ 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/app/components/workbench/Workbench.client.tsx b/app/components/workbench/Workbench.client.tsx index b8142a66..839e9a80 100644 --- a/app/components/workbench/Workbench.client.tsx +++ b/app/components/workbench/Workbench.client.tsx @@ -122,15 +122,26 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
{selectedView === 'code' && ( - { - workbenchStore.toggleTerminal(!workbenchStore.showTerminal.get()); - }} - > -
- Toggle Terminal - + <> + { + workbenchStore.downloadZip(); + }} + > +
+ Download Code + + { + workbenchStore.toggleTerminal(!workbenchStore.showTerminal.get()); + }} + > +
+ Toggle Terminal + + )} 1) { + let currentFolder = zip; + for (let i = 0; i < pathSegments.length - 1; i++) { + currentFolder = currentFolder.folder(pathSegments[i])!; + } + currentFolder.file(pathSegments[pathSegments.length - 1], dirent.content); + } else { + // If there's only one segment, it's a file in the root + zip.file(relativePath, dirent.content); + } + } + } + + const content = await zip.generateAsync({ type: 'blob' }); + saveAs(content, 'project.zip'); + } } export const workbenchStore = new WorkbenchStore(); diff --git a/package.json b/package.json index 6cc49c7e..7f3faead 100644 --- a/package.json +++ b/package.json @@ -59,10 +59,12 @@ "ai": "^3.4.9", "date-fns": "^3.6.0", "diff": "^5.2.0", + "file-saver": "^2.0.5", "framer-motion": "^11.2.12", "isbot": "^4.1.0", "istextorbinary": "^9.5.0", "jose": "^5.6.3", + "jszip": "^3.10.1", "nanostores": "^0.10.3", "ollama-ai-provider": "^0.15.2", "react": "^18.2.0", @@ -84,6 +86,7 @@ "@cloudflare/workers-types": "^4.20240620.0", "@remix-run/dev": "^2.10.0", "@types/diff": "^5.2.1", + "@types/file-saver": "^2.0.7", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", "fast-glob": "^3.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75f0b99c..69a4b0c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,6 +119,9 @@ importers: diff: specifier: ^5.2.0 version: 5.2.0 + file-saver: + specifier: ^2.0.5 + version: 2.0.5 framer-motion: specifier: ^11.2.12 version: 11.2.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -131,6 +134,9 @@ importers: jose: specifier: ^5.6.3 version: 5.6.3 + jszip: + specifier: ^3.10.1 + version: 3.10.1 nanostores: specifier: ^0.10.3 version: 0.10.3 @@ -189,6 +195,9 @@ importers: '@types/diff': specifier: ^5.2.1 version: 5.2.1 + '@types/file-saver': + specifier: ^2.0.7 + version: 2.0.7 '@types/react': specifier: ^18.2.20 version: 18.3.3 @@ -1772,6 +1781,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/file-saver@2.0.7': + resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} + '@types/hast@2.3.10': resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} @@ -2900,6 +2912,9 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-saver@2.0.5: + resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -3181,6 +3196,9 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immutable@4.3.7: resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} @@ -3396,6 +3414,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==} @@ -3410,6 +3431,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.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} @@ -6912,6 +6936,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/file-saver@2.0.7': {} + '@types/hast@2.3.10': dependencies: '@types/unist': 2.0.10 @@ -8396,6 +8422,8 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-saver@2.0.5: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -8747,6 +8775,8 @@ snapshots: ignore@5.3.1: {} + immediate@3.0.6: {} + immutable@4.3.7: optional: true @@ -8915,6 +8945,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 @@ -8928,6 +8965,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lilconfig@3.1.2: {} loader-utils@3.3.1: {}