mirror of
https://github.com/morten-olsen/parcel.git
synced 2026-02-08 01:36:24 +01:00
update
This commit is contained in:
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
|
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
|
||||||
run: |
|
run: |
|
||||||
yarn install
|
yarn install
|
||||||
yarn build
|
NODE_ENV=production yarn build
|
||||||
|
|
||||||
- name: Deploy 🚀
|
- name: Deploy 🚀
|
||||||
uses: JamesIves/github-pages-deploy-action@3.5.9
|
uses: JamesIves/github-pages-deploy-action@3.5.9
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import AppRouter from './Router';
|
|||||||
const App: React.FC = () => (
|
const App: React.FC = () => (
|
||||||
<GithubProvider username="morten-olsen">
|
<GithubProvider username="morten-olsen">
|
||||||
<EncryptionProvider>
|
<EncryptionProvider>
|
||||||
<Layout>
|
<Layout style={{minHeight:"100vh"}}>
|
||||||
<Layout.Content style={{ padding: '25px' }}>
|
<Layout.Content style={{ padding: '25px', flex: 1 }}>
|
||||||
<AppRouter/>
|
<AppRouter/>
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
|
|
||||||
import Encrypt from './screens/Encrypt';
|
import Encrypt from './screens/Encrypt';
|
||||||
|
import Welcome from './screens/Welcome';
|
||||||
import Debug from './screens/Debug';
|
import Debug from './screens/Debug';
|
||||||
|
|
||||||
const AppRouter: React.FC = () => (
|
const AppRouter: React.FC = () => (
|
||||||
@@ -14,6 +15,9 @@ const AppRouter: React.FC = () => (
|
|||||||
<Route path="/debug">
|
<Route path="/debug">
|
||||||
<Debug />
|
<Debug />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route path="/welcome">
|
||||||
|
<Welcome />
|
||||||
|
</Route>
|
||||||
<Route path="/">
|
<Route path="/">
|
||||||
<Encrypt />
|
<Encrypt />
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -1,46 +1,22 @@
|
|||||||
import React, { Fragment, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Menu, Dropdown, Form } from 'antd';
|
import { Radio, Divider } from 'antd';
|
||||||
import { DownOutlined, FileOutlined, FileTextOutlined } from '@ant-design/icons';
|
import { FileOutlined, FileTextOutlined } from '@ant-design/icons';
|
||||||
import AddText from './AddText';
|
import AddText from './AddText';
|
||||||
import AddFile from './AddFile';
|
import AddFile from './AddFile';
|
||||||
|
|
||||||
const layout = {
|
const DEFAULT_VALUE = 'text';
|
||||||
labelCol: { span: 2 },
|
|
||||||
};
|
|
||||||
|
|
||||||
const Add: React.FC = () => {
|
const Add: React.FC = () => {
|
||||||
const [type, setType] = useState<'file' | 'text'>('text');
|
const [type, setType] = useState<'file' | 'text'>(DEFAULT_VALUE);
|
||||||
|
|
||||||
const menu = (
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => setType('file')}
|
|
||||||
active={type === 'file'}
|
|
||||||
icon={<FileOutlined />}
|
|
||||||
>
|
|
||||||
File
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => setType('text')}
|
|
||||||
active={type === 'text'}
|
|
||||||
icon={<FileTextOutlined />}
|
|
||||||
>
|
|
||||||
Text
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form {...layout}>
|
<Divider>
|
||||||
<Form.Item
|
<Radio.Group onChange={evt => setType(evt.target.value)} defaultValue={DEFAULT_VALUE}>
|
||||||
label="I want to encrypt a"
|
<Radio.Button value="text"><FileTextOutlined /> Text</Radio.Button>
|
||||||
>
|
<Radio.Button value="file"><FileOutlined /> File</Radio.Button>
|
||||||
<Dropdown overlay={menu}>
|
</Radio.Group>
|
||||||
<a>{type} <DownOutlined /></a>
|
</Divider>
|
||||||
</Dropdown>
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
{type === 'text' && <AddText />}
|
{type === 'text' && <AddText />}
|
||||||
{type === 'file' && <AddFile />}
|
{type === 'file' && <AddFile />}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import React, { useContext, useCallback } from 'react';
|
import React, { useContext, useCallback } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Layout } from 'antd';
|
import { Layout } from 'antd';
|
||||||
import { UploadOutlined } from '@ant-design/icons';
|
import { FileAddTwoTone } from '@ant-design/icons';
|
||||||
import { useDropzone } from 'react-dropzone';
|
import { useDropzone } from 'react-dropzone';
|
||||||
import EncryptionContext from '../contexts/Encryption';
|
import EncryptionContext from '../contexts/Encryption';
|
||||||
|
|
||||||
const Icon = styled(UploadOutlined)`
|
const Icon = styled(FileAddTwoTone)`
|
||||||
font-size: 100px;
|
font-size: 100px;
|
||||||
|
margin-bottom: 20px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DropWrapper = styled(Layout)`
|
const DropWrapper = styled(Layout)`
|
||||||
|
|||||||
@@ -3,14 +3,6 @@ import { Input, Form, Button } from 'antd';
|
|||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import EncryptionContext from '../contexts/Encryption';
|
import EncryptionContext from '../contexts/Encryption';
|
||||||
|
|
||||||
const layout = {
|
|
||||||
labelCol: { span: 2 },
|
|
||||||
};
|
|
||||||
|
|
||||||
const tailLayout = {
|
|
||||||
wrapperCol: { offset: 2 },
|
|
||||||
};
|
|
||||||
|
|
||||||
const AddText : React.FC = () => {
|
const AddText : React.FC = () => {
|
||||||
const { addText } = useContext(EncryptionContext);
|
const { addText } = useContext(EncryptionContext);
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
@@ -23,25 +15,23 @@ const AddText : React.FC = () => {
|
|||||||
}, [text, addText]);
|
}, [text, addText]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...layout}>
|
<Form>
|
||||||
<Form.Item
|
<Form.Item>
|
||||||
label="Name"
|
|
||||||
>
|
|
||||||
<Input
|
<Input
|
||||||
|
placeholder="Title"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={evt => setName(evt.target.value)}
|
onChange={evt => setName(evt.target.value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item>
|
||||||
label="Message"
|
|
||||||
>
|
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
|
placeholder="Your message here..."
|
||||||
value={text}
|
value={text}
|
||||||
rows={10}
|
rows={6}
|
||||||
onChange={evt => setText(evt.target.value)}
|
onChange={evt => setText(evt.target.value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item {...tailLayout}>
|
<Form.Item>
|
||||||
<Button
|
<Button
|
||||||
onClick={add}
|
onClick={add}
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import React, {useMemo} from 'react';
|
|||||||
import {
|
import {
|
||||||
List,
|
List,
|
||||||
Button,
|
Button,
|
||||||
|
Tooltip,
|
||||||
|
Popconfirm,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
@@ -46,12 +48,12 @@ const share = async (file: FileType, fileData: File[]) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const IconText = ({ icon, text, ...props }) => (
|
const IconText = ({ icon, text, ...props }) => (
|
||||||
|
<Tooltip title={text}>
|
||||||
<Button
|
<Button
|
||||||
{...props}
|
{...props}
|
||||||
icon={React.createElement(icon)}
|
icon={React.createElement(icon)}
|
||||||
>
|
/>
|
||||||
{text}
|
</Tooltip>
|
||||||
</Button>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const FileView: React.FC<Props> = ({
|
const FileView: React.FC<Props> = ({
|
||||||
@@ -67,12 +69,18 @@ const FileView: React.FC<Props> = ({
|
|||||||
|
|
||||||
if (file.link) {
|
if (file.link) {
|
||||||
actions.push(
|
actions.push(
|
||||||
|
<Popconfirm
|
||||||
|
title="Are you sure delete this file?"
|
||||||
|
onConfirm={remove}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
<IconText
|
<IconText
|
||||||
icon={DeleteOutlined}
|
icon={DeleteOutlined}
|
||||||
danger
|
danger
|
||||||
text="Delete"
|
text="Delete"
|
||||||
onClick={remove}
|
|
||||||
/>
|
/>
|
||||||
|
</Popconfirm>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ const EncryptionProvider: React.FC = ({
|
|||||||
|
|
||||||
const add = (name: string) => {
|
const add = (name: string) => {
|
||||||
const id = nanoid();
|
const id = nanoid();
|
||||||
message.info(`Beginning to encrypt ${name}`);
|
|
||||||
const file: FileType = {
|
const file: FileType = {
|
||||||
name: `${name}.asc`,
|
name: `${name}.asc`,
|
||||||
reciever: username,
|
reciever: username,
|
||||||
|
|||||||
@@ -4,5 +4,6 @@ import { render } from 'react-dom';
|
|||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
|
root.style.height = '100%';
|
||||||
document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
render(<App />, root);
|
render(<App />, root);
|
||||||
|
|||||||
@@ -1,32 +1,28 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
import { Collapse, Badge } from 'antd';
|
import { Divider, PageHeader } from 'antd';
|
||||||
import Profile from '../components/Profile';
|
import { useHistory } from 'react-router';
|
||||||
import Add from '../components/Add';
|
import Add from '../components/Add';
|
||||||
import FileList from '../components/FileList';
|
import FileList from '../components/FileList';
|
||||||
import EncryptionContext from '../contexts/Encryption';
|
import EncryptionContext from '../contexts/Encryption';
|
||||||
|
|
||||||
const Encrypt: React.FC = () => {
|
const Encrypt: React.FC = () => {
|
||||||
|
const history = useHistory();
|
||||||
const { files } = useContext(EncryptionContext);
|
const { files } = useContext(EncryptionContext);
|
||||||
|
useEffect(() => {
|
||||||
|
if (localStorage.getItem('welcome') !== 'seen') {
|
||||||
|
history.replace('/welcome');
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Collapse ghost defaultActiveKey={[2, 3]}>
|
|
||||||
<Collapse.Panel key={2} header="Encrypt">
|
|
||||||
<Add />
|
<Add />
|
||||||
</Collapse.Panel>
|
{Object.keys(files).length > 0 && (
|
||||||
<Collapse.Panel
|
<>
|
||||||
key={3}
|
<Divider>Files</Divider>
|
||||||
header={(
|
|
||||||
<Badge count={Object.keys(files).length} offset={[20, 7]}>
|
|
||||||
Files
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<FileList />
|
<FileList />
|
||||||
</Collapse.Panel>
|
</>
|
||||||
<Collapse.Panel key={1} header="Profile">
|
)}
|
||||||
<Profile />
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
54
src/screens/Welcome.tsx
Normal file
54
src/screens/Welcome.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { Space, Layout, Button, Typography, notification } from 'antd';
|
||||||
|
import { AlignLeftOutlined, EyeInvisibleTwoTone, ArrowRightOutlined } from '@ant-design/icons';
|
||||||
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
|
const openNotification = () => {
|
||||||
|
notification.warn({
|
||||||
|
message: 'Slow down!',
|
||||||
|
description: 'I am still working on this, but thanks for the interrest.'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const Welcome: React.FC = () => {
|
||||||
|
const history = useHistory();
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem('welcome', 'seen');
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout style={{ maxWidth: 800, margin: 'auto', textAlign: 'center' }}>
|
||||||
|
<Space direction="vertical">
|
||||||
|
<EyeInvisibleTwoTone style={{ fontSize: 200 }} />
|
||||||
|
<Typography.Title level={1}>Protect before sending</Typography.Title>
|
||||||
|
<p>
|
||||||
|
The internet can seem like a scary place, especially if you want to send sensitiv information across it.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The truth is that a lot of systems, including e-mails, was not build for the internet that we have today.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This is why it is so important to make sure your documents are well protected before sharing.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This tool can be used to protect information before sharing them with me. The documents will be encrypted so that only I can ever unlock them, so no snoppy man in the middle...
|
||||||
|
</p>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<ArrowRightOutlined />}
|
||||||
|
onClick={() => history.push('/')}
|
||||||
|
>
|
||||||
|
Start protecting!
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
icon={<AlignLeftOutlined />}
|
||||||
|
onClick={openNotification}
|
||||||
|
>
|
||||||
|
Read all the technical stuff
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Welcome;
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
import webpack, { Configuration } from 'webpack';
|
import { Configuration } from 'webpack';
|
||||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
const __DEV__ = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
const config: Configuration = {
|
const config: Configuration = {
|
||||||
mode: 'development',
|
mode: __DEV__ ? 'development' : 'production',
|
||||||
entry: {
|
entry: {
|
||||||
app: [
|
app: [
|
||||||
'react-hot-loader/patch',
|
...(__DEV__ ? ['react-hot-loader/patch'] : []),
|
||||||
path.join(__dirname, 'src', 'index.tsx'),
|
path.join(__dirname, 'src', 'index.tsx'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -20,7 +22,10 @@ const config: Configuration = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new HtmlWebpackPlugin(),
|
new HtmlWebpackPlugin({
|
||||||
|
title: 'Parcel',
|
||||||
|
minify: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [{
|
rules: [{
|
||||||
|
|||||||
Reference in New Issue
Block a user