From 7dd12e9915917dc68263aba132731b917d1d10ea Mon Sep 17 00:00:00 2001 From: tianma Date: Tue, 30 Jun 2026 17:59:53 +0800 Subject: [PATCH] feat(web): redesign assets pane with grid layout, search, lightbox and drag-drop upload --- apps/web/src/components/AssetsPane.tsx | 542 +++++++++++++++++++++-- apps/web/src/components/WorkspaceApp.tsx | 2 +- bun.lock | 16 + package.json | 2 + 4 files changed, 534 insertions(+), 28 deletions(-) diff --git a/apps/web/src/components/AssetsPane.tsx b/apps/web/src/components/AssetsPane.tsx index 4fe3f1b4..3f006ad7 100644 --- a/apps/web/src/components/AssetsPane.tsx +++ b/apps/web/src/components/AssetsPane.tsx @@ -1,8 +1,39 @@ -import { useQuery } from "@tanstack/react-query"; -import { Archive, HardDrive, ImageIcon, File as FileIcon, ExternalLink, ChevronLeft } from "lucide-react"; +import { useState, useCallback, useMemo, useRef } from "react"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useDropzone } from "react-dropzone"; +import Lightbox from "yet-another-react-lightbox"; +import Zoom from "yet-another-react-lightbox/plugins/zoom"; +import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails"; + +import "yet-another-react-lightbox/styles.css"; +import "yet-another-react-lightbox/plugins/thumbnails.css"; + +import { + Archive, + HardDrive, + ImageIcon, + File as FileIcon, + ExternalLink, + ChevronLeft, + Search, + Grid, + List, + UploadCloud, + FileText, + FileSpreadsheet, + FileArchive, + Music, + Video, + X, + Loader2, + FileUp, +} from "lucide-react"; + import { Button } from "@/components/ui/button"; import { api } from "@/lib/api"; import { formatDateTime } from "@/lib/utils"; +import { compressImageForUpload } from "@/lib/image-compression"; +import type { MemoDetail } from "@edgeever/shared"; export const formatBytes = (bytes: number) => { if (!Number.isFinite(bytes) || bytes <= 0) { @@ -16,15 +47,95 @@ export const formatBytes = (bytes: number) => { return `${exponent === 0 ? value.toFixed(0) : value.toFixed(value >= 10 ? 1 : 2)} ${units[exponent]}`; }; +const DOCUMENT_MIME_TYPES = new Set([ + "application/pdf", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.ms-excel", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "text/plain", + "text/markdown", + "application/json", + "application/xml", + "text/html", + "text/css", + "text/javascript", +]); + +const getFileIcon = (mimeType: string | null, filename: string | null) => { + const mime = (mimeType || "").toLowerCase(); + const ext = (filename || "").split(".").pop()?.toLowerCase() || ""; + + if (mime.startsWith("image/")) return ; + if (mime.startsWith("audio/")) return ; + if (mime.startsWith("video/")) return