release: v0.12.0 (#520)
Forty-one commits since v0.11.0. See CHANGELOG.md for the full list and the upgrade notes.
This commit is contained in:
@@ -2,6 +2,7 @@ import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { imageUrl } from '@/lib/urls';
|
||||
import { SubpageSectionConfig } from '@/lib/config';
|
||||
import { getServerDictionary } from '@/lib/i18n/server';
|
||||
|
||||
interface SubpageAlbum {
|
||||
id: string;
|
||||
@@ -27,22 +28,26 @@ interface SubpageGridViewProps {
|
||||
sections?: SubpageSectionConfig[];
|
||||
/** 1-based position among all subpages — feeds the "03 — Collection" kicker. */
|
||||
index?: number;
|
||||
/** `--subpage-columns` / `--subpage-gap` from the resolved grid config. */
|
||||
gridStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const pad2 = (n: number) => String(n).padStart(2, '0');
|
||||
const photoCount = (n: number) => `${n} ${n === 1 ? 'photo' : 'photos'}`;
|
||||
const photoCount = (n: number) => getServerDictionary().common.photos(n);
|
||||
|
||||
function AlbumGrid({
|
||||
albums,
|
||||
placeholderMap,
|
||||
slug,
|
||||
gridStyle,
|
||||
}: {
|
||||
albums: SubpageAlbum[];
|
||||
placeholderMap: Map<string, Placeholder | null>;
|
||||
slug: string;
|
||||
gridStyle?: React.CSSProperties;
|
||||
}) {
|
||||
return (
|
||||
<div className="subpage-grid">
|
||||
<div className="subpage-grid" style={gridStyle}>
|
||||
{albums.map((album, i) => {
|
||||
const ph = placeholderMap.get(album.id) ?? null;
|
||||
return (
|
||||
@@ -51,7 +56,10 @@ function AlbumGrid({
|
||||
href={`/${slug}/${album.slug}`}
|
||||
className="subpage-grid__item"
|
||||
style={ph?.dominantColor ? { backgroundColor: ph.dominantColor } : undefined}
|
||||
aria-label={`${album.albumName}, ${photoCount(album.assetCount)}`}
|
||||
aria-label={getServerDictionary().subpage.coverAria(
|
||||
album.albumName,
|
||||
photoCount(album.assetCount),
|
||||
)}
|
||||
>
|
||||
<span className="subpage-grid__item-media">
|
||||
{album.albumThumbnailAssetId ? (
|
||||
@@ -105,11 +113,13 @@ export function SubpageGridView({
|
||||
coverPlaceholders,
|
||||
sections,
|
||||
index,
|
||||
gridStyle,
|
||||
}: SubpageGridViewProps) {
|
||||
// Build lookup maps once
|
||||
const albumMap = new Map(albums.map((a) => [a.id, a]));
|
||||
const placeholderMap = new Map(albums.map((a, i) => [a.id, coverPlaceholders[i] ?? null]));
|
||||
|
||||
const t = getServerDictionary();
|
||||
const hasSections = sections && sections.length > 0;
|
||||
const totalPhotos = albums.reduce((sum, a) => sum + a.assetCount, 0);
|
||||
|
||||
@@ -120,21 +130,21 @@ export function SubpageGridView({
|
||||
<div className="subpage-header__main">
|
||||
{index !== undefined && (
|
||||
<p className="subpage-header__kicker" aria-hidden="true">
|
||||
{pad2(index)} — Collection
|
||||
{t.subpage.collectionKicker(pad2(index))}
|
||||
</p>
|
||||
)}
|
||||
{title && <h1 className="subpage-title">{title}</h1>}
|
||||
{subtitle && <p className="subpage-subtitle">{subtitle}</p>}
|
||||
</div>
|
||||
<p className="subpage-header__meta" aria-hidden="true">
|
||||
{albums.length} {albums.length === 1 ? 'album' : 'albums'} · {photoCount(totalPhotos)}
|
||||
{t.common.albums(albums.length)} · {photoCount(totalPhotos)}
|
||||
</p>
|
||||
</header>
|
||||
)}
|
||||
|
||||
{/* Typographic Table of Contents */}
|
||||
{hasSections && (
|
||||
<nav className="subpage-toc" aria-label="Sections">
|
||||
<nav className="subpage-toc" aria-label={t.subpage.sectionsNav}>
|
||||
{sections.map((sec, i) => (
|
||||
<span key={sec.slug} className="subpage-toc__entry">
|
||||
<a href={`#${sec.slug}`} className="subpage-toc__link">
|
||||
@@ -160,13 +170,23 @@ export function SubpageGridView({
|
||||
{sec.description && <p className="subpage-section__desc">{sec.description}</p>}
|
||||
<div className="subpage-section__rule" aria-hidden="true" />
|
||||
</header>
|
||||
<AlbumGrid albums={sectionAlbums} placeholderMap={placeholderMap} slug={slug} />
|
||||
<AlbumGrid
|
||||
albums={sectionAlbums}
|
||||
placeholderMap={placeholderMap}
|
||||
slug={slug}
|
||||
gridStyle={gridStyle}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
/* Flat layout (no sections) */
|
||||
<AlbumGrid albums={albums} placeholderMap={placeholderMap} slug={slug} />
|
||||
<AlbumGrid
|
||||
albums={albums}
|
||||
placeholderMap={placeholderMap}
|
||||
slug={slug}
|
||||
gridStyle={gridStyle}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user