Files
website/src/routes/trackers/ai/+layout.svelte

130 lines
3.1 KiB
Svelte

<script lang="ts">
import { page } from '$app/state';
import { resolve } from '$app/paths';
import TrackerIcon from '#lib/components/TrackerIcon.svelte';
import PrivateLock from '#lib/components/PrivateLock.svelte';
import Newspaper from 'lucide-svelte/icons/newspaper';
import Bot from 'lucide-svelte/icons/bot';
import Gauge from 'lucide-svelte/icons/gauge';
import SlidersHorizontal from 'lucide-svelte/icons/sliders-horizontal';
let { data, children } = $props();
const tabs = $derived([
{ name: 'news', href: '/trackers/ai', icon: Newspaper, locked: false },
...(data.owner
? [
{ name: 'bots', href: '/trackers/ai/bots', icon: Bot, locked: true },
{ name: 'usage', href: '/trackers/ai/usage', icon: Gauge, locked: true },
{ name: 'setup', href: '/trackers/ai/setup', icon: SlidersHorizontal, locked: true }
]
: [])
]);
</script>
<div class="ai-page">
<header class="ai-head">
<TrackerIcon name="ai" class="size-10" />
<div>
<h1>ai</h1>
<p>
AI and software news, plus what my bots are doing, how much I use each model and how each
one is set up.
</p>
</div>
</header>
<nav class="ai-tabs" aria-label="AI tracker sections">
{#each tabs as tab (tab.href)}
{@const active = page.url.pathname === tab.href}
<a
href={resolve(tab.href as '/trackers/ai')}
class={{ active }}
aria-current={active ? 'page' : undefined}
><span class="tab-icon tab-{tab.name}"><tab.icon size={14} /></span
>{tab.name}{#if tab.locked}<PrivateLock size={11} />{/if}</a
>
{/each}
</nav>
{@render children()}
</div>
<style>
.ai-page {
max-width: 72rem;
margin: 0 auto;
padding: 2rem 1rem 3rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.ai-head {
display: flex;
align-items: center;
gap: 0.85rem;
}
.ai-head h1 {
font-size: 2rem;
font-weight: 600;
letter-spacing: -0.02em;
line-height: 1.1;
}
.ai-head p {
color: var(--site-muted);
font-size: 0.9rem;
}
.ai-tabs {
display: flex;
gap: 0.35rem;
overflow-x: auto;
scrollbar-width: none;
border-bottom: 1px solid var(--site-border);
padding-bottom: 0.6rem;
}
.ai-tabs a {
display: inline-flex;
align-items: center;
gap: 0.45rem;
padding: 0.35rem 0.75rem 0.35rem 0.4rem;
border: 1px solid var(--site-border);
border-radius: 999px;
font-size: 0.85rem;
color: var(--site-muted);
white-space: nowrap;
text-decoration: none;
transition:
color 0.15s,
border-color 0.15s,
background 0.15s;
}
.ai-tabs a:hover {
color: var(--site-text);
border-color: var(--site-muted);
}
.ai-tabs a.active {
background: var(--site-text);
border-color: var(--site-text);
color: var(--site-bg);
}
.tab-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.5rem;
height: 1.5rem;
border-radius: 999px;
color: #fff;
}
.tab-news {
background: linear-gradient(135deg, #38bdf8, #2563eb);
}
.tab-bots {
background: linear-gradient(135deg, #fb923c, #db2777);
}
.tab-usage {
background: linear-gradient(135deg, #34d399, #0d9488);
}
.tab-setup {
background: linear-gradient(135deg, #a78bfa, #6d28d9);
}
</style>