mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-02-04 08:06:56 +00:00
디렉터리 페이지에서 하위 디렉터리도 가상 리스트로 표시하도록 개선
This commit is contained in:
@@ -13,24 +13,38 @@
|
||||
|
||||
let { class: className, count, item, itemHeight, placeholder }: Props = $props();
|
||||
|
||||
let element: HTMLElement | undefined = $state();
|
||||
let scrollMargin = $state(0);
|
||||
|
||||
const virtualizer = $derived(
|
||||
createWindowVirtualizer({
|
||||
count,
|
||||
estimateSize: itemHeight,
|
||||
scrollMargin,
|
||||
}),
|
||||
);
|
||||
|
||||
const measureItem = (node: HTMLElement) => {
|
||||
$effect(() => $virtualizer.measureElement(node));
|
||||
};
|
||||
|
||||
$effect(() => {
|
||||
if (!element) return;
|
||||
|
||||
const observer = new ResizeObserver(() => {
|
||||
scrollMargin = element!.getBoundingClientRect().top + window.scrollY;
|
||||
});
|
||||
observer.observe(element.parentElement!);
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class={["relative", className]}>
|
||||
<div bind:this={element} class={["relative", className]}>
|
||||
<div style:height="{$virtualizer.getTotalSize()}px">
|
||||
{#each $virtualizer.getVirtualItems() as virtualItem (virtualItem.key)}
|
||||
<div
|
||||
class="absolute left-0 top-0 w-full"
|
||||
style:transform="translateY({virtualItem.start}px)"
|
||||
style:transform="translateY({virtualItem.start - scrollMargin}px)"
|
||||
data-index={virtualItem.index}
|
||||
use:measureItem
|
||||
>
|
||||
|
||||
@@ -145,7 +145,9 @@
|
||||
</button>
|
||||
<TopBarMenu
|
||||
bind:isOpen={isMenuOpen}
|
||||
directoryId={page.url.searchParams.get("from") === "category" ? $info?.parentId : undefined}
|
||||
directoryId={["category", "gallery"].includes(page.url.searchParams.get("from") ?? "")
|
||||
? $info?.parentId
|
||||
: undefined}
|
||||
{fileBlob}
|
||||
filename={$info?.name}
|
||||
/>
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
|
||||
<TopBar title="사진 및 동영상" />
|
||||
<FullscreenDiv>
|
||||
<Gallery {files} onFileClick={({ id }) => goto(`/file/${id}`)} />
|
||||
<Gallery {files} onFileClick={({ id }) => goto(`/file/${id}?from=gallery`)} />
|
||||
</FullscreenDiv>
|
||||
|
||||
@@ -25,56 +25,57 @@
|
||||
showParentEntry = false,
|
||||
}: Props = $props();
|
||||
|
||||
type FileEntry =
|
||||
type Entry =
|
||||
| { type: "parent" }
|
||||
| { type: "directory"; name: string; details: (typeof info.subDirectories)[number] }
|
||||
| { type: "file"; name: string; details: (typeof info.files)[number] }
|
||||
| { type: "uploading-file"; name: string; details: LiveFileUploadState };
|
||||
|
||||
const toFileEntry =
|
||||
<T extends FileEntry["type"]>(type: T) =>
|
||||
(details: Extract<FileEntry, { type: T }>["details"]) => ({
|
||||
const toEntry =
|
||||
<T extends Exclude<Entry["type"], "parent">>(type: T) =>
|
||||
(details: Extract<Entry, { type: T }>["details"]) => ({
|
||||
type,
|
||||
name: details.name,
|
||||
details,
|
||||
});
|
||||
|
||||
const subDirectories = $derived(
|
||||
sortEntries(structuredClone($state.snapshot(info.subDirectories))),
|
||||
);
|
||||
const files = $derived(
|
||||
sortEntries<FileEntry>([
|
||||
...info.files.map(toFileEntry("file")),
|
||||
...getUploadingFiles(info.id).map(toFileEntry("uploading-file")),
|
||||
const entries = $derived([
|
||||
...(showParentEntry ? ([{ type: "parent" }] as const) : []),
|
||||
...sortEntries(info.subDirectories.map(toEntry("directory"))),
|
||||
...sortEntries([
|
||||
...info.files.map(toEntry("file")),
|
||||
...getUploadingFiles(info.id).map(toEntry("uploading-file")),
|
||||
]),
|
||||
);
|
||||
]);
|
||||
</script>
|
||||
|
||||
{#if subDirectories.length + files.length > 0 || showParentEntry}
|
||||
<div class="space-y-1 pb-[4.5rem]">
|
||||
{#if showParentEntry}
|
||||
{#if entries.length > 0}
|
||||
<div class="pb-[4.5rem]">
|
||||
<RowVirtualizer
|
||||
count={entries.length}
|
||||
itemHeight={(index) => 56 + (index + 1 < entries.length ? 4 : 0)}
|
||||
>
|
||||
{#snippet item(index)}
|
||||
{@const entry = entries[index]!}
|
||||
<div class={index + 1 < entries.length ? "pb-1" : ""}>
|
||||
{#if entry.type === "parent"}
|
||||
<ActionEntryButton class="h-14" onclick={onParentClick}>
|
||||
<DirectoryEntryLabel type="parent-directory" name=".." />
|
||||
</ActionEntryButton>
|
||||
{/if}
|
||||
{#each subDirectories as subDirectory}
|
||||
<SubDirectory info={subDirectory} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
|
||||
{/each}
|
||||
{#if files.length > 0}
|
||||
<RowVirtualizer
|
||||
count={files.length}
|
||||
itemHeight={(index) => 56 + (index + 1 < files.length ? 4 : 0)}
|
||||
>
|
||||
{#snippet item(index)}
|
||||
{@const file = files[index]!}
|
||||
<div class={index + 1 < files.length ? "pb-1" : ""}>
|
||||
{#if file.type === "file"}
|
||||
<File info={file.details} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
|
||||
{:else if entry.type === "directory"}
|
||||
<SubDirectory
|
||||
info={entry.details}
|
||||
onclick={onEntryClick}
|
||||
onOpenMenuClick={onEntryMenuClick}
|
||||
/>
|
||||
{:else if entry.type === "file"}
|
||||
<File info={entry.details} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
|
||||
{:else}
|
||||
<UploadingFile state={file.details} />
|
||||
<UploadingFile state={entry.details} />
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</RowVirtualizer>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-grow items-center justify-center">
|
||||
|
||||
Reference in New Issue
Block a user