fix: resolve hydration mismatch (error #418), CSP map blockages, and lightbox visibility

This commit is contained in:
ralksta
2026-03-07 10:18:20 +01:00
parent 4370603a6e
commit 09f358559e
4 changed files with 28 additions and 34 deletions

View File

@@ -31,7 +31,6 @@ export interface PhotoItem {
interface PhotoGridProps { interface PhotoGridProps {
assets: PhotoItem[]; assets: PhotoItem[];
albumId: string;
layout?: 'masonry' | 'uniform' | 'showcase' | 'filmstrip' | 'editorial-flow'; layout?: 'masonry' | 'uniform' | 'showcase' | 'filmstrip' | 'editorial-flow';
gridStyle?: React.CSSProperties; gridStyle?: React.CSSProperties;
} }
@@ -50,11 +49,15 @@ function buildPhotoHash(index: number): string {
} }
export function PhotoGrid({ assets, layout = 'masonry', gridStyle }: PhotoGridProps) { export function PhotoGrid({ assets, layout = 'masonry', gridStyle }: PhotoGridProps) {
const [lightboxIndex, setLightboxIndex] = useState<number | null>(() => { const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
if (typeof window === 'undefined') return null;
// ── Initial hash check (Client-only to avoid hydration mismatch) ──
useEffect(() => {
const idx = parsePhotoHash(window.location.hash); const idx = parsePhotoHash(window.location.hash);
return idx !== null && idx < assets.length ? idx : null; if (idx !== null && idx < assets.length) {
}); setLightboxIndex(idx);
}
}, [assets.length]);
// ── Sync URL hash when lightbox state changes ───────────────── // ── Sync URL hash when lightbox state changes ─────────────────
useEffect(() => { useEffect(() => {
@@ -136,9 +139,8 @@ export function PhotoGrid({ assets, layout = 'masonry', gridStyle }: PhotoGridPr
{assets.map((asset, index) => ( {assets.map((asset, index) => (
<FadeIn key={asset.id} delay={index < 12 ? index * 50 : 0}> <FadeIn key={asset.id} delay={index < 12 ? index * 50 : 0}>
<div <div
className={`photo-grid__item${ className={`photo-grid__item${layout === 'showcase' && index === 0 ? ' photo-grid__featured' : ''
layout === 'showcase' && index === 0 ? ' photo-grid__featured' : '' }`}
}`}
onClick={() => openLightbox(index)} onClick={() => openLightbox(index)}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') { if (e.key === 'Enter' || e.key === ' ') {

View File

@@ -164,7 +164,6 @@ export default async function PathPage({ params }: PathPageProps) {
</div> </div>
<PhotoGrid <PhotoGrid
assets={images} assets={images}
albumId={album.id}
layout={resolveLayout(spGrid)} layout={resolveLayout(spGrid)}
gridStyle={buildGridStyle(spGrid)} gridStyle={buildGridStyle(spGrid)}
/> />
@@ -214,7 +213,6 @@ export default async function PathPage({ params }: PathPageProps) {
</div> </div>
<PhotoGrid <PhotoGrid
assets={images} assets={images}
albumId={album.id}
layout={resolveLayout(result.subpage.grid)} layout={resolveLayout(result.subpage.grid)}
gridStyle={buildGridStyle(result.subpage.grid)} gridStyle={buildGridStyle(result.subpage.grid)}
/> />
@@ -292,7 +290,6 @@ export default async function PathPage({ params }: PathPageProps) {
</div> </div>
<PhotoGrid <PhotoGrid
assets={images} assets={images}
albumId={album.id}
layout={resolveLayout()} layout={resolveLayout()}
gridStyle={buildGridStyle()} gridStyle={buildGridStyle()}
/> />

View File

@@ -1,35 +1,30 @@
# ── Gallery Configuration ────────────────────────────────────── # ── Gallery Structure ──────────────────────────────────────────────
# Album and subpage definitions for your public gallery. # This file defines WHICH albums and subpages are shown.
# Secrets (API key, server URL) stay in .env.local. # Global settings (theme, map, legal, title) now live in content/settings.yaml.
# Hero images for the homepage carousel (Immich asset UUIDs)
hero: hero:
- 03c0df0e-01d7-4cc7-8352-cf30d2289ad6 - 03c0df0e-01d7-4cc7-8352-cf30d2289ad6
- a492300b-14ca-4167-a2c9-815c820a8802 - a492300b-14ca-4167-a2c9-815c820a8802
- 7fdc0891-8e9d-48f1-9f1b-a8697c6dbea1 - 7fdc0891-8e9d-48f1-9f1b-a8697c6dbea1
- c023e78a-1718-4c1a-aaa1-c22368d0be6c
- 1d518119-d333-40db-a81f-e7ca80c1a66e
# Standalone albums shown directly on the homepage # Standalone albums (shown on the home page)
albums: #albums:
- a89c6085-a105-46c2-baa4-338bc69cab93: "Wüstenzauber" # - "your-album-uuid-1"
- 9aee9367-a239-4651-980d-3368bc70b7b6: "Heimatliebe" # - "your-album-uuid-2"
# Subpages group multiple albums under one URL path # Subpages: group albums under custom URL paths
subpages: subpages:
Deutschland: Deutschland:
- 9aee9367-a239-4651-980d-3368bc70b7b6 - 9aee9367-a239-4651-980d-3368bc70b7b6: "Kloster Chorin"
- 371336b4-eb59-409c-b24e-a613f81ede5a: "2025 Oktober - Sanssouci im Herbst"
- b55b4a94-b1b6-4eb8-8ce0-32238a78150f: "An der Ostsee"
Dubai: Dubai:
- a89c6085-a105-46c2-baa4-338bc69cab93: "Burj Khalifa & Co" - a89c6085-a105-46c2-baa4-338bc69cab93: "Dubai 2024"
# Support for subpages with passwords or custom grids in the map format # Support for subpages with passwords or custom grids in the map format
Polen: Polen:
password: clientpass123 password: clientpass123
albums: albums:
- 4ad0ed89-55de-4e69-937f-2d9988f63ad1: "Krakau & mehr" - 4ad0ed89-55de-4e69-937f-2d9988f63ad1: "Krakau & mehr"
# Footer — optional minimal footer with social links
footer:
name: Ralf Ohlenbostel
instagram: quasiralf
# email: hello@example.com
# website: https://example.com
# Enable the /map page
map: true

View File

@@ -4,11 +4,11 @@ import type { NextConfig } from 'next';
// Locks down the public-facing site to only trusted sources. // Locks down the public-facing site to only trusted sources.
const cspDirectives = [ const cspDirectives = [
"default-src 'self'", "default-src 'self'",
"script-src 'self' 'unsafe-inline'", "script-src 'self' 'unsafe-inline' 'unsafe-eval'", // Added unsafe-eval for some client-side libs if needed
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://unpkg.com", "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://unpkg.com",
"font-src 'self' https://fonts.gstatic.com", "font-src 'self' https://fonts.gstatic.com",
"img-src 'self' data: https://*.basemaps.cartocdn.com https://a.basemaps.cartocdn.com https://b.basemaps.cartocdn.com https://c.basemaps.cartocdn.com https://d.basemaps.cartocdn.com https://unpkg.com", "img-src 'self' data: blob: https://*.basemaps.cartocdn.com https://*.tile.openstreetmap.org https://unpkg.com", // Added blob: and osm
"connect-src 'self'", "connect-src 'self' https://fonts.googleapis.com https://fonts.gstatic.com", // Added fonts for connectivity checks
"frame-ancestors 'none'", "frame-ancestors 'none'",
"base-uri 'self'", "base-uri 'self'",
"form-action 'self'", "form-action 'self'",