11"use client" ;
22
33import { useState } from "react" ;
4+ import Button from "./shared/Button" ;
5+ import { EllipsisVerticalIcon } from "@heroicons/react/24/outline" ;
6+ import { getFileIcon , formatFileSize , formatDate , type FileType } from "../lib/helpers" ;
47
5- export type FileType = "folder" | "file" | "image" | "document" | "other" ;
8+ export type { FileType } ;
69
710export interface FileItemData {
811 id : string ;
@@ -22,95 +25,6 @@ interface FileItemProps {
2225 isSelected ?: boolean ;
2326}
2427
25- function getFileIcon ( type : FileType , mimeType ?: string ) {
26- switch ( type ) {
27- case "folder" :
28- return (
29- < svg
30- className = "h-6 w-6 text-yellow-500"
31- fill = "currentColor"
32- viewBox = "0 0 24 24"
33- aria-hidden = "true"
34- >
35- < path d = "M10 4H4c-1.11 0-2 .89-2 2v12c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2h-8l-2-2z" />
36- </ svg >
37- ) ;
38- case "image" :
39- return (
40- < svg
41- className = "h-6 w-6 text-green-500"
42- fill = "none"
43- stroke = "currentColor"
44- viewBox = "0 0 24 24"
45- aria-hidden = "true"
46- >
47- < path
48- strokeLinecap = "round"
49- strokeLinejoin = "round"
50- strokeWidth = { 2 }
51- d = "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
52- />
53- </ svg >
54- ) ;
55- case "document" :
56- return (
57- < svg
58- className = "h-6 w-6 text-blue-500"
59- fill = "none"
60- stroke = "currentColor"
61- viewBox = "0 0 24 24"
62- aria-hidden = "true"
63- >
64- < path
65- strokeLinecap = "round"
66- strokeLinejoin = "round"
67- strokeWidth = { 2 }
68- d = "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
69- />
70- </ svg >
71- ) ;
72- default :
73- return (
74- < svg
75- className = "h-6 w-6 text-gray-500"
76- fill = "none"
77- stroke = "currentColor"
78- viewBox = "0 0 24 24"
79- aria-hidden = "true"
80- >
81- < path
82- strokeLinecap = "round"
83- strokeLinejoin = "round"
84- strokeWidth = { 2 }
85- d = "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
86- />
87- </ svg >
88- ) ;
89- }
90- }
91-
92- function formatFileSize ( bytes ?: number ) : string {
93- if ( ! bytes ) return "" ;
94- if ( bytes < 1024 ) return `${ bytes } B` ;
95- if ( bytes < 1024 * 1024 ) return `${ ( bytes / 1024 ) . toFixed ( 1 ) } KB` ;
96- if ( bytes < 1024 * 1024 * 1024 ) return `${ ( bytes / ( 1024 * 1024 ) ) . toFixed ( 1 ) } MB` ;
97- return `${ ( bytes / ( 1024 * 1024 * 1024 ) ) . toFixed ( 1 ) } GB` ;
98- }
99-
100- function formatDate ( date ?: Date ) : string {
101- if ( ! date ) return "" ;
102- const now = new Date ( ) ;
103- const diff = now . getTime ( ) - date . getTime ( ) ;
104- const days = Math . floor ( diff / ( 1000 * 60 * 60 * 24 ) ) ;
105-
106- if ( days === 0 ) return "Today" ;
107- if ( days === 1 ) return "Yesterday" ;
108- if ( days < 7 ) return `${ days } days ago` ;
109- if ( days < 30 ) return `${ Math . floor ( days / 7 ) } weeks ago` ;
110-
111- return date . toLocaleDateString ( ) ;
112- }
113-
11428export default function FileItem ( {
11529 file,
11630 view,
@@ -122,12 +36,11 @@ export default function FileItem({
12236
12337 if ( view === "grid" ) {
12438 return (
125- < div
126- className = { `group relative flex cursor-pointer flex-col items-center justify-center rounded-lg border-2 p-2 transition-colors sm:p-4 ${
127- isSelected
128- ? "border-purple-500 bg-purple-50"
39+ < section
40+ className = { `group relative flex cursor-pointer flex-col items-center justify-center rounded-lg border-2 p-2 transition-colors sm:p-4 ${ isSelected
41+ ? "border-[#7B42F6] bg-[#F9F6FF]"
12942 : "border-transparent bg-white hover:border-gray-300 hover:bg-gray-50"
130- } `}
43+ } `}
13144 onMouseEnter = { ( ) => setIsHovered ( true ) }
13245 onMouseLeave = { ( ) => setIsHovered ( false ) }
13346 onClick = { ( ) => onSelect ( file ) }
@@ -142,16 +55,15 @@ export default function FileItem({
14255 < p className = "max-w-full truncate text-center text-xs font-medium text-black sm:text-sm" >
14356 { file . name }
14457 </ p >
145- </ div >
58+ </ section >
14659 ) ;
14760 }
14861
14962 // List view
15063 return (
151- < div
152- className = { `group flex cursor-pointer items-center gap-2 border-b border-gray-100 px-2 py-2 transition-colors sm:gap-4 sm:px-4 sm:py-3 ${
153- isSelected ? "bg-purple-50" : "bg-white hover:bg-gray-50"
154- } `}
64+ < section
65+ className = { `group flex cursor-pointer items-center gap-2 border-b border-gray-100 px-2 py-2 transition-colors sm:gap-4 sm:px-4 sm:py-3 ${ isSelected ? "bg-[#F9F6FF]" : "bg-white hover:bg-gray-50"
66+ } `}
15567 onMouseEnter = { ( ) => setIsHovered ( true ) }
15668 onMouseLeave = { ( ) => setIsHovered ( false ) }
15769 onClick = { ( ) => onSelect ( file ) }
@@ -174,33 +86,19 @@ export default function FileItem({
17486 </ div >
17587 { isHovered && (
17688 < div className = "flex-shrink-0" >
177- < button
178- type = "button"
179- className = "cursor-pointer rounded-md p-1 text-gray-600 hover:bg-gray-200"
89+ < Button
90+ variant = "icon"
18091 aria-label = "More options"
18192 onClick = { ( e ) => {
18293 e . stopPropagation ( ) ;
18394 // Handle more options
18495 } }
18596 >
186- < svg
187- className = "h-4 w-4 sm:h-5 sm:w-5"
188- fill = "none"
189- stroke = "currentColor"
190- viewBox = "0 0 24 24"
191- aria-hidden = "true"
192- >
193- < path
194- strokeLinecap = "round"
195- strokeLinejoin = "round"
196- strokeWidth = { 2 }
197- d = "M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z"
198- />
199- </ svg >
200- </ button >
97+ < EllipsisVerticalIcon className = "h-4 w-4 sm:h-5 sm:w-5" />
98+ </ Button >
20199 </ div >
202100 ) }
203- </ div >
101+ </ section >
204102 ) ;
205103}
206104
0 commit comments