"use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import nProgress from "nprogress"; import { useMemo, useState } from "react"; import toast from "react-hot-toast"; import { z } from "zod"; import { Schema_File } from "~/schema"; import { cn } from "~/utils"; import Icon from "~/components/Icon"; import { Button } from "~/components/ui/button"; import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, } from "~/components/ui/drawer"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "~/components/ui/dropdown-menu"; import useMediaQuery from "~/hooks/useMediaQuery"; import bytesToReadable from "~/utils/bytesFormat"; import { durationToReadable } from "~/utils/durationFormat"; import { getPreviewIcon } from "~/utils/previewHelper"; import config from "~/config/gIndex.config"; import { CreateDownloadToken } from "./actions"; type Props = { data: z.infer; disabled?: boolean; }; export default function FileGrid({ data, disabled }: Props) { const pathname = usePathname(); const filePath = useMemo(() => { // const currentPath = pathname.startsWith("/e") ? pathname : `/e${pathname}`; // Set to pathname to remove the /e prefix const path = [pathname, encodeURIComponent(data.name)] .join("/") .replace(/\/+/g, "/"); return new URL(path, config.basePath).pathname; }, [data, pathname]); const [thumbnailURL, setThumbnailURL] = useState( `/api/thumb/${data.encryptedId}?size=2`, ); const [actionOpen, setActionOpen] = useState(false); const isDesktop = useMediaQuery("(min-width: 768px)"); const onCopy = async (e: React.MouseEvent) => { e.stopPropagation(); try { toast.promise( navigator.clipboard.writeText( new URL(filePath, config.basePath).toString(), ), { loading: "Copying link...", success: "Link copied!", error: "Failed to copy link", }, ); } catch (error) { const e = error as Error; console.error(e.message); } }; const onDownload = async (e: React.MouseEvent) => { e.stopPropagation(); toast.loading("Creating download token...", { id: `download-${data.encryptedId}`, }); try { const token = await CreateDownloadToken(); if (!token) throw new Error("Failed to create download token"); toast.success("Opening download link...", { id: `download-${data.encryptedId}`, }); const timeout = setTimeout(() => { clearTimeout(timeout); window.open(`/api/download/${data.encryptedId}?token=${token}`); }, 1000); } catch (error) { const e = error as Error; console.error(e.message); toast.error(e.message, { id: `download-${data.encryptedId}`, }); } }; return (
{isDesktop ? ( Copy link {data.mimeType.includes("folder") ? null : ( Download )} ) : ( Actions What would you like to do with this file?
{data.mimeType.includes("folder") ? null : ( )}
)} { if (disabled) { e.preventDefault(); e.stopPropagation(); await new Promise((resolve) => setTimeout(resolve, 500)); nProgress.done(true); } }} href={filePath} className={cn( "h-full w-full", "rounded-[var(--radius)]", "flex flex-col content-stretch justify-stretch gap-3", "hover:bg-muted/50", "transition", "border border-border", )} >
{/* If it's media, show thumbnail */}
{data.thumbnailLink && (data.mimeType.startsWith("video") || data.mimeType.startsWith("image")) ? ( <> {data.name} { if (thumbnailURL.includes("size=2")) { setThumbnailURL(`/api/thumb/${data.encryptedId}`); } }} className='rounded-top-[var(--radius)] absolute -z-0 h-32 w-full flex-shrink-0 flex-grow-0 object-cover opacity-50' /> {data.name} { if (thumbnailURL.includes("size=2")) { setThumbnailURL(`/api/thumb/${data.encryptedId}`); } }} className='relative z-0 h-32 w-full flex-shrink-0 flex-grow-0 object-contain backdrop-blur' /> {data.mimeType.startsWith("video") && ( <>
{durationToReadable( data.videoMediaMetadata?.durationMillis || 0, )}
)} ) : ( )}
{/* File data */}
{config.siteConfig.showFileExtension ? data.name : data.fileExtension ? data.name.replace(new RegExp(`.${data.fileExtension}$`), "") : data.name}
{data.mimeType.includes("folder") ? "folder" : data.fileExtension || "unknown"} {!data.mimeType.includes("folder") && ( <> {config.siteConfig.showFileExtension ? null : ( )} {bytesToReadable(data.size || 0)} )}
{new Date(data.modifiedTime).toLocaleDateString()}
); }