Use unoptimized next/image with pre-sized R2 URLs (-sm/-md/-lg) when a public R2 domain is configured. Falls back to the original file if a sized variant is missing.
Co-authored-by: Cursor <cursoragent@cursor.com>
Include Dockerfile, compose file, dockerignore, and next.config output standalone for server deployment.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove avatar/hero photos and gallery stats from the public About view and admin editor, and add env-backed defaults for ABOUT_TITLE and ABOUT_SUBHEAD.
Co-authored-by: Cursor <cursoragent@cursor.com>
Set trustHost and explicitly provide AUTH_SECRET in NextAuth config
so auth routes do not fail host/config validation on non-Vercel
platforms like EdgeOne.
Co-authored-by: Cursor <cursoragent@cursor.com>
HAS_VERCEL_BLOB_STORAGE depends on BLOB_READ_WRITE_TOKEN which is a
server-only env var (not NEXT_PUBLIC_*), so it evaluates to false in
the browser. When the R2 presigned-URL PUT fails (e.g. due to missing
CORS on the R2 bucket), the fallback branch was unreachable and the
original "Failed to fetch" error propagated to the UI.
vercelBlobUploadFromClient works client-side because it obtains the
token via a server round-trip to handleUploadUrl, so try it
unconditionally as a fallback.
Co-authored-by: Cursor <cursoragent@cursor.com>
Route public paths through proxy without invoking auth so category pages no longer fail with runtime auth errors on EdgeOne.
Co-authored-by: Cursor <cursoragent@cursor.com>
Allow disabling static generation and tuning static params limits via env vars to reduce build output size on low-disk CI providers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Validate presigned upload responses and fall back to Vercel Blob when third-party storage upload fails so photo uploads remain available.
Co-authored-by: Cursor <cursoragent@cursor.com>
Switch next.config.ts from CommonJS export to default export so OpenNext wrappers can import the original config during type checking.
Co-authored-by: Cursor <cursoragent@cursor.com>
Guard the OG photo grid against empty URL results so prerendering does not crash when an optimized image fetch fails.
Co-authored-by: Cursor <cursoragent@cursor.com>
* add masonry layout for photo grids
- NEXT_PUBLIC_MASONRY_GRID env variable to turn masonry layout on and
off
- added PhotoGridMasonry.tsx to handle masonry layout
* fixed albums showing all photos when masonry grid is enabled
* only render infinite photo scroll for masonry grid when total photo count is greater than loaded photos
* fixed masonry grid lcp warnings
* add NEXT_PUBLIC_MASONRY_GRID description to README
* Use custom icon for masonry layout
* Add masonry to in-app config
* Simplify masonry architecture
---------
Co-authored-by: Sam Becker <sam@sambecker.com>
Handle null exif.tags in getOffsetFromExif
`Object.values()` throws "Cannot convert undefined or null to object"
when `exif.tags` or `exifr` is null/undefined. This occurs when
uploading images that lack EXIF data (e.g., AI-generated images,
screenshots, or graphics). The issue is reproducible on Chrome but
not on Safari, likely due to differences in how each browser's
EXIF parsing pipeline populates these values.
This fix adds nullish coalescing fallbacks (`?? {}`) so that
`Object.values()` always receives a valid object.
* Fix optional chaining in getOffsetFromExif
If `exif` itself is null/undefined,
accessing `exif.tags` would throw before the `??` fallback kicks in.