ui: separate trackers from projects; keep header dropdown on top
- /trackers index, Trackers section on the homepage and in the header nav; /projects lists only projects (tracker URLs unchanged) - header is its own z-50 layer and <main> is isolated, so maps, charts and sticky tables no longer paint over the nav dropdowns
This commit is contained in:
63
src/lib/components/CatalogGrid.svelte
Normal file
63
src/lib/components/CatalogGrid.svelte
Normal file
@@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
// Card grid shared by the home page, /projects and /trackers.
|
||||
import { resolve } from '$app/paths';
|
||||
import ArrowRight from 'lucide-svelte/icons/arrow-right';
|
||||
import ExternalLink from 'lucide-svelte/icons/external-link';
|
||||
import * as Card from '#lib/components/ui/card/index.js';
|
||||
import ProjectIcon from '#lib/components/ProjectIcon.svelte';
|
||||
|
||||
type Item = { name: string; subtitle: string; href: string; external: boolean };
|
||||
let {
|
||||
items,
|
||||
subtitleClass = 'mt-1 block text-sm text-muted-foreground'
|
||||
}: { items: readonly Item[]; subtitleClass?: string } = $props();
|
||||
</script>
|
||||
|
||||
<ul class="grid gap-3 sm:grid-cols-2">
|
||||
{#each items as project (project.name)}
|
||||
<li>
|
||||
<Card.Root class="h-full py-0 transition-colors hover:bg-muted/50"
|
||||
><Card.Content class="p-0">
|
||||
{#if project.external}
|
||||
<a
|
||||
href={project.href}
|
||||
rel="external"
|
||||
class="flex min-h-28 items-start justify-between gap-4 p-5"
|
||||
>
|
||||
<span class="flex min-w-0 items-start gap-3">
|
||||
<span
|
||||
class="mt-0.5 flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-[var(--site-surface)] text-[var(--site-muted)]"
|
||||
>
|
||||
<ProjectIcon name={project.name} class="size-5" />
|
||||
</span>
|
||||
<span class="min-w-0"
|
||||
><span class="block font-medium">{project.name}</span><span class={subtitleClass}
|
||||
>{project.subtitle}</span
|
||||
></span
|
||||
>
|
||||
</span><ExternalLink size={18} aria-hidden="true" class="text-[var(--site-muted)]" />
|
||||
</a>
|
||||
{:else}
|
||||
<a
|
||||
href={resolve(project.href as '/')}
|
||||
class="flex min-h-28 items-start justify-between gap-4 p-5"
|
||||
>
|
||||
<span class="flex min-w-0 items-start gap-3">
|
||||
<span
|
||||
class="mt-0.5 flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-[var(--site-surface)] text-[var(--site-muted)]"
|
||||
>
|
||||
<ProjectIcon name={project.name} class="size-5" />
|
||||
</span>
|
||||
<span class="min-w-0"
|
||||
><span class="block font-medium">{project.name}</span><span class={subtitleClass}
|
||||
>{project.subtitle}</span
|
||||
></span
|
||||
>
|
||||
</span><ArrowRight size={18} aria-hidden="true" class="text-[var(--site-muted)]" />
|
||||
</a>
|
||||
{/if}
|
||||
</Card.Content></Card.Root
|
||||
>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -15,6 +15,7 @@
|
||||
import House from 'lucide-svelte/icons/house';
|
||||
import Globe2 from 'lucide-svelte/icons/globe-2';
|
||||
import Languages from 'lucide-svelte/icons/languages';
|
||||
import ListChecks from 'lucide-svelte/icons/list-checks';
|
||||
import Music2 from 'lucide-svelte/icons/music-2';
|
||||
import PawPrint from 'lucide-svelte/icons/paw-print';
|
||||
import Trophy from 'lucide-svelte/icons/trophy';
|
||||
@@ -32,7 +33,8 @@
|
||||
'language learner': Languages,
|
||||
'money tracker': Wallet,
|
||||
'cs prices': CandlestickChart,
|
||||
'house tracker': House
|
||||
'house tracker': House,
|
||||
lists: ListChecks
|
||||
};
|
||||
|
||||
const Icon = $derived(icons[name as keyof typeof icons] ?? FolderKanban);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Real projects (tools and experiments). Personal data trackers live in `trackers`.
|
||||
export const projects = [
|
||||
{
|
||||
name: 'vash esports',
|
||||
@@ -5,18 +6,6 @@ export const projects = [
|
||||
href: 'https://esports.vash.software',
|
||||
external: true
|
||||
},
|
||||
{
|
||||
name: 'game tracker',
|
||||
subtitle: 'every pokemon in every game, and call of duty camo mastery',
|
||||
href: '/projects/game-tracker',
|
||||
external: false
|
||||
},
|
||||
{
|
||||
name: 'animaldex',
|
||||
subtitle: 'add neighborhood pets to the world map',
|
||||
href: '/projects/animaldex',
|
||||
external: false
|
||||
},
|
||||
{
|
||||
name: 'osu! map finder',
|
||||
subtitle: 'find osu! maps for Spotify songs/albums/playlists',
|
||||
@@ -40,6 +29,16 @@ export const projects = [
|
||||
subtitle: 'Dutch, Korean and English, from zero to fluent',
|
||||
href: '/projects/language-learner',
|
||||
external: false
|
||||
}
|
||||
] as const;
|
||||
|
||||
// Trackers keep their existing /projects/... URLs (no moves, so no redirects needed).
|
||||
export const trackers = [
|
||||
{
|
||||
name: 'game tracker',
|
||||
subtitle: 'every pokemon in every game, and call of duty camo mastery',
|
||||
href: '/projects/game-tracker',
|
||||
external: false
|
||||
},
|
||||
{
|
||||
name: 'money tracker',
|
||||
@@ -58,5 +57,17 @@ export const projects = [
|
||||
subtitle: 'Counter-Strike market prices across time',
|
||||
href: '/projects/cs-prices',
|
||||
external: false
|
||||
},
|
||||
{
|
||||
name: 'animaldex',
|
||||
subtitle: 'add neighborhood pets to the world map',
|
||||
href: '/projects/animaldex',
|
||||
external: false
|
||||
},
|
||||
{
|
||||
name: 'lists',
|
||||
subtitle: 'books, games, places and other things worth keeping',
|
||||
href: '/lists',
|
||||
external: false
|
||||
}
|
||||
] as const;
|
||||
|
||||
@@ -32,9 +32,14 @@ const publicPages: Record<string, { title: string; description: string }> = {
|
||||
'/projects': {
|
||||
title: 'Projects',
|
||||
description:
|
||||
'Software projects by Stan Runge, including Game Tracker, Animaldex and Derby Lens.'
|
||||
'Software projects by Stan Runge, including osu! map finder, Derby Lens and Language Learner.'
|
||||
},
|
||||
'/blog': { title: 'Blog', description: 'Articles and notes by Stan Runge.' },
|
||||
'/trackers': {
|
||||
title: 'Trackers',
|
||||
description:
|
||||
'Stan Runge’s trackers: games, money, houses, Counter-Strike prices, Animaldex and lists.'
|
||||
},
|
||||
'/lists': { title: 'Lists', description: 'Lists collected and maintained by Stan Runge.' },
|
||||
'/projects/game-tracker': {
|
||||
title: 'Game Tracker',
|
||||
|
||||
@@ -17,6 +17,7 @@ export function getTitle(path: string, environment: SiteEnvironment = null): str
|
||||
const titles: Record<string, string> = {
|
||||
'/': 'Home',
|
||||
'/projects': 'Projects',
|
||||
'/trackers': 'Trackers',
|
||||
'/blog': 'Blog',
|
||||
'/lists': 'Lists',
|
||||
'/login': 'Sign in',
|
||||
|
||||
Reference in New Issue
Block a user