first commit

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
michilis
2026-08-20 22:41:25 +02:00
co-authored by Cursor
commit aa1771ea20
136 changed files with 27069 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
---
import Moai from './Moai.astro';
import LanguageSwitcher from './LanguageSwitcher.astro';
import { localePath, useI18n } from '../i18n';
import { pageLocale } from '../i18n/paths';
interface Props {
current?: 'mints' | 'reviews' | 'wallets' | 'about';
/** Shows the compact search affordance next to the brand (mint pages, /mints). */
mintCount?: number;
}
const { current, mintCount } = Astro.props;
const { locale } = pageLocale(Astro);
const t = useI18n(locale);
/*
* Route slugs stay English in every language, so the href is the English path run
* through `localePath`. See src/i18n/routing.ts for why that trade was made.
*/
const links = [
{ path: '/mints', label: t('nav.mints'), key: 'mints' },
{ path: '/reviews', label: t('nav.reviews'), key: 'reviews' },
{ path: '/wallets', label: t('nav.wallets'), key: 'wallets' },
{ path: '/about', label: t('nav.about'), key: 'about' },
] as const;
---
<header class="topbar">
<div class="topbar-inner">
<a class="brand" href={localePath('/', locale)}>
<Moai />
{/* Below 420px the wordmark is what pushes the nav off the right edge. The
moai stays, and the name stays in the accessibility tree. */}
<span class="brand-text">Cashumints.space</span>
<span class="sr-only">Cashumints.space</span>
</a>
{
mintCount !== undefined && (
<a class="topbar-search" href={`${localePath('/mints', locale)}#mint-search`}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" />
</svg>
{t('nav.searchMints', { n: mintCount })}
<kbd>/</kbd>
</a>
)
}
<nav class="nav" aria-label={t('nav.main')}>
{
links.map((link) => (
<a
href={localePath(link.path, locale)}
aria-current={current === link.key ? 'page' : undefined}
>
{link.label}
</a>
))
}
</nav>
{/*
The language control, next to the account one and in every layout.
In the header rather than only in the footer because of who needs it: a reader who
landed on a page in a language they do not read should not have to scroll the whole
of it to get out. The footer keeps its own copy, where someone deliberately looking
for site settings expects to find one.
*/}
<LanguageSwitcher variant="menu" />
{/*
The account control. Prerendered logged out, because a static build cannot know
who is reading; the island swaps in the avatar and name from the stored session
and the cached profile on first paint, before any relay is asked anything.
*/}
<div class="auth" data-auth>
<button class="auth-login" type="button" data-login-open>{t('login.open')}</button>
</div>
</div>
</header>