---
import Base from '../../layouts/Base.astro';
import MintCard from '../../components/MintCard.astro';
import ReviewByUrl from '../../components/ReviewByUrl.astro';
import { fetchLnurlMints } from '../../lib/api';
import { localePath, useI18n, type Locale } from '../../i18n';
import { itemListNode } from '../../lib/schema';
import { isIndexableMint } from '../../lib/seo';
import { localePaths } from '../../i18n/paths';
/**
* The LNURL mint index. /mints' twin, and built from the same parts for the same reason
* /fedimints is: same container, same card, same search, same result line, same
* leave-and-return animation.
*
* Unlike /fedimints it keeps the full sort set including "recently seen online". That
* page drops it because a third of its rows have no `last_online` at all — nothing
* checks those federations, so ordering on the column is a shuffle rather than a sort.
* An LNURL mint is genuinely probed over HTTPS, exactly as a Cashu mint is, so every row
* here has a real answer and the sort means what it says.
*/
/** One page per locale: `/lnurl-mints`, `/es/lnurl-mints`, `/nl/lnurl-mints`. */
export const getStaticPaths = localePaths;
interface Props {
locale: Locale;
}
const { locale } = Astro.props;
// `t` formats the numbers inside its own strings, so no separate formatter is needed.
const t = useI18n(locale);
/*
One request, no N+1.
This used to be `fetchLnurlMints()` followed by one `fetchLnurlMint(host)` per mint,
purely to read the two probed facts behind the "no withdrawals" and "no mint / melt"
chips: an advertised withdraw ceiling of zero, and an unreachable Lightning node.
`MintListItem` carries both now, exactly as it carries the Cashu NUT switches, so the
chips come off the same payload as everything else — which is what makes the hydration
below possible without an N+1 in every visitor's browser.
*/
const mints = await fetchLnurlMints();
const online = mints.filter((m) => m.status === 'online').length;
const offline = mints.filter((m) => m.status === 'offline').length;
const description = t('lnurlMints.description', { total: mints.length, online, offline });
/*
* The index, as a list a crawler can read in order.
*
* Only the mints whose own pages are indexable: listing a page here while telling a
* crawler not to index it is a contradiction. The order is the server-rendered one,
* which is the score order; the sort control rewrites the DOM but not this markup,
* so `ItemListOrderDescending` describes what shipped.
*/
const canonical = new URL(localePath('/lnurl-mints', locale), Astro.site).href;
const schema = [
itemListNode({
canonical,
fragment: 'lnurl-mints',
name: t('lnurlMints.heading'),
items: mints.filter(isIndexableMint).map((mint) => ({
name: mint.name ?? mint.host,
url: new URL(localePath(`/lnurl-mint/${mint.host}`, locale), Astro.site).href,
})),
}),
];
---
{t('lnurlMints.lede')}
{t('lnurlMints.showing', { total: mints.length, online, offline })}
{t('lnurlMints.noResults')}
{mints.length === 0 &&{t('lnurlMints.emptyIndex')}
}