mirror of
https://github.com/pheralb/svgl.git
synced 2025-12-29 08:01:36 +08:00
🎨 Refactor grid and header components; improve props handling and layout consistency, update search functions to use new naming convention, and remove unused view transitions component
This commit is contained in:
@@ -2,13 +2,21 @@
|
||||
import type { Snippet } from "svelte";
|
||||
import { cn } from "@/utils/cn";
|
||||
|
||||
let { className, children }: { className?: string; children?: Snippet } =
|
||||
$props();
|
||||
interface GridProps {
|
||||
columns?: "default" | "4" | "3" | "2";
|
||||
className?: string;
|
||||
children?: Snippet;
|
||||
}
|
||||
|
||||
let { className, columns, children }: GridProps = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn(
|
||||
"grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5",
|
||||
columns === "4" && "lg:grid-cols-3 xl:grid-cols-4",
|
||||
columns === "3" && "lg:grid-cols-2 xl:grid-cols-3",
|
||||
columns === "2" && "md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import SendIcon from "@/components/ui/moving-icons/send-icon.svelte";
|
||||
|
||||
interface HeaderProps {
|
||||
githubStars: number;
|
||||
githubStars?: number;
|
||||
}
|
||||
|
||||
let { githubStars }: HeaderProps = $props();
|
||||
@@ -55,6 +55,7 @@
|
||||
/>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
{#if githubStars !== undefined}
|
||||
<a
|
||||
target="_blank"
|
||||
title="GitHub Repository"
|
||||
@@ -71,6 +72,19 @@
|
||||
: githubStars.toLocaleString()}
|
||||
</span>
|
||||
</a>
|
||||
{:else}
|
||||
<a
|
||||
target="_blank"
|
||||
title="GitHub Repository"
|
||||
href={globals.githubUrl}
|
||||
class={cn(
|
||||
buttonVariants({ variant: "ghost", size: "icon" }),
|
||||
"hover:bg-neutral-200 dark:hover:bg-neutral-800",
|
||||
)}
|
||||
>
|
||||
<Github size={20} />
|
||||
</a>
|
||||
{/if}
|
||||
<Separator orientation="vertical" />
|
||||
<a
|
||||
target="_blank"
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
searchValue: string;
|
||||
onSearch: (value: string) => void;
|
||||
placeholder?: string;
|
||||
iconSize?: number;
|
||||
inputClass?: string;
|
||||
}
|
||||
|
||||
let { searchValue, onSearch, placeholder }: Props = $props();
|
||||
let { searchValue, onSearch, placeholder, iconSize, inputClass }: Props =
|
||||
$props();
|
||||
let inputElement: HTMLInputElement;
|
||||
|
||||
const onInput = (event: Event) => {
|
||||
@@ -42,7 +45,7 @@
|
||||
|
||||
<div class="relative">
|
||||
<SearchIcon
|
||||
size={20}
|
||||
size={iconSize ? iconSize : 20}
|
||||
strokeWidth={2}
|
||||
class={cn(
|
||||
"pointer-events-none absolute top-1/2 left-2.5 -translate-y-1/2 transition-colors",
|
||||
@@ -65,6 +68,7 @@
|
||||
"bg-white dark:bg-neutral-900",
|
||||
"rounded-md border border-neutral-200 dark:border-neutral-800",
|
||||
"focus:border-neutral-400 focus:outline-none dark:focus:border-neutral-600",
|
||||
inputClass,
|
||||
)}
|
||||
/>
|
||||
{#if !searchValue}
|
||||
|
||||
@@ -477,17 +477,6 @@
|
||||
<span>Copy JS</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
class="justify-start"
|
||||
title="Copy as Svelte component"
|
||||
disabled={isLoading}
|
||||
onclick={() => convertSvgSvelteComponent(false)}
|
||||
>
|
||||
<Svelte size={18} />
|
||||
<span>Copy JS</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
class="justify-start"
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
let iconSize = 16;
|
||||
let iconStroke = 2;
|
||||
let cardDownloadStyles =
|
||||
"flex w-full h-full flex-col p-4 rounded-md shadow-sm dark:bg-neutral-800/20 bg-neutral-200/10 border border-neutral-200 dark:border-neutral-800 space-y-2";
|
||||
"flex w-full h-full flex-col p-4 rounded-md shadow-sm dark:bg-neutral-800/20 bg-neutral-200/10 border border-neutral-200 dark:border-neutral-800 space-y-1.5";
|
||||
let imgStyles = "my-7 h-10 select-none pointer-events-none";
|
||||
let badgeButtonStyles =
|
||||
"font-mono text-neutral-600 dark:text-neutral-400 text-xs";
|
||||
|
||||
// Functions:
|
||||
const handleDownloadSvg = async (url?: string) => {
|
||||
@@ -109,28 +112,23 @@
|
||||
>
|
||||
<DownloadIcon size={iconSize} strokeWidth={iconStroke} />
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content class="max-w-[630px]">
|
||||
<Dialog.Content>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Download {svgInfo.title} SVG</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
This logo has multiple options to download:
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<div
|
||||
class={cn(
|
||||
"flex h-full flex-col space-y-2 pt-2 pb-0.5",
|
||||
"md:flex-row md:items-center md:justify-center md:space-y-0 md:space-x-2",
|
||||
)}
|
||||
>
|
||||
<div class={cn("flex flex-col gap-4 md:flex-row")}>
|
||||
{#if typeof svgInfo.route === "string"}
|
||||
<div class={cardDownloadStyles}>
|
||||
<img
|
||||
src={isDarkTheme() ? svgInfo.route : svgInfo.route}
|
||||
alt={svgInfo.title}
|
||||
class="my-4 h-8"
|
||||
class={imgStyles}
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download logo"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -140,8 +138,11 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Icon logo</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.svg</span>
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
@@ -149,10 +150,10 @@
|
||||
<img
|
||||
src={isDarkTheme() ? svgInfo.route.dark : svgInfo.route.light}
|
||||
alt={svgInfo.title}
|
||||
class="my-4 h-10"
|
||||
class={imgStyles}
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Logo with light & dark variants"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -164,12 +165,15 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Light & dark variants</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.zip</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download light variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -179,12 +183,15 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Only light variant</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.svg</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download dark variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -194,8 +201,11 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Only dark variant</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.svg</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -205,10 +215,10 @@
|
||||
<img
|
||||
src={isDarkTheme() ? svgInfo.wordmark : svgInfo.wordmark}
|
||||
alt={svgInfo.title}
|
||||
class="my-4 h-8"
|
||||
class={imgStyles}
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download Wordmark logo"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -218,8 +228,11 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Wordmark logo</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.svg</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -231,10 +244,10 @@
|
||||
? svgInfo.wordmark.dark
|
||||
: svgInfo.wordmark.light}
|
||||
alt={svgInfo.title}
|
||||
class="my-4 h-10"
|
||||
class={imgStyles}
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download Wordmark light variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -248,12 +261,15 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Light & dark variants</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.zip</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download Wordmark light variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -263,12 +279,15 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Wordmark light variant</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.svg</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
class="justify-between"
|
||||
title="Download Wordmark dark variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -278,15 +297,16 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DownloadIcon class="mr-2" size={iconSize} />
|
||||
<div class="flex items-center space-x-2">
|
||||
<DownloadIcon size={iconSize} />
|
||||
<p>Wordmark dark variant</p>
|
||||
</div>
|
||||
<span class={badgeButtonStyles}>.svg</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<Dialog.Footer
|
||||
class="mt-3 text-xs text-neutral-600 dark:text-neutral-400"
|
||||
>
|
||||
<Dialog.Footer class="text-xs text-neutral-600 dark:text-neutral-400">
|
||||
<p>
|
||||
Remember to request permission from the creators for the use of the
|
||||
SVG. Modification is not allowed.
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
bind:ref
|
||||
data-slot="dialog-content"
|
||||
class={cn(
|
||||
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-2 rounded-lg border border-neutral-200 bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg dark:border-neutral-800 dark:bg-neutral-900",
|
||||
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-2 rounded-lg p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-2xl",
|
||||
"border border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-900",
|
||||
className,
|
||||
)}
|
||||
{...restProps}
|
||||
@@ -35,7 +36,10 @@
|
||||
{@render children?.()}
|
||||
{#if showCloseButton}
|
||||
<DialogPrimitive.Close
|
||||
class="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 dark:ring-offset-neutral-900 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
||||
class={cn(
|
||||
"absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
"ring-offset-white focus:ring-neutral-400 focus:ring-offset-2 data-[state=open]:bg-white data-[state=open]:text-neutral-500 dark:ring-offset-neutral-300 dark:focus:ring-neutral-700 dark:data-[state=open]:bg-neutral-900 dark:data-[state=open]:text-neutral-400",
|
||||
)}
|
||||
>
|
||||
<XIcon />
|
||||
<span class="sr-only">Close</span>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { onNavigate } from "$app/navigation";
|
||||
onNavigate((navigation) => {
|
||||
if (!document.startViewTransition) return;
|
||||
return new Promise((resolve) => {
|
||||
document.startViewTransition(async () => {
|
||||
resolve();
|
||||
await navigation.complete;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -5,10 +5,6 @@ export const load: LayoutServerLoad = async ({ fetch, setHeaders }) => {
|
||||
try {
|
||||
const response = await fetch(globals.apiGithubUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// 1 day cache:
|
||||
@@ -22,7 +18,7 @@ export const load: LayoutServerLoad = async ({ fetch, setHeaders }) => {
|
||||
} catch (error) {
|
||||
console.error("Error fetching GitHub data:", error);
|
||||
return {
|
||||
stars: 0,
|
||||
stars: null,
|
||||
error: "Failed to fetch repository data",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
// Providers:
|
||||
import { ModeWatcher } from "mode-watcher";
|
||||
import Sidebar from "@/components/layout/sidebar.svelte";
|
||||
import ViewTransitions from "@/components/viewTransitions.svelte";
|
||||
import Sonner from "@/components/ui/sonner/sonner.svelte";
|
||||
|
||||
// SSR Data:
|
||||
@@ -18,7 +17,6 @@
|
||||
</script>
|
||||
|
||||
<ModeWatcher />
|
||||
<ViewTransitions />
|
||||
<Sonner />
|
||||
<Header githubStars={data?.stars} />
|
||||
<Sidebar>
|
||||
|
||||
+14
-10
@@ -5,7 +5,7 @@
|
||||
import { cn } from "@/utils/cn";
|
||||
import { deleteParam } from "@/utils/searchParams";
|
||||
import { svgsData } from "@/data";
|
||||
import { searchWithFuse } from "@/utils/searchWithFuse";
|
||||
import { searchSvgsWithFuse } from "@/utils/searchWithFuse";
|
||||
|
||||
// Components:
|
||||
import Grid from "@/components/grid.svelte";
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import PageCard from "@/components/pageCard.svelte";
|
||||
import FolderIcon from "@lucide/svelte/icons/folder";
|
||||
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
|
||||
import PageHeader from "@/components/pageHeader.svelte";
|
||||
import Button from "@/components/ui/button/button.svelte";
|
||||
|
||||
@@ -43,17 +44,9 @@
|
||||
updateDisplaySvgs();
|
||||
return;
|
||||
}
|
||||
if (searchTerm.length < 3) {
|
||||
filteredSvgs = (sorted ? alphabeticallySorted : latestSorted).filter(
|
||||
(svg: iSVG) =>
|
||||
svg.title.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||
);
|
||||
} else {
|
||||
filteredSvgs = searchWithFuse(filteredSvgs)
|
||||
filteredSvgs = searchSvgsWithFuse(filteredSvgs)
|
||||
.search(searchTerm)
|
||||
.map((result) => result.item);
|
||||
}
|
||||
|
||||
updateDisplaySvgs();
|
||||
};
|
||||
|
||||
@@ -125,5 +118,16 @@
|
||||
<SvgCard svgInfo={svg} />
|
||||
{/each}
|
||||
</Grid>
|
||||
{#if showAll === false && filteredSvgs.length > maxDisplay}
|
||||
<div class="mt-6 flex justify-center">
|
||||
<Button variant="outline" size="lg" onclick={() => (showAll = true)}>
|
||||
<span>Show All</span>
|
||||
<span class="text-neutral-500 dark:text-neutral-700">
|
||||
(+ {filteredSvgs.length - maxDisplay} SVGs)
|
||||
</span>
|
||||
<ChevronDownIcon size={16} strokeWidth={2} />
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</Container>
|
||||
</PageCard>
|
||||
|
||||
+2
-9
@@ -2,7 +2,7 @@ import type { iSVG } from "@/types/svg";
|
||||
import type { Load } from "@sveltejs/kit";
|
||||
|
||||
import { svgsData } from "@/data";
|
||||
import { searchWithFuse } from "@/utils/searchWithFuse";
|
||||
import { searchSvgsWithFuse } from "@/utils/searchWithFuse";
|
||||
|
||||
export const load: Load = ({ url }) => {
|
||||
const searchParam = url.searchParams.get("search") || "";
|
||||
@@ -17,18 +17,11 @@ export const load: Load = ({ url }) => {
|
||||
if (!searchParam) {
|
||||
filteredSvgs = sortParam ? alphabeticallySorted : latestSorted;
|
||||
} else {
|
||||
if (searchParam.length < 3) {
|
||||
const baseData = sortParam ? alphabeticallySorted : latestSorted;
|
||||
filteredSvgs = baseData.filter((svg: iSVG) =>
|
||||
svg.title.toLowerCase().includes(searchParam.toLowerCase()),
|
||||
);
|
||||
} else {
|
||||
const baseData = sortParam ? alphabeticallySorted : latestSorted;
|
||||
filteredSvgs = searchWithFuse(baseData)
|
||||
filteredSvgs = searchSvgsWithFuse(baseData)
|
||||
.search(searchParam)
|
||||
.map((result) => result.item);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
searchTerm: searchParam,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
|
||||
export const load = async () => {
|
||||
return redirect(307, "/");
|
||||
};
|
||||
@@ -2,11 +2,8 @@
|
||||
import type { iSVG } from "@/types/svg";
|
||||
import type { PageProps } from "./$types";
|
||||
|
||||
import { page } from "$app/state";
|
||||
import { SvelteURLSearchParams } from "svelte/reactivity";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import { searchWithFuse } from "@/utils/searchWithFuse";
|
||||
import { searchSvgsWithFuse } from "@/utils/searchWithFuse";
|
||||
|
||||
// Components:
|
||||
import Grid from "@/components/grid.svelte";
|
||||
@@ -45,17 +42,9 @@
|
||||
updateDisplaySvgs();
|
||||
return;
|
||||
}
|
||||
if (searchTerm.length < 3) {
|
||||
filteredSvgs = (
|
||||
sorted ? data.alphabeticallySorted : data.latestSorted
|
||||
).filter((svg: iSVG) =>
|
||||
svg.title.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||
);
|
||||
} else {
|
||||
filteredSvgs = searchWithFuse(filteredSvgs)
|
||||
filteredSvgs = searchSvgsWithFuse(filteredSvgs)
|
||||
.search(searchTerm)
|
||||
.map((result) => result.item);
|
||||
}
|
||||
updateDisplaySvgs();
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { iSVG } from "@/types/svg";
|
||||
|
||||
import { error } from "@sveltejs/kit";
|
||||
import { getSvgsByCategory } from "@/data";
|
||||
import { searchWithFuse } from "@/utils/searchWithFuse";
|
||||
import { searchSvgsWithFuse } from "@/utils/searchWithFuse";
|
||||
|
||||
export const load: PageLoad = (async ({ params, url }) => {
|
||||
const { category } = params;
|
||||
@@ -26,18 +26,11 @@ export const load: PageLoad = (async ({ params, url }) => {
|
||||
if (!searchParam) {
|
||||
filteredSvgs = sortParam ? alphabeticallySorted : latestSorted;
|
||||
} else {
|
||||
if (searchParam.length < 3) {
|
||||
const baseData = sortParam ? alphabeticallySorted : latestSorted;
|
||||
filteredSvgs = baseData.filter((svg: iSVG) =>
|
||||
svg.title.toLowerCase().includes(searchParam.toLowerCase()),
|
||||
);
|
||||
} else {
|
||||
const baseData = sortParam ? alphabeticallySorted : latestSorted;
|
||||
filteredSvgs = searchWithFuse(baseData)
|
||||
filteredSvgs = searchSvgsWithFuse(baseData)
|
||||
.search(searchParam)
|
||||
.map((result) => result.item);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
category: formatCategory,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
|
||||
export const load = async () => {
|
||||
return redirect(307, "/");
|
||||
};
|
||||
Reference in New Issue
Block a user