From 4ea799ae80e00d0da339ab71efc31acf0d3aefd6 Mon Sep 17 00:00:00 2001 From: Daniel Luiz Alves Date: Thu, 3 Jul 2025 14:55:53 -0300 Subject: [PATCH] feat: add total storage usage label in multiple languages and enhance storage usage component - Introduced a new "total" label in various language translation files for storage usage. - Updated the StorageUsage component to display the total storage size alongside the progress bar. - Improved layout and styling in the QuickAccessCards component for better visual consistency. --- apps/web/messages/ar-SA.json | 1 + apps/web/messages/de-DE.json | 1 + apps/web/messages/en-US.json | 1 + apps/web/messages/es-ES.json | 1 + apps/web/messages/fr-FR.json | 1 + apps/web/messages/hi-IN.json | 1 + apps/web/messages/it-IT.json | 1 + apps/web/messages/ja-JP.json | 1 + apps/web/messages/ko-KR.json | 1 + apps/web/messages/nl-NL.json | 1 + apps/web/messages/pl-PL.json | 1 + apps/web/messages/pt-BR.json | 1 + apps/web/messages/ru-RU.json | 1 + apps/web/messages/tr-TR.json | 1 + apps/web/messages/zh-CN.json | 1 + .../components/quick-access-cards.tsx | 29 +++---- .../dashboard/components/storage-usage.tsx | 37 +++++--- apps/web/src/app/globals.css | 22 +++++ .../components/general/global-drop-zone.tsx | 2 +- .../components/modals/file-preview-modal.tsx | 3 + .../modals/previews/file-preview-render.tsx | 6 +- .../modals/previews/image-preview.tsx | 85 ++++++++++++++----- apps/web/src/hooks/use-file-manager.ts | 1 + 23 files changed, 149 insertions(+), 51 deletions(-) diff --git a/apps/web/messages/ar-SA.json b/apps/web/messages/ar-SA.json index 9f8fa07..9550f07 100644 --- a/apps/web/messages/ar-SA.json +++ b/apps/web/messages/ar-SA.json @@ -1401,6 +1401,7 @@ "ariaLabel": "شريط تقدم استخدام التخزين", "used": "المستخدمة", "available": "متاح", + "total": "الإجمالي", "loading": "جارٍ التحميل...", "retry": "إعادة المحاولة", "errors": { diff --git a/apps/web/messages/de-DE.json b/apps/web/messages/de-DE.json index cfb3899..8abde0e 100644 --- a/apps/web/messages/de-DE.json +++ b/apps/web/messages/de-DE.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Fortschrittsbalken der Speichernutzung", "used": "genutzt", "available": "verfügbar", + "total": "Gesamt", "loading": "Wird geladen...", "retry": "Wiederholen", "errors": { diff --git a/apps/web/messages/en-US.json b/apps/web/messages/en-US.json index 50c092c..7f35e0a 100644 --- a/apps/web/messages/en-US.json +++ b/apps/web/messages/en-US.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Storage usage progress bar", "used": "used", "available": "available", + "total": "Total", "loading": "Loading...", "retry": "Retry", "errors": { diff --git a/apps/web/messages/es-ES.json b/apps/web/messages/es-ES.json index b74c7b6..3d8b958 100644 --- a/apps/web/messages/es-ES.json +++ b/apps/web/messages/es-ES.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Barra de progreso del uso de almacenamiento", "used": "usados", "available": "disponible", + "total": "Total", "loading": "Cargando...", "retry": "Reintentar", "errors": { diff --git a/apps/web/messages/fr-FR.json b/apps/web/messages/fr-FR.json index 410f572..5d7f976 100644 --- a/apps/web/messages/fr-FR.json +++ b/apps/web/messages/fr-FR.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Barre de progression de l'utilisation du stockage", "used": "utilisé", "available": "disponible", + "total": "Total", "loading": "Chargement...", "retry": "Réessayer", "errors": { diff --git a/apps/web/messages/hi-IN.json b/apps/web/messages/hi-IN.json index 3861dcf..0d692b1 100644 --- a/apps/web/messages/hi-IN.json +++ b/apps/web/messages/hi-IN.json @@ -1399,6 +1399,7 @@ "ariaLabel": "स्टोरेज उपयोग प्रगति पट्टी", "used": "उपयोग किया गया", "available": "उपलब्ध", + "total": "कुल", "loading": "लोड हो रहा है...", "retry": "पुनः प्रयास करें", "errors": { diff --git a/apps/web/messages/it-IT.json b/apps/web/messages/it-IT.json index fc6d5fd..2c754cf 100644 --- a/apps/web/messages/it-IT.json +++ b/apps/web/messages/it-IT.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Barra di progresso utilizzo archiviazione", "used": "utilizzato", "available": "disponibile", + "total": "Totale", "loading": "Caricamento...", "retry": "Riprova", "errors": { diff --git a/apps/web/messages/ja-JP.json b/apps/web/messages/ja-JP.json index 31617ff..9fa3cdb 100644 --- a/apps/web/messages/ja-JP.json +++ b/apps/web/messages/ja-JP.json @@ -1399,6 +1399,7 @@ "ariaLabel": "ストレージ使用状況のプログレスバー", "used": "使用済み", "available": "利用可能", + "total": "合計", "loading": "読み込み中...", "retry": "再試行", "errors": { diff --git a/apps/web/messages/ko-KR.json b/apps/web/messages/ko-KR.json index 46e193e..bcfc703 100644 --- a/apps/web/messages/ko-KR.json +++ b/apps/web/messages/ko-KR.json @@ -1399,6 +1399,7 @@ "ariaLabel": "스토리지 사용량 진행 바", "used": "사용됨", "available": "사용 가능", + "total": "총계", "loading": "로딩 중...", "retry": "다시 시도", "errors": { diff --git a/apps/web/messages/nl-NL.json b/apps/web/messages/nl-NL.json index e28b2c6..33df881 100644 --- a/apps/web/messages/nl-NL.json +++ b/apps/web/messages/nl-NL.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Opslaggebruik voortgangsbalk", "used": "gebruikt", "available": "beschikbaar", + "total": "Totaal", "loading": "Laden...", "retry": "Opnieuw proberen", "errors": { diff --git a/apps/web/messages/pl-PL.json b/apps/web/messages/pl-PL.json index 1039dce..aac96fb 100644 --- a/apps/web/messages/pl-PL.json +++ b/apps/web/messages/pl-PL.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Pasek postępu użycia pamięci", "used": "użyte", "available": "dostępne", + "total": "Razem", "loading": "Ładowanie...", "retry": "Spróbuj ponownie", "errors": { diff --git a/apps/web/messages/pt-BR.json b/apps/web/messages/pt-BR.json index 0d2168e..7287f86 100644 --- a/apps/web/messages/pt-BR.json +++ b/apps/web/messages/pt-BR.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Barra de progresso do uso de armazenamento", "used": "usado", "available": "disponível", + "total": "Total", "loading": "Carregando...", "retry": "Tentar novamente", "errors": { diff --git a/apps/web/messages/ru-RU.json b/apps/web/messages/ru-RU.json index 988d3e4..88d46e0 100644 --- a/apps/web/messages/ru-RU.json +++ b/apps/web/messages/ru-RU.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Индикатор использования хранилища", "used": "Использовано", "available": "Доступно", + "total": "Всего", "loading": "Загрузка...", "retry": "Повторить", "errors": { diff --git a/apps/web/messages/tr-TR.json b/apps/web/messages/tr-TR.json index 0c59a7d..d5cf742 100644 --- a/apps/web/messages/tr-TR.json +++ b/apps/web/messages/tr-TR.json @@ -1399,6 +1399,7 @@ "ariaLabel": "Depolama kullanım ilerleme çubuğu", "used": "kullanıldı", "available": "kullanılabilir", + "total": "Toplam", "loading": "Yükleniyor...", "retry": "Tekrar Dene", "errors": { diff --git a/apps/web/messages/zh-CN.json b/apps/web/messages/zh-CN.json index 070383d..ef1a461 100644 --- a/apps/web/messages/zh-CN.json +++ b/apps/web/messages/zh-CN.json @@ -1399,6 +1399,7 @@ "ariaLabel": "存储使用进度条", "used": "已使用:", "available": "可用", + "total": "总计", "loading": "加载中...", "retry": "重试", "errors": { diff --git a/apps/web/src/app/dashboard/components/quick-access-cards.tsx b/apps/web/src/app/dashboard/components/quick-access-cards.tsx index 42baba8..5fef4af 100644 --- a/apps/web/src/app/dashboard/components/quick-access-cards.tsx +++ b/apps/web/src/app/dashboard/components/quick-access-cards.tsx @@ -11,45 +11,42 @@ export function QuickAccessCards() { const QUICK_ACCESS_ITEMS = [ { title: t("quickAccess.files.title"), - icon: , + icon: , description: t("quickAccess.files.description"), path: "/files", - color: "bg-primary", }, { title: t("quickAccess.shares.title"), - icon: , + icon: , description: t("quickAccess.shares.description"), path: "/shares", - color: "bg-orange-400", }, { title: t("quickAccess.reverseShares.title"), - icon: , + icon: , description: t("quickAccess.reverseShares.description"), path: "/reverse-shares", - color: "bg-blue-500", }, ] as const; return ( -
+
{QUICK_ACCESS_ITEMS.map((card) => ( router.push(card.path)} > - -
-
+ +
+
{card.icon}
-
-

{card.title}

-

{card.description}

+
+

{card.title}

+

+ {card.description} +

diff --git a/apps/web/src/app/dashboard/components/storage-usage.tsx b/apps/web/src/app/dashboard/components/storage-usage.tsx index 75be4fd..6caa10f 100644 --- a/apps/web/src/app/dashboard/components/storage-usage.tsx +++ b/apps/web/src/app/dashboard/components/storage-usage.tsx @@ -26,10 +26,13 @@ export function StorageUsage({ diskSpace, diskSpaceError, onRetry }: StorageUsag
-

- - {t("storageUsage.title")} -

+
+

+ + {t("storageUsage.title")} +

+ {t("storageUsage.total")}: -- +
@@ -54,10 +57,13 @@ export function StorageUsage({ diskSpace, diskSpaceError, onRetry }: StorageUsag
-

- - {t("storageUsage.title")} -

+
+

+ + {t("storageUsage.title")} +

+ {t("storageUsage.total")}: -- +
@@ -75,15 +81,20 @@ export function StorageUsage({ diskSpace, diskSpaceError, onRetry }: StorageUsag
-

- - {t("storageUsage.title")} -

+
+

+ + {t("storageUsage.title")} +

+ + {t("storageUsage.total")}: {formatStorageSize(diskSpace?.diskSizeGB || 0)} + +
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index dc52dc9..91c89dd 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -126,3 +126,25 @@ @apply bg-background text-foreground; } } + +/* Line clamp utilities */ +.line-clamp-1 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +.line-clamp-2 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.line-clamp-3 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; +} diff --git a/apps/web/src/components/general/global-drop-zone.tsx b/apps/web/src/components/general/global-drop-zone.tsx index 03c5717..c816883 100644 --- a/apps/web/src/components/general/global-drop-zone.tsx +++ b/apps/web/src/components/general/global-drop-zone.tsx @@ -206,7 +206,7 @@ export function GlobalDropZone({ onSuccess, children }: GlobalDropZoneProps) { if (file) { const timestamp = Date.now(); const extension = file.type.split("/")[1] || "png"; - const fileName = `pasted-image-${timestamp}.${extension}`; + const fileName = `${timestamp}.${extension}`; const renamedFile = new File([file], fileName, { type: file.type }); diff --git a/apps/web/src/components/modals/file-preview-modal.tsx b/apps/web/src/components/modals/file-preview-modal.tsx index ec4a23d..119bcb1 100644 --- a/apps/web/src/components/modals/file-preview-modal.tsx +++ b/apps/web/src/components/modals/file-preview-modal.tsx @@ -17,6 +17,7 @@ interface FilePreviewModalProps { objectName: string; type?: string; id?: string; + description?: string; }; isReverseShare?: boolean; } @@ -48,6 +49,8 @@ export function FilePreviewModal({ isOpen, onClose, file, isReverseShare = false pdfAsBlob={previewState.pdfAsBlob} pdfLoadFailed={previewState.pdfLoadFailed} onPdfLoadError={previewState.handlePdfLoadError} + description={file.description} + onDownload={previewState.handleDownload} />
diff --git a/apps/web/src/components/modals/previews/file-preview-render.tsx b/apps/web/src/components/modals/previews/file-preview-render.tsx index 802c92d..1f71150 100644 --- a/apps/web/src/components/modals/previews/file-preview-render.tsx +++ b/apps/web/src/components/modals/previews/file-preview-render.tsx @@ -16,6 +16,8 @@ interface FilePreviewRendererProps { pdfAsBlob: boolean; pdfLoadFailed: boolean; onPdfLoadError: () => void; + description?: string; + onDownload?: () => void; } export function FilePreviewRenderer({ @@ -28,6 +30,8 @@ export function FilePreviewRenderer({ pdfAsBlob, pdfLoadFailed, onPdfLoadError, + description, + onDownload, }: FilePreviewRendererProps) { if (isLoading) { return ; @@ -63,7 +67,7 @@ export function FilePreviewRenderer({ return ; case "image": - return ; + return ; case "audio": return ; diff --git a/apps/web/src/components/modals/previews/image-preview.tsx b/apps/web/src/components/modals/previews/image-preview.tsx index c821421..efb844e 100644 --- a/apps/web/src/components/modals/previews/image-preview.tsx +++ b/apps/web/src/components/modals/previews/image-preview.tsx @@ -1,7 +1,8 @@ "use client"; import { useEffect, useState } from "react"; -import { IconMaximize, IconX } from "@tabler/icons-react"; +import { IconDownload, IconMaximize, IconX } from "@tabler/icons-react"; +import { useTranslations } from "next-intl"; import { createPortal } from "react-dom"; import { AspectRatio } from "@/components/ui/aspect-ratio"; @@ -10,10 +11,13 @@ import { Button } from "@/components/ui/button"; interface ImagePreviewProps { src: string; alt: string; + description?: string; + onDownload?: () => void; } -export function ImagePreview({ src, alt }: ImagePreviewProps) { +export function ImagePreview({ src, alt, description, onDownload }: ImagePreviewProps) { const [isFullscreen, setIsFullscreen] = useState(false); + const t = useTranslations(); const handleExpandClick = () => { setIsFullscreen(true); @@ -29,7 +33,19 @@ export function ImagePreview({ src, alt }: ImagePreviewProps) { } }; - // Handle ESC key press + const handleDownload = () => { + if (onDownload) { + onDownload(); + } else { + const link = document.createElement("a"); + link.href = src; + link.download = alt; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + }; + useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape" && isFullscreen) { @@ -39,7 +55,6 @@ export function ImagePreview({ src, alt }: ImagePreviewProps) { if (isFullscreen) { document.addEventListener("keydown", handleKeyDown); - // Prevent body scroll when fullscreen is open document.body.style.overflow = "hidden"; } @@ -76,26 +91,56 @@ export function ImagePreview({ src, alt }: ImagePreviewProps) { typeof window !== "undefined" && createPortal(
- +
+
+ + +
+
- {alt} e.stopPropagation()} - style={{ maxWidth: "100vw", maxHeight: "100vh" }} - /> +
+
+ {alt} e.stopPropagation()} + /> +
+
+ +
+
+
+ {alt} + {description &&

{description}

} +
+
+
, document.body )} diff --git a/apps/web/src/hooks/use-file-manager.ts b/apps/web/src/hooks/use-file-manager.ts index dca09c5..90efe39 100644 --- a/apps/web/src/hooks/use-file-manager.ts +++ b/apps/web/src/hooks/use-file-manager.ts @@ -18,6 +18,7 @@ interface FileToDelete { interface PreviewFile { name: string; objectName: string; + description?: string; } interface FileToShare {