11"use client" ;
22
3- import { Work } from "@/types/work" ;
43import { Button } from "@/components/ui/button" ;
54import {
65 Card ,
@@ -9,10 +8,11 @@ import {
98 CardHeader ,
109 CardTitle ,
1110} from "@/components/ui/card" ;
12- import { Badge } from "@/components/ui/badge " ;
13- import { X , Download , FileImage , Code , Calendar , User } from "lucide-react " ;
14- import { motion , AnimatePresence } from "framer-motion " ;
11+ import { Work } from "@/types/work " ;
12+ import { AnimatePresence , motion } from "framer-motion " ;
13+ import { Code , Download , X , Copy } from "lucide-react " ;
1514import Image from "next/image" ;
15+ import { useEffect , useState } from "react" ;
1616
1717interface WorkViewerProps {
1818 work : Work | null ;
@@ -27,6 +27,19 @@ export function WorkViewer({
2727 onClose,
2828 onDownload,
2929} : WorkViewerProps ) {
30+ useEffect ( ( ) => {
31+ const handleEsc = ( event : KeyboardEvent ) => {
32+ if ( isOpen && event . key === "Escape" ) {
33+ onClose ( ) ;
34+ }
35+ } ;
36+
37+ document . addEventListener ( "keydown" , handleEsc ) ;
38+ return ( ) => {
39+ document . removeEventListener ( "keydown" , handleEsc ) ;
40+ } ;
41+ } , [ isOpen , onClose ] ) ;
42+
3043 if ( ! work ) return null ;
3144
3245 const handleDownload = ( ) => {
@@ -35,14 +48,21 @@ export function WorkViewer({
3548 }
3649 } ;
3750
38- const formatDate = ( dateString : string ) => {
39- return new Date ( dateString ) . toLocaleDateString ( "en-US" , {
40- year : "numeric" ,
41- month : "long" ,
42- day : "numeric" ,
43- hour : "2-digit" ,
44- minute : "2-digit" ,
45- } ) ;
51+ const [ copied , setCopied ] = useState ( false ) ;
52+
53+ const handleCopy = async ( ) => {
54+ if ( ! work ?. svg_data ) return ;
55+
56+ const text = work . svg_data ;
57+
58+ try {
59+ await navigator . clipboard . writeText ( text ) ;
60+ setCopied ( true ) ;
61+ setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
62+ return ;
63+ } catch ( e ) {
64+ console . error ( "Copy failed" , e ) ;
65+ }
4666 } ;
4767
4868 return (
@@ -75,7 +95,7 @@ export function WorkViewer({
7595 </ Button >
7696
7797 < div className = "pr-12" >
78- < CardTitle className = "text-xl sm:text-2xl font-semibold text-slate-900 dark:text-neutral-100 mb-2 " >
98+ < CardTitle className = "text-xl sm:text-2xl font-semibold text-slate-900 dark:text-neutral-100" >
7999 { work . title }
80100 </ CardTitle >
81101 { work . description && (
@@ -84,19 +104,6 @@ export function WorkViewer({
84104 </ CardDescription >
85105 ) }
86106 </ div >
87-
88- < div className = "flex flex-wrap gap-2 mt-4" >
89- < Badge className = "text-xs px-3 py-1 bg-white dark:bg-neutral-800 text-slate-700 dark:text-neutral-300 rounded-md" >
90- < FileImage className = "mr-1 h-3 w-3" />
91- Original Image
92- </ Badge >
93- { work . svg_data && (
94- < Badge className = "text-xs px-3 py-1 bg-emerald-100 dark:bg-violet-900/50 text-emerald-700 dark:text-violet-300 rounded-md" >
95- < Code className = "mr-1 h-3 w-3" />
96- SVG Available
97- </ Badge >
98- ) }
99- </ div >
100107 </ CardHeader >
101108
102109 < CardContent className = "p-6" >
@@ -126,14 +133,26 @@ export function WorkViewer({
126133 SVG Output
127134 </ h3 >
128135 { work . svg_data && (
129- < Button
130- onClick = { handleDownload }
131- size = "sm"
132- className = "bg-emerald-600 hover:bg-emerald-700 dark:bg-violet-600 dark:hover:bg-violet-700 text-white rounded-md px-4 py-2 text-sm"
133- >
134- < Download className = "mr-1 h-4 w-4" />
135- Download
136- </ Button >
136+ < div className = "flex items-center gap-2" >
137+ < Button
138+ onClick = { handleCopy }
139+ size = "sm"
140+ variant = "outline"
141+ className = "bg-slate-50 hover:bg-slate-100 dark:bg-neutral-800 dark:hover:bg-neutral-700 text-slate-700 dark:text-neutral-200 rounded-md px-3 py-2 text-sm"
142+ >
143+ < Copy className = "mr-1 h-4 w-4" />
144+ { copied ? "Copied!" : "Copy" }
145+ </ Button >
146+
147+ < Button
148+ onClick = { handleDownload }
149+ size = "sm"
150+ className = "bg-emerald-600 hover:bg-emerald-700 dark:bg-violet-600 dark:hover:bg-violet-700 text-white rounded-md px-4 py-2 text-sm"
151+ >
152+ < Download className = "mr-1 h-4 w-4" />
153+ Download
154+ </ Button >
155+ </ div >
137156 ) }
138157 </ div >
139158
@@ -152,73 +171,6 @@ export function WorkViewer({
152171 </ div >
153172 </ div >
154173 </ div >
155-
156- { /* Metadata */ }
157- < div className = "mt-8 p-4 bg-slate-50/50 dark:bg-neutral-800/50 rounded-lg border" >
158- < h4 className = "text-lg font-semibold text-slate-900 dark:text-neutral-100 mb-4" >
159- Work Details
160- </ h4 >
161- < div className = "grid grid-cols-1 md:grid-cols-2 gap-4" >
162- < div className = "flex items-center gap-3 p-3 bg-white dark:bg-neutral-900 rounded-md border" >
163- < Calendar className = "h-4 w-4 text-emerald-600 dark:text-violet-500" />
164- < div >
165- < span className = "text-slate-600 dark:text-neutral-400 text-sm" >
166- Created:
167- </ span >
168- < p className = "text-sm font-medium text-slate-900 dark:text-neutral-100" >
169- { formatDate ( work . created_at ) }
170- </ p >
171- </ div >
172- </ div >
173- < div className = "flex items-center gap-3 p-3 bg-white dark:bg-neutral-900 rounded-md border" >
174- < Calendar className = "h-4 w-4 text-emerald-600 dark:text-violet-500" />
175- < div >
176- < span className = "text-slate-600 dark:text-neutral-400 text-sm" >
177- Updated:
178- </ span >
179- < p className = "text-sm font-medium text-slate-900 dark:text-neutral-100" >
180- { formatDate ( work . updated_at ) }
181- </ p >
182- </ div >
183- </ div >
184- < div className = "flex items-center gap-3 p-3 bg-white dark:bg-neutral-900 rounded-md border" >
185- < User className = "h-4 w-4 text-emerald-600 dark:text-violet-500" />
186- < div >
187- < span className = "text-slate-600 dark:text-neutral-400 text-sm" >
188- ID:
189- </ span >
190- < p className = "font-mono text-xs font-medium text-slate-900 dark:text-neutral-100" >
191- { work . id }
192- </ p >
193- </ div >
194- </ div >
195- < div className = "flex items-center gap-3 p-3 bg-white dark:bg-neutral-900 rounded-md border" >
196- < FileImage className = "h-4 w-4 text-emerald-600 dark:text-violet-500" />
197- < div >
198- < span className = "text-slate-600 dark:text-neutral-400 text-sm" >
199- Status:
200- </ span >
201- < div className = "flex items-center gap-2" >
202- { work . svg_data ? (
203- < >
204- < div className = "w-2 h-2 bg-emerald-500 rounded-full" > </ div >
205- < span className = "text-sm font-medium text-emerald-600 dark:text-emerald-400" >
206- Processed
207- </ span >
208- </ >
209- ) : (
210- < >
211- < div className = "w-2 h-2 bg-amber-500 rounded-full" > </ div >
212- < span className = "text-sm font-medium text-amber-600 dark:text-amber-400" >
213- Processing
214- </ span >
215- </ >
216- ) }
217- </ div >
218- </ div >
219- </ div >
220- </ div >
221- </ div >
222174 </ CardContent >
223175 </ Card >
224176 </ motion . div >
0 commit comments