Add lnurl list/detail routes, OG fixtures, i18n strings, and the write/ index client flows so the site surfaces the new mint type end to end. Co-authored-by: Cursor <cursoragent@cursor.com>
128 lines
5.1 KiB
Plaintext
128 lines
5.1 KiB
Plaintext
---
|
|
/**
|
|
* The site footer: one component, every page, three zones.
|
|
*
|
|
* Zone one is four columns — who this is, then the two link groups people actually
|
|
* navigate to, then the language control. Zone two is a thin bar with the copyright
|
|
* and the credit, and nothing else: the moment anything else moves into that row it
|
|
* stops being a signature and starts being a fourth navigation surface.
|
|
*
|
|
* What used to be here was four flat rows, the last of which was ~20 raw language
|
|
* links wrapped over two lines. That wall is now the same switcher the header carries
|
|
* (see LanguageSwitcher.astro, `placement="footer"`), so there is one language control
|
|
* on the site in two places rather than two controls that happen to agree.
|
|
*
|
|
* Everything below is static per locale and prerenders. No hex, no npub, no counts,
|
|
* nothing fetched: the footer is the one region of every page that must be identical
|
|
* on the home page and on a mint page that failed to load.
|
|
*/
|
|
import LanguageSwitcher from './LanguageSwitcher.astro';
|
|
import Moai from './Moai.astro';
|
|
import { localePath, useI18n } from '../i18n';
|
|
import { pageLocale } from '../i18n/paths';
|
|
|
|
const year = new Date().getFullYear();
|
|
const GITHUB = 'https://github.com/Azzamo-net/cashumints.space';
|
|
|
|
const { locale } = pageLocale(Astro);
|
|
const t = useI18n(locale);
|
|
|
|
/*
|
|
* Route slugs stay English in every language and `localePath` adds the prefix, exactly
|
|
* as the header does. See src/i18n/routing.ts for why that trade was made.
|
|
*/
|
|
const explore = [
|
|
{ href: localePath('/mints', locale), label: t('footer.allMints') },
|
|
{ href: localePath('/fedimints', locale), label: t('footer.allFedimints') },
|
|
{ href: localePath('/lnurl-mints', locale), label: t('footer.allLnurlMints') },
|
|
{ href: localePath('/reviews', locale), label: t('footer.allReviews') },
|
|
{ href: localePath('/wallets', locale), label: t('footer.wallets') },
|
|
];
|
|
|
|
/*
|
|
* GitHub sits in this column rather than beside the credit line because it is a place
|
|
* to go, not a signature. It is the only external link in the columns, so it carries
|
|
* `rel="noopener"` and nothing else needs to.
|
|
*/
|
|
const site = [
|
|
{ href: localePath('/about', locale), label: t('footer.about'), external: false },
|
|
{ href: GITHUB, label: 'GitHub', external: true },
|
|
{ href: localePath('/terms', locale), label: t('footer.terms'), external: false },
|
|
{ href: localePath('/privacy', locale), label: t('footer.privacy'), external: false },
|
|
{ href: localePath('/disclaimer', locale), label: t('footer.disclaimer'), external: false },
|
|
];
|
|
|
|
/*
|
|
* One sentence with a link in the middle of it, so the whole thing is one string a
|
|
* translator can reorder. The only interpolated value is markup this file wrote, and
|
|
* the label inside it is a name, so there is nothing here that could come from a mint,
|
|
* a relay or a reader.
|
|
*/
|
|
const madeBy = t('footer.madeBy', {
|
|
azzamo: '<a href="https://azzamo.net" rel="noopener">Azzamo</a>',
|
|
});
|
|
---
|
|
|
|
<footer class="site-footer" role="contentinfo">
|
|
<div class="foot-cols">
|
|
{/*
|
|
The brand column. The custodial warning lives here, under the description,
|
|
because it is the most honest sentence on the site and it was previously an
|
|
orphan floating at the bottom right of the last row. It is set in `--muted`
|
|
rather than `--faint`: quiet, but a step louder than the link columns, which is
|
|
the only typographic claim this footer makes about relative importance.
|
|
*/}
|
|
<div class="foot-brand">
|
|
<a class="foot-mark" href={localePath('/', locale)}>
|
|
<Moai size={20} />
|
|
<span>Cashumints.space</span>
|
|
</a>
|
|
<p class="foot-desc">{t('footer.tagline')}</p>
|
|
<p class="foot-warn">{t('footer.warning')}</p>
|
|
</div>
|
|
|
|
{/*
|
|
One nav landmark over both link columns, not one per column: a screen reader
|
|
listing landmarks should find "Footer", not "Footer" twice. The language control
|
|
carries its own nav, because it is a different kind of thing — it does not take
|
|
you to another page, it takes you to this page again.
|
|
*/}
|
|
<nav class="foot-nav" aria-label={t('footer.nav')}>
|
|
<div class="foot-col">
|
|
<h2 class="foot-head">{t('footer.col.explore')}</h2>
|
|
<ul>
|
|
{explore.map((link) => (
|
|
<li><a href={link.href}>{link.label}</a></li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="foot-col">
|
|
<h2 class="foot-head">{t('footer.col.site')}</h2>
|
|
<ul>
|
|
{site.map((link) => (
|
|
<li>
|
|
<a href={link.href} rel={link.external ? 'noopener' : undefined}>{link.label}</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="foot-col foot-lang">
|
|
<h2 class="foot-head">{t('lang.label')}</h2>
|
|
<LanguageSwitcher placement="footer" />
|
|
</div>
|
|
</div>
|
|
|
|
{/*
|
|
The bottom bar. Two items, and the discipline is that it stays two items: the
|
|
copyright and who made it. Everything else that was ever tempted into this row now
|
|
has a column above it.
|
|
*/}
|
|
<div class="foot-bar">
|
|
<span>{t('footer.copyright', { year: String(year) })}</span>
|
|
<span class="foot-credit" set:html={madeBy} />
|
|
</div>
|
|
</footer>
|