Rename routes to paths
This commit is contained in:
parent
a904558730
commit
4c725dd481
@ -18,7 +18,7 @@ import {
|
||||
getBlobUploadUrls,
|
||||
} from '@/services/blob';
|
||||
import { getPhotos, getPhotosCount } from '@/services/postgres';
|
||||
import { routeForPhoto } from '@/site/routes';
|
||||
import { pathForPhoto, pathForPhotoEdit } from '@/site/paths';
|
||||
import { getPhotosLimitForQuery, titleForPhoto } from '@/photo';
|
||||
import MorePhotos from '@/components/MorePhotos';
|
||||
|
||||
@ -74,7 +74,7 @@ export default async function AdminPage({
|
||||
<div className="flex flex-col md:flex-row">
|
||||
<Link
|
||||
key={photo.id}
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
className="sm:w-[50%] flex items-center gap-2"
|
||||
>
|
||||
{photo.title ||
|
||||
@ -97,7 +97,7 @@ export default async function AdminPage({
|
||||
{photo.takenAtNaive}
|
||||
</div>
|
||||
</div>
|
||||
<EditButton href={`/admin/photos/${photo.idShort}/edit`} />
|
||||
<EditButton href={pathForPhotoEdit(photo)} />
|
||||
<FormWithConfirm
|
||||
action={deletePhotoAction}
|
||||
confirmText={
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
getPhotosTakenBeforePhoto,
|
||||
} from '@/services/postgres';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { absoluteRouteForPhotoImage } from '@/site/routes';
|
||||
import { absolutePathForPhotoImage } from '@/site/paths';
|
||||
|
||||
const THUMBNAILS_TO_SHOW_MAX = 12;
|
||||
|
||||
@ -33,7 +33,7 @@ export async function generateMetadata({
|
||||
|
||||
const title = titleForPhoto(photo);
|
||||
const description = ogImageDescriptionForPhoto(photo);
|
||||
const images = absoluteRouteForPhotoImage(photo);
|
||||
const images = absolutePathForPhotoImage(photo);
|
||||
|
||||
return {
|
||||
title,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isRouteProtected } from '@/site/routes';
|
||||
import { isPathProtected } from '@/site/paths';
|
||||
import NextAuth, { User, type DefaultSession } from 'next-auth';
|
||||
import Credentials from 'next-auth/providers/credentials';
|
||||
|
||||
@ -38,7 +38,7 @@ export const {
|
||||
authorized({ auth, request }) {
|
||||
const { pathname } = request.nextUrl;
|
||||
|
||||
const isUrlProtected = isRouteProtected(pathname);
|
||||
const isUrlProtected = isPathProtected(pathname);
|
||||
const isUserLoggedIn = !!auth?.user;
|
||||
const isRequestAuthorized = !isUrlProtected || isUserLoggedIn;
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import { useSession, signOut } from 'next-auth/react';
|
||||
import ThemeSwitcher from '@/site/ThemeSwitcher';
|
||||
import SiteGrid from './SiteGrid';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { isRouteSignIn } from '@/site/routes';
|
||||
import { isPathSignIn } from '@/site/paths';
|
||||
|
||||
const LINK_STYLE = cc(
|
||||
'cursor-pointer',
|
||||
@ -48,7 +48,7 @@ export default function FooterAuth() {
|
||||
Sign In
|
||||
</Link>}
|
||||
</div>
|
||||
{!isRouteSignIn(path) && <ThemeSwitcher />}
|
||||
{!isPathSignIn(path) && <ThemeSwitcher />}
|
||||
</div>}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -3,7 +3,7 @@ import SiteGrid from '@/components/SiteGrid';
|
||||
import ImageLarge from '@/components/ImageLarge';
|
||||
import { cc } from '@/utility/css';
|
||||
import Link from 'next/link';
|
||||
import { routeForPhoto } from '@/site/routes';
|
||||
import { pathForPhoto } from '@/site/paths';
|
||||
import SharePhotoButton from './SharePhotoButton';
|
||||
import PhotoTags from '@/tag/PhotoTags';
|
||||
|
||||
@ -32,7 +32,7 @@ export default function PhotoLarge({
|
||||
<ImageLarge
|
||||
className="w-full"
|
||||
alt={titleForPhoto(photo)}
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
src={photo.url}
|
||||
aspectRatio={photo.aspectRatio}
|
||||
blurData={photo.blurData}
|
||||
@ -48,7 +48,7 @@ export default function PhotoLarge({
|
||||
)}>
|
||||
{renderMiniGrid(<>
|
||||
<Link
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
className="font-bold uppercase"
|
||||
>
|
||||
{titleForPhoto(photo)}
|
||||
|
||||
@ -5,7 +5,7 @@ import { Photo } from '@/photo';
|
||||
import Link from 'next/link';
|
||||
import { AnimationConfig } from '../components/AnimateItems';
|
||||
import { useAppState } from '@/state';
|
||||
import { routeForPhoto } from '@/site/routes';
|
||||
import { pathForPhoto } from '@/site/paths';
|
||||
|
||||
export default function PhotoLink({
|
||||
photo,
|
||||
@ -23,7 +23,7 @@ export default function PhotoLink({
|
||||
return (
|
||||
photo
|
||||
? <Link
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
prefetch={prefetch}
|
||||
onClick={() => {
|
||||
if (nextPhotoAnimation) {
|
||||
|
||||
@ -4,7 +4,7 @@ import { useEffect } from 'react';
|
||||
import { Photo, getNextPhoto, getPreviousPhoto } from '@/photo';
|
||||
import PhotoLink from './PhotoLink';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { isRoutePhotoShare, routeForPhoto } from '@/site/routes';
|
||||
import { isPathPhotoShare, pathForPhoto } from '@/site/paths';
|
||||
import { useAppState } from '@/state';
|
||||
import { AnimationConfig } from '@/components/AnimateItems';
|
||||
|
||||
@ -23,7 +23,7 @@ export default function PhotoLinks({
|
||||
|
||||
const { setNextPhotoAnimation } = useAppState();
|
||||
|
||||
const isRouteShare = isRoutePhotoShare(pathname);
|
||||
const isRouteShare = isPathPhotoShare(pathname);
|
||||
const previousPhoto = getPreviousPhoto(photo, photos);
|
||||
const nextPhoto = getNextPhoto(photo, photos);
|
||||
|
||||
@ -34,14 +34,14 @@ export default function PhotoLinks({
|
||||
case 'J':
|
||||
if (previousPhoto) {
|
||||
setNextPhotoAnimation?.(ANIMATION_RIGHT);
|
||||
router.push(routeForPhoto(previousPhoto, isRouteShare));
|
||||
router.push(pathForPhoto(previousPhoto, isRouteShare));
|
||||
}
|
||||
break;
|
||||
case 'ARROWRIGHT':
|
||||
case 'L':
|
||||
if (nextPhoto) {
|
||||
setNextPhotoAnimation?.(ANIMATION_LEFT);
|
||||
router.push(routeForPhoto(nextPhoto, isRouteShare));
|
||||
router.push(pathForPhoto(nextPhoto, isRouteShare));
|
||||
}
|
||||
break;
|
||||
case 'ESCAPE':
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
import Modal from '@/components/Modal';
|
||||
import PhotoOGTile from '@/photo/PhotoOGTile';
|
||||
import { absoluteRouteForPhoto, routeForPhoto } from '@/site/routes';
|
||||
import { absolutePathForPhoto, pathForPhoto } from '@/site/paths';
|
||||
import { TbPhotoShare } from 'react-icons/tb';
|
||||
import { cc } from '@/utility/css';
|
||||
import { BiCopy } from 'react-icons/bi';
|
||||
@ -11,10 +11,10 @@ import { toast } from 'sonner';
|
||||
import { FiCheckSquare } from 'react-icons/fi';
|
||||
|
||||
export default function PhotoModal({ photo }: { photo: Photo }) {
|
||||
const shareUrl = absoluteRouteForPhoto(photo);
|
||||
const shareUrl = absolutePathForPhoto(photo);
|
||||
|
||||
return (
|
||||
<Modal onClosePath={routeForPhoto(photo)}>
|
||||
<Modal onClosePath={pathForPhoto(photo)}>
|
||||
<div className="space-y-3 md:space-y-4 w-full">
|
||||
<div className={cc(
|
||||
'flex items-center gap-x-3',
|
||||
|
||||
@ -10,7 +10,7 @@ import { cc } from '@/utility/css';
|
||||
import Link from 'next/link';
|
||||
import { BiError } from 'react-icons/bi';
|
||||
import { IMAGE_OG_HEIGHT, IMAGE_OG_RATIO, IMAGE_OG_WIDTH } from '@/site';
|
||||
import { absoluteRouteForPhotoImage, routeForPhoto } from '@/site/routes';
|
||||
import { absolutePathForPhotoImage, pathForPhoto } from '@/site/paths';
|
||||
import Spinner from '@/components/Spinner';
|
||||
|
||||
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
|
||||
@ -47,7 +47,7 @@ export default function PhotoOGTile({
|
||||
return (
|
||||
<Link
|
||||
key={photo.id}
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
className={cc(
|
||||
'group',
|
||||
'block w-full rounded-md overflow-hidden',
|
||||
@ -84,7 +84,7 @@ export default function PhotoOGTile({
|
||||
loadingState === 'loading' && 'opacity-0',
|
||||
'transition-opacity',
|
||||
)}
|
||||
src={absoluteRouteForPhotoImage(photo)}
|
||||
src={absolutePathForPhotoImage(photo)}
|
||||
width={IMAGE_OG_WIDTH}
|
||||
height={IMAGE_OG_HEIGHT}
|
||||
onLoad={() => {
|
||||
|
||||
@ -2,7 +2,7 @@ import { Photo, titleForPhoto } from '.';
|
||||
import ImageSmall from '@/components/ImageSmall';
|
||||
import Link from 'next/link';
|
||||
import { cc } from '@/utility/css';
|
||||
import { routeForPhoto } from '@/site/routes';
|
||||
import { pathForPhoto } from '@/site/paths';
|
||||
|
||||
export default function PhotoSmall({
|
||||
photo,
|
||||
@ -13,7 +13,7 @@ export default function PhotoSmall({
|
||||
}) {
|
||||
return (
|
||||
<Link
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
className={cc(
|
||||
'active:brightness-75',
|
||||
selected && 'brightness-50',
|
||||
|
||||
@ -2,7 +2,7 @@ import { Photo, titleForPhoto } from '.';
|
||||
import ImageTiny from '@/components/ImageTiny';
|
||||
import Link from 'next/link';
|
||||
import { cc } from '@/utility/css';
|
||||
import { routeForPhoto } from '@/site/routes';
|
||||
import { pathForPhoto } from '@/site/paths';
|
||||
|
||||
export default function PhotoTiny({
|
||||
className,
|
||||
@ -15,7 +15,7 @@ export default function PhotoTiny({
|
||||
}) {
|
||||
return (
|
||||
<Link
|
||||
href={routeForPhoto(photo)}
|
||||
href={pathForPhoto(photo)}
|
||||
className={cc(
|
||||
className,
|
||||
'active:brightness-75',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Photo } from '.';
|
||||
import { routeForPhoto } from '@/site/routes';
|
||||
import { pathForPhoto } from '@/site/paths';
|
||||
import { TbPhotoShare } from 'react-icons/tb';
|
||||
import IconPathButton from '@/components/IconPathButton';
|
||||
|
||||
@ -12,7 +12,7 @@ export default function SharePhotoButton({
|
||||
}) {
|
||||
return (
|
||||
<IconPathButton
|
||||
path={routeForPhoto(photo, true)}
|
||||
path={pathForPhoto(photo, true)}
|
||||
prefetch={prefetch}
|
||||
>
|
||||
<TbPhotoShare size={17} />
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {
|
||||
ABSOLUTE_ROUTE_FOR_HOME_IMAGE,
|
||||
absoluteRouteForPhotoImage,
|
||||
} from '@/site/routes';
|
||||
ABSOLUTE_PATH_FOR_HOME_IMAGE,
|
||||
absolutePathForPhotoImage,
|
||||
} from '@/site/paths';
|
||||
import { formatDateFromPostgresString } from '@/utility/date';
|
||||
import {
|
||||
formatAperture,
|
||||
@ -140,11 +140,11 @@ export const generateOgImageMetaForPhotos = (photos: Photo[]): Metadata => {
|
||||
// Show multiple photos once a 3x2 grid is available
|
||||
return {
|
||||
openGraph: {
|
||||
images: ABSOLUTE_ROUTE_FOR_HOME_IMAGE,
|
||||
images: ABSOLUTE_PATH_FOR_HOME_IMAGE,
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
images: ABSOLUTE_ROUTE_FOR_HOME_IMAGE,
|
||||
images: ABSOLUTE_PATH_FOR_HOME_IMAGE,
|
||||
},
|
||||
};
|
||||
} else if (photos.length > 0) {
|
||||
@ -152,11 +152,11 @@ export const generateOgImageMetaForPhotos = (photos: Photo[]): Metadata => {
|
||||
const photo = photos[0];
|
||||
return {
|
||||
openGraph: {
|
||||
images: absoluteRouteForPhotoImage(photo),
|
||||
images: absolutePathForPhotoImage(photo),
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
images: absoluteRouteForPhotoImage(photo),
|
||||
images: absolutePathForPhotoImage(photo),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { BLOB_BASE_URL } from '@/site';
|
||||
import { ROUTE_ADMIN_UPLOAD_BLOB_HANDLER } from '@/site/routes';
|
||||
import { PATH_ADMIN_UPLOAD_BLOB_HANDLER } from '@/site/paths';
|
||||
import { del, list, put } from '@vercel/blob';
|
||||
import { upload } from '@vercel/blob/client';
|
||||
|
||||
@ -43,7 +43,7 @@ export const uploadPhotoFromClient = async (
|
||||
file,
|
||||
{
|
||||
access: 'public',
|
||||
handleUploadUrl: ROUTE_ADMIN_UPLOAD_BLOB_HANDLER,
|
||||
handleUploadUrl: PATH_ADMIN_UPLOAD_BLOB_HANDLER,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
41
src/site/paths.ts
Normal file
41
src/site/paths.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Photo } from '@/photo';
|
||||
import { BASE_URL } from './config';
|
||||
|
||||
const PREFIX_PHOTO = '/p';
|
||||
const PREFIX_TAG = '/t';
|
||||
const PREFIX_ADMIN = '/admin';
|
||||
|
||||
export const PATH_ADMIN_PHOTOS = `${PREFIX_ADMIN}/photos`;
|
||||
export const PATH_ADMIN_UPLOAD = `${PREFIX_ADMIN}/uploads`;
|
||||
export const PATH_ADMIN_UPLOAD_BLOB_HANDLER = `${PATH_ADMIN_UPLOAD}/blob`;
|
||||
|
||||
export const ABSOLUTE_PATH_FOR_HOME_IMAGE = `${BASE_URL}/home-image`;
|
||||
|
||||
export const pathForPhoto = (photo: Photo, share?: boolean) =>
|
||||
share
|
||||
? `${PREFIX_PHOTO}/${photo.idShort}/share`
|
||||
: `${PREFIX_PHOTO}/${photo.idShort}`;
|
||||
|
||||
export const pathForPhotoEdit = (photo: Photo) =>
|
||||
`${PATH_ADMIN_PHOTOS}/${photo.idShort}/edit`;
|
||||
|
||||
export const pathForTag = (tag: string) => `${PREFIX_TAG}/${tag}`;
|
||||
|
||||
export const absolutePathForPhoto = (photo: Photo) =>
|
||||
`${BASE_URL}${pathForPhoto(photo)}`;
|
||||
|
||||
export const absolutePathForPhotoImage = (photo: Photo) =>
|
||||
`${absolutePathForPhoto(photo)}/image`;
|
||||
|
||||
export const isPathPhoto = (pathname = '') =>
|
||||
/^\/p\/[^/]+\/?$/.test(pathname);
|
||||
|
||||
export const isPathPhotoShare = (pathname = '') =>
|
||||
/^\/p\/[^/]+\/share\/?$/.test(pathname);
|
||||
|
||||
export const isPathSignIn = (pathname = '') =>
|
||||
pathname.startsWith('/sign-in');
|
||||
|
||||
export const isPathProtected = (pathname = '') =>
|
||||
pathname.startsWith(PREFIX_ADMIN) ||
|
||||
pathname === '/checklist';
|
||||
@ -1,36 +0,0 @@
|
||||
import { Photo } from '@/photo';
|
||||
import { BASE_URL } from './config';
|
||||
|
||||
const PHOTO_PREFIX = '/p';
|
||||
const TAG_PREFIX = '/t';
|
||||
|
||||
export const ROUTE_ADMIN_UPLOAD = '/admin/uploads';
|
||||
export const ROUTE_ADMIN_UPLOAD_BLOB_HANDLER = '/admin/uploads/blob';
|
||||
|
||||
export const ABSOLUTE_ROUTE_FOR_HOME_IMAGE = `${BASE_URL}/home-image`;
|
||||
|
||||
export const routeForPhoto = (photo: Photo, share?: boolean) =>
|
||||
share
|
||||
? `${PHOTO_PREFIX}/${photo.idShort}/share`
|
||||
: `${PHOTO_PREFIX}/${photo.idShort}`;
|
||||
|
||||
export const routeForTag = (tag: string) => `${TAG_PREFIX}/${tag}`;
|
||||
|
||||
export const absoluteRouteForPhoto = (photo: Photo) =>
|
||||
`${BASE_URL}${routeForPhoto(photo)}`;
|
||||
|
||||
export const absoluteRouteForPhotoImage = (photo: Photo) =>
|
||||
`${absoluteRouteForPhoto(photo)}/image`;
|
||||
|
||||
export const isRoutePhoto = (pathname = '') =>
|
||||
/^\/p\/[^/]+\/?$/.test(pathname);
|
||||
|
||||
export const isRoutePhotoShare = (pathname = '') =>
|
||||
/^\/p\/[^/]+\/share\/?$/.test(pathname);
|
||||
|
||||
export const isRouteSignIn = (pathname = '') =>
|
||||
pathname.startsWith('/sign-in');
|
||||
|
||||
export const isRouteProtected = (pathname = '') =>
|
||||
pathname.startsWith('/admin') ||
|
||||
pathname === '/checklist';
|
||||
@ -1,5 +1,5 @@
|
||||
import Link from 'next/link';
|
||||
import { routeForTag } from '@/site/routes';
|
||||
import { pathForTag } from '@/site/paths';
|
||||
import { FaTag } from 'react-icons/fa';
|
||||
|
||||
export default function PhotoTag({
|
||||
@ -10,7 +10,7 @@ export default function PhotoTag({
|
||||
return (
|
||||
<Link
|
||||
key={tag}
|
||||
href={routeForTag(tag)}
|
||||
href={pathForTag(tag)}
|
||||
className="flex items-center gap-x-1.5"
|
||||
>
|
||||
<FaTag size={11} />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user