+
+
+
+
{category}
{categoryCounts[category]}
diff --git a/src/components/layout/showSidebarLinks.svelte b/src/components/layout/showSidebarLinks.svelte
index 304917b..1e7f24b 100644
--- a/src/components/layout/showSidebarLinks.svelte
+++ b/src/components/layout/showSidebarLinks.svelte
@@ -1,22 +1,74 @@
-{#each sidebarLinks as sidebarLink}
-
-
- {sidebarLink.title}
-
-{/each}
+
+
+ Home
+
+
+
+ {#if favoritesCount > 0}
+
+ {/if}
+
+
+
+ API
+
+
+
+ Extensions
+
diff --git a/src/components/layout/sidebarBadgeClasses.ts b/src/components/layout/sidebarBadgeClasses.ts
new file mode 100644
index 0000000..b5bbfed
--- /dev/null
+++ b/src/components/layout/sidebarBadgeClasses.ts
@@ -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",
+);
diff --git a/src/components/layout/sidebarItemClasses.ts b/src/components/layout/sidebarItemClasses.ts
index 7a668ce..324f94c 100644
--- a/src/components/layout/sidebarItemClasses.ts
+++ b/src/components/layout/sidebarItemClasses.ts
@@ -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",
diff --git a/src/components/layout/sidebarLinks.ts b/src/components/layout/sidebarLinks.ts
deleted file mode 100644
index 1e9981b..0000000
--- a/src/components/layout/sidebarLinks.ts
+++ /dev/null
@@ -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,
- },
-];
diff --git a/src/components/pageCard.svelte b/src/components/pageCard.svelte
new file mode 100644
index 0000000..3d13789
--- /dev/null
+++ b/src/components/pageCard.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+ {@render children?.()}
+
+
diff --git a/src/components/sortSvgs.svelte b/src/components/sortSvgs.svelte
new file mode 100644
index 0000000..434809a
--- /dev/null
+++ b/src/components/sortSvgs.svelte
@@ -0,0 +1,51 @@
+
+
+
diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts
new file mode 100644
index 0000000..98b5872
--- /dev/null
+++ b/src/routes/+layout.server.ts
@@ -0,0 +1,29 @@
+import type { LayoutServerLoad } from "./$types";
+import { globals } from "@/globals";
+
+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:
+ setHeaders({
+ "cache-control": "public, max-age=86400",
+ });
+
+ return {
+ stars: data.stargazers_count,
+ };
+ } catch (error) {
+ console.error("Error fetching GitHub data:", error);
+ return {
+ stars: 0,
+ error: "Failed to fetch repository data",
+ };
+ }
+};
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index a5f6f8f..1311282 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -1,4 +1,6 @@
-
+
{@render children?.()}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index e4b779d..ba713ff 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -2,21 +2,20 @@
import type { iSVG } from "@/types/svg";
import type { PageProps } from "./$types";
- import Fuse from "fuse.js";
import { cn } from "@/utils/cn";
import { svgsData } from "@/data";
+ import { searchWithFuse } from "@/utils/searchWithFuse";
// Components:
import Grid from "@/components/grid.svelte";
import Search from "@/components/search.svelte";
import SvgCard from "@/components/svgCard.svelte";
+ import SortSvgs from "@/components/sortSvgs.svelte";
import Container from "@/components/container.svelte";
- import { buttonVariants } from "@/components/ui/button";
+ import PageCard from "@/components/pageCard.svelte";
import FolderIcon from "@lucide/svelte/icons/folder";
import FolderSearchIcon from "@lucide/svelte/icons/folder-search";
- import ArrowUpDownIcon from "@lucide/svelte/icons/arrow-up-down";
- import ArrowDownUpIcon from "@lucide/svelte/icons/arrow-down-up";
// SSR Data:
let { data }: PageProps = $props();
@@ -31,15 +30,6 @@
const { latestSorted, alphabeticallySorted } = data;
- // Fuse.js Search (solo para búsquedas del lado cliente):
- const fuse = new Fuse
(svgsData, {
- keys: ["title"],
- threshold: 0.35,
- ignoreLocation: true,
- isCaseSensitive: false,
- shouldSort: true,
- });
-
const updateDisplaySvgs = () => {
displaySvgs = showAll ? filteredSvgs : filteredSvgs.slice(0, maxDisplay);
};
@@ -56,17 +46,14 @@
svg.title.toLowerCase().includes(searchTerm.toLowerCase()),
);
} else {
- filteredSvgs = fuse.search(searchTerm).map((result) => result.item);
+ filteredSvgs = searchWithFuse(filteredSvgs)
+ .search(searchTerm)
+ .map((result) => result.item);
}
updateDisplaySvgs();
};
- const sort = () => {
- sorted = !sorted;
- searchSvgs();
- };
-
const handleSearch = (value: string) => {
searchTerm = value;
searchSvgs();
@@ -83,65 +70,47 @@
placeholder="Search..."
/>
-
+
-
- {#if !searchTerm}
-
-
- {svgsData.length}
- logos
-
- {:else}
-
-
- {filteredSvgs.length}
- logos
-
- {/if}
-
-
+ {#if !searchTerm}
+
+
+ {svgsData.length}
+ logos
+
+ {:else}
+
+
+ {filteredSvgs.length}
+ logos
+
+ {/if}
-
-
- {#each displaySvgs as svg}
-
- {/each}
-
-
+
{
+ sorted = value;
+ searchSvgs();
+ }}
+ />
-
+
+
+ {#each displaySvgs as svg}
+
+ {/each}
+
+
+
diff --git a/src/routes/+page.ts b/src/routes/+page.ts
index 6946071..6b87a58 100644
--- a/src/routes/+page.ts
+++ b/src/routes/+page.ts
@@ -1,8 +1,8 @@
import type { iSVG } from "@/types/svg";
import type { Load } from "@sveltejs/kit";
-import Fuse from "fuse.js";
import { svgsData } from "@/data";
+import { searchWithFuse } from "@/utils/searchWithFuse";
export const load: Load = ({ url }) => {
const searchParam = url.searchParams.get("search") || "";
@@ -17,21 +17,15 @@ export const load: Load = ({ url }) => {
if (!searchParam) {
filteredSvgs = sortParam ? alphabeticallySorted : latestSorted;
} else {
- const fuse = new Fuse(svgsData, {
- keys: ["title"],
- threshold: 0.35,
- ignoreLocation: true,
- isCaseSensitive: false,
- shouldSort: true,
- });
-
if (searchParam.length < 3) {
const baseData = sortParam ? alphabeticallySorted : latestSorted;
filteredSvgs = baseData.filter((svg: iSVG) =>
svg.title.toLowerCase().includes(searchParam.toLowerCase()),
);
} else {
- filteredSvgs = fuse.search(searchParam).map((result) => result.item);
+ filteredSvgs = searchWithFuse(filteredSvgs)
+ .search(searchParam)
+ .map((result) => result.item);
}
}
diff --git a/src/routes/directory/[category]/+page.svelte b/src/routes/directory/[category]/+page.svelte
new file mode 100644
index 0000000..c08fe8e
--- /dev/null
+++ b/src/routes/directory/[category]/+page.svelte
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {data.category.slice(0, 1).toUpperCase() + data.category.slice(1)}
+
+
-
+ {#if !searchTerm}
+
+ {data.svgs.length} SVGs
+
+ {:else}
+
+ {filteredSvgs.length}
+ search results
+
+ {/if}
+
+
+
+
+ {#each filteredSvgs as svg}
+
+ {/each}
+
+
+
diff --git a/src/routes/directory/[category]/+page.ts b/src/routes/directory/[category]/+page.ts
new file mode 100644
index 0000000..5d7db34
--- /dev/null
+++ b/src/routes/directory/[category]/+page.ts
@@ -0,0 +1,48 @@
+import type { PageLoad } from "./$types";
+import type { iSVG } from "@/types/svg";
+
+import { svgs } from "@/data/svgs";
+import { error } from "@sveltejs/kit";
+import { searchWithFuse } from "@/utils/searchWithFuse";
+
+export const load: PageLoad = (async ({ params, url }) => {
+ const { category } = params;
+ const searchParam = url.searchParams.get("search") || "";
+
+ const svgsByCategory = svgs.filter((svg: iSVG) => {
+ if (Array.isArray(svg.category)) {
+ return svg.category.some(
+ (categoryItem) => categoryItem.toLowerCase() === category.toLowerCase(),
+ );
+ } else {
+ return svg.category.toLowerCase() === category.toLowerCase();
+ }
+ });
+
+ if (svgsByCategory.length === 0) {
+ throw error(404, "Category not found");
+ }
+
+ let filteredSvgs: iSVG[] = [];
+
+ if (!searchParam) {
+ filteredSvgs = svgsByCategory;
+ } else {
+ if (searchParam.length < 3) {
+ filteredSvgs = svgsByCategory.filter((svg: iSVG) =>
+ svg.title.toLowerCase().includes(searchParam.toLowerCase()),
+ );
+ } else {
+ filteredSvgs = searchWithFuse(svgsByCategory)
+ .search(searchParam)
+ .map((result) => result.item);
+ }
+ }
+
+ return {
+ category: category,
+ searchTerm: searchParam,
+ svgs: svgsByCategory,
+ filteredSvgs: filteredSvgs,
+ };
+}) satisfies PageLoad;