Skip to content

Commit e018095

Browse files
committed
Allow downloaded exported folders as zip
Signed-off-by: Zvonimir Fras <zvonimir@zvonimirfras.com>
1 parent 5551d7e commit e018095

File tree

3 files changed

+130
-34
lines changed

3 files changed

+130
-34
lines changed

app/src/routes/edit/share-options/exports/export-modal.tsx

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
TreeView,
1515
InlineNotification
1616
} from '@carbon/react';
17-
import { Copy } from '@carbon/react/icons';
17+
import { Copy, Download } from '@carbon/react/icons';
1818
import { css } from 'emotion';
1919
import Editor, { useMonaco } from '@monaco-editor/react';
2020

@@ -30,6 +30,7 @@ import { GlobalStateContext } from '../../../../context';
3030
import { ExportImageComponent } from './export-image-component';
3131
import { filenameToLanguage, getFragmentJsonExportString } from '@carbon-builder/sdk-react';
3232
import JSONCrush from 'jsoncrush';
33+
import JSZip from 'jszip';
3334

3435
const exportCodeModalStyle = css`
3536
.cds--tab-content {
@@ -88,6 +89,17 @@ const versionDropdownStyle = css`
8889
right: 1rem;
8990
`;
9091

92+
const addToZip = (parent: JSZip, items: any[]) => {
93+
items.forEach(item => {
94+
if (item.items && item.items.length) {
95+
const folder = parent.folder(item.name);
96+
addToZip(folder as JSZip, item.items);
97+
} else {
98+
parent.file(item.name, item.code);
99+
}
100+
});
101+
};
102+
91103
const renderCodeTree = (nodes: any, path = '') => {
92104
if (!nodes) {
93105
return;
@@ -109,7 +121,26 @@ const renderCodeTree = (nodes: any, path = '') => {
109121
renderIcon={icon}
110122
isExpanded={isExpanded}
111123
value={code}
112-
label={name}
124+
className={css`.cds--tree-node__icon { align-self: center; }`}
125+
label={<>
126+
{name}
127+
{
128+
items && items.length > 0 &&
129+
<Button
130+
hasIconOnly
131+
onClick={() => {
132+
const zip = new JSZip();
133+
addToZip(zip, items);
134+
zip.generateAsync({ type: 'blob' }).then(content => {
135+
saveBlob(content, `${name}.zip`);
136+
});
137+
}}
138+
iconDescription='Download as ZIP'
139+
className={css`margin-left: 0.5rem;`}
140+
kind='ghost'
141+
size='sm'
142+
renderIcon={Download} />}
143+
</>}
113144
{...nodeProps}>
114145
{renderCodeTree(items, fullPath)}
115146
</TreeNode>;
@@ -228,7 +259,7 @@ export const ExportModal = () => {
228259
}
229260

230261
setSelectedAngularFileItem(fileItem || selectedAngularFileItem);
231-
// eslint-disable-next-line react-hooks/exhaustive-deps
262+
// eslint-disable-next-line react-hooks/exhaustive-deps
232263
}, [angularCode, fragmentExportModal.isVisible]);
233264

234265
useEffect(() => {
@@ -297,10 +328,10 @@ export const ExportModal = () => {
297328
{
298329
fragmentExportModal.isVisible &&
299330
<Tabs
300-
selectedIndex={+settings?.selectedExportTabIndex || 0}
301-
onChange={({ selectedIndex }: {selectedIndex: number}) => {
302-
setSettings({ ...settings, selectedExportTabIndex: selectedIndex });
303-
}}>
331+
selectedIndex={+settings?.selectedExportTabIndex || 0}
332+
onChange={({ selectedIndex }: { selectedIndex: number }) => {
333+
setSettings({ ...settings, selectedExportTabIndex: selectedIndex });
334+
}}>
304335
<TabList aria-label='Export list' className={tabListStyle}>
305336
<Tab>Angular</Tab>
306337
<Tab>React</Tab>

package-lock.json

Lines changed: 91 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"html-react-parser": "4.2.2",
1616
"jsoncrush": "1.1.8",
1717
"jspdf": "2.5.1",
18+
"jszip": "3.10.1",
1819
"lodash": "4.17.21",
1920
"lz-string": "1.4.4",
2021
"octokit": "3.1.1",

0 commit comments

Comments
 (0)