site: visible RSS pill on category and tag pages
Autodiscovery alone is invisible since browsers dropped feed-detection UI — add a small RSS pill in the subheader (new feedHref prop on BaseLayout) linking to the page's scoped feed. Claude-Session: https://claude.ai/code/session_01WZaczDJjL3xZ3u5spsN5AL
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## July 2026
|
## July 2026
|
||||||
|
|
||||||
- Feeds for everything: alongside the existing `/rss.xml`, add a JSON Feed 1.1 at `/feed.json`, per-category RSS at `/categories/<name>/rss.xml`, and per-tag RSS at `/tags/<name>/rss.xml` — all derived from a shared `src/lib/feed.ts` item source (reviews + posts + bundles, same visibility rules as the site). Category/tag pages advertise their scoped feed via `<link rel="alternate">` autodiscovery; a new `/feeds/` directory page (linked from the footer) lists every feed with entry counts; every RSS feed carries an `atom:link` self reference and renders as a readable page in browsers via `public/feed.xsl`
|
- Feeds for everything: alongside the existing `/rss.xml`, add a JSON Feed 1.1 at `/feed.json`, per-category RSS at `/categories/<name>/rss.xml`, and per-tag RSS at `/tags/<name>/rss.xml` — all derived from a shared `src/lib/feed.ts` item source (reviews + posts + bundles, same visibility rules as the site). Category/tag pages advertise their scoped feed via `<link rel="alternate">` autodiscovery and show a visible RSS pill in the subheader (browsers dropped feed-detection UI years ago, so autodiscovery alone is invisible); a new `/feeds/` directory page (linked from the footer) lists every feed with entry counts; every RSS feed carries an `atom:link` self reference and renders as a readable page in browsers via `public/feed.xsl`
|
||||||
- Programmatic-reader pass: build-generated `/llms.txt` (llmstxt.org format — site description, feed/endpoint map, and every review, bundle, and post with one-line descriptions), `SearchAction` on the home-page `WebSite` JSON-LD wired to `/search/?q=`, and a "For robots" section on `/feeds/` documenting `search.json`, `llms.txt`, the sitemap, and JSON-LD coverage
|
- Programmatic-reader pass: build-generated `/llms.txt` (llmstxt.org format — site description, feed/endpoint map, and every review, bundle, and post with one-line descriptions), `SearchAction` on the home-page `WebSite` JSON-LD wired to `/search/?q=`, and a "For robots" section on `/feeds/` documenting `search.json`, `llms.txt`, the sitemap, and JSON-LD coverage
|
||||||
- Autonomous pipeline overhaul: new `/daily-pipeline` skill chains capture → bundle → review graduation → pick-of-the-day → build → commit → push and ends with a digest; `daily-finds` gains a score-and-shortlist stage (up to 12 `shortlist: true` finds per run, top 1-3 flagged as review candidates), feed-first fetching (`fetch: "feed"` + `feedUrl` in sources.json), cadence-aware scanning, and authority to apply mechanical source maintenance itself; `build-bundle`/`cluster-bundles`/`build-review` gain unattended `auto` modes (publish + log instead of pausing for confirmation), and `build-bundle weekly` writes a date-based "week's catch" so shortlisted finds never sit unbundled for weeks
|
- Autonomous pipeline overhaul: new `/daily-pipeline` skill chains capture → bundle → review graduation → pick-of-the-day → build → commit → push and ends with a digest; `daily-finds` gains a score-and-shortlist stage (up to 12 `shortlist: true` finds per run, top 1-3 flagged as review candidates), feed-first fetching (`fetch: "feed"` + `feedUrl` in sources.json), cadence-aware scanning, and authority to apply mechanical source maintenance itself; `build-bundle`/`cluster-bundles`/`build-review` gain unattended `auto` modes (publish + log instead of pausing for confirmation), and `build-bundle weekly` writes a date-based "week's catch" so shortlisted finds never sit unbundled for weeks
|
||||||
- Review heroes are now auto-discovered: `src/lib/hero.ts` globs `reviews/*/hero.<ext>` (images and `hero.mp4`), so a new review needs no registration — only legacy non-`hero`-named assets remain as explicit overrides; both hero globs also accept `.avif`
|
- Review heroes are now auto-discovered: `src/lib/hero.ts` globs `reviews/*/hero.<ext>` (images and `hero.mp4`), so a new review needs no registration — only legacy non-`hero`-named assets remain as explicit overrides; both hero globs also accept `.avif`
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Built with [Astro](https://astro.build) + MDX.
|
|||||||
- Auto-generated `/categories/<name>/` and `/tags/<name>/` listing pages — finds excluded by design
|
- Auto-generated `/categories/<name>/` and `/tags/<name>/` listing pages — finds excluded by design
|
||||||
- **Amazon affiliate handling** in `src/lib/affiliate.ts`: outbound links to Amazon (`amazon.com`, `amzn.to`, `a.co`, `smile.amazon.com`) get the configured tracking ID appended automatically; the link gets `rel="sponsored"`, an "Affiliate" badge appears next to it, and a one-line disclosure is shown beneath. Finds and reviews also take an optional `amazonLink` frontmatter field (canonical `/dp/<ASIN>` form) rendered as an "Also on Amazon" link — the capture pipeline populates it when a shortlisted physical product has an exact Amazon match. Add additional marketplace IDs (e.g. `amazon.co.uk`) to the `AMAZON_TAGS` map when needed
|
- **Amazon affiliate handling** in `src/lib/affiliate.ts`: outbound links to Amazon (`amazon.com`, `amzn.to`, `a.co`, `smile.amazon.com`) get the configured tracking ID appended automatically; the link gets `rel="sponsored"`, an "Affiliate" badge appears next to it, and a one-line disclosure is shown beneath. Finds and reviews also take an optional `amazonLink` frontmatter field (canonical `/dp/<ASIN>` form) rendered as an "Also on Amazon" link — the capture pipeline populates it when a shortlisted physical product has an exact Amazon match. Add additional marketplace IDs (e.g. `amazon.co.uk`) to the `AMAZON_TAGS` map when needed
|
||||||
- **SEO surface**: single `<SEO>` component owning canonical, Open Graph, Twitter Card, feed autodiscovery, and JSON-LD; per-page structured data (`Review`, `BlogPosting`, `Product`, `Article`, `CollectionPage`, `ItemList`, `BreadcrumbList`, `WebSite` with `SearchAction`, `Organization`); auto-generated `sitemap-index.xml` (excludes `/grid/` and `/index3/`); `robots.txt`; static OG image fallbacks under `/public/og/`; promoted finds canonical to their review
|
- **SEO surface**: single `<SEO>` component owning canonical, Open Graph, Twitter Card, feed autodiscovery, and JSON-LD; per-page structured data (`Review`, `BlogPosting`, `Product`, `Article`, `CollectionPage`, `ItemList`, `BreadcrumbList`, `WebSite` with `SearchAction`, `Organization`); auto-generated `sitemap-index.xml` (excludes `/grid/` and `/index3/`); `robots.txt`; static OG image fallbacks under `/public/og/`; promoted finds canonical to their review
|
||||||
- **Feeds everywhere**: site-wide RSS 2.0 at `/rss.xml` and JSON Feed 1.1 at `/feed.json`, plus per-category (`/categories/<name>/rss.xml`) and per-tag (`/tags/<name>/rss.xml`) RSS feeds, all derived from a single item source in `src/lib/feed.ts`; category/tag pages advertise their scoped feed via `<link rel="alternate">`; a human-readable directory at `/feeds/` (footer-linked) lists every feed with counts; RSS renders as a readable page in browsers via `public/feed.xsl`
|
- **Feeds everywhere**: site-wide RSS 2.0 at `/rss.xml` and JSON Feed 1.1 at `/feed.json`, plus per-category (`/categories/<name>/rss.xml`) and per-tag (`/tags/<name>/rss.xml`) RSS feeds, all derived from a single item source in `src/lib/feed.ts`; category/tag pages advertise their scoped feed via `<link rel="alternate">` and show a visible RSS pill in the subheader; a human-readable directory at `/feeds/` (footer-linked) lists every feed with counts; RSS renders as a readable page in browsers via `public/feed.xsl`
|
||||||
- **Programmatic surface**: build-generated `/llms.txt` (llmstxt.org format — site map with every review/bundle/post and one-line descriptions, plus feed and endpoint pointers) and the full-site JSON index at `/search.json`, both documented in the "For robots" section of `/feeds/`
|
- **Programmatic surface**: build-generated `/llms.txt` (llmstxt.org format — site map with every review/bundle/post and one-line descriptions, plus feed and endpoint pointers) and the full-site JSON index at `/search.json`, both documented in the "For robots" section of `/feeds/`
|
||||||
- Custom 404 page with recent-reviews and navigation fallback
|
- Custom 404 page with recent-reviews and navigation fallback
|
||||||
- Light/dark mode via `prefers-color-scheme`
|
- Light/dark mode via `prefers-color-scheme`
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ interface Props {
|
|||||||
jsonLd?: Record<string, unknown> | Record<string, unknown>[];
|
jsonLd?: Record<string, unknown> | Record<string, unknown>[];
|
||||||
/** Page-scoped feeds (category/tag) advertised alongside the site-wide ones. */
|
/** Page-scoped feeds (category/tag) advertised alongside the site-wide ones. */
|
||||||
feeds?: Array<{ title: string; href: string }>;
|
feeds?: Array<{ title: string; href: string }>;
|
||||||
|
/** Visible RSS pill in the subheader pointing at this page's scoped feed. */
|
||||||
|
feedHref?: string;
|
||||||
/** Opt into the wider content tier on roomy viewports (grid/listing pages). */
|
/** Opt into the wider content tier on roomy viewports (grid/listing pages). */
|
||||||
wide?: boolean;
|
wide?: boolean;
|
||||||
}
|
}
|
||||||
@@ -43,6 +45,7 @@ const {
|
|||||||
articleTags,
|
articleTags,
|
||||||
jsonLd,
|
jsonLd,
|
||||||
feeds,
|
feeds,
|
||||||
|
feedHref,
|
||||||
wide,
|
wide,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
const siteName = 'Unique';
|
const siteName = 'Unique';
|
||||||
@@ -113,6 +116,11 @@ const year = new Date().getFullYear();
|
|||||||
Updated <time datetime={updatedDate.toISOString()}>{fmtLong.format(updatedDate)}</time>
|
Updated <time datetime={updatedDate.toISOString()}>{fmtLong.format(updatedDate)}</time>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
{feedHref && (
|
||||||
|
<p class="subheader-feed">
|
||||||
|
<a href={feedHref}>RSS</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
@@ -305,6 +313,23 @@ const year = new Date().getFullYear();
|
|||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
.subheader-feed { margin: 0.45rem 0 0; }
|
||||||
|
.subheader-feed a {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.05rem 0.5rem;
|
||||||
|
font-family: ui-sans-serif, system-ui, -apple-system, 'Helvetica Neue', sans-serif;
|
||||||
|
font-size: 0.66rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: var(--rule);
|
||||||
|
color: var(--muted);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
.subheader-feed a:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.masthead-row {
|
.masthead-row {
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const breadcrumbs = buildBreadcrumbs([
|
|||||||
ogImage={ogImage}
|
ogImage={ogImage}
|
||||||
jsonLd={[collectionPage, itemList, breadcrumbs]}
|
jsonLd={[collectionPage, itemList, breadcrumbs]}
|
||||||
feeds={[{ title: `Unique — ${category} (RSS)`, href: `/categories/${category}/rss.xml` }]}
|
feeds={[{ title: `Unique — ${category} (RSS)`, href: `/categories/${category}/rss.xml` }]}
|
||||||
|
feedHref={`/categories/${category}/rss.xml`}
|
||||||
wide
|
wide
|
||||||
>
|
>
|
||||||
<EntryGrid entries={entries} />
|
<EntryGrid entries={entries} />
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const breadcrumbs = buildBreadcrumbs([
|
|||||||
ogImage={ogImage}
|
ogImage={ogImage}
|
||||||
jsonLd={[collectionPage, itemList, breadcrumbs]}
|
jsonLd={[collectionPage, itemList, breadcrumbs]}
|
||||||
feeds={[{ title: `Unique — #${tag} (RSS)`, href: `/tags/${tag}/rss.xml` }]}
|
feeds={[{ title: `Unique — #${tag} (RSS)`, href: `/tags/${tag}/rss.xml` }]}
|
||||||
|
feedHref={`/tags/${tag}/rss.xml`}
|
||||||
wide
|
wide
|
||||||
>
|
>
|
||||||
<EntryGrid entries={entries} />
|
<EntryGrid entries={entries} />
|
||||||
|
|||||||
Reference in New Issue
Block a user