디렉터리 페이지에 상위 디렉터리로 이동 버튼 추가

This commit is contained in:
static
2025-12-27 03:04:09 +09:00
parent 9eb67d5877
commit 576d41da7f
5 changed files with 48 additions and 8 deletions

View File

@@ -3,6 +3,7 @@
import { IconLabel } from "$lib/components/molecules";
import IconFolder from "~icons/material-symbols/folder";
import IconDriveFolderUpload from "~icons/material-symbols/drive-folder-upload";
import IconDraft from "~icons/material-symbols/draft";
interface Props {
@@ -11,7 +12,7 @@
subtext?: string;
textClass?: ClassValue;
thumbnail?: string;
type: "directory" | "file";
type: "directory" | "parent-directory" | "file";
}
let {
@@ -30,6 +31,8 @@
<img src={thumbnail} alt={name} loading="lazy" class="aspect-square rounded object-cover" />
{:else if type === "directory"}
<IconFolder />
{:else if type === "parent-directory"}
<IconDriveFolderUpload class="text-yellow-500" />
{:else}
<IconDraft class="text-blue-400" />
{/if}

View File

@@ -23,6 +23,7 @@ import { trpc } from "$trpc/client";
export type DirectoryInfo =
| {
id: "root";
parentId?: undefined;
dataKey?: undefined;
dataKeyVersion?: undefined;
name?: undefined;
@@ -31,6 +32,7 @@ export type DirectoryInfo =
}
| {
id: number;
parentId: DirectoryId;
dataKey?: CryptoKey;
dataKeyVersion?: Date;
name: string;
@@ -93,7 +95,13 @@ const fetchDirectoryInfoFromIndexedDB = async (
info.set({ id, subDirectoryIds, fileIds });
} else {
if (!directory) return;
info.set({ id, name: directory.name, subDirectoryIds, fileIds });
info.set({
id,
parentId: directory.parentId,
name: directory.name,
subDirectoryIds,
fileIds,
});
}
};
@@ -124,6 +132,7 @@ const fetchDirectoryInfoFromServer = async (
info.set({
id,
parentId: metadata!.parent,
dataKey,
dataKeyVersion: new Date(metadata!.dekVersion),
name,

View File

@@ -44,12 +44,13 @@
{#if directoryId}
{@render menuButton(IconFolderOpen, "폴더에서 보기", () =>
goto(directoryId === "root" ? "/directory" : `/directory/${directoryId}`),
goto(
directoryId === "root" ? "/directory?from=file" : `/directory/${directoryId}?from=file`,
),
)}
{/if}
{#if fileBlob}
{@render menuButton(IconCloudDownload, "다운로드", () => {
console.log(filename);
FileSaver.saveAs(fileBlob, filename);
})}
{/if}

View File

@@ -2,6 +2,7 @@
import { onMount } from "svelte";
import type { Writable } from "svelte/store";
import { goto } from "$app/navigation";
import { page } from "$app/state";
import { FloatingButton } from "$lib/components/atoms";
import { TopBar } from "$lib/components/molecules";
import { getDirectoryInfo, type DirectoryInfo } from "$lib/modules/filesystem";
@@ -42,6 +43,9 @@
let isEntryRenameModalOpen = $state(false);
let isEntryDeleteModalOpen = $state(false);
let isFromFilePage = $derived(page.url.searchParams.get("from") === "file");
let showTopBar = $derived(data.id !== "root" || isFromFilePage);
const uploadFile = () => {
const files = fileInput?.files;
if (!files || files.length === 0) return;
@@ -86,11 +90,11 @@
<input bind:this={fileInput} onchange={uploadFile} type="file" multiple class="hidden" />
<div class="flex h-full flex-col">
{#if data.id !== "root"}
{#if showTopBar}
<TopBar title={$info?.name} class="flex-shrink-0" />
{/if}
{#if $info}
<div class={["flex flex-grow flex-col px-4 pb-4", data.id === "root" && "pt-4"]}>
<div class={["flex flex-grow flex-col px-4 pb-4", !showTopBar && "pt-4"]}>
<div class="flex gap-x-2">
<UploadStatusCard onclick={() => goto("/file/uploads")} />
<DownloadStatusCard onclick={() => goto("/file/downloads")} />
@@ -103,6 +107,13 @@
context.selectedEntry = entry;
isEntryMenuBottomSheetOpen = true;
}}
showParentEntry={isFromFilePage && $info.parentId !== undefined}
onParentClick={() =>
goto(
$info.parentId === "root"
? "/directory?from=file"
: `/directory/${$info.parentId}?from=file`,
)}
/>
{/key}
</div>

View File

@@ -1,6 +1,8 @@
<script lang="ts">
import { untrack } from "svelte";
import { get, type Writable } from "svelte/store";
import { ActionEntryButton } from "$lib/components/atoms";
import { DirectoryEntryLabel } from "$lib/components/molecules";
import {
getDirectoryInfo,
getFileInfo,
@@ -23,10 +25,19 @@
info: DirectoryInfo;
onEntryClick: (entry: SelectedEntry) => void;
onEntryMenuClick: (entry: SelectedEntry) => void;
onParentClick?: () => void;
showParentEntry?: boolean;
sortBy?: SortBy;
}
let { info, onEntryClick, onEntryMenuClick, sortBy = SortBy.NAME_ASC }: Props = $props();
let {
info,
onEntryClick,
onEntryMenuClick,
onParentClick,
showParentEntry = false,
sortBy = SortBy.NAME_ASC,
}: Props = $props();
interface DirectoryEntry {
name?: string;
@@ -106,8 +117,13 @@
});
</script>
{#if subDirectories.length + files.length > 0}
{#if subDirectories.length + files.length > 0 || showParentEntry}
<div class="space-y-1 pb-[4.5rem]">
{#if showParentEntry}
<ActionEntryButton class="h-14" onclick={onParentClick}>
<DirectoryEntryLabel type="parent-directory" name=".." />
</ActionEntryButton>
{/if}
{#each subDirectories as { info }}
<SubDirectory {info} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
{/each}