feat: allow subpages to override title and add subtitle in gallery.yaml

This commit is contained in:
ralksta
2026-03-08 22:46:27 +01:00
parent 88f03fe2ce
commit 32bb6cb2ca
6 changed files with 57 additions and 34 deletions

1
.gitignore vendored
View File

@@ -31,6 +31,7 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
.pnpm-debug.log* .pnpm-debug.log*
server.log
# env files (can opt-in for committing if needed) # env files (can opt-in for committing if needed)
.env* .env*

View File

@@ -17,46 +17,56 @@ interface Placeholder {
interface SubpageGridViewProps { interface SubpageGridViewProps {
slug: string; slug: string;
title?: string;
subtitle?: string;
albums: SubpageAlbum[]; albums: SubpageAlbum[];
coverPlaceholders: (Placeholder | null)[]; coverPlaceholders: (Placeholder | null)[];
} }
export function SubpageGridView({ slug, albums, coverPlaceholders }: SubpageGridViewProps) { export function SubpageGridView({ slug, title, subtitle, albums, coverPlaceholders }: SubpageGridViewProps) {
return ( return (
<div className="subpage-grid"> <div className="subpage-container">
{albums.map((album, i) => { {(title || subtitle) && (
const ph = coverPlaceholders[i]; <header className="subpage-header">
return ( {title && <h1 className="subpage-title">{title}</h1>}
<Link {subtitle && <p className="subpage-subtitle">{subtitle}</p>}
key={album.id} </header>
href={`/${slug}/${album.slug}`} )}
className="subpage-grid__item" <div className="subpage-grid">
style={ph?.dominantColor ? { backgroundColor: ph.dominantColor } : undefined} {albums.map((album, i) => {
> const ph = coverPlaceholders[i];
{album.albumThumbnailAssetId ? ( return (
<Image <Link
src={imageUrl(album.albumThumbnailAssetId, 'preview')} key={album.id}
alt={album.albumName} href={`/${slug}/${album.slug}`}
fill className="subpage-grid__item"
sizes="(max-width: 600px) 100vw, (max-width: 1000px) 50vw, 33vw" style={ph?.dominantColor ? { backgroundColor: ph.dominantColor } : undefined}
loading="lazy" >
{...(ph ? { placeholder: 'blur' as const, blurDataURL: ph.blurDataURL } : {})} {album.albumThumbnailAssetId ? (
/> <Image
) : ( src={imageUrl(album.albumThumbnailAssetId, 'preview')}
<div className="skeleton" style={{ width: '100%', height: '100%' }} /> alt={album.albumName}
)} fill
<span className="subpage-grid__item-badge"> sizes="(max-width: 600px) 100vw, (max-width: 1000px) 50vw, 33vw"
{album.assetCount} {album.assetCount === 1 ? 'photo' : 'photos'} loading="lazy"
</span> {...(ph ? { placeholder: 'blur' as const, blurDataURL: ph.blurDataURL } : {})}
<div className="subpage-grid__item-overlay"> />
<span className="subpage-grid__item-title">{album.albumName}</span> ) : (
<span className="subpage-grid__item-count"> <div className="skeleton" style={{ width: '100%', height: '100%' }} />
)}
<span className="subpage-grid__item-badge">
{album.assetCount} {album.assetCount === 1 ? 'photo' : 'photos'} {album.assetCount} {album.assetCount === 1 ? 'photo' : 'photos'}
</span> </span>
</div> <div className="subpage-grid__item-overlay">
</Link> <span className="subpage-grid__item-title">{album.albumName}</span>
); <span className="subpage-grid__item-count">
})} {album.assetCount} {album.assetCount === 1 ? 'photo' : 'photos'}
</span>
</div>
</Link>
);
})}
</div>
</div> </div>
); );
} }

View File

@@ -222,6 +222,8 @@ export default async function PathPage({ params }: PathPageProps) {
return ( return (
<SubpageGridView <SubpageGridView
slug={slug} slug={slug}
title={result.subpage.title || result.subpage.name}
subtitle={result.subpage.subtitle}
albums={albums} albums={albums}
coverPlaceholders={coverPlaceholders} coverPlaceholders={coverPlaceholders}
/> />

View File

@@ -18,6 +18,8 @@ subpages:
- "album-uuid-3" - "album-uuid-3"
- "album-uuid-4" - "album-uuid-4"
"Projects": "Projects":
title: "My Creative Projects" # Optional: Header title, defaults to Navigation key ("Projects")
subtitle: "A collection of 2026 highlights in 35mm film." # Optional: Sub-text for headers
password: "your-password" # Optional protection password: "your-password" # Optional protection
albums: albums:
- "album-uuid-5" - "album-uuid-5"

View File

@@ -78,6 +78,8 @@ export function getConfig(): AppConfig {
return { return {
name: sp.name, name: sp.name,
slug: slugify(sp.name), slug: slugify(sp.name),
title: sp.title,
subtitle: sp.subtitle,
albumIds: sp.albums.map((entry) => processAlbumEntry(entry, `subpage "${sp.name}"`)), albumIds: sp.albums.map((entry) => processAlbumEntry(entry, `subpage "${sp.name}"`)),
password: sp.password, password: sp.password,
...(sp.grid ? { ...(sp.grid ? {
@@ -95,12 +97,14 @@ export function getConfig(): AppConfig {
if (Array.isArray(value)) { if (Array.isArray(value)) {
return { name, slug: slugify(name), albumIds: value.map((entry) => processAlbumEntry(entry, `subpage "${name}"`)) }; return { name, slug: slugify(name), albumIds: value.map((entry) => processAlbumEntry(entry, `subpage "${name}"`)) };
} }
interface SubpageObjectValue { albums?: Array<string | Record<string, string>>; password?: string; grid?: { columns?: number; gap?: number; aspectRatio?: string; layout?: string; }; } interface SubpageObjectValue { title?: string; subtitle?: string; albums?: Array<string | Record<string, string>>; password?: string; grid?: { columns?: number; gap?: number; aspectRatio?: string; layout?: string; }; }
const sp = value as SubpageObjectValue; const sp = value as SubpageObjectValue;
const albumEntries = sp.albums || []; const albumEntries = sp.albums || [];
return { return {
name, name,
slug: slugify(name), slug: slugify(name),
title: sp.title,
subtitle: sp.subtitle,
albumIds: albumEntries.map((entry) => processAlbumEntry(entry, `subpage "${name}"`)), albumIds: albumEntries.map((entry) => processAlbumEntry(entry, `subpage "${name}"`)),
password: sp.password, password: sp.password,
...(sp.grid ? { ...(sp.grid ? {

View File

@@ -1,6 +1,8 @@
export interface SubpageConfig { export interface SubpageConfig {
name: string; name: string;
slug: string; slug: string;
title?: string;
subtitle?: string;
albumIds: string[]; albumIds: string[];
password?: string; password?: string;
grid?: Partial<GridConfig>; grid?: Partial<GridConfig>;
@@ -79,6 +81,8 @@ export interface GalleryYaml {
| Record<string, string[] | Array<string | Record<string, string>>> | Record<string, string[] | Array<string | Record<string, string>>>
| Array<{ | Array<{
name: string; name: string;
title?: string;
subtitle?: string;
albums: Array<string | Record<string, string>>; albums: Array<string | Record<string, string>>;
password?: string; password?: string;
grid?: { grid?: {