mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-02-03 23:56:53 +00:00
이름 검색 로직 개선 및 뒤로가기로 검색 페이지로 돌아온 경우에 필터 및 검색 결과가 유지되도록 개선
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
"autoprefixer": "^10.4.23",
|
||||
"axios": "^1.13.2",
|
||||
"dexie": "^4.2.1",
|
||||
"es-hangul": "^2.3.8",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-svelte": "^3.14.0",
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -84,6 +84,9 @@ importers:
|
||||
dexie:
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1
|
||||
es-hangul:
|
||||
specifier: ^2.3.8
|
||||
version: 2.3.8
|
||||
eslint:
|
||||
specifier: ^9.39.2
|
||||
version: 9.39.2(jiti@1.21.7)
|
||||
@@ -989,6 +992,9 @@ packages:
|
||||
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-hangul@2.3.8:
|
||||
resolution: {integrity: sha512-VrJuqYBC7W04aKYjCnswomuJNXQRc0q33SG1IltVrRofi2YEE6FwVDPlsEJIdKbHwsOpbBL/mk9sUaBxVpbd+w==}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2781,6 +2787,8 @@ snapshots:
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
|
||||
es-hangul@2.3.8: {}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
||||
@@ -553,7 +553,7 @@ export const searchFiles = async (
|
||||
: await baseQuery.execute();
|
||||
return files.map((file) => ({
|
||||
id: file.id,
|
||||
parentId: file.parent_id ?? "root",
|
||||
parentId: file.parent_id ?? ("root" as const),
|
||||
userId: file.user_id,
|
||||
path: file.path,
|
||||
mekVersion: file.master_encryption_key_version,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./concurrency";
|
||||
export * from "./format";
|
||||
export * from "./gotoStateful";
|
||||
export * from "./search";
|
||||
export * from "./sort";
|
||||
|
||||
28
src/lib/utils/search.ts
Normal file
28
src/lib/utils/search.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { disassemble, getChoseong } from "es-hangul";
|
||||
|
||||
const normalize = (s: string) => {
|
||||
return s.normalize("NFC").toLowerCase().replace(/\s/g, "");
|
||||
};
|
||||
|
||||
const extractHangul = (s: string) => {
|
||||
return s.replace(/[^가-힣ㄱ-ㅎㅏ-ㅣ]/g, "");
|
||||
};
|
||||
|
||||
const hangulSearch = (original: string, query: string) => {
|
||||
original = extractHangul(original);
|
||||
query = extractHangul(query);
|
||||
if (!original || !query) return false;
|
||||
|
||||
return (
|
||||
disassemble(original).includes(disassemble(query)) ||
|
||||
getChoseong(original).includes(getChoseong(query))
|
||||
);
|
||||
};
|
||||
|
||||
export const searchString = (original: string, query: string) => {
|
||||
original = normalize(original);
|
||||
query = normalize(query);
|
||||
if (!original || !query) return false;
|
||||
|
||||
return original.includes(query) || hangulSearch(original, query);
|
||||
};
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { Snapshot } from "@sveltejs/kit";
|
||||
import superjson, { type SuperJSONResult } from "superjson";
|
||||
import { untrack } from "svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
import { goto } from "$app/navigation";
|
||||
import { Chip, FullscreenDiv, RowVirtualizer } from "$lib/components/atoms";
|
||||
@@ -8,7 +11,7 @@
|
||||
type MaybeDirectoryInfo,
|
||||
} from "$lib/modules/filesystem";
|
||||
import { masterKeyStore } from "$lib/stores";
|
||||
import { HybridPromise, sortEntries } from "$lib/utils";
|
||||
import { HybridPromise, searchString, sortEntries } from "$lib/utils";
|
||||
import Directory from "./Directory.svelte";
|
||||
import File from "./File.svelte";
|
||||
import SearchBar from "./SearchBar.svelte";
|
||||
@@ -17,15 +20,24 @@
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
interface SearchFilters {
|
||||
name: string;
|
||||
includeImages: boolean;
|
||||
includeVideos: boolean;
|
||||
includeDirectories: boolean;
|
||||
searchInDirectory: boolean;
|
||||
categories: SearchFilter["categories"];
|
||||
}
|
||||
|
||||
let directoryInfo: MaybeDirectoryInfo | undefined = $state();
|
||||
|
||||
let filters = $state({
|
||||
let filters: SearchFilters = $state({
|
||||
name: "",
|
||||
includeImages: false,
|
||||
includeVideos: false,
|
||||
includeDirectories: false,
|
||||
searchInDirectory: false,
|
||||
categories: [] as SearchFilter["categories"],
|
||||
categories: [],
|
||||
});
|
||||
let hasCategoryFilter = $derived(filters.categories.length > 0);
|
||||
let hasAnyFilter = $derived(
|
||||
@@ -36,11 +48,12 @@
|
||||
filters.name.trim().length > 0,
|
||||
);
|
||||
|
||||
let isRestoredFromSnapshot = $state(false);
|
||||
let serverResult: SearchResult | undefined = $state();
|
||||
let result = $derived.by(() => {
|
||||
if (!serverResult) return [];
|
||||
|
||||
const nameFilter = filters.name.trim().toLowerCase();
|
||||
const nameFilter = filters.name.trim();
|
||||
const hasTypeFilter =
|
||||
filters.includeImages || filters.includeVideos || filters.includeDirectories;
|
||||
|
||||
@@ -58,7 +71,7 @@
|
||||
|
||||
return sortEntries(
|
||||
[...directories, ...files].filter(
|
||||
({ name }) => !nameFilter || name.toLowerCase().includes(nameFilter),
|
||||
({ name }) => !nameFilter || searchString(name, nameFilter),
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -81,6 +94,20 @@
|
||||
}
|
||||
};
|
||||
|
||||
export const snapshot: Snapshot<{
|
||||
filters: SearchFilters;
|
||||
serverResult: SuperJSONResult;
|
||||
}> = {
|
||||
capture() {
|
||||
return { filters, serverResult: superjson.serialize(serverResult) };
|
||||
},
|
||||
restore(value) {
|
||||
filters = value.filters;
|
||||
serverResult = superjson.deserialize(value.serverResult, { inPlace: true });
|
||||
isRestoredFromSnapshot = true;
|
||||
},
|
||||
};
|
||||
|
||||
$effect(() => {
|
||||
if (data.directoryId) {
|
||||
HybridPromise.resolve(getDirectoryInfo(data.directoryId, $masterKeyStore?.get(1)?.key!)).then(
|
||||
@@ -96,6 +123,16 @@
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
// Svelte sucks
|
||||
hasAnyFilter;
|
||||
filters.searchInDirectory;
|
||||
filters.categories.length;
|
||||
|
||||
if (untrack(() => isRestoredFromSnapshot)) {
|
||||
isRestoredFromSnapshot = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAnyFilter) {
|
||||
requestSearch(
|
||||
{
|
||||
|
||||
@@ -91,5 +91,5 @@ export const requestSearch = async (filter: SearchFilter, masterKey: CryptoKey)
|
||||
),
|
||||
]);
|
||||
|
||||
return { directories, files };
|
||||
return { directories, files } satisfies SearchResult;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user