site: rename "finds" superposts → "bundles" + 2026-05-06 capture run
Collection rename: src/content/finds/ → src/content/bundles/, URLs /finds/<slug>/ → /bundles/<slug>/, internal symbols (FindsPost → Bundle, findListMosaic → bundleMosaic, findsReferencing → bundlesReferencing, Entry.type 'finds' → 'bundle'). Skills build-finds/cluster-finds renamed to build-bundle/cluster-bundles. The `find` collection (individual items) is unchanged. New content: 4 reviews graduated (finalist, gum-shell, tablepro, valchoose-barf-bags) and 6 bundles for 2026-05-06 (constrain-the-surface, menu-bar-singletons, on-device-by-design, six-american-detours, six-lines-six-origins, things-in-the-terminal). Adds EntryGrid component.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import { getCollection, render } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import SourceBadge from '../../components/SourceBadge.astro';
|
||||
import EditAction from '../../components/EditAction.astro';
|
||||
import { sourceSlug } from '../../lib/sources';
|
||||
import {
|
||||
resolveExternalLink,
|
||||
AFFILIATE_REL,
|
||||
@@ -75,6 +75,9 @@ const breadcrumbs = buildBreadcrumbs([
|
||||
{ name: review.data.category, url: `/categories/${review.data.category}/` },
|
||||
{ name: review.data.name, url: `/reviews/${review.id}/` },
|
||||
]);
|
||||
|
||||
const categoryLabel =
|
||||
review.data.category.charAt(0).toUpperCase() + review.data.category.slice(1);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
@@ -91,49 +94,27 @@ const breadcrumbs = buildBreadcrumbs([
|
||||
jsonLd={[reviewSchema, breadcrumbs]}
|
||||
>
|
||||
<article>
|
||||
<header class="review-header">
|
||||
{review.data.source && (
|
||||
<p class="source-line"><SourceBadge source={review.data.source} /></p>
|
||||
)}
|
||||
<p class="meta">
|
||||
<a href={`/categories/${review.data.category}/`} class="category">
|
||||
{review.data.category}
|
||||
</a>
|
||||
{
|
||||
external && (
|
||||
<>
|
||||
<span class="dot">·</span>
|
||||
<a
|
||||
href={external.href}
|
||||
target="_blank"
|
||||
rel={external.isAffiliate ? AFFILIATE_REL : 'noopener noreferrer'}
|
||||
>
|
||||
{linkLabel} ↗
|
||||
</a>
|
||||
{external.isAffiliate && <span class="aff-badge">Affiliate</span>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
</p>
|
||||
{external?.isAffiliate && (
|
||||
<p class="aff-disclosure">{AFFILIATE_DISCLOSURE}</p>
|
||||
)}
|
||||
</header>
|
||||
|
||||
{fromFindItem && (
|
||||
<p class="from-find">
|
||||
← First surfaced on{' '}
|
||||
<time datetime={fromFindItem.data.date.toISOString()}>
|
||||
{fmt.format(fromFindItem.data.date)}
|
||||
</time>{' '}
|
||||
as <a href={`/find/${fromFindItem.id}/`}>a find</a>
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div class="body">
|
||||
<Content />
|
||||
</div>
|
||||
|
||||
{external && (
|
||||
<p class="external">
|
||||
<a
|
||||
href={external.href}
|
||||
target="_blank"
|
||||
rel={external.isAffiliate ? AFFILIATE_REL : 'noopener noreferrer'}
|
||||
>
|
||||
{linkLabel} ↗
|
||||
</a>
|
||||
{external.isAffiliate && <span class="aff-badge">Affiliate</span>}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{external?.isAffiliate && (
|
||||
<p class="aff-disclosure">{AFFILIATE_DISCLOSURE}</p>
|
||||
)}
|
||||
|
||||
{import.meta.env.DEV && (
|
||||
<div class="edit-toolbar">
|
||||
<EditAction
|
||||
@@ -145,61 +126,50 @@ const breadcrumbs = buildBreadcrumbs([
|
||||
</div>
|
||||
)}
|
||||
|
||||
{
|
||||
review.data.tags.length > 0 && (
|
||||
<footer class="tags">
|
||||
{review.data.tags.map((tag) => (
|
||||
<a href={`/tags/${tag}/`} class="tag">#{tag}</a>
|
||||
))}
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
<aside class="colophon" aria-label="Colophon">
|
||||
<dl>
|
||||
{review.data.source && (
|
||||
<>
|
||||
<dt>Via</dt>
|
||||
<dd>
|
||||
<a href={`/sources/#${sourceSlug(review.data.source)}`}>
|
||||
{review.data.source}
|
||||
</a>
|
||||
</dd>
|
||||
</>
|
||||
)}
|
||||
<dt>Filed under</dt>
|
||||
<dd>
|
||||
<a href={`/categories/${review.data.category}/`}>{categoryLabel}</a>
|
||||
</dd>
|
||||
{fromFindItem && (
|
||||
<>
|
||||
<dt>First surfaced</dt>
|
||||
<dd>
|
||||
<time datetime={fromFindItem.data.date.toISOString()}>
|
||||
{fmt.format(fromFindItem.data.date)}
|
||||
</time>
|
||||
{' '}as <a href={`/find/${fromFindItem.id}/`}>a find</a>
|
||||
</dd>
|
||||
</>
|
||||
)}
|
||||
{review.data.tags.length > 0 && (
|
||||
<>
|
||||
<dt>Tagged</dt>
|
||||
<dd class="colophon-tags">
|
||||
{review.data.tags.map((tag) => (
|
||||
<a href={`/tags/${tag}/`}>#{tag}</a>
|
||||
))}
|
||||
</dd>
|
||||
</>
|
||||
)}
|
||||
</dl>
|
||||
</aside>
|
||||
|
||||
<p class="back"><a href="/">← back</a></p>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.source-line { margin: 0 0 0.5rem; }
|
||||
.from-find {
|
||||
margin: 0 0 1.5rem;
|
||||
padding: 0.6rem 0.85rem;
|
||||
background: var(--rule);
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
.from-find time { color: var(--muted); }
|
||||
.review-header {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.meta {
|
||||
margin: 0.5rem 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.meta .dot { margin: 0 0.4rem; }
|
||||
.meta .category { color: var(--muted); }
|
||||
.meta .category:hover { color: var(--accent); }
|
||||
.aff-badge {
|
||||
display: inline-block;
|
||||
margin-left: 0.45rem;
|
||||
padding: 0.12rem 0.45rem;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
background: var(--rule);
|
||||
border-radius: 999px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.aff-disclosure {
|
||||
margin: 0.6rem 0 0;
|
||||
font-size: 0.78rem;
|
||||
color: var(--muted);
|
||||
font-style: italic;
|
||||
}
|
||||
.body :global(p) { margin: 0 0 1rem; }
|
||||
.body :global(h2) { font-size: 1.3rem; margin: 2rem 0 0.75rem; }
|
||||
.body :global(h3) { font-size: 1.1rem; margin: 1.5rem 0 0.5rem; }
|
||||
@@ -299,16 +269,6 @@ const breadcrumbs = buildBreadcrumbs([
|
||||
margin: 0 0 1.75rem;
|
||||
}
|
||||
.body :global(blockquote p) { margin: 0; }
|
||||
.tags {
|
||||
margin-top: 2.5rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--rule);
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.tag { font-size: 0.85rem; color: var(--muted); }
|
||||
.tag:hover { color: var(--accent); }
|
||||
.back { margin-top: 2rem; font-size: 0.9rem; }
|
||||
.edit-toolbar {
|
||||
margin: 2rem 0 0;
|
||||
|
||||
Reference in New Issue
Block a user