diff --git a/html.html b/html.html
index 73568ca..5922fc4 100644
--- a/html.html
+++ b/html.html
@@ -2,6 +2,7 @@
+
<%= htmlWebpackPlugin.options.title %>
diff --git a/package.json b/package.json
index db6eecc..0ff10ce 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@babel/preset-typescript": "^7.10.4",
"@hot-loader/react-dom": "^16.13.0",
"@types/html-webpack-plugin": "^3.2.3",
+ "@types/jszip": "^3.4.1",
"@types/openpgp": "^4.4.12",
"@types/react": "^16.9.46",
"@types/react-dom": "^16.9.8",
@@ -39,6 +40,7 @@
"webpack-subresource-integrity": "^1.4.1"
},
"dependencies": {
+ "jszip": "^3.5.0",
"nanoid": "^3.1.12",
"openpgp": "^4.10.7",
"react": "^16.13.1",
diff --git a/src/components/File.tsx b/src/components/File.tsx
index 8b7ac63..a3e92da 100644
--- a/src/components/File.tsx
+++ b/src/components/File.tsx
@@ -14,22 +14,13 @@ import {
ShareAltOutlined,
} from '@ant-design/icons';
import { FileType } from '../contexts/Encryption';
+import { downloadLink } from '../helpers/files';
interface Props {
remove: () => void;
file: FileType;
}
-const downloadLink = (name: string, blob: Blob) => {
- const url = URL.createObjectURL(blob);
- const downloadLink = document.createElement('a');
- downloadLink.href = url;
- downloadLink.download = name;
- document.body.appendChild(downloadLink);
- downloadLink.click();
- document.body.removeChild(downloadLink);
-};
-
const icons: {[name: string]: any} = {
encrypting: ,
failed: ,
diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx
index 2e4ded6..83bc44c 100644
--- a/src/components/FileList.tsx
+++ b/src/components/FileList.tsx
@@ -1,25 +1,39 @@
import React, { useContext } from 'react';
-import { List, Empty } from 'antd';
+import { Space, List, Empty, Button } from 'antd';
+import { DownloadOutlined } from '@ant-design/icons';
import EncryptionContext from '../contexts/Encryption';
+import useDownloadAll from '../hooks/useDownloadAll';
import File from './File';
const Encrypt: React.FC = () => {
const { files, deleteFile } = useContext(EncryptionContext);
+ const { status, downloadAll } = useDownloadAll();
if (Object.keys(files).length === 0) {
return
}
return (
-
- {Object.entries(files).map(([id, file]) => (
- deleteFile(id)}
- />
- ))}
-
+
+
+ {Object.entries(files).map(([id, file]) => (
+ deleteFile(id)}
+ />
+ ))}
+
+ {downloadAll && (
+ }
+ disabled={status !== 'ready'}
+ onClick={downloadAll}
+ >
+ Download all
+
+ )}
+
);
};
diff --git a/src/contexts/Github.tsx b/src/contexts/Github.tsx
index 7eb76ab..b768baf 100644
--- a/src/contexts/Github.tsx
+++ b/src/contexts/Github.tsx
@@ -1,7 +1,6 @@
import React, { createContext } from 'react';
const data = require('../../data.json');
-console.log('d', data);
interface GithubContextType {
username: string;
@@ -13,7 +12,7 @@ const GithubProvider: React.FC = ({
children,
}) => (
{children}
diff --git a/src/helpers/files.ts b/src/helpers/files.ts
new file mode 100644
index 0000000..ccc96af
--- /dev/null
+++ b/src/helpers/files.ts
@@ -0,0 +1,9 @@
+export const downloadLink = (name: string, blob: Blob) => {
+ const url = URL.createObjectURL(blob);
+ const downloadLink = document.createElement('a');
+ downloadLink.href = url;
+ downloadLink.download = name;
+ document.body.appendChild(downloadLink);
+ downloadLink.click();
+ document.body.removeChild(downloadLink);
+};
diff --git a/src/hooks/useDownloadAll.ts b/src/hooks/useDownloadAll.ts
new file mode 100644
index 0000000..64860fa
--- /dev/null
+++ b/src/hooks/useDownloadAll.ts
@@ -0,0 +1,33 @@
+import { useState, useContext, useCallback } from 'react';
+import EncryptionContext from '../contexts/Encryption';
+import Zip from 'jszip';
+import { downloadLink } from '../helpers/files';
+
+type Statuses = 'packing' | 'ready';
+
+const useDownloadAll = () => {
+ const [status, setStatus] = useState('ready');
+ const { files } = useContext(EncryptionContext);
+ const allFilesReady = Object.values(files).filter(f => f.link).length > 1;
+
+ const downloadAll = useCallback(() => {
+ setStatus('packing');
+ const run = async () => {
+ const zip = new Zip();
+ Object.values(files).map((file) => {
+ zip.file(file.name, file.link!);
+ });
+ const link = await zip.generateAsync({ type: 'blob' });
+ setStatus('ready');
+ downloadLink('all-files.zip', link);
+ };
+ run();
+ }, [files]);
+
+ return {
+ status,
+ downloadAll: allFilesReady ? downloadAll : undefined,
+ };
+};
+
+export default useDownloadAll;
diff --git a/src/index.tsx b/src/index.tsx
index ab4d2bb..4654e63 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -5,26 +5,28 @@ import 'antd/dist/antd.css';
import { render } from 'react-dom';
import App from './App';
-OfflinePluginRuntime.install({
- onUpdating: () => {
- console.log('SW Event:', 'onUpdating');
- },
- onUpdateReady: () => {
- console.log('SW Event:', 'onUpdateReady');
- OfflinePluginRuntime.applyUpdate();
- },
- onUpdated: () => {
- notification.success({
- message: 'Your app has been updated',
- });
- },
- onUpdateFailed: () => {
- notification.warn({
- message: 'Could not update to the latest version',
- });
- console.log('SW Event:', 'onUpdateFailed');
- }
-});
+if (!__DEV__) {
+ OfflinePluginRuntime.install({
+ onUpdating: () => {
+ console.log('SW Event:', 'onUpdating');
+ },
+ onUpdateReady: () => {
+ console.log('SW Event:', 'onUpdateReady');
+ OfflinePluginRuntime.applyUpdate();
+ },
+ onUpdated: () => {
+ notification.success({
+ message: 'Your app has been updated',
+ });
+ },
+ onUpdateFailed: () => {
+ notification.warn({
+ message: 'Could not update to the latest version',
+ });
+ console.log('SW Event:', 'onUpdateFailed');
+ }
+ });
+}
const root = document.createElement('div');
root.style.height = '100%';
diff --git a/src/screens/Encrypt.tsx b/src/screens/Encrypt.tsx
index d5ae47a..b685af3 100644
--- a/src/screens/Encrypt.tsx
+++ b/src/screens/Encrypt.tsx
@@ -1,5 +1,5 @@
import React, { useContext, useEffect } from 'react';
-import { Divider, PageHeader } from 'antd';
+import { Divider } from 'antd';
import { useHistory } from 'react-router';
import Add from '../components/Add';
import FileList from '../components/FileList';
diff --git a/webpack.config.ts b/webpack.config.ts
index e0d0cf3..0923e93 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -1,4 +1,4 @@
-import { Configuration } from 'webpack';
+import webpack, { Configuration } from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import SriPlugin from 'webpack-subresource-integrity';
import path from 'path';
@@ -46,9 +46,9 @@ const config: Configuration = {
minify: true,
template: path.join(__dirname, 'html.html'),
}),
- new OfflinePlugin({
+ ...(__DEV__ ? [] : [new OfflinePlugin({
events: true,
- }),
+ })]),
],
module: {
rules: [{
diff --git a/yarn.lock b/yarn.lock
index 822a28d..bd2e628 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1407,6 +1407,13 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==
+"@types/jszip@^3.4.1":
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/@types/jszip/-/jszip-3.4.1.tgz#e7a4059486e494c949ef750933d009684227846f"
+ integrity sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A==
+ dependencies:
+ jszip "*"
+
"@types/minimatch@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@@ -4498,6 +4505,11 @@ iferr@^0.1.5:
resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
+immediate@~3.0.5:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
+ integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
+
import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
@@ -5030,6 +5042,16 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
+jszip@*, jszip@^3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6"
+ integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==
+ dependencies:
+ lie "~3.3.0"
+ pako "~1.0.2"
+ readable-stream "~2.3.6"
+ set-immediate-shim "~1.0.1"
+
killable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -5079,6 +5101,13 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
+lie@~3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
+ integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
+ dependencies:
+ immediate "~3.0.5"
+
load-bmfont@^1.3.1, load-bmfont@^1.4.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9"
@@ -5854,7 +5883,7 @@ pako@^0.2.5:
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
-pako@^1.0.5, pako@~1.0.5:
+pako@^1.0.5, pako@~1.0.2, pako@~1.0.5:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@@ -7628,6 +7657,11 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+set-immediate-shim@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+ integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
+
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"