site: ui/ux refresh, seo pass, find/lists indexes, 25 new finds
- newspaper-style masthead (stats | "Unique" | About/Blog) on every page with per-page italic subheader + last-updated date on listing pages; sitewide 42rem reading width - pinterest home (hero + masonry, "load more"); old list view at /index3/ - new pages: /about, /blog, /legal, /find/, /finds/, custom 404 - footer collection links now clickable; "founded" stat replaces "updated" in the masthead - centralised SEO component with per-page json-ld (Review, BlogPosting, Product, Article, CollectionPage, ItemList, BreadcrumbList, etc.); @astrojs/sitemap + @astrojs/rss; robots.txt; promoted finds canonical to their review - memoize getSiteStats() so the masthead/footer counts don't multiply per-page build cost - 25 new daily-finds captures
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
---
|
||||
export interface OgImage {
|
||||
url: string;
|
||||
width: number;
|
||||
height: number;
|
||||
alt: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
canonicalPath?: string;
|
||||
canonicalOverride?: string;
|
||||
ogType?: 'website' | 'article';
|
||||
ogImage?: OgImage;
|
||||
noindex?: boolean;
|
||||
publishedTime?: Date;
|
||||
modifiedTime?: Date;
|
||||
articleTags?: string[];
|
||||
jsonLd?: Record<string, unknown> | Record<string, unknown>[];
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
canonicalPath,
|
||||
canonicalOverride,
|
||||
ogType = 'website',
|
||||
ogImage,
|
||||
noindex = false,
|
||||
publishedTime,
|
||||
modifiedTime,
|
||||
articleTags = [],
|
||||
jsonLd,
|
||||
} = Astro.props;
|
||||
|
||||
const SITE_NAME = 'Unique';
|
||||
const titleTag = title === SITE_NAME ? SITE_NAME : `${title} — ${SITE_NAME}`;
|
||||
|
||||
const canonicalUrl =
|
||||
canonicalOverride ??
|
||||
new URL(canonicalPath ?? Astro.url.pathname, Astro.site).href;
|
||||
|
||||
const jsonLdBlocks = jsonLd
|
||||
? Array.isArray(jsonLd)
|
||||
? jsonLd
|
||||
: [jsonLd]
|
||||
: [];
|
||||
---
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{titleTag}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={canonicalUrl} />
|
||||
{noindex && <meta name="robots" content="noindex,nofollow" />}
|
||||
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<meta name="theme-color" content="#fafaf7" media="(prefers-color-scheme: light)" />
|
||||
<meta name="theme-color" content="#161613" media="(prefers-color-scheme: dark)" />
|
||||
<link rel="alternate" type="application/rss+xml" title={`${SITE_NAME} — RSS`} href="/rss.xml" />
|
||||
|
||||
<meta property="og:type" content={ogType} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:url" content={canonicalUrl} />
|
||||
<meta property="og:site_name" content={SITE_NAME} />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
{ogImage && (
|
||||
<>
|
||||
<meta property="og:image" content={ogImage.url} />
|
||||
<meta property="og:image:width" content={String(ogImage.width)} />
|
||||
<meta property="og:image:height" content={String(ogImage.height)} />
|
||||
<meta property="og:image:alt" content={ogImage.alt} />
|
||||
{ogImage.type && <meta property="og:image:type" content={ogImage.type} />}
|
||||
</>
|
||||
)}
|
||||
|
||||
{ogType === 'article' && publishedTime && (
|
||||
<meta property="article:published_time" content={publishedTime.toISOString()} />
|
||||
)}
|
||||
{ogType === 'article' && modifiedTime && (
|
||||
<meta property="article:modified_time" content={modifiedTime.toISOString()} />
|
||||
)}
|
||||
{ogType === 'article' &&
|
||||
articleTags.map((t) => <meta property="article:tag" content={t} />)}
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
{ogImage && (
|
||||
<>
|
||||
<meta name="twitter:image" content={ogImage.url} />
|
||||
<meta name="twitter:image:alt" content={ogImage.alt} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{jsonLdBlocks.map((block) => (
|
||||
<script type="application/ld+json" is:inline set:html={JSON.stringify(block)} />
|
||||
))}
|
||||
Reference in New Issue
Block a user