diff --git a/src/app/(isr)/photos/[photoId]/image/route.tsx b/src/app/(isr)/p/[photoId]/image/route.tsx similarity index 100% rename from src/app/(isr)/photos/[photoId]/image/route.tsx rename to src/app/(isr)/p/[photoId]/image/route.tsx diff --git a/src/app/(isr)/photos/[photoId]/layout.tsx b/src/app/(isr)/p/[photoId]/layout.tsx similarity index 93% rename from src/app/(isr)/photos/[photoId]/layout.tsx rename to src/app/(isr)/p/[photoId]/layout.tsx index 2593f32e..fc34b456 100644 --- a/src/app/(isr)/photos/[photoId]/layout.tsx +++ b/src/app/(isr)/p/[photoId]/layout.tsx @@ -5,7 +5,6 @@ import SiteGrid from '@/components/SiteGrid'; import { PHOTOS_PER_REQUEST, ogImageDescriptionForPhoto, - ogImageUrlForPhoto, titleForPhoto, } from '@/photo'; import PhotoGrid from '@/photo/PhotoGrid'; @@ -19,6 +18,7 @@ import { getPhotosTakenBeforePhoto, } from '@/services/postgres'; import { redirect } from 'next/navigation'; +import { absoluteRouteForPhotoImage } from '@/site/routes'; export const runtime = 'edge'; @@ -35,7 +35,7 @@ export async function generateMetadata( const title = titleForPhoto(photo); const description = ogImageDescriptionForPhoto(photo); - const images = ogImageUrlForPhoto(photo); + const images = absoluteRouteForPhotoImage(photo); return { title, @@ -44,7 +44,7 @@ export async function generateMetadata( title, images, description, - url: `${BASE_URL}/photos/${photo.idShort}`, + url: `${BASE_URL}/p/${photo.idShort}`, }, twitter: { title, diff --git a/src/app/(isr)/photos/[photoId]/page.tsx b/src/app/(isr)/p/[photoId]/page.tsx similarity index 100% rename from src/app/(isr)/photos/[photoId]/page.tsx rename to src/app/(isr)/p/[photoId]/page.tsx diff --git a/src/app/(isr)/photos/[photoId]/share/page.tsx b/src/app/(isr)/p/[photoId]/share/page.tsx similarity index 100% rename from src/app/(isr)/photos/[photoId]/share/page.tsx rename to src/app/(isr)/p/[photoId]/share/page.tsx diff --git a/src/cache/index.ts b/src/cache/index.ts index 2e0bb7cf..058c8832 100644 --- a/src/cache/index.ts +++ b/src/cache/index.ts @@ -7,8 +7,8 @@ const TAG_PHOTOS = 'photos'; const PHOTO_PATHS = [ '/', '/grid', - '/photos/[photoId]', - '/photos/[photoId]/image', + '/p/[photoId]', + '/p/[photoId]/image', '/admin/photos', '/admin/photos/[photoId]', '/admin/photos/[photoId]/edit', diff --git a/src/middleware.ts b/src/middleware.ts index b1663f29..68633bdd 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -7,6 +7,13 @@ export default function middleware(req: NextRequest, res:NextResponse) { if (pathname === '/admin') { return NextResponse.redirect(new URL('/admin/photos', req.url)); + } else if (/^\/photos\/(.)+$/.test(pathname)) { + // Accept full /photos/* paths, but redirect to /p/* + const matches = pathname.match(/^\/photos\/(.+)$/); + return NextResponse.redirect(new URL( + `/p/${matches?.[1]}`, + req.url, + )); } return auth( diff --git a/src/photo/PhotoOGTile.tsx b/src/photo/PhotoOGTile.tsx index 78c9858e..bbe91458 100644 --- a/src/photo/PhotoOGTile.tsx +++ b/src/photo/PhotoOGTile.tsx @@ -4,7 +4,6 @@ import { useEffect, useState } from 'react'; import { Photo, ogImageDescriptionForPhoto, - ogImageUrlForPhoto, titleForPhoto, } from '@/photo'; import { cc } from '@/utility/css'; @@ -12,7 +11,7 @@ import Link from 'next/link'; import { BiError } from 'react-icons/bi'; import Spinner from '@/components/Spinner'; import { IMAGE_OG_HEIGHT, IMAGE_OG_RATIO, IMAGE_OG_WIDTH } from '@/site'; -import { routeForPhoto } from '@/site/routes'; +import { absoluteRouteForPhotoImage, routeForPhoto } from '@/site/routes'; export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed'; @@ -84,7 +83,7 @@ export default function PhotoOGTile({ loadingState === 'loading' && 'opacity-0', 'transition-opacity', )} - src={ogImageUrlForPhoto(photo)} + src={absoluteRouteForPhotoImage(photo)} width={IMAGE_OG_WIDTH} height={IMAGE_OG_HEIGHT} onLoad={() => { diff --git a/src/photo/index.ts b/src/photo/index.ts index beb384c2..f30b9444 100644 --- a/src/photo/index.ts +++ b/src/photo/index.ts @@ -1,4 +1,4 @@ -import { BASE_URL } from '@/site/config'; +import { absoluteRouteForPhotoImage } from '@/site/routes'; import { formatDateFromPostgresString } from '@/utility/date'; import { formatAperture, @@ -102,9 +102,6 @@ export const photoStatsAsString = (photo: Photo) => [ photo.isoFormatted, ].join(' '); -export const ogImageUrlForPhoto = (photo: Photo) => - `${BASE_URL}/photos/${photo.idShort}/image`; - export const ogImageDescriptionForPhoto = (photo: Photo) => photo.takenAtNaiveFormatted?.toUpperCase(); @@ -137,11 +134,11 @@ export const getPhotosLimitForQuery = ( export const generateImageMetaForPhoto = (photo?: Photo): Metadata => photo ? { openGraph: { - images: ogImageUrlForPhoto(photo), + images: absoluteRouteForPhotoImage(photo), }, twitter: { card: 'summary_large_image', - images: ogImageUrlForPhoto(photo), + images: absoluteRouteForPhotoImage(photo), }, } : {}; diff --git a/src/site/routes.ts b/src/site/routes.ts index 19a66dcb..08197e63 100644 --- a/src/site/routes.ts +++ b/src/site/routes.ts @@ -7,17 +7,20 @@ export const ROUTE_ADMIN_UPLOAD_BLOB_HANDLER = '/admin/uploads/blob'; export const routeForPhoto = (photo: Photo, share?: boolean) => share - ? `/photos/${photo.idShort}/share` - : `/photos/${photo.idShort}`; + ? `/p/${photo.idShort}/share` + : `/p/${photo.idShort}`; export const absoluteRouteForPhoto = (photo: Photo) => `${BASE_URL}${routeForPhoto(photo)}`; +export const absoluteRouteForPhotoImage = (photo: Photo) => + `${absoluteRouteForPhoto(photo)}/image`; + export const isRoutePhoto = (pathname = '') => - /^\/photos\/[^/]+\/?$/.test(pathname); + /^\/p\/[^/]+\/?$/.test(pathname); export const isRoutePhotoShare = (pathname = '') => - /^\/photos\/[^/]+\/share\/?$/.test(pathname); + /^\/p\/[^/]+\/share\/?$/.test(pathname); export const isRouteSignIn = (pathname = '') => pathname.startsWith('/sign-in');