Rename routes to paths

This commit is contained in:
Sam Becker 2023-09-14 16:15:14 -05:00
parent a904558730
commit 4c725dd481
17 changed files with 82 additions and 77 deletions

View File

@ -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={

View File

@ -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,

View File

@ -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;

View File

@ -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>}
/>
);

View File

@ -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)}

View File

@ -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) {

View File

@ -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':

View File

@ -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',

View File

@ -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={() => {

View File

@ -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',

View File

@ -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',

View File

@ -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} />

View File

@ -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),
},
};
}

View File

@ -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
View 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';

View File

@ -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';

View File

@ -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} />