검색 필터에 즐겨찾기 여부 추가

This commit is contained in:
static
2026-01-18 13:29:06 +09:00
parent 63163d6279
commit 72babc532f
7 changed files with 57 additions and 11 deletions

View File

@@ -20,7 +20,12 @@ export const getFileCacheIndex = async () => {
}; };
export const storeFileCacheIndex = async (fileCacheIndex: FileCacheIndex) => { export const storeFileCacheIndex = async (fileCacheIndex: FileCacheIndex) => {
await cacheIndex.fileCache.put(fileCacheIndex); await cacheIndex.fileCache.put({
fileId: fileCacheIndex.fileId,
cachedAt: fileCacheIndex.cachedAt,
lastRetrievedAt: fileCacheIndex.lastRetrievedAt,
size: fileCacheIndex.size,
});
}; };
export const deleteFileCacheIndex = async (fileId: number) => { export const deleteFileCacheIndex = async (fileId: number) => {

View File

@@ -74,7 +74,11 @@ export const getDirectoryInfo = async (id: number) => {
}; };
export const storeDirectoryInfo = async (directoryInfo: DirectoryInfo) => { export const storeDirectoryInfo = async (directoryInfo: DirectoryInfo) => {
await filesystem.directory.upsert(directoryInfo.id, { ...directoryInfo }); await filesystem.directory.upsert(directoryInfo.id, {
parentId: directoryInfo.parentId,
name: directoryInfo.name,
isFavorite: directoryInfo.isFavorite,
});
}; };
export const deleteDirectoryInfo = async (id: number) => { export const deleteDirectoryInfo = async (id: number) => {
@@ -108,7 +112,15 @@ export const bulkGetFileInfos = async (ids: number[]) => {
}; };
export const storeFileInfo = async (fileInfo: FileInfo) => { export const storeFileInfo = async (fileInfo: FileInfo) => {
await filesystem.file.upsert(fileInfo.id, { ...fileInfo }); await filesystem.file.upsert(fileInfo.id, {
parentId: fileInfo.parentId,
name: fileInfo.name,
contentType: fileInfo.contentType,
createdAt: fileInfo.createdAt,
lastModifiedAt: fileInfo.lastModifiedAt,
categoryIds: fileInfo.categoryIds,
isFavorite: fileInfo.isFavorite,
});
}; };
export const deleteFileInfo = async (id: number) => { export const deleteFileInfo = async (id: number) => {
@@ -135,7 +147,12 @@ export const getCategoryInfo = async (id: number) => {
}; };
export const storeCategoryInfo = async (categoryInfo: CategoryInfo) => { export const storeCategoryInfo = async (categoryInfo: CategoryInfo) => {
await filesystem.category.upsert(categoryInfo.id, { ...categoryInfo }); await filesystem.category.upsert(categoryInfo.id, {
parentId: categoryInfo.parentId,
name: categoryInfo.name,
files: categoryInfo.files,
isFileRecursive: categoryInfo.isFileRecursive,
});
}; };
export const updateCategoryInfo = async (id: number, changes: { isFileRecursive?: boolean }) => { export const updateCategoryInfo = async (id: number, changes: { isFileRecursive?: boolean }) => {

View File

@@ -25,6 +25,7 @@
includeImages: boolean; includeImages: boolean;
includeVideos: boolean; includeVideos: boolean;
includeDirectories: boolean; includeDirectories: boolean;
searchInFavorites: boolean;
searchInDirectory: boolean; searchInDirectory: boolean;
categories: SearchFilter["categories"]; categories: SearchFilter["categories"];
} }
@@ -36,6 +37,7 @@
includeImages: false, includeImages: false,
includeVideos: false, includeVideos: false,
includeDirectories: false, includeDirectories: false,
searchInFavorites: false,
searchInDirectory: false, searchInDirectory: false,
categories: [], categories: [],
}); });
@@ -45,6 +47,7 @@
filters.includeImages || filters.includeImages ||
filters.includeVideos || filters.includeVideos ||
filters.includeDirectories || filters.includeDirectories ||
filters.searchInFavorites ||
filters.name.trim().length > 0, filters.name.trim().length > 0,
); );
@@ -81,7 +84,9 @@
return sortEntries( return sortEntries(
[...directories, ...files].filter( [...directories, ...files].filter(
({ name }) => !nameFilter || searchString(name, nameFilter), (entry) =>
(!nameFilter || searchString(entry.name, nameFilter)) &&
(!filters.searchInFavorites || entry.isFavorite),
), ),
); );
}); });
@@ -118,7 +123,7 @@
}, },
}; };
$effect(() => { $effect.pre(() => {
if (data.directoryId) { if (data.directoryId) {
HybridPromise.resolve(getDirectoryInfo(data.directoryId, $masterKeyStore?.get(1)?.key!)).then( HybridPromise.resolve(getDirectoryInfo(data.directoryId, $masterKeyStore?.get(1)?.key!)).then(
(res) => { (res) => {
@@ -132,6 +137,10 @@
} }
}); });
$effect.pre(() => {
filters.searchInFavorites = data.fromFavorites;
});
$effect(() => { $effect(() => {
// Svelte sucks // Svelte sucks
hasAnyFilter; hasAnyFilter;
@@ -172,6 +181,7 @@
{#if !hasCategoryFilter} {#if !hasCategoryFilter}
<Chip bind:selected={filters.includeDirectories}>폴더</Chip> <Chip bind:selected={filters.includeDirectories}>폴더</Chip>
{/if} {/if}
<Chip bind:selected={filters.searchInFavorites}>즐겨찾기</Chip>
{#if directoryInfo?.exists} {#if directoryInfo?.exists}
<Chip bind:selected={filters.searchInDirectory}> <Chip bind:selected={filters.searchInDirectory}>
위치: {directoryInfo.name} 위치: {directoryInfo.name}

View File

@@ -4,15 +4,18 @@ import type { PageLoad } from "./$types";
export const load: PageLoad = ({ url }) => { export const load: PageLoad = ({ url }) => {
const directoryId = url.searchParams.get("directoryId"); const directoryId = url.searchParams.get("directoryId");
const from = url.searchParams.get("from");
const zodRes = z const zodRes = z
.object({ .object({
directoryId: z.coerce.number().int().positive().nullable(), directoryId: z.coerce.number().int().positive().nullable(),
from: z.enum(["favorites"]).nullable(),
}) })
.safeParse({ directoryId }); .safeParse({ directoryId, from });
if (!zodRes.success) error(400, "Invalid query parameters"); if (!zodRes.success) error(400, "Invalid query parameters");
return { return {
directoryId: zodRes.data.directoryId, directoryId: zodRes.data.directoryId,
fromFavorites: zodRes.data.from === "favorites",
}; };
}; };

View File

@@ -2,11 +2,14 @@
import { onMount } from "svelte"; import { onMount } from "svelte";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
import { RowVirtualizer } from "$lib/components/atoms"; import { RowVirtualizer } from "$lib/components/atoms";
import { TopBar } from "$lib/components/molecules";
import { masterKeyStore } from "$lib/stores"; import { masterKeyStore } from "$lib/stores";
import Directory from "./Directory.svelte"; import Directory from "./Directory.svelte";
import File from "./File.svelte"; import File from "./File.svelte";
import { requestFavoriteEntries, requestRemoveFavorite, type FavoriteEntry } from "./service"; import { requestFavoriteEntries, requestRemoveFavorite, type FavoriteEntry } from "./service";
import IconSearch from "~icons/material-symbols/search";
let { data } = $props(); let { data } = $props();
let entries: FavoriteEntry[] = $state([]); let entries: FavoriteEntry[] = $state([]);
@@ -41,14 +44,22 @@
<title>즐겨찾기</title> <title>즐겨찾기</title>
</svelte:head> </svelte:head>
<div class="flex h-full flex-col p-4"> <TopBar title="즐겨찾기" showBackButton={false}>
<button
onclick={() => goto("/search?from=favorites")}
class="w-full rounded-full p-1 text-2xl active:bg-black active:bg-opacity-[0.04]"
>
<IconSearch />
</button>
</TopBar>
<div class="flex h-full flex-col p-4 !pt-0">
{#if isLoading} {#if isLoading}
<div class="flex flex-grow items-center justify-center"> <div class="flex flex-grow items-center justify-center">
<p class="text-gray-500"> <p class="text-gray-500">
{#if data.favorites.files.length === 0 && data.favorites.directories.length === 0} {#if data.favorites.files.length === 0 && data.favorites.directories.length === 0}
즐겨찾기한 항목이 없어요. 즐겨찾기한 항목이 없어요.
{:else} {:else}
로딩 중... 즐겨찾기 목록을 불러오고 있어요.
{/if} {/if}
</p> </p>
</div> </div>

View File

@@ -20,5 +20,5 @@
actionButtonIcon={IconClose} actionButtonIcon={IconClose}
onActionButtonClick={onRemoveClick} onActionButtonClick={onRemoveClick}
> >
<DirectoryEntryLabel type="directory" name={info.name} /> <DirectoryEntryLabel type="directory" name={info.name} isFavorite />
</ActionEntryButton> </ActionEntryButton>

View File

@@ -23,5 +23,5 @@
actionButtonIcon={IconClose} actionButtonIcon={IconClose}
onActionButtonClick={onRemoveClick} onActionButtonClick={onRemoveClick}
> >
<DirectoryEntryLabel type="file" thumbnail={$thumbnail} name={info.name} /> <DirectoryEntryLabel type="file" thumbnail={$thumbnail} name={info.name} isFavorite />
</ActionEntryButton> </ActionEntryButton>