/** * Homepage — renders different hero layouts based on theme config. * * Styles: split, fullbleed, minimal, stacked, typographic, mosaic. */ import Link from 'next/link'; import Image from 'next/image'; import { immich } from '@/lib/immich'; import { getConfig } from '@/lib/config'; import { imageUrl, assetPlaceholder } from '@/lib/urls'; import { HeroCarousel } from '@/components/HeroCarousel'; import { FadeIn } from '@/components/FadeIn'; // Render at request time — requires live Immich connection export const dynamic = 'force-dynamic'; /** Shared nav links for hero sections. */ function HeroNavLinks({ subpages, albums, }: { subpages: { slug: string; name: string }[]; albums: { id: string; slug: string; albumName: string }[]; }) { return ( <> {subpages.map((sp) => ( {sp.name} ))} {albums.map((album) => ( {album.albumName} ))} ); } export default async function HomePage() { const config = getConfig(); const [subpages, albums] = await Promise.all([ immich.getSubpages(), immich.getStandaloneAlbums(), ]); // Fetch ThumbHash for all hero images const heroData = await Promise.all( config.heroImages.map(async (id) => { const asset = await immich.getAssetInfo(id); const ph = asset ? assetPlaceholder(asset) : null; return { src: imageUrl(id, 'preview'), ...(ph ? { blurDataURL: ph.blurDataURL } : {}), }; }), ); const heroStyle = config.theme.heroStyle; // ── Typographic: no image, pure text ─────────────────────────── if (heroStyle === 'typographic') { return (

{config.siteTitle}

{config.siteSubtitle && (

{config.siteSubtitle}

)}
); } // ── Stacked: fullbleed image + text at bottom + thumbnail strip ─ if (heroStyle === 'stacked') { // Fetch album thumbnails for the strip const allEntries = [ ...subpages.map((sp) => ({ slug: sp.slug, name: sp.name })), ...albums.map((a) => ({ slug: a.slug, name: a.albumName })), ]; return (

{config.siteTitle}

{config.siteSubtitle && (

{config.siteSubtitle}

)}
); } // ── Mosaic: multi-image grid with frosted title overlay ──────── if (heroStyle === 'mosaic') { return (
{heroData.slice(0, 6).map((img, i) => (
))}

{config.siteTitle}

{config.siteSubtitle && (

{config.siteSubtitle}

)}
); } // ── Minimal: pure text, no image, simple centered ────────────── if (heroStyle === 'minimal') { return (

{config.siteTitle}

{config.siteSubtitle && (

{config.siteSubtitle}

)}
); } // ── Fullbleed: full-viewport image + centered overlay ─────────── if (heroStyle === 'fullbleed') { return (

{config.siteTitle}

{config.siteSubtitle && (

{config.siteSubtitle}

)}
); } // ── Split: left text panel, right image (default) ─────────────── return (
{/* ── Left Panel ──────────────────────────────── */}

{config.siteTitle}

{config.siteSubtitle && (

{config.siteSubtitle}

)}
{/* ── Right Panel (Hero Carousel) ─────────────── */}
); }