🚀 Create directory page + fix page components + improve header & sidebar items

This commit is contained in:
pheralb
2025-08-27 15:32:14 +01:00
parent 78cccd21e9
commit 1a3efeaede
14 changed files with 433 additions and 144 deletions
+24 -12
View File
@@ -8,10 +8,17 @@
import Github from "@/components/logos/github.svelte";
import Twitter from "@/components/logos/twitter.svelte";
import { Separator } from "@/components/ui/separator";
import Badge from "@/components/ui/badge/badge.svelte";
import { buttonVariants } from "@/components/ui/button";
import SendIcon from "@/components/ui/moving-icons/send-icon.svelte";
interface HeaderProps {
githubStars: number;
}
let { githubStars }: HeaderProps = $props();
const headerItemsClasses = cn(
buttonVariants({ variant: "ghost" }),
"hover:bg-neutral-200 dark:hover:bg-neutral-800",
@@ -32,10 +39,8 @@
</a>
<Badge variant="outline">{globals.currentVersion}</Badge>
</div>
<div class="flex items-center">
<div
class="mr-4 flex items-center space-x-0.5 border-r border-neutral-300 pr-3 dark:border-neutral-800"
>
<div class="flex h-8 items-center">
<div class="flex items-center space-x-0.5">
<a
target="_blank"
title="X/Twitter"
@@ -44,16 +49,23 @@
>
<Twitter size={18} />
</a>
<a
target="_blank"
title="GitHub Repository"
href={globals.githubUrl}
class={cn(headerItemsClasses, "h-9 w-9")}
>
<Github size={20} />
</a>
<ModeToggle className={cn(headerItemsClasses, "h-9 w-9")} />
</div>
<Separator orientation="vertical" class="mx-2 h-8" />
<a
target="_blank"
title="GitHub Repository"
href={globals.githubUrl}
class={cn(headerItemsClasses, "h-9 w-fit")}
>
<Github size={20} />
<span class="text-neutral-600 dark:text-neutral-400">
{githubStars >= 1000
? `${(githubStars / 1000).toFixed(1)}k`
: githubStars.toLocaleString()}
</span>
</a>
<Separator orientation="vertical" class="mr-3 ml-2" />
<a
target="_blank"
href={globals.submitUrl}
+3 -4
View File
@@ -5,7 +5,9 @@
import { svgs } from "@/data/svgs";
import { page } from "$app/state";
import { getCategories } from "@/data";
import { sidebarItemClasses } from "./sidebarItemClasses";
import { sidebarBadgeClasses } from "./sidebarBadgeClasses";
// Get category counts:
const categories: tCategory[] = getCategories();
@@ -30,10 +32,7 @@
>
<p class="truncate">{category}</p>
<span
class={cn(
"dark:bg-dark rounded-lg border border-neutral-200 bg-white px-2 py-0.5 font-mono text-xs font-medium text-neutral-600 shadow-sm dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-400",
page.url.pathname && "border-transparent",
)}
class={cn(sidebarBadgeClasses, page.url.pathname && "border-transparent")}
>
{categoryCounts[category]}
</span>
+67 -15
View File
@@ -1,22 +1,74 @@
<script lang="ts">
import { cn } from "@/utils/cn";
import { page } from "$app/state";
import favoritesStore from "@/stores/favorites.store";
import { sidebarLinks } from "./sidebarLinks";
import { sidebarItemClasses } from "./sidebarItemClasses";
import { sidebarBadgeClasses } from "./sidebarBadgeClasses";
import Box from "@lucide/svelte/icons/box";
import House from "@lucide/svelte/icons/house";
import Heart from "@lucide/svelte/icons/heart";
import Cloud from "@lucide/svelte/icons/cloud";
let favorites = $derived($favoritesStore);
let favoritesCount = $derived(favoritesStore.getCount(favorites));
</script>
{#each sidebarLinks as sidebarLink}
<a
href={sidebarLink.href}
data-sveltekit-preload-data
class={cn(
sidebarItemClasses.base,
"justify-start space-x-3",
page.url.pathname === sidebarLink.href && sidebarItemClasses.active,
)}
>
<sidebarLink.icon size={16} />
<p class="truncate">{sidebarLink.title}</p>
</a>
{/each}
<a
href="/"
data-sveltekit-preload-data
class={cn(
sidebarItemClasses.base,
"justify-start space-x-3",
page.url.pathname === "/" && sidebarItemClasses.active,
)}
>
<House size={16} />
<p class="truncate">Home</p>
</a>
<a
href="/favorites"
data-sveltekit-preload-data
class={cn(
sidebarItemClasses.base,
"justify-between",
String(page.url.pathname) === "/favorites" && sidebarItemClasses.active,
)}
>
<div class="flex items-center space-x-3">
<Heart size={16} />
<p class="truncate">Favorites</p>
</div>
{#if favoritesCount > 0}
<span
class={cn(sidebarBadgeClasses, page.url.pathname && "border-transparent")}
>
{favoritesCount}
</span>
{/if}
</a>
<a
href="/api"
data-sveltekit-preload-data
class={cn(
sidebarItemClasses.base,
"justify-start space-x-3",
String(page.url.pathname) === "/api" && sidebarItemClasses.active,
)}
>
<Cloud size={16} />
<p class="truncate">API</p>
</a>
<a
href="/extensions"
data-sveltekit-preload-data
class={cn(
sidebarItemClasses.base,
"justify-start space-x-3",
String(page.url.pathname) === "/extensions" && sidebarItemClasses.active,
)}
>
<Box size={16} />
<p class="truncate">Extensions</p>
</a>
@@ -0,0 +1,6 @@
import { cn } from "@/utils/cn";
export const sidebarBadgeClasses = cn(
"animate-in zoom-in-20 fade-in",
"dark:bg-dark rounded-lg border border-neutral-200 bg-white px-2 py-0.5 font-mono text-xs font-medium text-neutral-600 shadow-sm dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-400",
);
+1 -1
View File
@@ -2,7 +2,7 @@ import { cn } from "@/utils/cn";
export const sidebarItemClasses = {
base: cn(
"rounded-md px-2 py-1.5",
"rounded-md px-2 py-1.5 h-8",
"flex w-full items-center justify-between space-x-3 text-sm",
"text-neutral-600 dark:text-neutral-400",
"hover:text-black dark:hover:text-white",
-27
View File
@@ -1,27 +0,0 @@
import BoxIcon from "@lucide/svelte/icons/box";
import HouseIcon from "@lucide/svelte/icons/house";
import CloudIcon from "@lucide/svelte/icons/cloud";
import HeartIcon from "@lucide/svelte/icons/heart";
export const sidebarLinks = [
{
title: "Home",
href: "/",
icon: HouseIcon,
},
{
title: "Favorites",
href: "/favorites",
icon: HeartIcon,
},
{
title: "API",
href: "/api",
icon: CloudIcon,
},
{
title: "Extensions",
href: "/extensions",
icon: BoxIcon,
},
];
+26
View File
@@ -0,0 +1,26 @@
<script lang="ts">
import type { Snippet } from "svelte";
import { cn } from "@/utils/cn";
interface PageCardProps {
children: Snippet;
}
let { children }: PageCardProps = $props();
</script>
<div
class={cn(
"mt-2.5 overflow-hidden",
"rounded-md border border-neutral-200 dark:border-neutral-800",
"bg-white dark:bg-neutral-900/40",
)}
>
<div
class={cn(
"max-h-[calc(100vh-8.6rem)] min-h-[calc(100vh-8.6rem)] overflow-y-auto",
)}
>
{@render children?.()}
</div>
</div>
+51
View File
@@ -0,0 +1,51 @@
<script lang="ts">
import { page } from "$app/state";
import { goto } from "$app/navigation";
import { SvelteURLSearchParams } from "svelte/reactivity";
import { cn } from "@/utils/cn";
import { buttonVariants } from "@/components/ui/button";
import ArrowUpDownIcon from "@lucide/svelte/icons/arrow-up-down";
import ArrowDownUpIcon from "@lucide/svelte/icons/arrow-down-up";
interface Props {
className?: string;
isSorted: boolean;
onSortedChange: (isSorted: boolean) => void;
}
let { className, isSorted, onSortedChange }: Props = $props();
let sorted = $state<boolean>(isSorted);
const sort = () => {
const newSorted = !sorted;
sorted = newSorted;
const params = new SvelteURLSearchParams(page.url.searchParams);
if (newSorted) {
params.set("sort", "alphabetical");
} else {
params.delete("sort");
}
goto(`?${params.toString()}`, {
keepFocus: true,
noScroll: true,
replaceState: true,
});
onSortedChange(sorted);
};
</script>
<button
class={cn(buttonVariants({ variant: "ghost", class: "px-2.5" }), className)}
onclick={() => sort()}
>
{#if sorted}
<ArrowDownUpIcon size={16} strokeWidth={2} />
{:else}
<ArrowUpDownIcon size={16} strokeWidth={2} />
{/if}
<span>{sorted ? "Sort by latest" : "Sort A-Z"}</span>
</button>