Skip to content

Commit 368dde7

Browse files
committed
feat: enhance frontend layout and styling for image upload
- Update the main page layout with a gradient background and improved header section - Add a GitHub link with an icon for project visibility - Refactor the UploadZone component for better styling and user experience - Introduce a backdrop blur utility class in CSS for enhanced visual effects - Update 404 and index HTML files to reflect new styles and scripts This commit improves the overall user interface and experience for the Discord image upload application.
1 parent 3846bcb commit 368dde7

File tree

13 files changed

+167
-103
lines changed

13 files changed

+167
-103
lines changed

frontend/src/app/globals.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,10 @@
5656
body {
5757
@apply bg-background text-foreground;
5858
}
59+
}
60+
61+
@layer utilities {
62+
.backdrop-blur-sm {
63+
backdrop-filter: blur(4px);
64+
}
5965
}

frontend/src/app/page.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,32 @@ import UploadZone from "@/components/upload-zone";
22

33
export default function Home() {
44
return (
5-
<div className="min-h-screen bg-background flex items-center justify-center p-4">
6-
<UploadZone />
5+
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-gray-100 dark:from-gray-900 dark:to-slate-800">
6+
<div className="container mx-auto px-4 py-8 min-h-screen flex flex-col">
7+
<header className="text-center mb-8">
8+
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-2">
9+
Discord Image
10+
</h1>
11+
<p className="text-lg text-gray-600 dark:text-gray-300 mb-4">
12+
Fast, secure image hosting for Discord
13+
</p>
14+
<a
15+
href="https://github.com/missuo/discord-image"
16+
target="_blank"
17+
rel="noopener noreferrer"
18+
className="inline-flex items-center gap-2 text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 transition-colors"
19+
>
20+
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
21+
<path fillRule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clipRule="evenodd"/>
22+
</svg>
23+
View on GitHub
24+
</a>
25+
</header>
26+
27+
<main className="flex-1 flex items-center justify-center">
28+
<UploadZone />
29+
</main>
30+
</div>
731
</div>
832
);
933
}

frontend/src/components/upload-zone.tsx

Lines changed: 125 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Button } from "@/components/ui/button";
55
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
66
import { Input } from "@/components/ui/input";
77
import { toast } from "@/hooks/use-toast";
8-
import { Upload, Image, Copy, Link } from "lucide-react";
8+
import { Upload, Copy, Link } from "lucide-react";
99

1010
interface UploadResult {
1111
url: string;
@@ -146,45 +146,60 @@ export default function UploadZone() {
146146
}, [handlePaste]);
147147

148148
return (
149-
<div className="w-full max-w-2xl mx-auto p-4">
150-
<Card className="mb-6">
151-
<CardHeader>
152-
<CardTitle className="flex items-center gap-2">
153-
<Image className="w-6 h-6" />
154-
Discord Image Upload
155-
</CardTitle>
156-
<CardDescription>
157-
Upload your images to Discord. Supports drag & drop and clipboard paste.
158-
</CardDescription>
159-
</CardHeader>
160-
<CardContent>
149+
<div className="w-full max-w-4xl mx-auto">
150+
<Card className="mb-6 shadow-lg border-0 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm">
151+
<CardContent className="p-8">
161152
<div
162-
className={`border-2 border-dashed rounded-lg p-8 text-center transition-colors ${
153+
className={`border-2 border-dashed rounded-xl p-12 text-center transition-all duration-300 ${
163154
isDragging
164-
? "border-primary bg-primary/10"
165-
: "border-muted-foreground/25 hover:border-muted-foreground/50"
155+
? "border-blue-500 bg-blue-50/50 dark:bg-blue-900/20 scale-105"
156+
: "border-gray-300 dark:border-gray-600 hover:border-blue-400 dark:hover:border-blue-500 hover:bg-gray-50/50 dark:hover:bg-gray-700/50"
166157
}`}
167158
onDragOver={handleDragOver}
168159
onDragLeave={handleDragLeave}
169160
onDrop={handleDrop}
170161
>
171-
<Upload className="w-12 h-12 mx-auto mb-4 text-muted-foreground" />
172-
<p className="text-lg mb-2">
173-
{isDragging ? "Drop your image here" : "Drag & drop an image here"}
174-
</p>
175-
<p className="text-sm text-muted-foreground mb-4">
176-
or click to browse files (max 25MB)
177-
</p>
178-
<p className="text-sm text-muted-foreground mb-4">
179-
You can also paste images from clipboard (Ctrl/Cmd + V)
180-
</p>
181-
<Button
182-
onClick={() => fileInputRef.current?.click()}
183-
disabled={uploading}
184-
size="lg"
185-
>
186-
{uploading ? "Uploading..." : "Select Image"}
187-
</Button>
162+
<div className="flex flex-col items-center">
163+
<div className={`p-4 rounded-full mb-6 transition-all duration-300 ${
164+
isDragging
165+
? "bg-blue-100 dark:bg-blue-900/40"
166+
: "bg-gray-100 dark:bg-gray-700"
167+
}`}>
168+
<Upload className={`w-12 h-12 transition-colors ${
169+
isDragging
170+
? "text-blue-600 dark:text-blue-400"
171+
: "text-gray-400 dark:text-gray-500"
172+
}`} />
173+
</div>
174+
175+
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">
176+
{isDragging ? "Drop your image here" : "Upload your image"}
177+
</h3>
178+
179+
<p className="text-gray-600 dark:text-gray-300 mb-6 max-w-md">
180+
Drag & drop, browse files, or paste from clipboard
181+
</p>
182+
183+
<div className="flex flex-col sm:flex-row gap-4 items-center">
184+
<Button
185+
onClick={() => fileInputRef.current?.click()}
186+
disabled={uploading}
187+
size="lg"
188+
className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 text-lg font-medium transition-all duration-200"
189+
>
190+
{uploading ? "Uploading..." : "Browse Files"}
191+
</Button>
192+
193+
<div className="text-sm text-gray-500 dark:text-gray-400">
194+
or press <kbd className="px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded text-xs font-mono">Ctrl+V</kbd>
195+
</div>
196+
</div>
197+
198+
<div className="mt-6 text-xs text-gray-500 dark:text-gray-400">
199+
Maximum file size: 25MB • Supported formats: PNG, JPG, GIF, WebP
200+
</div>
201+
</div>
202+
188203
<Input
189204
ref={fileInputRef}
190205
type="file"
@@ -197,69 +212,88 @@ export default function UploadZone() {
197212
</Card>
198213

199214
{uploadResult && linkFormats && (
200-
<Card>
201-
<CardHeader>
202-
<CardTitle className="flex items-center gap-2">
203-
<Link className="w-5 h-5" />
215+
<Card className="shadow-lg border-0 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm">
216+
<CardHeader className="pb-4">
217+
<CardTitle className="flex items-center gap-3 text-xl">
218+
<div className="p-2 bg-green-100 dark:bg-green-900/40 rounded-lg">
219+
<Link className="w-5 h-5 text-green-600 dark:text-green-400" />
220+
</div>
204221
Upload Complete
205222
</CardTitle>
206-
<CardDescription>
207-
Your image has been uploaded. Copy the links below:
223+
<CardDescription className="text-base">
224+
Your image has been uploaded successfully. Choose your preferred format:
208225
</CardDescription>
209226
</CardHeader>
210-
<CardContent className="space-y-4">
211-
<div className="flex items-center gap-2">
212-
<label className="text-sm font-medium min-w-[80px]">Direct URL:</label>
213-
<Input
214-
readOnly
215-
value={linkFormats.direct}
216-
className="flex-1"
217-
/>
218-
<Button
219-
variant="outline"
220-
size="sm"
221-
onClick={() => copyToClipboard(linkFormats.direct, "Direct URL")}
222-
>
223-
<Copy className="w-4 h-4" />
224-
</Button>
225-
</div>
226-
<div className="flex items-center gap-2">
227-
<label className="text-sm font-medium min-w-[80px]">Markdown:</label>
228-
<Input
229-
readOnly
230-
value={linkFormats.markdown}
231-
className="flex-1"
232-
/>
233-
<Button
234-
variant="outline"
235-
size="sm"
236-
onClick={() => copyToClipboard(linkFormats.markdown, "Markdown")}
237-
>
238-
<Copy className="w-4 h-4" />
239-
</Button>
240-
</div>
241-
<div className="flex items-center gap-2">
242-
<label className="text-sm font-medium min-w-[80px]">HTML:</label>
243-
<Input
244-
readOnly
245-
value={linkFormats.html}
246-
className="flex-1"
247-
/>
248-
<Button
249-
variant="outline"
250-
size="sm"
251-
onClick={() => copyToClipboard(linkFormats.html, "HTML")}
252-
>
253-
<Copy className="w-4 h-4" />
254-
</Button>
227+
<CardContent className="space-y-6">
228+
<div className="grid gap-4">
229+
<div className="space-y-2">
230+
<label className="text-sm font-semibold text-gray-700 dark:text-gray-300">Direct URL</label>
231+
<div className="flex gap-2">
232+
<Input
233+
readOnly
234+
value={linkFormats.direct}
235+
className="flex-1 font-mono text-sm bg-gray-50 dark:bg-gray-900 border-gray-200 dark:border-gray-600"
236+
/>
237+
<Button
238+
variant="outline"
239+
size="sm"
240+
onClick={() => copyToClipboard(linkFormats.direct, "Direct URL")}
241+
className="shrink-0 hover:bg-blue-50 dark:hover:bg-blue-900/20"
242+
>
243+
<Copy className="w-4 h-4" />
244+
</Button>
245+
</div>
246+
</div>
247+
248+
<div className="space-y-2">
249+
<label className="text-sm font-semibold text-gray-700 dark:text-gray-300">Markdown</label>
250+
<div className="flex gap-2">
251+
<Input
252+
readOnly
253+
value={linkFormats.markdown}
254+
className="flex-1 font-mono text-sm bg-gray-50 dark:bg-gray-900 border-gray-200 dark:border-gray-600"
255+
/>
256+
<Button
257+
variant="outline"
258+
size="sm"
259+
onClick={() => copyToClipboard(linkFormats.markdown, "Markdown")}
260+
className="shrink-0 hover:bg-blue-50 dark:hover:bg-blue-900/20"
261+
>
262+
<Copy className="w-4 h-4" />
263+
</Button>
264+
</div>
265+
</div>
266+
267+
<div className="space-y-2">
268+
<label className="text-sm font-semibold text-gray-700 dark:text-gray-300">HTML</label>
269+
<div className="flex gap-2">
270+
<Input
271+
readOnly
272+
value={linkFormats.html}
273+
className="flex-1 font-mono text-sm bg-gray-50 dark:bg-gray-900 border-gray-200 dark:border-gray-600"
274+
/>
275+
<Button
276+
variant="outline"
277+
size="sm"
278+
onClick={() => copyToClipboard(linkFormats.html, "HTML")}
279+
className="shrink-0 hover:bg-blue-50 dark:hover:bg-blue-900/20"
280+
>
281+
<Copy className="w-4 h-4" />
282+
</Button>
283+
</div>
284+
</div>
255285
</div>
256-
<div className="mt-4 p-4 bg-muted rounded-lg">
257-
<p className="text-sm text-muted-foreground mb-2">Preview:</p>
258-
<img
259-
src={uploadResult.url}
260-
alt="Uploaded image preview"
261-
className="max-w-full max-h-64 object-contain rounded-lg border"
262-
/>
286+
287+
<div className="pt-4 border-t border-gray-200 dark:border-gray-600">
288+
<p className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">Preview</p>
289+
<div className="bg-gray-50 dark:bg-gray-900 p-4 rounded-xl border border-gray-200 dark:border-gray-600">
290+
{/* eslint-disable-next-line @next/next/no-img-element */}
291+
<img
292+
src={uploadResult.url}
293+
alt="Uploaded image preview"
294+
className="max-w-full max-h-80 object-contain rounded-lg mx-auto shadow-sm"
295+
/>
296+
</div>
263297
</div>
264298
</CardContent>
265299
</Card>

0 commit comments

Comments
 (0)