Skip to content

Commit 0e0d10a

Browse files
authored
Merge pull request #2 from plainbelt/base64
Base64
2 parents 5235799 + fac0ed6 commit 0e0d10a

File tree

8 files changed

+196
-34
lines changed

8 files changed

+196
-34
lines changed

src/components/Main.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MarkdownToHtml from './md-to-html/MarkdownToHtml';
55
import UnixTimestamp from './unix-timestamp/UnixTimestamp';
66
import HtmlPreview from './html-preview/HtmlPreview';
77
import QrCode from './qrcode/QrCode';
8+
import Base64 from './base64/Base64';
89

910
const Main = () => {
1011
const routes = [
@@ -32,13 +33,19 @@ const Main = () => {
3233
name: 'QRCode Generator',
3334
Component: QrCode,
3435
},
36+
{
37+
icon: <FontAwesomeIcon icon="code" />,
38+
path: '/base64',
39+
name: 'Base64 Encoder',
40+
Component: Base64,
41+
},
3542
];
3643

3744
return (
3845
<div className="absolute inset-0 flex flex-col overflow-hidden">
3946
<main className="relative flex flex-1 min-h-0">
4047
{/* Left sidebar */}
41-
<nav className="flex flex-col w-1/4 overflow-x-hidden overflow-y-auto bg-gray-200">
48+
<nav className="flex flex-col w-1/4 overflow-x-hidden overflow-y-auto bg-gray-300">
4249
<div
4350
className="px-2 my-6"
4451
role="menu"
@@ -60,7 +67,7 @@ const Main = () => {
6067
</nav>
6168

6269
{/* Main content */}
63-
<section className="relative flex flex-col w-full bg-gray-100">
70+
<section className="relative flex flex-col w-full bg-gray-200">
6471
<div className="h-full overflow-x-hidden overflow-y-auto px-6 my-6">
6572
{routes.map(({ path, Component }) => (
6673
<Route key={path} exact path={path}>

src/components/base64/Base64.tsx

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { ipcRenderer, clipboard } from 'electron';
3+
4+
const Base64 = () => {
5+
const [input, setInput] = useState('Raw data');
6+
const [encode, setEncode] = useState(true);
7+
const [string, setString] = useState(true);
8+
const [output, setOutput] = useState(btoa('Raw data'));
9+
const [opening, setOpening] = useState(false);
10+
const [copied, setCopied] = useState(false);
11+
12+
const handleChangeInput = (evt: { target: { value: string } }) =>
13+
setInput(evt.target.value);
14+
15+
const handleOpenInput = async () => {
16+
setOpening(true);
17+
const content = await ipcRenderer.invoke('open-file', []);
18+
if (string) {
19+
setInput(Buffer.from(content).toString());
20+
} else {
21+
setInput(content);
22+
}
23+
setOpening(false);
24+
};
25+
26+
const handleClipboardInput = () => {
27+
setInput(clipboard.readText());
28+
};
29+
30+
const handleCopyOutput = () => {
31+
setCopied(true);
32+
clipboard.write({ text: output });
33+
setTimeout(() => setCopied(false), 500);
34+
};
35+
36+
useEffect(() => {
37+
try {
38+
if (encode) {
39+
setOutput(Buffer.from(input).toString('base64'));
40+
} else {
41+
setOutput(Buffer.from(input, 'base64').toString());
42+
}
43+
} catch (e) {
44+
setOutput(e.message);
45+
}
46+
}, [input, encode]);
47+
48+
return (
49+
<div className="min-h-full flex flex-col">
50+
<div className="flex justify-between mb-1">
51+
<span className="flex space-x-2">
52+
<button type="button" className="btn" onClick={handleClipboardInput}>
53+
Clipboard
54+
</button>
55+
<button
56+
type="button"
57+
className="btn"
58+
onClick={handleOpenInput}
59+
disabled={opening}
60+
>
61+
Open...
62+
</button>
63+
<div className="flex space-x-2 items-center">
64+
<label htmlFor="string" className="flex items-center space-x-1">
65+
<input
66+
type="radio"
67+
className="btn"
68+
name="string"
69+
id="string"
70+
checked={string}
71+
onChange={() => setString(true)}
72+
/>
73+
<p>Text</p>
74+
</label>
75+
<label htmlFor="raw" className="flex items-center space-x-1">
76+
<input
77+
type="radio"
78+
className="btn"
79+
name="string"
80+
id="raw"
81+
checked={!string}
82+
onChange={() => setString(false)}
83+
/>
84+
<p>Binary</p>
85+
</label>
86+
</div>
87+
</span>
88+
<span className="flex space-x-4">
89+
<div className="flex space-x-4 items-center">
90+
<label htmlFor="encoder" className="flex items-center space-x-1">
91+
<input
92+
type="radio"
93+
className="btn"
94+
name="encode"
95+
id="encoder"
96+
checked={encode}
97+
onChange={() => setEncode(true)}
98+
/>
99+
<p>Encode</p>
100+
</label>
101+
<label htmlFor="decoder" className="flex items-center space-x-1">
102+
<input
103+
type="radio"
104+
className="btn"
105+
name="encode"
106+
id="decoder"
107+
checked={!encode}
108+
onChange={() => setEncode(false)}
109+
/>
110+
<p>Decode</p>
111+
</label>
112+
</div>
113+
<button
114+
type="button"
115+
className="btn"
116+
onClick={handleCopyOutput}
117+
disabled={copied}
118+
>
119+
{copied ? 'Copied' : 'Copy'}
120+
</button>
121+
</span>
122+
</div>
123+
<div className="flex min-h-full flex-1">
124+
<textarea
125+
onChange={handleChangeInput}
126+
className="flex-1 min-h-full bg-white p-4 rounded-md"
127+
value={input}
128+
disabled={opening}
129+
/>
130+
<div className="mx-1" />
131+
<textarea
132+
className="flex-1 min-h-full bg-gray-100 p-4 rounded-md"
133+
value={output}
134+
readOnly
135+
/>
136+
</div>
137+
</div>
138+
);
139+
};
140+
141+
export default Base64;

src/components/html-preview/HtmlPreview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const HtmlPreview = () => {
1515
setOpening(true);
1616
const filters = [{ name: 'HTML Files', extensions: ['htm', 'html'] }];
1717
const content = await ipcRenderer.invoke('open-file', filters);
18-
setHtml(content);
18+
setHtml(Buffer.from(content).toString());
1919
setOpening(false);
2020
};
2121

@@ -47,7 +47,7 @@ const HtmlPreview = () => {
4747
/>
4848
<div className="mx-1" />
4949
<section
50-
className="flex-1 min-h-full bg-blue-50 p-4 prose rounded-md"
50+
className="flex-1 min-h-full bg-gray-100 p-4 prose rounded-md"
5151
dangerouslySetInnerHTML={{ __html: html }}
5252
/>
5353
</div>

src/components/md-to-html/MarkdownToHtml.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const Md2Html = () => {
77
const [md, setMd] = useState('# Hello\n> This is a quote');
88
const [preview, setPreview] = useState(true);
99
const [opening, setOpening] = useState(false);
10+
const [copied, setCopied] = useState(false);
1011

1112
const handleChange = (evt: { target: { value: string } }) =>
1213
setMd(evt.target.value);
@@ -17,7 +18,7 @@ const Md2Html = () => {
1718
{ name: 'Markdown Files', extensions: ['md', 'markdown', 'txt'] },
1819
];
1920
const content = await ipcRenderer.invoke('open-file', filters);
20-
setMd(content);
21+
setMd(Buffer.from(content).toString());
2122
setOpening(false);
2223
};
2324

@@ -26,7 +27,9 @@ const Md2Html = () => {
2627
};
2728

2829
const handleCopy = () => {
30+
setCopied(true);
2931
clipboard.write({ text: marked(md) });
32+
setTimeout(() => setCopied(false), 500);
3033
};
3134

3235
return (
@@ -53,8 +56,13 @@ const Md2Html = () => {
5356
>
5457
{preview ? 'Raw HTML' : 'Preview'}
5558
</button>
56-
<button type="button" className="btn" onClick={handleCopy}>
57-
Copy
59+
<button
60+
type="button"
61+
className="btn"
62+
onClick={handleCopy}
63+
disabled={copied}
64+
>
65+
{copied ? 'Copied' : 'Copy'}
5866
</button>
5967
</span>
6068
</div>
@@ -68,14 +76,14 @@ const Md2Html = () => {
6876
<div className="mx-1" />
6977
{preview ? (
7078
<section
71-
className="flex-1 min-h-full bg-blue-50 p-4 prose w-full rounded-md"
79+
className="flex-1 min-h-full bg-gray-100 p-4 prose w-full rounded-md"
7280
dangerouslySetInnerHTML={{ __html: marked(md) }}
7381
/>
7482
) : (
7583
<textarea
76-
className="flex-1 min-h-full bg-blue-100 p-4 rounded-md"
84+
className="flex-1 min-h-full bg-gray-100 p-4 rounded-md"
7785
value={marked(md)}
78-
disabled
86+
readOnly
7987
/>
8088
)}
8189
</div>

src/components/qrcode/QrCode.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const HtmlPreview = () => {
2727
setOpening(true);
2828
const filters = [{ name: 'Text Files', extensions: ['txt'] }];
2929
const data = await ipcRenderer.invoke('open-file', filters);
30-
setContent(data);
30+
setContent(Buffer.from(data).toString());
3131
setOpening(false);
3232
};
3333

@@ -77,7 +77,7 @@ const HtmlPreview = () => {
7777
value={content}
7878
/>
7979
<div className="mx-1" />
80-
<section className="flex-1 min-h-full flex items-center p-4 prose bg-white rounded-md">
80+
<section className="flex-1 min-h-full flex items-center p-4 prose bg-gray-100 rounded-md">
8181
{qrCode && <img src={qrCode} alt={content} />}
8282
</section>
8383
</div>

src/components/unix-timestamp/UnixTimestamp.tsx

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const UnixTimestampConverter = () => {
3939
const handleCopy = () => {
4040
clipboard.write({ text: `${date.unix()}` });
4141
setCopied(true);
42-
setTimeout(() => setCopied(false), 1_000);
42+
setTimeout(() => setCopied(false), 500);
4343
};
4444

4545
const handleChangeEpoch = (evt: { target: { value: string } }) => {
@@ -64,23 +64,7 @@ const UnixTimestampConverter = () => {
6464

6565
return (
6666
<div className="min-h-full flex flex-col">
67-
<section className="mb-4 space-y-1 flex items-center space-x-2 border-b pb-4">
68-
<p>The current Unix epoch time is</p>
69-
<span className="text-base bg-blue-200 px-2 py-1 rounded font-mono">
70-
{date.unix()}
71-
</span>
72-
<button
73-
type="button"
74-
className="btn"
75-
onClick={handleCopy}
76-
disabled={copied}
77-
>
78-
Copy
79-
</button>
80-
</section>
81-
8267
<section className="flex justify-start space-x-2 mb-4">
83-
<p>Input:</p>
8468
<button type="button" className="btn" onClick={handleClipboard}>
8569
Clipboard
8670
</button>
@@ -120,7 +104,7 @@ const UnixTimestampConverter = () => {
120104
</label>
121105
</section>
122106

123-
<section className="flex flex-col space-y-4 w-full p-4 pb-8 rounded-md bg-gray-200 border">
107+
<section className="flex flex-col space-y-4 w-full p-4 pb-8 rounded-md shadow-sm bg-gray-100 border mb-4">
124108
<section className="flex items-center justify-between space-x-4">
125109
<label htmlFor="local" className="flex-1">
126110
<span>Local:</span>
@@ -188,6 +172,20 @@ const UnixTimestampConverter = () => {
188172
</label>
189173
</section>
190174
</section>
175+
<section className="pt-4 space-y-1 flex items-center space-x-2 pb-4">
176+
<p>The current Unix epoch time is</p>
177+
<span className="bg-gray-100 border shadow-sm px-2 py-0.5 rounded-md font-mono">
178+
{date.unix()}
179+
</span>
180+
<button
181+
type="button"
182+
className="btn"
183+
onClick={handleCopy}
184+
disabled={copied}
185+
>
186+
{copied ? 'Copied' : 'Copy'}
187+
</button>
188+
</section>
191189
</div>
192190
);
193191
};

src/helpers/fontAwesome.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { library } from '@fortawesome/fontawesome-svg-core';
22
import { fab, faMarkdown, faHtml5 } from '@fortawesome/free-brands-svg-icons';
3-
import { faClock, faCopy, faQrcode } from '@fortawesome/free-solid-svg-icons';
3+
import {
4+
faClock,
5+
faCode,
6+
faCopy,
7+
faQrcode,
8+
} from '@fortawesome/free-solid-svg-icons';
49

5-
library.add(fab, faMarkdown, faClock, faHtml5, faQrcode, faCopy);
10+
library.add(fab, faMarkdown, faClock, faHtml5, faQrcode, faCopy, faCode);

src/main.dev.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ const createWindow = async () => {
118118
/**
119119
* Handlers events from React
120120
*/
121+
122+
// This method return a Buffer, if you want to convert to string
123+
// use Buffer.from(buffer).toString()
121124
ipcMain.handle(
122125
'open-file',
123126
async (_event: IpcMainInvokeEvent, filters: FileFilter[]) => {
@@ -126,10 +129,10 @@ ipcMain.handle(
126129
filters,
127130
});
128131

129-
let content = '';
132+
let content;
130133
if (files) {
131134
const buffer = await promisify(fs.readFile)(files.filePaths[0]);
132-
content = buffer.toString();
135+
content = buffer;
133136
}
134137
return content;
135138
}

0 commit comments

Comments
 (0)