@@ -13,7 +13,6 @@ import {
1313 Upload ,
1414 Workflow as WorkflowIcon ,
1515} from "lucide-react" ;
16- import Image from "next/image" ;
1716import { useRouter } from "next/navigation" ;
1817import { useCallback , useEffect , useState } from "react" ;
1918import { Button } from "@/components/ui/button" ;
@@ -199,16 +198,17 @@ export default function FlowPage() {
199198 return (
200199 < div className = "flex-1 p-11 px-14 bg-background" >
201200 { /* Header */ }
202- < div className = "flex items-start justify-between mb-2" >
203- < div >
204- < h1 className = "text-[30px] font-semibold text-[#1F1F23] leading-none tracking-tight" >
205- Flow
206- </ h1 >
207- < p className = "text-[16px] font-normal text-[#858589] mt-2" >
208- Build workflows or run models directly
209- </ p >
210- </ div >
201+ < div className = "flex items-center justify-end mb-2" >
211202 < div className = "flex items-center gap-2.5" >
203+ < div className = "relative" >
204+ < Search className = "absolute left-3.5 top-1/2 -translate-y-1/2 size-[18px] text-[#858589]" />
205+ < Input
206+ placeholder = "Search workflows..."
207+ value = { searchQuery }
208+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
209+ className = "pl-10.5 h-10 w-[280px] text-[15px] bg-[#EFEFEF] border-transparent rounded-[8px] placeholder-[#858589] font-normal focus-visible:ring-0 focus-visible:border-gray-300"
210+ />
211+ </ div >
212212 < Button
213213 variant = "outline"
214214 onClick = { importWorkflow }
@@ -227,55 +227,11 @@ export default function FlowPage() {
227227 </ div >
228228 </ div >
229229
230- { /* System Workflows */ }
230+ { /* Your Workflows */ }
231231 < section className = "mt-11" >
232- < h2 className = "text-[20px] font-semibold text-gray-900 mb-1 tracking-tight" >
233- System Workflows
232+ < h2 className = "text-[20px] font-semibold text-gray-900 tracking-tight mb-1 " >
233+ Your Workflows
234234 </ h2 >
235- < p className = "text-[15px] text-[#858589] mb-5" >
236- Prebuilt workflow templates - click to open and start using.
237- </ p >
238-
239- < div className = "flex flex-wrap gap-8 max-w-[1300px]" >
240- { /* Racing car template */ }
241- < button
242- type = "button"
243- onClick = { ( ) => createWorkflow ( "racing-car" ) }
244- className = "group text-left bg-[#F3F3F3] rounded-[12px] overflow-hidden shadow-[0_1px_2px_rgba(0,0,0,0.06)] hover:shadow-md transition-all cursor-pointer flex flex-col w-[320px] shrink-0"
245- >
246- < div className = "aspect-[16/11] relative overflow-hidden bg-gray-100 w-full" >
247- < Image
248- src = "/porsche-rear.png"
249- alt = "AI Racing Car Generator"
250- fill
251- className = "object-cover group-hover:scale-105 transition-transform duration-300"
252- />
253- </ div >
254- < div className = "p-4 text-center w-full" >
255- < span className = "text-[18px] font-medium text-gray-900" >
256- AI Racing Car Generator
257- </ span >
258- </ div >
259- </ button >
260- </ div >
261- </ section >
262-
263- { /* Your Workflows */ }
264- < section className = "mt-14" >
265- < div className = "flex items-center justify-between mb-1" >
266- < h2 className = "text-[20px] font-semibold text-gray-900 tracking-tight" >
267- Your Workflows
268- </ h2 >
269- < div className = "relative" >
270- < Search className = "absolute left-3.5 top-1/2 -translate-y-1/2 size-[18px] text-[#858589]" />
271- < Input
272- placeholder = "Search workflows..."
273- value = { searchQuery }
274- onChange = { ( e ) => setSearchQuery ( e . target . value ) }
275- className = "pl-10.5 h-11 w-[360px] text-[15px] bg-[#EFEFEF] border-transparent rounded-[12px] placeholder-[#858589] font-normal focus-visible:ring-0 focus-visible:border-gray-300"
276- />
277- </ div >
278- </ div >
279235 < p className = "text-[15px] text-[#858589] mb-5" >
280236 Open one to edit, run, and review history.
281237 </ p >
@@ -304,26 +260,62 @@ export default function FlowPage() {
304260 No workflows match "{ searchQuery } "
305261 </ p >
306262 ) : (
307- < div className = "flex flex-wrap gap-7 max-w-[1300px] " >
263+ < div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5 " >
308264 { filtered . map ( ( wf ) => (
309265 < div
310266 key = { wf . id }
311- className = "group flex flex-col bg-[#F3F3F3] rounded-[12px] overflow-hidden shadow-[0_1px_2px_rgba(0,0,0,0.06)] transition-all w-[320px] shrink-0 relative"
267+ className = "group flex flex-col bg-[#F3F3F3] rounded-[12px] overflow-hidden shadow-[0_1px_2px_rgba(0,0,0,0.06)] hover:shadow-md transition-all relative cursor-pointer"
268+ onClick = { ( ) => router . push ( `/app/workflows/${ wf . id } ` ) }
269+ onKeyDown = { ( e ) => {
270+ if ( e . key === "Enter" ) router . push ( `/app/workflows/${ wf . id } ` ) ;
271+ } }
312272 >
313- { /* Card image container */ }
314- < div className = "relative aspect-[16/11] overflow-hidden w-full" >
315- < Image
316- src = "/porsche-rear.png"
317- alt = { wf . name }
318- fill
319- className = "object-cover cursor-pointer group-hover:scale-105 transition-transform duration-300"
320- onClick = { ( ) => router . push ( `/app/workflows/${ wf . id } ` ) }
321- />
273+ { /* Decorative header */ }
274+ < div className = "relative h-28 bg-gradient-to-br from-[#E8E8ED] via-[#EAEAF0] to-[#E0E0E8] overflow-hidden" >
275+ { /* Abstract node graph pattern */ }
276+ < svg
277+ className = "absolute inset-0 w-full h-full opacity-[0.18]"
278+ viewBox = "0 0 320 112"
279+ fill = "none"
280+ >
281+ < title > Workflow pattern</ title >
282+ < circle cx = "80" cy = "36" r = "14" stroke = "#888" strokeWidth = "1.5" />
283+ < circle cx = "160" cy = "56" r = "14" stroke = "#888" strokeWidth = "1.5" />
284+ < circle cx = "240" cy = "36" r = "14" stroke = "#888" strokeWidth = "1.5" />
285+ < circle cx = "200" cy = "88" r = "10" stroke = "#888" strokeWidth = "1.5" />
286+ < circle cx = "120" cy = "84" r = "10" stroke = "#888" strokeWidth = "1.5" />
287+ < line x1 = "94" y1 = "36" x2 = "146" y2 = "56" stroke = "#888" strokeWidth = "1.2" />
288+ < line x1 = "174" y1 = "56" x2 = "226" y2 = "36" stroke = "#888" strokeWidth = "1.2" />
289+ < line x1 = "160" y1 = "70" x2 = "200" y2 = "78" stroke = "#888" strokeWidth = "1.2" />
290+ < line x1 = "160" y1 = "70" x2 = "120" y2 = "74" stroke = "#888" strokeWidth = "1.2" />
291+ </ svg >
292+ < div className = "absolute top-4 left-4" >
293+ < div className = "flex h-10 w-10 items-center justify-center rounded-[10px] bg-white/70 backdrop-blur-sm shadow-sm" >
294+ < WorkflowIcon className = "size-5 text-[#555]" />
295+ </ div >
296+ </ div >
322297
323- { /* Menu on upper right of image */ }
324- < div className = "absolute top-3 right-3 z-10" >
298+ { /* Running indicator */ }
299+ { wf . isRunning && (
300+ < div className = "absolute top-3.5 right-12 bg-white/90 backdrop-blur-xs px-2 py-0.5 rounded-full flex items-center gap-1 shadow-xs border border-gray-100" >
301+ < span className = "relative flex h-1.5 w-1.5" >
302+ < span className = "absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75" />
303+ < span className = "relative inline-flex h-1.5 w-1.5 rounded-full bg-green-500" />
304+ </ span >
305+ < span className = "text-[10px] font-semibold text-green-700" >
306+ Running
307+ </ span >
308+ </ div >
309+ ) }
310+
311+ { /* Menu */ }
312+ < div
313+ className = "absolute top-3 right-3 z-10"
314+ onClick = { ( e ) => e . stopPropagation ( ) }
315+ onKeyDown = { ( e ) => e . stopPropagation ( ) }
316+ >
325317 < DropdownMenu >
326- < DropdownMenuTrigger className = "flex h-7 w-7 items-center justify-center rounded-md bg-white/80 backdrop-blur-xs text-gray-600 hover:bg-white hover:text-gray-900 shadow-xs cursor-pointer" >
318+ < DropdownMenuTrigger className = "flex h-7 w-7 items-center justify-center rounded-md bg-white/60 backdrop-blur-xs text-gray-500 hover:bg-white hover:text-gray-900 shadow-xs cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity " >
327319 < MoreHorizontal className = "size-4" />
328320 </ DropdownMenuTrigger >
329321 < DropdownMenuContent align = "end" sideOffset = { 4 } >
@@ -365,18 +357,6 @@ export default function FlowPage() {
365357 </ DropdownMenuContent >
366358 </ DropdownMenu >
367359 </ div >
368-
369- { wf . isRunning && (
370- < div className = "absolute top-3 right-12 z-10 bg-white/90 backdrop-blur-xs px-2 py-0.5 rounded-full flex items-center gap-1 shadow-xs border border-gray-100" >
371- < span className = "relative flex h-1.5 w-1.5" >
372- < span className = "absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75" />
373- < span className = "relative inline-flex h-1.5 w-1.5 rounded-full bg-green-500" />
374- </ span >
375- < span className = "text-[10px] font-semibold text-green-700" >
376- Running
377- </ span >
378- </ div >
379- ) }
380360 </ div >
381361
382362 { /* Card content */ }
@@ -387,22 +367,20 @@ export default function FlowPage() {
387367 className = "h-7 text-sm border-gray-300 bg-white"
388368 value = { renameValue }
389369 onChange = { ( e ) => setRenameValue ( e . target . value ) }
370+ onClick = { ( e ) => e . stopPropagation ( ) }
390371 onKeyDown = { ( e ) => {
372+ e . stopPropagation ( ) ;
391373 if ( e . key === "Enter" ) renameWorkflow ( wf . id ) ;
392374 if ( e . key === "Escape" ) setRenaming ( null ) ;
393375 } }
394376 onBlur = { ( ) => renameWorkflow ( wf . id ) }
395377 />
396378 ) : (
397379 < >
398- < button
399- type = "button"
400- onClick = { ( ) => router . push ( `/app/workflows/${ wf . id } ` ) }
401- className = "text-[18px] font-medium text-gray-900 truncate block w-full text-left hover:text-indigo-600 transition-colors cursor-pointer"
402- >
380+ < span className = "text-[16px] font-medium text-gray-900 truncate block" >
403381 { wf . name }
404- </ button >
405- < span className = "text-[14px ] text-[#858589] mt-1 block font-normal" >
382+ </ span >
383+ < span className = "text-[13px ] text-[#858589] mt-1 block font-normal" >
406384 Edited { timeAgo ( wf . updatedAt ) }
407385 </ span >
408386 </ >
0 commit comments