mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 08:10:28 +09:00
컴포넌트를 도메인과 무관한 UI 컴포넌트와 도메인 컴포넌트로 재구성하고 중복된 파일 목록 컴포넌트 통합 및 모듈 간 의존성 방향을 ESLint로 강제
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e82c5e556
commit
877cf9c42e
94 files changed
+398
-518
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { AdaptiveDiv } from "#lib/components/atoms/index.js";
|
||||
import { AdaptiveDiv } from "#lib/ui/index.js";
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { BottomDiv, Button, FullscreenDiv, TextInput } from "#lib/components/atoms/index.js";
|
||||
import { TitledDiv, TopBar } from "#lib/components/molecules/index.js";
|
||||
import { showToast, tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { changePassword as requestPasswordChange } from "#lib/features/auth/index.js";
|
||||
import { tryAction } from "#lib/features/errors.js";
|
||||
import {
|
||||
BottomDiv,
|
||||
Button,
|
||||
FullscreenDiv,
|
||||
TextInput,
|
||||
TitledDiv,
|
||||
TopBar,
|
||||
showToast,
|
||||
} from "#lib/ui/index.js";
|
||||
|
||||
let oldPassword = $state("");
|
||||
let newPassword = $state("");
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import {
|
||||
downloadMasterKeys,
|
||||
keyring,
|
||||
requestClientRegistrationAndSessionUpgrade,
|
||||
} from "#lib/client/keys/index.js";
|
||||
import { ForceLoginModal } from "#lib/features/auth/components/index.js";
|
||||
import { login as requestLogin, logout as requestLogout } from "#lib/features/auth/index.js";
|
||||
import { showErrorToast } from "#lib/features/errors.js";
|
||||
import { cleanupDeletedFileCaches } from "#lib/features/filesystem/index.js";
|
||||
import {
|
||||
BottomDiv,
|
||||
Button,
|
||||
FullscreenDiv,
|
||||
TextButton,
|
||||
TextInput,
|
||||
} from "#lib/components/atoms/index.js";
|
||||
import { TitledDiv } from "#lib/components/molecules/index.js";
|
||||
import { ForceLoginModal } from "#lib/components/organisms/index.js";
|
||||
import {
|
||||
downloadMasterKeys,
|
||||
keyring,
|
||||
requestClientRegistrationAndSessionUpgrade,
|
||||
} from "#lib/client/keys/index.js";
|
||||
import { showErrorToast, showToast } from "#lib/client/toast.svelte.js";
|
||||
import { login as requestLogin, logout as requestLogout } from "#lib/features/auth/index.js";
|
||||
import { cleanupDeletedFileCaches } from "#lib/features/filesystem/index.js";
|
||||
TitledDiv,
|
||||
showToast,
|
||||
} from "#lib/ui/index.js";
|
||||
import { isTRPCClientError } from "#trpc/client.js";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { TitledDiv } from "#lib/components/molecules/index.js";
|
||||
import {
|
||||
downloadMasterKeys,
|
||||
generatePublicKeyFingerprint,
|
||||
keyring,
|
||||
} from "#lib/client/keys/index.js";
|
||||
import { FullscreenDiv, TitledDiv } from "#lib/ui/index.js";
|
||||
|
||||
import IconFingerprint from "~icons/material-symbols/fingerprint";
|
||||
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
import { untrack } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import { FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { Categories, IconEntryButton, TopBar } from "#lib/components/molecules/index.js";
|
||||
import { captureVideoThumbnail } from "#lib/client/media/thumbnail.js";
|
||||
import { getFileDownloadState } from "#lib/client/transfer/index.js";
|
||||
import { showErrorToast, tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { showErrorToast, tryAction } from "#lib/features/errors.js";
|
||||
import { Categories } from "#lib/features/filesystem/components/index.js";
|
||||
import {
|
||||
addFileToCategory,
|
||||
getFileContent,
|
||||
@@ -19,6 +18,7 @@
|
||||
type DataKey,
|
||||
type FileInfo,
|
||||
} from "#lib/features/filesystem/index.js";
|
||||
import { FullscreenDiv, IconEntryButton, TopBar } from "#lib/ui/index.js";
|
||||
import AddToCategoryBottomSheet from "./AddToCategoryBottomSheet.svelte";
|
||||
import DownloadStatus from "./DownloadStatus.svelte";
|
||||
import TopBarMenu from "./TopBarMenu.svelte";
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { SubCategories } from "#lib/components/molecules/index.js";
|
||||
import { CategoryCreateModal } from "#lib/components/organisms/index.js";
|
||||
import { tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { tryAction } from "#lib/features/errors.js";
|
||||
import { SubCategories, CategoryCreateModal } from "#lib/features/filesystem/components/index.js";
|
||||
import { createCategory, useCategory } from "#lib/features/filesystem/index.js";
|
||||
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "#lib/ui/index.js";
|
||||
|
||||
interface Props {
|
||||
onAddToCategoryClick: (categoryId: number) => void;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import {
|
||||
getDownloadingFiles,
|
||||
clearDownloadedFiles,
|
||||
type FileDownloadState,
|
||||
} from "#lib/client/transfer/index.js";
|
||||
import { bulkGetFileInfo, type MaybeFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { FullscreenDiv, TopBar } from "#lib/ui/index.js";
|
||||
import File from "./File.svelte";
|
||||
|
||||
let downloadingFiles: { info: MaybeFileInfo; state: FileDownloadState }[] = $state([]);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import { getUploadingFiles, clearUploadedFiles } from "#lib/client/transfer/index.js";
|
||||
import { FullscreenDiv, TopBar } from "#lib/ui/index.js";
|
||||
import File from "./File.svelte";
|
||||
|
||||
const uploadingFiles = getUploadingFiles();
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import {
|
||||
FileThumbnailButton,
|
||||
FullscreenDiv,
|
||||
RowVirtualizer,
|
||||
} from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import { FileThumbnailButton } from "#lib/features/filesystem/components/index.js";
|
||||
import {
|
||||
bulkGetFileInfo,
|
||||
type MaybeFileInfo,
|
||||
type SummarizedFileInfo,
|
||||
} from "#lib/features/filesystem/index.js";
|
||||
import { FullscreenDiv, RowVirtualizer, TopBar } from "#lib/ui/index.js";
|
||||
import { formatDate, formatDateSortable, SortBy, sortEntries } from "#lib/utils/index.js";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<script lang="ts">
|
||||
import FileSaver from "file-saver";
|
||||
import { goto } from "$app/navigation";
|
||||
import { BottomDiv, Button, FullscreenDiv, TextButton } from "#lib/components/atoms/index.js";
|
||||
import { TitledDiv } from "#lib/components/molecules/index.js";
|
||||
import {
|
||||
keyring,
|
||||
registerInitialMasterKeyAndHmacSecret,
|
||||
@@ -10,7 +8,14 @@
|
||||
requestSessionUpgrade,
|
||||
serializeClientKeys,
|
||||
} from "#lib/client/keys/index.js";
|
||||
import { showToast } from "#lib/client/toast.svelte.js";
|
||||
import {
|
||||
BottomDiv,
|
||||
Button,
|
||||
FullscreenDiv,
|
||||
TextButton,
|
||||
TitledDiv,
|
||||
showToast,
|
||||
} from "#lib/ui/index.js";
|
||||
import BeforeContinueBottomSheet from "./BeforeContinueBottomSheet.svelte";
|
||||
import BeforeContinueModal from "./BeforeContinueModal.svelte";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "#lib/ui/index.js";
|
||||
|
||||
interface Props {
|
||||
onRetryClick: () => void;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ActionModal } from "#lib/components/molecules/index.js";
|
||||
import { ActionModal } from "#lib/ui/index.js";
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { BottomDiv, Button, FullscreenDiv, TextButton } from "#lib/components/atoms/index.js";
|
||||
import { TitledDiv } from "#lib/components/molecules/index.js";
|
||||
import { ForceLoginModal } from "#lib/components/organisms/index.js";
|
||||
import {
|
||||
generateClientKeys,
|
||||
generateInitialHmacSecret,
|
||||
@@ -13,8 +10,16 @@
|
||||
registerInitialMasterKeyAndHmacSecret,
|
||||
requestClientRegistrationAndSessionUpgrade,
|
||||
} from "#lib/client/keys/index.js";
|
||||
import { showToast } from "#lib/client/toast.svelte.js";
|
||||
import { ForceLoginModal } from "#lib/features/auth/components/index.js";
|
||||
import { cleanupDeletedFileCaches } from "#lib/features/filesystem/index.js";
|
||||
import {
|
||||
BottomDiv,
|
||||
Button,
|
||||
FullscreenDiv,
|
||||
TextButton,
|
||||
TitledDiv,
|
||||
showToast,
|
||||
} from "#lib/ui/index.js";
|
||||
import { gotoStateful } from "#lib/utils/index.js";
|
||||
import Order from "./Order.svelte";
|
||||
|
||||
|
||||
@@ -4,17 +4,16 @@
|
||||
import { untrack } from "svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
import { goto } from "$app/navigation";
|
||||
import { Chip, FullscreenDiv, RowVirtualizer } from "#lib/components/atoms/index.js";
|
||||
import { showErrorToast } from "#lib/client/toast.svelte.js";
|
||||
import { showErrorToast } from "#lib/features/errors.js";
|
||||
import { DirectoryEntry, FileEntry } from "#lib/features/filesystem/components/index.js";
|
||||
import {
|
||||
getDirectoryInfo,
|
||||
type LocalCategoryInfo,
|
||||
type MaybeDirectoryInfo,
|
||||
} from "#lib/features/filesystem/index.js";
|
||||
import { search, type SearchFilter, type SearchResult } from "#lib/features/search/index.js";
|
||||
import { Chip, FullscreenDiv, RowVirtualizer } from "#lib/ui/index.js";
|
||||
import { searchString, sortEntries } from "#lib/utils/index.js";
|
||||
import Directory from "./Directory.svelte";
|
||||
import File from "./File.svelte";
|
||||
import SearchBar from "./SearchBar.svelte";
|
||||
import SelectCategoryBottomSheet from "./SelectCategoryBottomSheet.svelte";
|
||||
|
||||
@@ -236,9 +235,9 @@
|
||||
{#snippet item(index)}
|
||||
{@const info = result[index]!}
|
||||
{#if info.type === "directory"}
|
||||
<Directory {info} onclick={() => goto(`/directory/${info.id}?from=search`)} />
|
||||
<DirectoryEntry {info} onclick={() => goto(`/directory/${info.id}?from=search`)} />
|
||||
{:else}
|
||||
<File {info} onclick={() => goto(`/file/${info.id}?from=search`)} />
|
||||
<FileEntry {info} onclick={() => goto(`/file/${info.id}?from=search`)} />
|
||||
{/if}
|
||||
{/snippet}
|
||||
</RowVirtualizer>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import type { SubDirectoryInfo } from "#lib/features/filesystem/index.js";
|
||||
|
||||
interface Props {
|
||||
info: SubDirectoryInfo;
|
||||
onclick: () => void;
|
||||
}
|
||||
|
||||
let { info, onclick }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ActionEntryButton class="h-14" {onclick}>
|
||||
<DirectoryEntryLabel type="directory" name={info.name} isFavorite={info.isFavorite} />
|
||||
</ActionEntryButton>
|
||||
@@ -1,26 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import { getFileThumbnail } from "#lib/client/cache/index.js";
|
||||
import type { SummarizedFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { formatDateTime } from "#lib/utils/index.js";
|
||||
|
||||
interface Props {
|
||||
info: SummarizedFileInfo;
|
||||
onclick: () => void;
|
||||
}
|
||||
|
||||
let { info, onclick }: Props = $props();
|
||||
|
||||
let thumbnail = $derived(getFileThumbnail(info));
|
||||
</script>
|
||||
|
||||
<ActionEntryButton class="h-14" {onclick}>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite={info.isFavorite}
|
||||
/>
|
||||
</ActionEntryButton>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { SubCategories } from "#lib/components/molecules/index.js";
|
||||
import { SubCategories } from "#lib/features/filesystem/components/index.js";
|
||||
import { useCategory, type LocalCategoryInfo } from "#lib/features/filesystem/index.js";
|
||||
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "#lib/ui/index.js";
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
|
||||
+2
-3
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import type { FileCacheIndex } from "#lib/client/storage/indexedDB/index.js";
|
||||
import {
|
||||
getFileCacheIndex,
|
||||
deleteFileCache as doDeleteFileCache,
|
||||
} from "#lib/client/cache/index.js";
|
||||
import type { FileCacheIndex } from "#lib/client/storage/indexedDB/index.js";
|
||||
import { bulkGetFileInfo, type MaybeFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { FullscreenDiv, TopBar } from "#lib/ui/index.js";
|
||||
import { formatFileSize } from "#lib/utils/index.js";
|
||||
import File from "./File.svelte";
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { BottomDiv, Button, FullscreenDiv } from "#lib/components/atoms/index.js";
|
||||
import { IconEntryButton, TopBar } from "#lib/components/molecules/index.js";
|
||||
import { deleteAllFileThumbnailCaches } from "#lib/client/cache/index.js";
|
||||
import { FileEntry } from "#lib/features/filesystem/components/index.js";
|
||||
import type { MaybeFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { BottomDiv, Button, FullscreenDiv, IconEntryButton, TopBar } from "#lib/ui/index.js";
|
||||
import { sortEntries } from "#lib/utils/index.js";
|
||||
import File from "./File.svelte";
|
||||
import {
|
||||
getThumbnailGenerationStatus,
|
||||
clearThumbnailGenerationStatuses,
|
||||
@@ -15,10 +14,19 @@
|
||||
type GenerationStatus,
|
||||
} from "./service";
|
||||
|
||||
import IconCamera from "~icons/material-symbols/camera";
|
||||
import IconDelete from "~icons/material-symbols/delete";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const statusTexts = {
|
||||
queued: "대기 중",
|
||||
"generation-pending": "준비 중",
|
||||
generating: "생성하는 중",
|
||||
uploading: "업로드하는 중",
|
||||
error: "실패",
|
||||
} as const;
|
||||
|
||||
let fileInfos: MaybeFileInfo[] = $state([]);
|
||||
let files = $derived(
|
||||
fileInfos
|
||||
@@ -69,11 +77,18 @@
|
||||
<div class="space-y-2">
|
||||
{#each files as { info, status } (info.id)}
|
||||
{#if info.exists}
|
||||
<File
|
||||
<FileEntry
|
||||
{info}
|
||||
{status}
|
||||
onclick={({ id }) => goto(`/file/${id}`)}
|
||||
onGenerateThumbnailClick={requestThumbnailGeneration}
|
||||
showThumbnail={false}
|
||||
subtext={status && statusTexts[status]}
|
||||
onclick={() => goto(`/file/${info.id}`)}
|
||||
action={!status || status === "error"
|
||||
? {
|
||||
icon: IconCamera,
|
||||
onclick: () => requestThumbnailGeneration(info),
|
||||
class: "text-gray-800",
|
||||
}
|
||||
: undefined}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<script module lang="ts">
|
||||
const subtexts = {
|
||||
queued: "대기 중",
|
||||
"generation-pending": "준비 중",
|
||||
generating: "생성하는 중",
|
||||
uploading: "업로드하는 중",
|
||||
error: "실패",
|
||||
} as const;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import type { FileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { formatDateTime } from "#lib/utils/index.js";
|
||||
import type { GenerationStatus } from "./service";
|
||||
|
||||
import IconCamera from "~icons/material-symbols/camera";
|
||||
|
||||
interface Props {
|
||||
info: FileInfo;
|
||||
onclick: (file: FileInfo) => void;
|
||||
onGenerateThumbnailClick: (file: FileInfo) => void;
|
||||
status: Exclude<GenerationStatus, "uploaded"> | undefined;
|
||||
}
|
||||
|
||||
let { info, onclick, onGenerateThumbnailClick, status }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ActionEntryButton
|
||||
class="h-14"
|
||||
onclick={() => onclick(info)}
|
||||
actionButtonIcon={!status || status === "error" ? IconCamera : undefined}
|
||||
onActionButtonClick={() => onGenerateThumbnailClick(info)}
|
||||
actionButtonClass="text-gray-800"
|
||||
>
|
||||
{@const subtext = status
|
||||
? subtexts[status]
|
||||
: formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
<DirectoryEntryLabel type="file" name={info.name} {subtext} />
|
||||
</ActionEntryButton>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { AdaptiveDiv } from "#lib/components/atoms/index.js";
|
||||
import { AdaptiveDiv } from "#lib/ui/index.js";
|
||||
import BottomBar from "./BottomBar.svelte";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import { AdaptiveDiv } from "#lib/components/atoms/index.js";
|
||||
import { AdaptiveDiv } from "#lib/ui/index.js";
|
||||
|
||||
import IconHome from "~icons/material-symbols/home";
|
||||
import IconFolder from "~icons/material-symbols/folder";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { CheckBox, RowVirtualizer } from "#lib/components/atoms/index.js";
|
||||
import { SubCategories, TopBar } from "#lib/components/molecules/index.js";
|
||||
import { CategoryCreateModal } from "#lib/components/organisms/index.js";
|
||||
import { tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { tryAction } from "#lib/features/errors.js";
|
||||
import {
|
||||
FileEntry,
|
||||
SubCategories,
|
||||
CategoryCreateModal,
|
||||
} from "#lib/features/filesystem/components/index.js";
|
||||
import {
|
||||
createCategory,
|
||||
deleteCategory,
|
||||
@@ -13,13 +15,14 @@
|
||||
useCategory,
|
||||
type LocalCategoryInfo,
|
||||
} from "#lib/features/filesystem/index.js";
|
||||
import { CheckBox, OverlayGroup, RowVirtualizer, TopBar } from "#lib/ui/index.js";
|
||||
import { sortEntries } from "#lib/utils/index.js";
|
||||
import CategoryDeleteModal from "./CategoryDeleteModal.svelte";
|
||||
import CategoryMenuBottomSheet from "./CategoryMenuBottomSheet.svelte";
|
||||
import CategoryRenameModal from "./CategoryRenameModal.svelte";
|
||||
import File from "./File.svelte";
|
||||
import { createContext } from "./service.svelte";
|
||||
|
||||
import IconClose from "~icons/material-symbols/close";
|
||||
import IconMoreVert from "~icons/material-symbols/more-vert";
|
||||
|
||||
let { data } = $props();
|
||||
@@ -28,10 +31,9 @@
|
||||
const category = useCategory(() => data.id);
|
||||
let info = $derived(category.current);
|
||||
|
||||
let isCategoryCreateModalOpen = $state(false);
|
||||
let isCategoryMenuBottomSheetOpen = $state(false);
|
||||
let isCategoryRenameModalOpen = $state(false);
|
||||
let isCategoryDeleteModalOpen = $state(false);
|
||||
const overlays = new OverlayGroup<
|
||||
"categoryCreate" | "categoryMenu" | "categoryRename" | "categoryDelete"
|
||||
>();
|
||||
|
||||
let files = $derived(
|
||||
sortEntries(
|
||||
@@ -59,11 +61,11 @@
|
||||
<SubCategories
|
||||
{info}
|
||||
onSubCategoryClick={({ id }) => goto(`/category/${id}`)}
|
||||
onSubCategoryCreateClick={() => (isCategoryCreateModalOpen = true)}
|
||||
onSubCategoryCreateClick={() => overlays.open("categoryCreate")}
|
||||
subCategoryCreatePosition="bottom"
|
||||
onSubCategoryMenuClick={(subCategory) => {
|
||||
context.selectedCategory = subCategory;
|
||||
isCategoryMenuBottomSheetOpen = true;
|
||||
overlays.open("categoryMenu");
|
||||
}}
|
||||
subCategoryMenuIcon={IconMoreVert}
|
||||
/>
|
||||
@@ -89,15 +91,18 @@
|
||||
>
|
||||
{#snippet item(index)}
|
||||
{@const { details } = files[index]!}
|
||||
<File
|
||||
<FileEntry
|
||||
info={details}
|
||||
onclick={({ id }) => goto(`/file/${id}?from=category`)}
|
||||
onRemoveClick={!details.isRecursive
|
||||
? ({ id }) =>
|
||||
tryAction(
|
||||
() => removeFileFromCategory(id, data.id as number),
|
||||
"카테고리에서 파일을 제거하지 못했어요.",
|
||||
)
|
||||
onclick={() => goto(`/file/${details.id}?from=category`)}
|
||||
action={!details.isRecursive
|
||||
? {
|
||||
icon: IconClose,
|
||||
onclick: () =>
|
||||
tryAction(
|
||||
() => removeFileFromCategory(details.id, data.id as number),
|
||||
"카테고리에서 파일을 제거하지 못했어요.",
|
||||
),
|
||||
}
|
||||
: undefined}
|
||||
/>
|
||||
{/snippet}
|
||||
@@ -112,24 +117,18 @@
|
||||
</div>
|
||||
|
||||
<CategoryCreateModal
|
||||
bind:isOpen={isCategoryCreateModalOpen}
|
||||
bind:isOpen={overlays.getter("categoryCreate"), overlays.setter("categoryCreate")}
|
||||
onCreateClick={(name: string) =>
|
||||
tryAction(() => createCategory(data.id, name), "카테고리를 만들지 못했어요.")}
|
||||
/>
|
||||
|
||||
<CategoryMenuBottomSheet
|
||||
bind:isOpen={isCategoryMenuBottomSheetOpen}
|
||||
onRenameClick={() => {
|
||||
isCategoryMenuBottomSheetOpen = false;
|
||||
isCategoryRenameModalOpen = true;
|
||||
}}
|
||||
onDeleteClick={() => {
|
||||
isCategoryMenuBottomSheetOpen = false;
|
||||
isCategoryDeleteModalOpen = true;
|
||||
}}
|
||||
bind:isOpen={overlays.getter("categoryMenu"), overlays.setter("categoryMenu")}
|
||||
onRenameClick={() => overlays.open("categoryRename")}
|
||||
onDeleteClick={() => overlays.open("categoryDelete")}
|
||||
/>
|
||||
<CategoryRenameModal
|
||||
bind:isOpen={isCategoryRenameModalOpen}
|
||||
bind:isOpen={overlays.getter("categoryRename"), overlays.setter("categoryRename")}
|
||||
onRenameClick={(newName: string) =>
|
||||
tryAction(
|
||||
() => renameCategory({ ...context.selectedCategory!, parentId: data.id }, newName),
|
||||
@@ -137,7 +136,7 @@
|
||||
)}
|
||||
/>
|
||||
<CategoryDeleteModal
|
||||
bind:isOpen={isCategoryDeleteModalOpen}
|
||||
bind:isOpen={overlays.getter("categoryDelete"), overlays.setter("categoryDelete")}
|
||||
onDeleteClick={() =>
|
||||
tryAction(
|
||||
() => deleteCategory({ ...context.selectedCategory!, parentId: data.id }),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ActionModal } from "#lib/components/molecules/index.js";
|
||||
import { ActionModal } from "#lib/ui/index.js";
|
||||
import { truncateString } from "#lib/utils/index.js";
|
||||
import { useContext } from "./service.svelte";
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { BottomSheet } from "#lib/components/atoms/index.js";
|
||||
import { CategoryLabel, IconEntryButton } from "#lib/components/molecules/index.js";
|
||||
import { BottomSheet, CategoryLabel, IconEntryButton } from "#lib/ui/index.js";
|
||||
import { useContext } from "./service.svelte";
|
||||
|
||||
import IconEdit from "~icons/material-symbols/edit";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { RenameModal } from "#lib/components/organisms/index.js";
|
||||
import { RenameModal } from "#lib/ui/index.js";
|
||||
import { useContext } from "./service.svelte";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import { getFileThumbnail } from "#lib/client/cache/index.js";
|
||||
import type { CategoryFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { formatDateTime } from "#lib/utils/index.js";
|
||||
import type { SelectedFile } from "./service.svelte";
|
||||
|
||||
import IconClose from "~icons/material-symbols/close";
|
||||
|
||||
interface Props {
|
||||
info: CategoryFileInfo;
|
||||
onclick: (file: SelectedFile) => void;
|
||||
onRemoveClick?: (file: SelectedFile) => void;
|
||||
}
|
||||
|
||||
let { info, onclick, onRemoveClick }: Props = $props();
|
||||
|
||||
let thumbnail = $derived(getFileThumbnail(info));
|
||||
</script>
|
||||
|
||||
<ActionEntryButton
|
||||
class="h-14"
|
||||
onclick={() => onclick(info)}
|
||||
actionButtonIcon={onRemoveClick && IconClose}
|
||||
onActionButtonClick={() => onRemoveClick?.(info)}
|
||||
>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite={info.isFavorite}
|
||||
/>
|
||||
</ActionEntryButton>
|
||||
@@ -1,18 +1,20 @@
|
||||
import { getContext, setContext } from "svelte";
|
||||
import type { SelectedCategory } from "#lib/components/molecules/index.js";
|
||||
import { createContext as createSvelteContext } from "svelte";
|
||||
import type { SelectedCategory } from "#lib/features/filesystem/components/index.js";
|
||||
|
||||
export interface SelectedFile {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Context {
|
||||
selectedCategory?: SelectedCategory;
|
||||
}
|
||||
|
||||
const [getContext, setContext] = createSvelteContext<Context>();
|
||||
|
||||
export const createContext = () => {
|
||||
const context = $state({
|
||||
selectedCategory: undefined as SelectedCategory | undefined,
|
||||
});
|
||||
return setContext("context", context);
|
||||
const context: Context = $state({});
|
||||
return setContext(context);
|
||||
};
|
||||
|
||||
export const useContext = () => {
|
||||
return getContext<ReturnType<typeof createContext>>("context");
|
||||
};
|
||||
export const useContext = getContext;
|
||||
@@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import { FloatingButton } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import { tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { tryAction } from "#lib/features/errors.js";
|
||||
import { createDirectory, uploadFile, useDirectory } from "#lib/features/filesystem/index.js";
|
||||
import { FloatingButton, OverlayGroup, TopBar } from "#lib/ui/index.js";
|
||||
import DirectoryCreateModal from "./DirectoryCreateModal.svelte";
|
||||
import DirectoryEntries from "./DirectoryEntries";
|
||||
import DownloadStatusCard from "./DownloadStatusCard.svelte";
|
||||
@@ -28,14 +27,12 @@
|
||||
let duplicatedFile: File | undefined = $state();
|
||||
let resolveForDuplicateFileModal: ((res: boolean) => void) | undefined = $state();
|
||||
|
||||
let isEntryCreateBottomSheetOpen = $state(false);
|
||||
let isDirectoryCreateModalOpen = $state(false);
|
||||
const overlays = new OverlayGroup<
|
||||
"entryCreate" | "directoryCreate" | "entryMenu" | "entryRename" | "entryDelete"
|
||||
>();
|
||||
// Shown independently as it is requested while uploading in the background
|
||||
let isDuplicateFileModalOpen = $state(false);
|
||||
|
||||
let isEntryMenuBottomSheetOpen = $state(false);
|
||||
let isEntryRenameModalOpen = $state(false);
|
||||
let isEntryDeleteModalOpen = $state(false);
|
||||
|
||||
let showParentEntry = $derived(
|
||||
["file", "search", "favorite"].includes(page.url.searchParams.get("from") ?? ""),
|
||||
);
|
||||
@@ -96,7 +93,7 @@
|
||||
onEntryClick={({ type, id }) => goto(`/${type}/${id}`)}
|
||||
onEntryMenuClick={(entry) => {
|
||||
context.selectedEntry = entry;
|
||||
isEntryMenuBottomSheetOpen = true;
|
||||
overlays.open("entryMenu");
|
||||
}}
|
||||
showParentEntry={showParentEntry && data.id !== "root"}
|
||||
onParentClick={() =>
|
||||
@@ -114,23 +111,20 @@
|
||||
<FloatingButton
|
||||
icon={IconAdd}
|
||||
onclick={() => {
|
||||
isEntryCreateBottomSheetOpen = true;
|
||||
overlays.open("entryCreate");
|
||||
}}
|
||||
class="right-4 bottom-24"
|
||||
/>
|
||||
<EntryCreateBottomSheet
|
||||
bind:isOpen={isEntryCreateBottomSheetOpen}
|
||||
onDirectoryCreateClick={() => {
|
||||
isEntryCreateBottomSheetOpen = false;
|
||||
isDirectoryCreateModalOpen = true;
|
||||
}}
|
||||
bind:isOpen={overlays.getter("entryCreate"), overlays.setter("entryCreate")}
|
||||
onDirectoryCreateClick={() => overlays.open("directoryCreate")}
|
||||
onFileUploadClick={() => {
|
||||
isEntryCreateBottomSheetOpen = false;
|
||||
overlays.close();
|
||||
fileInput?.click();
|
||||
}}
|
||||
/>
|
||||
<DirectoryCreateModal
|
||||
bind:isOpen={isDirectoryCreateModalOpen}
|
||||
bind:isOpen={overlays.getter("directoryCreate"), overlays.setter("directoryCreate")}
|
||||
onCreateClick={(name) =>
|
||||
tryAction(() => createDirectory(data.id, name), "폴더를 만들지 못했어요.")}
|
||||
/>
|
||||
@@ -148,15 +142,9 @@
|
||||
/>
|
||||
|
||||
<EntryMenuBottomSheet
|
||||
bind:isOpen={isEntryMenuBottomSheetOpen}
|
||||
onRenameClick={() => {
|
||||
isEntryMenuBottomSheetOpen = false;
|
||||
isEntryRenameModalOpen = true;
|
||||
}}
|
||||
onDeleteClick={() => {
|
||||
isEntryMenuBottomSheetOpen = false;
|
||||
isEntryDeleteModalOpen = true;
|
||||
}}
|
||||
bind:isOpen={overlays.getter("entryMenu"), overlays.setter("entryMenu")}
|
||||
onRenameClick={() => overlays.open("entryRename")}
|
||||
onDeleteClick={() => overlays.open("entryDelete")}
|
||||
onFavoriteClick={async () => {
|
||||
if (
|
||||
await tryAction(
|
||||
@@ -164,16 +152,16 @@
|
||||
"즐겨찾기를 변경하지 못했어요.",
|
||||
)
|
||||
) {
|
||||
isEntryMenuBottomSheetOpen = false;
|
||||
overlays.close();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<EntryRenameModal
|
||||
bind:isOpen={isEntryRenameModalOpen}
|
||||
bind:isOpen={overlays.getter("entryRename"), overlays.setter("entryRename")}
|
||||
onRenameClick={(newName: string) =>
|
||||
tryAction(() => renameEntry(context.selectedEntry!, newName), "이름을 바꾸지 못했어요.")}
|
||||
/>
|
||||
<EntryDeleteModal
|
||||
bind:isOpen={isEntryDeleteModalOpen}
|
||||
bind:isOpen={overlays.getter("entryDelete"), overlays.setter("entryDelete")}
|
||||
onDeleteClick={() => tryAction(() => deleteEntry(context.selectedEntry!), "삭제하지 못했어요.")}
|
||||
/>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { TextInputModal } from "#lib/components/organisms/index.js";
|
||||
import { TextInputModal } from "#lib/ui/index.js";
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton, RowVirtualizer } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import { getUploadingFiles, type LiveFileUploadState } from "#lib/client/transfer/index.js";
|
||||
import type { DirectoryInfo } from "#lib/features/filesystem/index.js";
|
||||
import { DirectoryEntry, FileEntry } from "#lib/features/filesystem/components/index.js";
|
||||
import type {
|
||||
DirectoryInfo,
|
||||
SubDirectoryInfo,
|
||||
SummarizedFileInfo,
|
||||
} from "#lib/features/filesystem/index.js";
|
||||
import { ActionEntryButton, RowVirtualizer, DirectoryEntryLabel } from "#lib/ui/index.js";
|
||||
import { sortEntries } from "#lib/utils/index.js";
|
||||
import File from "./File.svelte";
|
||||
import SubDirectory from "./SubDirectory.svelte";
|
||||
import UploadingFile from "./UploadingFile.svelte";
|
||||
import type { SelectedEntry } from "../service.svelte";
|
||||
|
||||
import IconMoreVert from "~icons/material-symbols/more-vert";
|
||||
|
||||
interface Props {
|
||||
info: DirectoryInfo;
|
||||
onEntryClick: (entry: SelectedEntry) => void;
|
||||
@@ -35,6 +39,11 @@
|
||||
<T extends Exclude<Entry["type"], "parent">>(type: T) =>
|
||||
(details: Extract<Entry, { type: T }>["details"]) => ({ type, name: details.name, details });
|
||||
|
||||
const toSelectedEntry = (
|
||||
type: SelectedEntry["type"],
|
||||
{ id, parentId, dataKey, name, isFavorite }: SubDirectoryInfo | SummarizedFileInfo,
|
||||
): SelectedEntry => ({ type, id, parentId, dataKey, name, isFavorite });
|
||||
|
||||
let entries = $derived([
|
||||
...(showParentEntry ? ([{ type: "parent" }] as const) : []),
|
||||
...sortEntries(info.subDirectories.map(toEntry("directory"))),
|
||||
@@ -63,13 +72,19 @@
|
||||
<DirectoryEntryLabel type="parent-directory" name=".." />
|
||||
</ActionEntryButton>
|
||||
{:else if entry.type === "directory"}
|
||||
<SubDirectory
|
||||
{@const selected = toSelectedEntry("directory", entry.details)}
|
||||
<DirectoryEntry
|
||||
info={entry.details}
|
||||
onclick={onEntryClick}
|
||||
onOpenMenuClick={onEntryMenuClick}
|
||||
onclick={() => onEntryClick(selected)}
|
||||
action={{ icon: IconMoreVert, onclick: () => onEntryMenuClick(selected) }}
|
||||
/>
|
||||
{:else if entry.type === "file"}
|
||||
<File info={entry.details} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
|
||||
{@const selected = toSelectedEntry("file", entry.details)}
|
||||
<FileEntry
|
||||
info={entry.details}
|
||||
onclick={() => onEntryClick(selected)}
|
||||
action={{ icon: IconMoreVert, onclick: () => onEntryMenuClick(selected) }}
|
||||
/>
|
||||
{:else}
|
||||
<UploadingFile state={entry.details} />
|
||||
{/if}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import { getFileThumbnail } from "#lib/client/cache/index.js";
|
||||
import type { SummarizedFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { formatDateTime } from "#lib/utils/index.js";
|
||||
import type { SelectedEntry } from "../service.svelte";
|
||||
|
||||
import IconMoreVert from "~icons/material-symbols/more-vert";
|
||||
|
||||
interface Props {
|
||||
info: SummarizedFileInfo;
|
||||
onclick: (entry: SelectedEntry) => void;
|
||||
onOpenMenuClick: (entry: SelectedEntry) => void;
|
||||
}
|
||||
|
||||
let { info, onclick, onOpenMenuClick }: Props = $props();
|
||||
|
||||
let thumbnail = $derived(getFileThumbnail(info));
|
||||
|
||||
const action = (callback: typeof onclick) => {
|
||||
callback({
|
||||
type: "file",
|
||||
id: info.id,
|
||||
parentId: info.parentId,
|
||||
dataKey: info.dataKey,
|
||||
name: info.name,
|
||||
isFavorite: info.isFavorite,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<ActionEntryButton
|
||||
class="h-14"
|
||||
onclick={() => action(onclick)}
|
||||
actionButtonIcon={IconMoreVert}
|
||||
onActionButtonClick={() => action(onOpenMenuClick)}
|
||||
>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite={info.isFavorite}
|
||||
/>
|
||||
</ActionEntryButton>
|
||||
@@ -1,36 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import type { SubDirectoryInfo } from "#lib/features/filesystem/index.js";
|
||||
import type { SelectedEntry } from "../service.svelte";
|
||||
|
||||
import IconMoreVert from "~icons/material-symbols/more-vert";
|
||||
|
||||
interface Props {
|
||||
info: SubDirectoryInfo;
|
||||
onclick: (entry: SelectedEntry) => void;
|
||||
onOpenMenuClick: (entry: SelectedEntry) => void;
|
||||
}
|
||||
|
||||
let { info, onclick, onOpenMenuClick }: Props = $props();
|
||||
|
||||
const action = (callback: typeof onclick) => {
|
||||
callback({
|
||||
type: "directory",
|
||||
id: info.id,
|
||||
parentId: info.parentId,
|
||||
dataKey: info.dataKey,
|
||||
name: info.name,
|
||||
isFavorite: info.isFavorite,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<ActionEntryButton
|
||||
class="h-14"
|
||||
onclick={() => action(onclick)}
|
||||
actionButtonIcon={IconMoreVert}
|
||||
onActionButtonClick={() => action(onOpenMenuClick)}
|
||||
>
|
||||
<DirectoryEntryLabel type="directory" name={info.name} isFavorite={info.isFavorite} />
|
||||
</ActionEntryButton>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ActionModal } from "#lib/components/molecules/index.js";
|
||||
import { ActionModal } from "#lib/ui/index.js";
|
||||
import { truncateString } from "#lib/utils/index.js";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { BottomSheet } from "#lib/components/atoms/index.js";
|
||||
import { IconEntryButton } from "#lib/components/molecules/index.js";
|
||||
import { BottomSheet, IconEntryButton } from "#lib/ui/index.js";
|
||||
|
||||
import IconCreateNewFolder from "~icons/material-symbols/create-new-folder";
|
||||
import IconUploadFile from "~icons/material-symbols/upload-file";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ActionModal } from "#lib/components/molecules/index.js";
|
||||
import { ActionModal } from "#lib/ui/index.js";
|
||||
import { truncateString } from "#lib/utils/index.js";
|
||||
import { useContext } from "./service.svelte";
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { BottomSheet } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel, IconEntryButton } from "#lib/components/molecules/index.js";
|
||||
import { BottomSheet, DirectoryEntryLabel, IconEntryButton } from "#lib/ui/index.js";
|
||||
import { useContext } from "./service.svelte";
|
||||
|
||||
import IconFavorite from "~icons/material-symbols/favorite";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { RenameModal } from "#lib/components/organisms/index.js";
|
||||
import { RenameModal } from "#lib/ui/index.js";
|
||||
import { useContext } from "./service.svelte";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getContext, setContext } from "svelte";
|
||||
import { createContext as createSvelteContext } from "svelte";
|
||||
import {
|
||||
deleteDirectory,
|
||||
deleteFile,
|
||||
@@ -18,16 +18,18 @@ export interface SelectedEntry {
|
||||
isFavorite: boolean;
|
||||
}
|
||||
|
||||
interface Context {
|
||||
selectedEntry?: SelectedEntry;
|
||||
}
|
||||
|
||||
const [getContext, setContext] = createSvelteContext<Context>();
|
||||
|
||||
export const createContext = () => {
|
||||
const context = $state({
|
||||
selectedEntry: undefined as SelectedEntry | undefined,
|
||||
});
|
||||
return setContext("context", context);
|
||||
const context: Context = $state({});
|
||||
return setContext(context);
|
||||
};
|
||||
|
||||
export const useContext = () => {
|
||||
return getContext<ReturnType<typeof createContext>>("context");
|
||||
};
|
||||
export const useContext = getContext;
|
||||
|
||||
export const renameEntry = async (entry: SelectedEntry, newName: string) => {
|
||||
if (entry.type === "directory") {
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { RowVirtualizer } from "#lib/components/atoms/index.js";
|
||||
import { TopBar } from "#lib/components/molecules/index.js";
|
||||
import Directory from "./Directory.svelte";
|
||||
import File from "./File.svelte";
|
||||
import { showErrorToast, tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { showErrorToast, tryAction } from "#lib/features/errors.js";
|
||||
import {
|
||||
getFavoriteEntries,
|
||||
removeFavorite,
|
||||
type FavoriteEntry,
|
||||
} from "#lib/features/favorites/index.js";
|
||||
import { DirectoryEntry, FileEntry } from "#lib/features/filesystem/components/index.js";
|
||||
import { RowVirtualizer, TopBar } from "#lib/ui/index.js";
|
||||
|
||||
import IconClose from "~icons/material-symbols/close";
|
||||
import IconSearch from "~icons/material-symbols/search";
|
||||
|
||||
let entries: FavoriteEntry[] = $state([]);
|
||||
@@ -68,16 +67,16 @@
|
||||
{#snippet item(index)}
|
||||
{@const entry = entries[index]!}
|
||||
{#if entry.type === "directory"}
|
||||
<Directory
|
||||
<DirectoryEntry
|
||||
info={entry.details}
|
||||
onclick={() => handleClick(entry)}
|
||||
onRemoveClick={() => handleRemove(entry)}
|
||||
action={{ icon: IconClose, onclick: () => handleRemove(entry) }}
|
||||
/>
|
||||
{:else}
|
||||
<File
|
||||
<FileEntry
|
||||
info={entry.details}
|
||||
onclick={() => handleClick(entry)}
|
||||
onRemoveClick={() => handleRemove(entry)}
|
||||
action={{ icon: IconClose, onclick: () => handleRemove(entry) }}
|
||||
/>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import type { SubDirectoryInfo } from "#lib/features/filesystem/index.js";
|
||||
|
||||
import IconClose from "~icons/material-symbols/close";
|
||||
|
||||
interface Props {
|
||||
info: SubDirectoryInfo;
|
||||
onclick: () => void;
|
||||
onRemoveClick: () => void;
|
||||
}
|
||||
|
||||
let { info, onclick, onRemoveClick }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ActionEntryButton
|
||||
class="h-14"
|
||||
{onclick}
|
||||
actionButtonIcon={IconClose}
|
||||
onActionButtonClick={onRemoveClick}
|
||||
>
|
||||
<DirectoryEntryLabel type="directory" name={info.name} isFavorite />
|
||||
</ActionEntryButton>
|
||||
@@ -1,34 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ActionEntryButton } from "#lib/components/atoms/index.js";
|
||||
import { DirectoryEntryLabel } from "#lib/components/molecules/index.js";
|
||||
import { getFileThumbnail } from "#lib/client/cache/index.js";
|
||||
import type { SummarizedFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { formatDateTime } from "#lib/utils/index.js";
|
||||
|
||||
import IconClose from "~icons/material-symbols/close";
|
||||
|
||||
interface Props {
|
||||
info: SummarizedFileInfo;
|
||||
onclick: () => void;
|
||||
onRemoveClick: () => void;
|
||||
}
|
||||
|
||||
let { info, onclick, onRemoveClick }: Props = $props();
|
||||
|
||||
let thumbnail = $derived(getFileThumbnail(info));
|
||||
</script>
|
||||
|
||||
<ActionEntryButton
|
||||
class="h-14"
|
||||
{onclick}
|
||||
actionButtonIcon={IconClose}
|
||||
onActionButtonClick={onRemoveClick}
|
||||
>
|
||||
<DirectoryEntryLabel
|
||||
type="file"
|
||||
thumbnail={thumbnail?.url}
|
||||
name={info.name}
|
||||
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
|
||||
isFavorite
|
||||
/>
|
||||
</ActionEntryButton>
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { EntryButton, FileThumbnailButton } from "#lib/components/atoms/index.js";
|
||||
import { FileThumbnailButton } from "#lib/features/filesystem/components/index.js";
|
||||
import { type SummarizedFileInfo } from "#lib/features/filesystem/index.js";
|
||||
import { EntryButton } from "#lib/ui/index.js";
|
||||
import { requestFreshMediaFilesRetrieval } from "./service";
|
||||
|
||||
let mediaFiles: SummarizedFileInfo[] = $state([]);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import MenuEntryButton from "./MenuEntryButton.svelte";
|
||||
import { tryAction } from "#lib/client/toast.svelte.js";
|
||||
import { logout as requestLogout } from "#lib/features/auth/index.js";
|
||||
import { tryAction } from "#lib/features/errors.js";
|
||||
|
||||
import IconStorage from "~icons/material-symbols/storage";
|
||||
import IconImage from "~icons/material-symbols/image";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { Component, Snippet } from "svelte";
|
||||
import type { ClassValue, SvelteHTMLElements } from "svelte/elements";
|
||||
import { IconEntryButton } from "#lib/components/molecules/index.js";
|
||||
import { IconEntryButton } from "#lib/ui/index.js";
|
||||
|
||||
interface Props {
|
||||
children: Snippet;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { getDownloadingFiles, getUploadingFiles } from "#lib/client/transfer/index.js";
|
||||
import { Toasts } from "#lib/components/atoms/index.js";
|
||||
import { Toasts } from "#lib/ui/index.js";
|
||||
import "../app.css";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
Reference in new issue
Block a user