Skip to content

Commit e00fb62

Browse files
committed
feat: new apps
1 parent 4ea6274 commit e00fb62

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import React, { useState } from 'react';
2+
import { Link } from 'react-router-dom';
3+
import { ArrowLeftIcon } from '@phosphor-icons/react';
4+
import colors from '../../config/colors';
5+
import usePageTitle from '../../utils/usePageTitle';
6+
import { useToast } from '../../hooks/useToast';
7+
8+
function Base64ConverterPage() {
9+
usePageTitle('Base64 Converter');
10+
const [inputText, setInputText] = useState('');
11+
const [outputText, setOutputText] = useState('');
12+
const { addToast } = useToast();
13+
14+
const encodeBase64 = () => {
15+
try {
16+
setOutputText(btoa(inputText));
17+
} catch (error) {
18+
addToast({
19+
title: 'Error',
20+
message: 'Failed to encode Base64. Invalid characters.',
21+
duration: 3000,
22+
});
23+
setOutputText('');
24+
}
25+
};
26+
27+
const decodeBase64 = () => {
28+
try {
29+
setOutputText(atob(inputText));
30+
} catch (error) {
31+
addToast({
32+
title: 'Error',
33+
message: 'Failed to decode Base64. Invalid Base64 string.',
34+
duration: 3000,
35+
});
36+
setOutputText('');
37+
}
38+
};
39+
40+
const copyToClipboard = (text) => {
41+
navigator.clipboard.writeText(text)
42+
.then(() => {
43+
addToast({
44+
title: 'Success',
45+
message: 'Copied to clipboard!',
46+
duration: 2000,
47+
});
48+
})
49+
.catch(() => {
50+
addToast({
51+
title: 'Error',
52+
message: 'Failed to copy!',
53+
duration: 2000,
54+
});
55+
});
56+
};
57+
58+
const cardStyle = {
59+
backgroundColor: colors['app-alpha-10'],
60+
borderColor: colors['app-alpha-50'],
61+
color: colors.app,
62+
};
63+
64+
const detailTextColor = colors['app-light'];
65+
66+
return (
67+
<div className="py-16 sm:py-24">
68+
<div className="mx-auto max-w-7xl px-6 lg:px-8 text-gray-300">
69+
<Link
70+
to="/apps"
71+
className="text-article hover:underline flex items-center justify-center gap-2 text-lg mb-4"
72+
>
73+
<ArrowLeftIcon size={24} /> Back to Apps
74+
</Link>
75+
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl mb-4 flex items-center">
76+
<span className="codex-color">fc</span>
77+
<span className="separator-color">::</span>
78+
<span className="apps-color">apps</span>
79+
<span className="separator-color">::</span>
80+
<span className="single-app-color">b64</span>
81+
</h1>
82+
<hr className="border-gray-700" />
83+
<div className="flex justify-center items-center mt-16">
84+
<div
85+
className="group bg-transparent border rounded-lg shadow-2xl p-6 flex flex-col justify-between relative transform transition-all duration-300 ease-in-out scale-105 overflow-hidden h-full w-full max-w-4xl"
86+
style={cardStyle}
87+
>
88+
<div
89+
className="absolute top-0 left-0 w-full h-full opacity-10"
90+
style={{
91+
backgroundImage:
92+
'radial-gradient(circle, white 1px, transparent 1px)',
93+
backgroundSize: '10px 10px',
94+
}}
95+
></div> <div className="relative z-10 p-1">
96+
<div className="mb-4">
97+
<label className="block text-lg font-semibold mb-2" style={{ color: cardStyle.color }}>Input Text</label>
98+
<textarea
99+
className="w-full h-32 p-4 bg-gray-900/50 font-mono resize-y border rounded-md focus:ring-0"
100+
style={{ borderColor: cardStyle.borderColor, color: detailTextColor }}
101+
value={inputText}
102+
onChange={(e) => setInputText(e.target.value)}
103+
placeholder="Enter text to encode or decode..."
104+
/>
105+
</div>
106+
<div className="flex justify-center gap-4 mb-4">
107+
<button
108+
onClick={encodeBase64}
109+
className="px-6 py-2 rounded-md text-lg font-arvo font-normal transition-colors duration-300 ease-in-out"
110+
style={{
111+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
112+
color: cardStyle.color,
113+
borderColor: cardStyle.borderColor,
114+
border: '1px solid',
115+
'--hover-bg-color': colors['app-alpha-50'],
116+
}}
117+
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--hover-bg-color)'}
118+
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.2)'}
119+
>
120+
Encode Base64
121+
</button>
122+
<button
123+
onClick={decodeBase64}
124+
className="px-6 py-2 rounded-md text-lg font-arvo font-normal transition-colors duration-300 ease-in-out"
125+
style={{
126+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
127+
color: cardStyle.color,
128+
borderColor: cardStyle.borderColor,
129+
border: '1px solid',
130+
'--hover-bg-color': colors['app-alpha-50'],
131+
}}
132+
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--hover-bg-color)'}
133+
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.2)'}
134+
>
135+
Decode Base64
136+
</button>
137+
</div>
138+
<div>
139+
<label className="block text-lg font-semibold mb-2" style={{ color: cardStyle.color }}>Output Text</label>
140+
<div className="relative">
141+
<textarea
142+
readOnly
143+
className="w-full h-32 p-4 bg-gray-800/50 font-mono resize-y border rounded-md"
144+
style={{ borderColor: cardStyle.borderColor, color: detailTextColor }}
145+
value={outputText}
146+
placeholder="Converted text will appear here..."
147+
/>
148+
<button
149+
onClick={() => copyToClipboard(outputText)}
150+
className="absolute top-2 right-2 px-3 py-1 bg-gray-700 text-white text-sm rounded hover:bg-gray-600"
151+
>
152+
Copy
153+
</button>
154+
</div>
155+
</div>
156+
</div>
157+
</div>
158+
</div>
159+
</div>
160+
</div>
161+
);
162+
}
163+
164+
export default Base64ConverterPage;

0 commit comments

Comments
 (0)