mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-14 22:08:45 +00:00
카테고리 목록 이름 기반 정렬 구현
This commit is contained in:
@@ -27,3 +27,32 @@ export const formatNetworkSpeed = (speed: number) => {
|
|||||||
if (speed < 1000 * 1000 * 1000) return `${(speed / 1000 / 1000).toFixed(1)} Mbps`;
|
if (speed < 1000 * 1000 * 1000) return `${(speed / 1000 / 1000).toFixed(1)} Mbps`;
|
||||||
return `${(speed / 1000 / 1000 / 1000).toFixed(1)} Gbps`;
|
return `${(speed / 1000 / 1000 / 1000).toFixed(1)} Gbps`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum SortBy {
|
||||||
|
NAME_ASC,
|
||||||
|
NAME_DESC,
|
||||||
|
}
|
||||||
|
|
||||||
|
type SortFunc = (a?: string, b?: string) => number;
|
||||||
|
|
||||||
|
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
||||||
|
|
||||||
|
const sortByNameAsc: SortFunc = (a, b) => {
|
||||||
|
if (a && b) return collator.compare(a, b);
|
||||||
|
if (a) return -1;
|
||||||
|
if (b) return 1;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortByNameDesc: SortFunc = (a, b) => -sortByNameAsc(a, b);
|
||||||
|
|
||||||
|
export const sortEntries = <T extends { name?: string }>(entries: T[], sortBy: SortBy) => {
|
||||||
|
let sortFunc: SortFunc;
|
||||||
|
if (sortBy === SortBy.NAME_ASC) {
|
||||||
|
sortFunc = sortByNameAsc;
|
||||||
|
} else {
|
||||||
|
sortFunc = sortByNameDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.sort((a, b) => sortFunc(a.name, b.name));
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Component } from "svelte";
|
import { untrack, type Component } from "svelte";
|
||||||
import type { SvelteHTMLElements } from "svelte/elements";
|
import type { SvelteHTMLElements } from "svelte/elements";
|
||||||
import type { Writable } from "svelte/store";
|
import { get, type Writable } from "svelte/store";
|
||||||
import type { CategoryInfo } from "$lib/modules/filesystem";
|
import type { CategoryInfo } from "$lib/modules/filesystem";
|
||||||
|
import { SortBy, sortEntries } from "$lib/modules/util";
|
||||||
import Category from "./Category.svelte";
|
import Category from "./Category.svelte";
|
||||||
import type { SelectedCategory } from "./service";
|
import type { SelectedCategory } from "./service";
|
||||||
|
|
||||||
@@ -11,16 +12,48 @@
|
|||||||
categoryMenuIcon?: Component<SvelteHTMLElements["svg"]>;
|
categoryMenuIcon?: Component<SvelteHTMLElements["svg"]>;
|
||||||
onCategoryClick: (category: SelectedCategory) => void;
|
onCategoryClick: (category: SelectedCategory) => void;
|
||||||
onCategoryMenuClick?: (category: SelectedCategory) => void;
|
onCategoryMenuClick?: (category: SelectedCategory) => void;
|
||||||
|
sortBy?: SortBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { categories, categoryMenuIcon, onCategoryClick, onCategoryMenuClick }: Props = $props();
|
let {
|
||||||
|
categories,
|
||||||
|
categoryMenuIcon,
|
||||||
|
onCategoryClick,
|
||||||
|
onCategoryMenuClick,
|
||||||
|
sortBy = SortBy.NAME_ASC,
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
|
let categoriesWithName: { name?: string; info: Writable<CategoryInfo | null> }[] = $state([]);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
categoriesWithName = categories.map((category) => ({
|
||||||
|
name: get(category)?.name,
|
||||||
|
info: category,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sort = () => {
|
||||||
|
sortEntries(categoriesWithName, sortBy);
|
||||||
|
};
|
||||||
|
return untrack(() => {
|
||||||
|
sort();
|
||||||
|
|
||||||
|
const unsubscribes = categoriesWithName.map((category) =>
|
||||||
|
category.info.subscribe((value) => {
|
||||||
|
if (category.name === value?.name) return;
|
||||||
|
category.name = value?.name;
|
||||||
|
sort();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return () => unsubscribes.forEach((unsubscribe) => unsubscribe());
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if categories.length > 0}
|
{#if categoriesWithName.length > 0}
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
{#each categories as category}
|
{#each categoriesWithName as { info }}
|
||||||
<Category
|
<Category
|
||||||
info={category}
|
{info}
|
||||||
menuIcon={categoryMenuIcon}
|
menuIcon={categoryMenuIcon}
|
||||||
onclick={onCategoryClick}
|
onclick={onCategoryClick}
|
||||||
onMenuClick={onCategoryMenuClick}
|
onMenuClick={onCategoryMenuClick}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Writable } from "svelte/store";
|
import { untrack } from "svelte";
|
||||||
|
import { get, type Writable } from "svelte/store";
|
||||||
import { CheckBox } from "$lib/components/inputs";
|
import { CheckBox } from "$lib/components/inputs";
|
||||||
import { getFileInfo, type FileInfo, type CategoryInfo } from "$lib/modules/filesystem";
|
import { getFileInfo, type FileInfo, type CategoryInfo } from "$lib/modules/filesystem";
|
||||||
|
import { SortBy, sortEntries } from "$lib/modules/util";
|
||||||
import type { SelectedCategory } from "$lib/molecules/Categories";
|
import type { SelectedCategory } from "$lib/molecules/Categories";
|
||||||
import SubCategories from "$lib/molecules/SubCategories.svelte";
|
import SubCategories from "$lib/molecules/SubCategories.svelte";
|
||||||
import { masterKeyStore } from "$lib/stores";
|
import { masterKeyStore } from "$lib/stores";
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
onSubCategoryClick: (subCategory: SelectedCategory) => void;
|
onSubCategoryClick: (subCategory: SelectedCategory) => void;
|
||||||
onSubCategoryCreateClick: () => void;
|
onSubCategoryCreateClick: () => void;
|
||||||
onSubCategoryMenuClick: (subCategory: SelectedCategory) => void;
|
onSubCategoryMenuClick: (subCategory: SelectedCategory) => void;
|
||||||
|
sortBy?: SortBy;
|
||||||
isFileRecursive: boolean;
|
isFileRecursive: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,21 +30,42 @@
|
|||||||
onSubCategoryClick,
|
onSubCategoryClick,
|
||||||
onSubCategoryCreateClick,
|
onSubCategoryCreateClick,
|
||||||
onSubCategoryMenuClick,
|
onSubCategoryMenuClick,
|
||||||
|
sortBy = SortBy.NAME_ASC,
|
||||||
isFileRecursive = $bindable(),
|
isFileRecursive = $bindable(),
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
let files: { info: Writable<FileInfo | null>; isRecursive: boolean }[] = $state([]);
|
let files: { name?: string; info: Writable<FileInfo | null>; isRecursive: boolean }[] = $state(
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
files =
|
files =
|
||||||
info.files
|
info.files
|
||||||
?.filter(({ isRecursive }) => isFileRecursive || !isRecursive)
|
?.filter(({ isRecursive }) => isFileRecursive || !isRecursive)
|
||||||
.map(({ id, isRecursive }) => ({
|
.map(({ id, isRecursive }) => {
|
||||||
info: getFileInfo(id, $masterKeyStore?.get(1)?.key!),
|
const info = getFileInfo(id, $masterKeyStore?.get(1)?.key!);
|
||||||
isRecursive,
|
return {
|
||||||
})) ?? [];
|
name: get(info)?.name,
|
||||||
|
info,
|
||||||
|
isRecursive,
|
||||||
|
};
|
||||||
|
}) ?? [];
|
||||||
|
|
||||||
// TODO: Sorting
|
const sort = () => {
|
||||||
|
sortEntries(files, sortBy);
|
||||||
|
};
|
||||||
|
return untrack(() => {
|
||||||
|
sort();
|
||||||
|
|
||||||
|
const unsubscribes = files.map((file) =>
|
||||||
|
file.info.subscribe((value) => {
|
||||||
|
if (file.name === value?.name) return;
|
||||||
|
file.name = value?.name;
|
||||||
|
sort();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return () => unsubscribes.forEach((unsubscribe) => unsubscribe());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
type DirectoryInfo,
|
type DirectoryInfo,
|
||||||
type FileInfo,
|
type FileInfo,
|
||||||
} from "$lib/modules/filesystem";
|
} from "$lib/modules/filesystem";
|
||||||
|
import { SortBy, sortEntries } from "$lib/modules/util";
|
||||||
import {
|
import {
|
||||||
fileUploadStatusStore,
|
fileUploadStatusStore,
|
||||||
isFileUploading,
|
isFileUploading,
|
||||||
@@ -15,7 +16,6 @@
|
|||||||
} from "$lib/stores";
|
} from "$lib/stores";
|
||||||
import File from "./File.svelte";
|
import File from "./File.svelte";
|
||||||
import SubDirectory from "./SubDirectory.svelte";
|
import SubDirectory from "./SubDirectory.svelte";
|
||||||
import { SortBy, sortEntries } from "./service";
|
|
||||||
import UploadingFile from "./UploadingFile.svelte";
|
import UploadingFile from "./UploadingFile.svelte";
|
||||||
import type { SelectedDirectoryEntry } from "../service";
|
import type { SelectedDirectoryEntry } from "../service";
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export { default } from "./DirectoryEntries.svelte";
|
export { default } from "./DirectoryEntries.svelte";
|
||||||
export * from "./service";
|
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
export enum SortBy {
|
|
||||||
NAME_ASC,
|
|
||||||
NAME_DESC,
|
|
||||||
}
|
|
||||||
|
|
||||||
type SortFunc = (a?: string, b?: string) => number;
|
|
||||||
|
|
||||||
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
|
||||||
|
|
||||||
const sortByNameAsc: SortFunc = (a, b) => {
|
|
||||||
if (a && b) return collator.compare(a, b);
|
|
||||||
if (a) return -1;
|
|
||||||
if (b) return 1;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortByNameDesc: SortFunc = (a, b) => -sortByNameAsc(a, b);
|
|
||||||
|
|
||||||
export const sortEntries = <T extends { name?: string }>(
|
|
||||||
entries: T[],
|
|
||||||
sortBy: SortBy = SortBy.NAME_ASC,
|
|
||||||
) => {
|
|
||||||
let sortFunc: SortFunc;
|
|
||||||
if (sortBy === SortBy.NAME_ASC) {
|
|
||||||
sortFunc = sortByNameAsc;
|
|
||||||
} else {
|
|
||||||
sortFunc = sortByNameDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
entries.sort((a, b) => sortFunc(a.name, b.name));
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user