Skip to content

Commit bde741c

Browse files
committed
feat: new apps
1 parent 859f9d9 commit bde741c

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed

src/pages/apps/UrlConverterPage.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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 UrlConverterPage() {
9+
usePageTitle('URL Encoder/Decoder');
10+
const [inputText, setInputText] = useState('');
11+
const [outputText, setOutputText] = useState('');
12+
const { addToast } = useToast();
13+
14+
const encodeUrl = () => {
15+
try {
16+
setOutputText(encodeURIComponent(inputText));
17+
} catch (error) {
18+
addToast({
19+
title: 'Error',
20+
message: 'Failed to encode URL.',
21+
duration: 3000,
22+
});
23+
setOutputText('');
24+
}
25+
};
26+
27+
const decodeUrl = () => {
28+
try {
29+
setOutputText(decodeURIComponent(inputText));
30+
} catch (error) {
31+
addToast({
32+
title: 'Error',
33+
message: 'Failed to decode URL. Invalid URL 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">url</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>
96+
<div className="relative z-10 p-1">
97+
<div className="mb-4">
98+
<label className="block text-lg font-semibold mb-2" style={{ color: cardStyle.color }}>Input Text</label>
99+
<textarea
100+
className="w-full h-32 p-4 bg-gray-900/50 font-mono resize-y border rounded-md focus:ring-0"
101+
style={{ borderColor: cardStyle.borderColor, color: detailTextColor }}
102+
value={inputText}
103+
onChange={(e) => setInputText(e.target.value)}
104+
placeholder="Enter URL or text to encode/decode..."
105+
/>
106+
</div>
107+
<div className="flex justify-center gap-4 mb-4">
108+
<button
109+
onClick={encodeUrl}
110+
className="px-6 py-2 rounded-md text-lg font-semibold transition-colors duration-300 ease-in-out"
111+
style={{
112+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
113+
color: cardStyle.color,
114+
borderColor: cardStyle.borderColor,
115+
border: '1px solid',
116+
'--hover-bg-color': colors['app-alpha-50'],
117+
}}
118+
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--hover-bg-color)'}
119+
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.2)'}
120+
>
121+
Encode URL
122+
</button>
123+
<button
124+
onClick={decodeUrl}
125+
className="px-6 py-2 rounded-md text-lg font-semibold transition-colors duration-300 ease-in-out"
126+
style={{
127+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
128+
color: cardStyle.color,
129+
borderColor: cardStyle.borderColor,
130+
border: '1px solid',
131+
'--hover-bg-color': colors['app-alpha-50'],
132+
}}
133+
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = 'var(--hover-bg-color)'}
134+
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.2)'}
135+
>
136+
Decode URL
137+
</button>
138+
</div>
139+
<div>
140+
<label className="block text-lg font-semibold mb-2" style={{ color: cardStyle.color }}>Output Text</label>
141+
<div className="relative">
142+
<textarea
143+
readOnly
144+
className="w-full h-32 p-4 bg-gray-800/50 font-mono resize-y border rounded-md"
145+
style={{ borderColor: cardStyle.borderColor, color: detailTextColor }}
146+
value={outputText}
147+
placeholder="Converted text will appear here..."
148+
/>
149+
<button
150+
onClick={() => copyToClipboard(outputText)}
151+
className="absolute top-2 right-2 px-3 py-1 bg-gray-700 text-white text-sm rounded hover:bg-gray-600"
152+
>
153+
Copy
154+
</button>
155+
</div>
156+
</div>
157+
</div>
158+
</div>
159+
</div>
160+
</div>
161+
</div>
162+
);
163+
}
164+
165+
export default UrlConverterPage;

0 commit comments

Comments
 (0)