mirror of
https://github.com/pheralb/svgl.git
synced 2025-12-29 08:01:36 +08:00
🛠️ Refactor search handling in search.svelte and +page.svelte; implement custom addParams and deleteParam utility
This commit is contained in:
@@ -2,12 +2,9 @@
|
|||||||
import { cn } from "@/utils/cn";
|
import { cn } from "@/utils/cn";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
import { page } from "$app/state";
|
import { addParams } from "@/utils/searchParams";
|
||||||
import { goto } from "$app/navigation";
|
|
||||||
|
|
||||||
import SearchIcon from "@lucide/svelte/icons/search";
|
import SearchIcon from "@lucide/svelte/icons/search";
|
||||||
import CommandIcon from "@lucide/svelte/icons/command";
|
import CommandIcon from "@lucide/svelte/icons/command";
|
||||||
import { SvelteURLSearchParams } from "svelte/reactivity";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
searchValue: string;
|
searchValue: string;
|
||||||
@@ -19,19 +16,12 @@
|
|||||||
let inputElement: HTMLInputElement;
|
let inputElement: HTMLInputElement;
|
||||||
|
|
||||||
const onInput = (event: Event) => {
|
const onInput = (event: Event) => {
|
||||||
const param = "search";
|
|
||||||
const value = (event.target as HTMLInputElement).value;
|
const value = (event.target as HTMLInputElement).value;
|
||||||
onSearch(value);
|
onSearch(value);
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams);
|
addParams({
|
||||||
if (value) {
|
params: {
|
||||||
params.set(param, value);
|
search: value,
|
||||||
} else {
|
},
|
||||||
params.delete(param);
|
|
||||||
}
|
|
||||||
goto(`?${params.toString()}`, {
|
|
||||||
keepFocus: true,
|
|
||||||
noScroll: true,
|
|
||||||
replaceState: true,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+19
-3
@@ -3,6 +3,7 @@
|
|||||||
import type { PageProps } from "./$types";
|
import type { PageProps } from "./$types";
|
||||||
|
|
||||||
import { cn } from "@/utils/cn";
|
import { cn } from "@/utils/cn";
|
||||||
|
import { deleteParam } from "@/utils/searchParams";
|
||||||
import { svgsData } from "@/data";
|
import { svgsData } from "@/data";
|
||||||
import { searchWithFuse } from "@/utils/searchWithFuse";
|
import { searchWithFuse } from "@/utils/searchWithFuse";
|
||||||
|
|
||||||
@@ -12,11 +13,12 @@
|
|||||||
import SvgCard from "@/components/svgs/svgCard.svelte";
|
import SvgCard from "@/components/svgs/svgCard.svelte";
|
||||||
import SortSvgs from "@/components/svgs/sortSvgs.svelte";
|
import SortSvgs from "@/components/svgs/sortSvgs.svelte";
|
||||||
import Container from "@/components/container.svelte";
|
import Container from "@/components/container.svelte";
|
||||||
|
import SearchXIcon from "@lucide/svelte/icons/search-x";
|
||||||
|
|
||||||
import PageCard from "@/components/pageCard.svelte";
|
import PageCard from "@/components/pageCard.svelte";
|
||||||
import PageHeader from "@/components/pageHeader.svelte";
|
|
||||||
import FolderIcon from "@lucide/svelte/icons/folder";
|
import FolderIcon from "@lucide/svelte/icons/folder";
|
||||||
import FolderSearchIcon from "@lucide/svelte/icons/folder-search";
|
import PageHeader from "@/components/pageHeader.svelte";
|
||||||
|
import Button from "@/components/ui/button/button.svelte";
|
||||||
|
|
||||||
// SSR Data:
|
// SSR Data:
|
||||||
let { data }: PageProps = $props();
|
let { data }: PageProps = $props();
|
||||||
@@ -60,6 +62,13 @@
|
|||||||
searchSvgs();
|
searchSvgs();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClearSearch = () => {
|
||||||
|
searchTerm = "";
|
||||||
|
filteredSvgs = sorted ? alphabeticallySorted : latestSorted;
|
||||||
|
deleteParam("search");
|
||||||
|
updateDisplaySvgs();
|
||||||
|
};
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
updateDisplaySvgs();
|
updateDisplaySvgs();
|
||||||
});
|
});
|
||||||
@@ -87,7 +96,14 @@
|
|||||||
<span>logos</span>
|
<span>logos</span>
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<FolderSearchIcon size={18} strokeWidth={1.5} />
|
<Button
|
||||||
|
title="Clear Search"
|
||||||
|
onclick={handleClearSearch}
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
>
|
||||||
|
<SearchXIcon size={18} strokeWidth={1.5} />
|
||||||
|
</Button>
|
||||||
<p>
|
<p>
|
||||||
<span class="font-mono">{filteredSvgs.length}</span>
|
<span class="font-mono">{filteredSvgs.length}</span>
|
||||||
<span>logos</span>
|
<span>logos</span>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import type { PageProps } from "./$types";
|
import type { PageProps } from "./$types";
|
||||||
|
|
||||||
import { page } from "$app/state";
|
import { page } from "$app/state";
|
||||||
import { goto } from "$app/navigation";
|
|
||||||
import { SvelteURLSearchParams } from "svelte/reactivity";
|
import { SvelteURLSearchParams } from "svelte/reactivity";
|
||||||
|
|
||||||
import { cn } from "@/utils/cn";
|
import { cn } from "@/utils/cn";
|
||||||
@@ -14,68 +13,70 @@
|
|||||||
import Search from "@/components/search.svelte";
|
import Search from "@/components/search.svelte";
|
||||||
import SvgCard from "@/components/svgs/svgCard.svelte";
|
import SvgCard from "@/components/svgs/svgCard.svelte";
|
||||||
import Container from "@/components/container.svelte";
|
import Container from "@/components/container.svelte";
|
||||||
|
import SearchXIcon from "@lucide/svelte/icons/search-x";
|
||||||
|
|
||||||
import PageCard from "@/components/pageCard.svelte";
|
import PageCard from "@/components/pageCard.svelte";
|
||||||
import PageHeader from "@/components/pageHeader.svelte";
|
import PageHeader from "@/components/pageHeader.svelte";
|
||||||
import FolderIcon from "@lucide/svelte/icons/folder-open";
|
import FolderIcon from "@lucide/svelte/icons/folder-open";
|
||||||
import ArrowLeftIcon from "@lucide/svelte/icons/arrow-left";
|
import ArrowLeftIcon from "@lucide/svelte/icons/arrow-left";
|
||||||
import { buttonVariants } from "@/components/ui/button";
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
|
import SortSvgs from "@/components/svgs/sortSvgs.svelte";
|
||||||
|
import { deleteParam } from "@/utils/searchParams";
|
||||||
|
|
||||||
// SSR Data:
|
// SSR Data:
|
||||||
let { data }: PageProps = $props();
|
let { data }: PageProps = $props();
|
||||||
const directoryData = $derived(data);
|
const directoryData = $derived(data);
|
||||||
|
|
||||||
// States:
|
// States:
|
||||||
|
let maxDisplay = 30;
|
||||||
let searchTerm = $state<string>(data.searchTerm || "");
|
let searchTerm = $state<string>(data.searchTerm || "");
|
||||||
let filteredSvgs = $derived<iSVG[]>(data.filteredSvgs);
|
let filteredSvgs = $derived<iSVG[]>(data.initialSvgs);
|
||||||
|
let sorted = $state<boolean>(data.sorted);
|
||||||
|
let displaySvgs = $state<iSVG[]>([]);
|
||||||
|
let showAll = $state<boolean>(false);
|
||||||
|
|
||||||
|
const updateDisplaySvgs = () => {
|
||||||
|
displaySvgs = showAll ? filteredSvgs : filteredSvgs.slice(0, maxDisplay);
|
||||||
|
};
|
||||||
|
|
||||||
const searchSvgs = () => {
|
const searchSvgs = () => {
|
||||||
if (!searchTerm) {
|
if (!searchTerm) {
|
||||||
filteredSvgs = data.svgs;
|
filteredSvgs = sorted ? data.alphabeticallySorted : data.latestSorted;
|
||||||
|
updateDisplaySvgs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (searchTerm.length < 3) {
|
if (searchTerm.length < 3) {
|
||||||
filteredSvgs = data.svgs.filter((svg: iSVG) =>
|
filteredSvgs = (
|
||||||
|
sorted ? data.alphabeticallySorted : data.latestSorted
|
||||||
|
).filter((svg: iSVG) =>
|
||||||
svg.title.toLowerCase().includes(searchTerm.toLowerCase()),
|
svg.title.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
filteredSvgs = searchWithFuse(data.svgs)
|
filteredSvgs = searchWithFuse(filteredSvgs)
|
||||||
.search(searchTerm)
|
.search(searchTerm)
|
||||||
.map((result) => result.item);
|
.map((result) => result.item);
|
||||||
}
|
}
|
||||||
|
updateDisplaySvgs();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = (value: string) => {
|
const handleSearch = (value: string) => {
|
||||||
searchTerm = value;
|
searchTerm = value;
|
||||||
|
|
||||||
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
||||||
if (value) {
|
|
||||||
params.set("search", value);
|
|
||||||
} else {
|
|
||||||
params.delete("search");
|
|
||||||
}
|
|
||||||
|
|
||||||
goto(`?${params.toString()}`, {
|
|
||||||
keepFocus: true,
|
|
||||||
noScroll: true,
|
|
||||||
replaceState: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
searchSvgs();
|
searchSvgs();
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatCategory = (category: string) =>
|
const handleClearSearch = () => {
|
||||||
category.charAt(0).toUpperCase() + category.slice(1);
|
searchTerm = "";
|
||||||
|
deleteParam("search");
|
||||||
|
updateDisplaySvgs();
|
||||||
|
};
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
filteredSvgs = data.svgs.filter((svg: iSVG) =>
|
updateDisplaySvgs();
|
||||||
svg.title.toLowerCase().includes(searchTerm.toLowerCase()),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{formatCategory(directoryData.category)} SVG logos - Svgl</title>
|
<title>{directoryData.category} SVG logos - Svgl</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<Search
|
<Search
|
||||||
@@ -91,24 +92,29 @@
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
class={cn(
|
class={cn(buttonVariants({ variant: "ghost", size: "icon" }))}
|
||||||
buttonVariants({ class: "group", variant: "ghost", size: "icon" }),
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<ArrowLeftIcon
|
<ArrowLeftIcon size={18} strokeWidth={1.5} />
|
||||||
size={18}
|
|
||||||
strokeWidth={1.5}
|
|
||||||
class="transition-transform group-hover:translate-x-[-2px]"
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
<FolderIcon size={18} strokeWidth={1.5} />
|
{#if searchTerm}
|
||||||
|
<Button
|
||||||
|
title="Clear Search"
|
||||||
|
onclick={handleClearSearch}
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
>
|
||||||
|
<SearchXIcon size={18} strokeWidth={1.5} />
|
||||||
|
</Button>
|
||||||
|
{:else}
|
||||||
|
<FolderIcon class="ml-1" size={18} strokeWidth={1.5} />
|
||||||
|
{/if}
|
||||||
<p>
|
<p>
|
||||||
{formatCategory(directoryData.category)}
|
{directoryData.category}
|
||||||
</p>
|
</p>
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
{#if !searchTerm}
|
{#if !searchTerm}
|
||||||
<p>
|
<p>
|
||||||
<span>{data.svgs.length} SVGs </span>
|
<span>{data.initialSvgs.length} SVGs </span>
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p>
|
<p>
|
||||||
@@ -117,6 +123,14 @@
|
|||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<SortSvgs
|
||||||
|
className={cn(filteredSvgs.length === 0 && "hidden")}
|
||||||
|
isSorted={sorted}
|
||||||
|
onSortedChange={(value) => {
|
||||||
|
sorted = value;
|
||||||
|
searchSvgs();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Container className="my-6">
|
<Container className="my-6">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { page } from "$app/state";
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
import { SvelteURLSearchParams } from "svelte/reactivity";
|
||||||
|
|
||||||
|
interface SearchParams {
|
||||||
|
params: Record<string, string | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const addParams = ({ params }: SearchParams) => {
|
||||||
|
const searchParams = new SvelteURLSearchParams(page.url.searchParams);
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
if (value) {
|
||||||
|
searchParams.set(key, value);
|
||||||
|
} else {
|
||||||
|
searchParams.delete(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
goto(`?${searchParams.toString()}`, {
|
||||||
|
keepFocus: true,
|
||||||
|
noScroll: true,
|
||||||
|
replaceState: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteParam = (key: string) => {
|
||||||
|
const params = new SvelteURLSearchParams(page.url.searchParams);
|
||||||
|
params.delete(key);
|
||||||
|
goto(`?${params.toString()}`, {
|
||||||
|
keepFocus: true,
|
||||||
|
noScroll: true,
|
||||||
|
replaceState: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { addParams, deleteParam };
|
||||||
Reference in New Issue
Block a user