Add Fedimint discovery, dual SQLite/Postgres storage, richer review handling, and generated social imagery.
94 lines
3.4 KiB
Plaintext
94 lines
3.4 KiB
Plaintext
---
|
|
import Moai from './Moai.astro';
|
|
import LanguageSwitcher from './LanguageSwitcher.astro';
|
|
import { localePath, useI18n } from '../i18n';
|
|
import { pageLocale } from '../i18n/paths';
|
|
|
|
interface Props {
|
|
current?: 'mints' | 'fedimints' | '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.
|
|
*/
|
|
/*
|
|
* "Cashu mints", not "Mints".
|
|
*
|
|
* Two ecosystems are listed now, so a bare "Mints" beside "Fedimints" reads as though
|
|
* federations were something other than mints — or as though the first link covered
|
|
* both. The extra word costs ~45px in the widest nav row and buys a label that is
|
|
* unambiguous at a glance. It is the same wording on /mints' own heading, in the
|
|
* breadcrumb and in the footer, so nothing calls the same page two things.
|
|
*/
|
|
const links = [
|
|
{ path: '/mints', label: t('nav.mints'), key: 'mints' },
|
|
{ path: '/fedimints', label: t('nav.fedimints'), key: 'fedimints' },
|
|
{ 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>
|