Skip to content

Commit

Permalink
handle folder uploads
Browse files Browse the repository at this point in the history
show image previews
  • Loading branch information
hzrd149 committed Feb 21, 2024
1 parent 9de628e commit 10d6fe0
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 26 deletions.
4 changes: 3 additions & 1 deletion src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
};
</script>

<div class="flex w-full flex-1 flex-col gap-2 overflow-y-auto overflow-x-hidden bg-white dark:bg-gray-900">
<div
class="flex w-full flex-1 flex-col gap-2 overflow-y-auto overflow-x-hidden bg-white text-gray-900 dark:bg-gray-900 dark:text-white"
>
{#if $activeUser}
<TopNav />
<Router {routes} />
Expand Down
22 changes: 20 additions & 2 deletions src/components/FileCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
? new URL(file.hash + (file.mimeType ? "." + mime.getExtension(file.mimeType) : ""), $servers[0]).toString()
: undefined;
$: extension = file.mimeType ? mime.getExtension(file.mimeType) : "bin";
$: preview = file.mimeType?.startsWith("image/") && file.size < 1024 * 100;
function toggleSelect() {
if (selected) dispatch("unselect", file.name);
else dispatch("select", file.name);
Expand Down Expand Up @@ -46,8 +49,12 @@
}}
bind:checked={selected}
/>
<div class="flex flex-grow items-center justify-center p-4 text-xl font-bold">
{file.mimeType ? mime.getExtension(file.mimeType) : "bin"}
<div class="flex flex-grow items-center justify-center overflow-hidden text-xl font-bold">
{#if preview && link}
<div class="preview-image" style="background-image: url({link});" />
{:else}
<span class="m-4">{extension}</span>
{/if}
</div>
<hr />
<div class="max-w-40 truncate px-4 py-2 text-center text-sm">{file.name}</div>
Expand All @@ -69,3 +76,14 @@
>
</Dropdown>
</a>

<style>
.preview-image {
image-rendering: pixelated;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
width: 100%;
height: 100%;
}
</style>
4 changes: 2 additions & 2 deletions src/components/SpeedDialMenu.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { SpeedDial, SpeedDialButton } from "flowbite-svelte";
import { UploadSolid, FolderSolid, GiftBoxSolid } from "flowbite-svelte-icons";
import { UploadSolid, FolderSolid, ArchiveSolid } from "flowbite-svelte-icons";
import UploadFileModal from "./UploadFileModal.svelte";
import NewDriveModal from "./NewDriveModal.svelte";
import NewFolderModal from "./NewFolderModal.svelte";
Expand All @@ -28,7 +28,7 @@
</SpeedDialButton>
{/if}
<SpeedDialButton name="Drive" on:click={() => (newDriveModal = true)}>
<GiftBoxSolid class="h-6 w-6" />
<ArchiveSolid class="h-6 w-6" />
</SpeedDialButton>
</SpeedDial>

Expand Down
26 changes: 26 additions & 0 deletions src/helpers/file-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export function readFileSystemFile(fileEntry: FileSystemFileEntry) {
return new Promise<File>((res, rej) => {
fileEntry.file(
(file) => res(file),
(err) => rej(err),
);
});
}
export function readFileSystemDirectory(directory: FileSystemDirectoryEntry) {
return new Promise<FileSystemEntry[]>((res, rej) => {
directory.createReader().readEntries(
(entries) => res(entries),
(err) => rej(err),
);
});
}

export async function getAllFileEntriesInTree(item: FileSystemEntry): Promise<FileSystemFileEntry[]> {
if (item.isFile) {
return [item as FileSystemFileEntry];
} else if (item.isDirectory) {
const entries = await readFileSystemDirectory(item as FileSystemDirectoryEntry);
return (await Promise.all(entries.map(getAllFileEntriesInTree))).flat();
}
return [];
}
80 changes: 59 additions & 21 deletions src/pages/Drive.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import RenameModal from "../components/RenameModal.svelte";
import { signEventTemplate } from "../services/ndk";
import { servers } from "../services/servers";
import { readFileSystemFile, getAllFileEntriesInTree, readFileSystemDirectory } from "../helpers/file-system";
export let params: Record<string, string | undefined> = {};
const naddr = params["naddr"];
Expand Down Expand Up @@ -116,39 +117,77 @@
function drop(e: DragEvent) {
e.preventDefault();
if (e.dataTransfer?.files.length) uploadFiles(e.dataTransfer.files);
if (e.dataTransfer?.files.length) {
uploadFiles(e.dataTransfer.items[0].webkitGetAsEntry() || e.dataTransfer.files);
}
}
function dragover(e: DragEvent) {
e.preventDefault();
}
async function uploadFiles(files: FileList, folder?: string) {
async function uploadFiles(fileList: FileList | FileSystemEntry, folder?: string) {
if (!drive) return;
const newTree = cloneTree(tree);
const path = parsePath(parsed.get("path"));
for (const file of files) {
try {
const auth = await BlossomClient.getUploadAuth(file, signEventTemplate);
let blob: Blob | undefined = undefined;
for (const server of $servers) {
async function uploadFile(file: File) {
const auth = await BlossomClient.getUploadAuth(file, signEventTemplate);
let descriptor: Blob | undefined = undefined;
for (const server of $servers) {
try {
descriptor = await BlossomClient.uploadBlob(server, file, auth);
} catch (e) {
console.log("Failed to upload to", server);
console.log(e);
}
}
return descriptor;
}
if (fileList instanceof FileSystemEntry) {
const getPath = (entry: FileSystemEntry) =>
folder ? [...path, folder, ...parsePath(entry.fullPath)] : [...path, ...parsePath(entry.fullPath)];
async function walkTree(entry: FileSystemEntry) {
if (entry instanceof FileSystemFileEntry && entry.isFile) {
try {
blob = await BlossomClient.uploadBlob(server, file, auth);
const file = await readFileSystemFile(entry);
let descriptor = await uploadFile(file);
if (descriptor) {
setFile(newTree, getPath(entry), {
hash: descriptor.sha256,
size: descriptor.size,
mimeType: descriptor.type,
});
}
} catch (e) {
console.log("Failed to upload to", server);
console.log("Failed to upload" + entry.fullPath);
console.log(e);
}
} else if (entry instanceof FileSystemDirectoryEntry && entry.isDirectory) {
const entries = await readFileSystemDirectory(entry);
// create empty folders
getFolder(newTree, getPath(entry), true);
for (const e of entries) await walkTree(e);
}
}
if (blob) {
setFile(newTree, folder ? [...path, folder, file.name] : [...path, file.name], {
hash: blob.sha256,
size: blob.size,
mimeType: blob.type,
});
await walkTree(fileList);
} else if (fileList instanceof FileList) {
for (const file of fileList) {
try {
let descriptor = await uploadFile(file);
if (descriptor) {
setFile(newTree, folder ? [...path, folder, file.name] : [...path, file.name], {
hash: descriptor.sha256,
size: descriptor.size,
mimeType: descriptor.type,
});
}
} catch (e) {
console.log("Failed to upload" + file.name);
console.log(e);
}
} catch (e) {
console.log("Failed to upload" + file.name);
console.log(e);
}
}
Expand All @@ -163,7 +202,7 @@
{#if !drive}
<Spinner />
{:else}
<main class="flex flex-grow flex-col gap-4 p-4">
<main class="flex flex-grow flex-col gap-4 p-4" on:drop={drop} on:dragover={dragover}>
<div class="flex justify-between gap-2">
<PathBreadcrumbs root={getDriveName(drive) ?? "Drive"} />
{#if selected.length > 0}
Expand All @@ -174,8 +213,7 @@
</div>
{/if}
</div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="flex flex-grow flex-wrap items-start gap-4" on:drop={drop} on:dragover={dragover}>
<div class="flex flex-wrap items-start gap-4">
{#each folders as folder}
<FolderCard
name={folder}
Expand Down
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { VitePWA } from "vite-plugin-pwa";
// https://vitejs.dev/config/
export default defineConfig({
base: process.env.VITE_BASE ?? "/",
build: { sourcemap: true },
plugins: [
svelte(),
VitePWA({
Expand Down

0 comments on commit 10d6fe0

Please sign in to comment.