From 820eb340cfbdcb35693c0cc02febf52d02bc29d2 Mon Sep 17 00:00:00 2001 From: florian <> Date: Tue, 9 Apr 2024 22:10:58 +0200 Subject: [PATCH] feat: Added server add button --- src/components/BlobList/BlobList.css | 8 ++- src/components/BlobList/BlobList.tsx | 23 ++++++-- src/components/ProgressBar/ProgressBar.tsx | 11 ++-- src/components/ServerList/ServerList.css | 21 +++++++ src/components/ServerList/ServerList.tsx | 54 +++++++++++------ src/pages/Home.tsx | 2 +- src/pages/Transfer.tsx | 8 +-- src/pages/Upload.tsx | 67 ++++++++++++++++++---- 8 files changed, 150 insertions(+), 44 deletions(-) diff --git a/src/components/BlobList/BlobList.css b/src/components/BlobList/BlobList.css index 7acef7f..c1d6e4b 100644 --- a/src/components/BlobList/BlobList.css +++ b/src/components/BlobList/BlobList.css @@ -12,7 +12,7 @@ .blob-list .blob { @apply p-1 hover:bg-zinc-700 rounded-md grid pr-4; - grid-template-columns: 2em auto 6em 10em 7em 3em; + grid-template-columns: 2em auto /*auto*/ 2em 6em 10em 7em 3em; } .blob-list .blob span { @@ -32,7 +32,7 @@ } .blog-list-header button { - @apply bg-zinc-800 hover:bg-zinc-700 p-2 ml-2 my-2 text-white rounded-lg disabled:text-zinc-700 disabled:bg-zinc-900; + @apply bg-zinc-800 hover:bg-zinc-700 p-2 ml-2 my-2 text-white rounded-lg disabled:text-zinc-700 disabled:bg-zinc-900; } .blog-list-header button.selected { @@ -42,3 +42,7 @@ .blog-list-header svg { @apply w-6 opacity-80 hover:opacity-100; } + +.blob-list .blob span a.pill { + @apply bg-zinc-700 p-1 px-2 rounded-2xl text-white; +} \ No newline at end of file diff --git a/src/components/BlobList/BlobList.tsx b/src/components/BlobList/BlobList.tsx index f704c93..367de2c 100644 --- a/src/components/BlobList/BlobList.tsx +++ b/src/components/BlobList/BlobList.tsx @@ -1,6 +1,7 @@ import { ClipboardDocumentIcon, DocumentIcon, + ExclamationTriangleIcon, FilmIcon, ListBulletIcon, MusicalNoteIcon, @@ -15,6 +16,7 @@ import { Document, Page } from 'react-pdf'; import * as id3 from 'id3js'; import { ID3Tag, ID3TagV2 } from 'id3js/lib/id3Tag'; import { useQueries } from '@tanstack/react-query'; +import { useServerInfo } from '../../utils/useServerInfo'; type ListMode = 'gallery' | 'list' | 'audio' | 'video' | 'docs'; @@ -28,6 +30,7 @@ type AudioBlob = BlobDescriptor & { id3?: ID3Tag; imageData?: string }; const BlobList = ({ blobs, onDelete, title }: BlobListProps) => { const [mode, setMode] = useState('list'); + const { distribution } = useServerInfo(); const images = useMemo( () => blobs.filter(b => b.type?.startsWith('image/')).sort((a, b) => (a.created > b.created ? -1 : 1)), // descending @@ -100,18 +103,18 @@ const BlobList = ({ blobs, onDelete, title }: BlobListProps) => {
{ navigator.clipboard.writeText(blob.url); }} > - + {onDelete && ( - onDelete(blob)} className=" cursor-pointer"> - + onDelete(blob)} className="cursor-pointer"> + )} @@ -289,6 +292,18 @@ const BlobList = ({ blobs, onDelete, title }: BlobListProps) => { {blob.sha256} + {/* + + 🌸 drive 📝 post + + */} + + {distribution[blob.sha256].servers.length == 1 ? ( + + ) : ( + '' + )} + {formatFileSize(blob.size)} {blob.type && `${blob.type}`} {formatDate(blob.created)} diff --git a/src/components/ProgressBar/ProgressBar.tsx b/src/components/ProgressBar/ProgressBar.tsx index 019aa4b..6859d9f 100644 --- a/src/components/ProgressBar/ProgressBar.tsx +++ b/src/components/ProgressBar/ProgressBar.tsx @@ -1,12 +1,15 @@ -const ProgressBar = ({ value, max }: { value: number; max: number }) => { +const ProgressBar = ({ value, max, description = '' }: { value: number; max: number; description?: string }) => { + //value=11;max=100;description="4,5 MB/s" + const percent = Math.floor((value * 100) / max); + const showDescription = percent > 10 && percent < 100; return (
{max !== undefined && value !== undefined && max > 0 && (
- {Math.floor((value * 100) / max)} % + {percent} % {showDescription ? description : ''}
)}
diff --git a/src/components/ServerList/ServerList.css b/src/components/ServerList/ServerList.css index e9df57b..31c860f 100644 --- a/src/components/ServerList/ServerList.css +++ b/src/components/ServerList/ServerList.css @@ -54,3 +54,24 @@ transform-origin: center; animation: spin 3s linear infinite; } + + +.server-list-header { + @apply flex flex-row mt-4; +} + +.server-list-header h2 { + @apply flex-grow; +} + +.server-list-header button { + @apply bg-zinc-800 hover:bg-zinc-700 p-2 ml-2 my-2 text-white rounded-lg disabled:text-zinc-700 disabled:bg-zinc-900; +} + +.server-list-header button.selected { + @apply bg-pink-700 text-white; +} + +.server-list-header svg { + @apply w-6 opacity-80 hover:opacity-100; +} diff --git a/src/components/ServerList/ServerList.tsx b/src/components/ServerList/ServerList.tsx index 755004a..77ed982 100644 --- a/src/components/ServerList/ServerList.tsx +++ b/src/components/ServerList/ServerList.tsx @@ -1,3 +1,4 @@ +import { PlusIcon, ServerIcon } from '@heroicons/react/24/outline'; import { useServerInfo } from '../../utils/useServerInfo'; import { Server as ServerType } from '../../utils/useServers'; import Server from './Server'; @@ -10,29 +11,50 @@ type ServerListProps = { onTransfer?: (server: string) => void; onCancel?: () => void; onCheck?: (server: string) => void; + title?: React.ReactElement; + showAddButton?: boolean; }; -export const ServerList = ({ servers, selectedServer, setSelectedServer, onTransfer, onCancel }: ServerListProps) => { +export const ServerList = ({ + servers, + selectedServer, + setSelectedServer, + onTransfer, + onCancel, + title, + showAddButton = false +}: ServerListProps) => { const { serverInfo, distribution } = useServerInfo(); const blobsWithOnlyOneOccurance = Object.values(distribution) .filter(d => d.servers.length == 1) .map(d => ({ ...d.blob, server: d.servers[0] })); return ( -
- {servers.map(server => ( - b.server == server.name).length} - > - ))} -
+ <> +
+ {title &&

{title}

} + {showAddButton &&
+ +
} +
+ +
+ {servers.map(server => ( + b.server == server.name).length} + > + ))} +
+ ); }; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 0a1fab9..5990cc0 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -54,13 +54,13 @@ function Home() { return ( <> -

Servers

navigate('/transfer/' + selectedServer)} onCheck={() => navigate('/check/' + selectedServer)} + title={<>Servers} > {selectedServer && serverInfo[selectedServer] && selectedServerBlobs && ( diff --git a/src/pages/Transfer.tsx b/src/pages/Transfer.tsx index 239ab05..3a20029 100644 --- a/src/pages/Transfer.tsx +++ b/src/pages/Transfer.tsx @@ -103,22 +103,18 @@ export const Transfer = () => { return ( transferSource && ( <> -

- Transfer Source -

s.name == transferSource)} onCancel={() => closeTransferMode()} + title={<> Transfer Source} > -

- Transfer Target -

s.name != transferSource) .sort()} selectedServer={transferTarget} setSelectedServer={setTransferTarget} + title={<> Transfer Target} > {transferTarget && transferJobs && transferJobs.length > 0 ? ( <> diff --git a/src/pages/Upload.tsx b/src/pages/Upload.tsx index b91c7e8..d207e57 100644 --- a/src/pages/Upload.tsx +++ b/src/pages/Upload.tsx @@ -4,7 +4,7 @@ import { BlobDescriptor, BlossomClient, SignedEvent } from 'blossom-client-sdk'; import { useNDK } from '../ndk'; import { useServerInfo } from '../utils/useServerInfo'; import { useQueryClient } from '@tanstack/react-query'; -import { ArrowUpOnSquareIcon } from '@heroicons/react/24/outline'; +import { ArrowUpOnSquareIcon, TrashIcon } from '@heroicons/react/24/outline'; import ProgressBar from '../components/ProgressBar/ProgressBar'; import { removeExifData } from '../exif'; import CheckBox from '../components/CheckBox/CheckBox'; @@ -25,9 +25,30 @@ function Upload() { const [transfers, setTransfers] = useState<{ [key: string]: TransferStats }>({}); const [files, setFiles] = useState([]); const [cleanPrivateData, setCleanPrivateData] = useState(true); + const [transferSpeed, setTransferSpeed] = useState(); + // const [resizeImages, setResizeImages] = useState(false); // const [publishToNostr, setPublishToNostr] = useState(false); + type ImageSize = { + width: number; + height: number; + }; + + const getImageSize = async (imageFile: File): Promise => { + const img = new Image(); + const objectUrl = URL.createObjectURL(imageFile); + const promise = new Promise((resolve, reject) => { + img.onload = () => { + resolve({ width: img.width, height: img.height }); + URL.revokeObjectURL(objectUrl); + }; + img.onerror = () => reject(); + }); + img.src = objectUrl; + return promise; + }; + async function uploadBlob( server: string, file: File, @@ -59,6 +80,12 @@ function Upload() { // TODO use https://github.com/davejm/client-compress // for image resizing + for (const file of filesToUpload) { + if (file.type.startsWith('image/')) { + const dimensions = await getImageSize(file); + console.log(dimensions); + } + } if (filesToUpload && filesToUpload.length) { // sum files sizes @@ -85,6 +112,7 @@ function Upload() { const uploadAuth = await BlossomClient.getUploadAuth(file, signEventTemplate, 'Upload Blob'); const newBlob = await uploadBlob(serverUrl, file, uploadAuth, progressEvent => { + setTransferSpeed(progressEvent.rate); setTransfers(ut => ({ ...ut, [server.name]: { ...ut[server.name], transferred: serverTransferred + progressEvent.loaded }, @@ -101,6 +129,7 @@ function Upload() { } queryClient.invalidateQueries({ queryKey: ['blobs', server.name] }); setFiles([]); + // TODO reset input control value?? } } }; @@ -118,6 +147,7 @@ function Upload() { if (selectedFiles && selectedFiles.length > 0) { const newFiles = Array.from(selectedFiles); setFiles(prevFiles => [...prevFiles, ...newFiles]); + clearTransfers(); } }; @@ -127,6 +157,7 @@ function Upload() { if (droppedFiles && droppedFiles.length > 0) { const newFiles = Array.from(droppedFiles); setFiles(prevFiles => [...prevFiles, ...newFiles]); + clearTransfers(); } }; @@ -145,7 +176,6 @@ function Upload() { > Browse or drag & drop -

Servers

{servers.map(s => ( @@ -157,14 +187,17 @@ function Upload() { label={s.name} > {transfers[s.name]?.enabled ? ( - + ) : (
)} ))}
-

Options

*/}
- +
+ + +
);