Refine admin tag editor

This commit is contained in:
Sam Becker 2023-10-06 20:41:42 -05:00
parent 1fd41462e7
commit 02fbf0a2e0
7 changed files with 84 additions and 20 deletions

View File

@ -6,6 +6,7 @@
"exif",
"hgetall",
"hset",
"Lightbox",
"nanoids",
"nextjs",
"qaub",

View File

@ -1,12 +1,13 @@
import AdminChildPage from '@/components/AdminChildPage';
import { redirect } from 'next/navigation';
import { getPhotosCached } from '@/cache';
import { getPhotosCached, getPhotosTagCountCached } from '@/cache';
import TagForm from '@/tag/TagForm';
import { PATH_ADMIN, PATH_ADMIN_TAGS } from '@/site/paths';
import { getPhotosTagCount } from '@/services/postgres';
import { PATH_ADMIN, PATH_ADMIN_TAGS, pathForTag } from '@/site/paths';
import PhotoTag from '@/tag/PhotoTag';
import { photoQuantityText } from '@/photo';
import PhotoGrid from '@/photo/PhotoGrid';
import { photoLabelForCount } from '@/photo';
import PhotoLightbox from '@/photo/PhotoLightbox';
const MAX_PHOTO_TO_SHOW = 6;
export const runtime = 'edge';
@ -19,8 +20,8 @@ export default async function PhotoPageEdit({ params: { tag } }: Props) {
count,
photos,
] = await Promise.all([
getPhotosTagCount(tag),
getPhotosCached({ tag }),
getPhotosTagCountCached(tag),
getPhotosCached({ tag, limit: MAX_PHOTO_TO_SHOW }),
]);
if (count === 0) { redirect(PATH_ADMIN); }
@ -32,18 +33,21 @@ export default async function PhotoPageEdit({ params: { tag } }: Props) {
breadcrumb={<div className="flex item gap-2">
<PhotoTag {...{ tag }} />
<div className="text-dim uppercase">
{photoQuantityText(count, false)}
<span>{count}</span>
<span className="hidden xs:inline-block">
&nbsp;
{photoLabelForCount(count)}
</span>
</div>
</div>}
>
<div className="space-y-8">
<PhotoGrid
photos={photos.slice(0, 12)}
animate={false}
small
<TagForm {...{ tag, photos }}>
<PhotoLightbox
{...{ count, photos }}
maxPhotosToShow={MAX_PHOTO_TO_SHOW}
moreLink={pathForTag(tag)}
/>
<TagForm {...{ tag, photos }} />
</div>
</TagForm>
</AdminChildPage>
);
};

View File

@ -20,7 +20,10 @@ function AdminChildPage({
contentMain={
<div className="space-y-6">
{backPath &&
<div className="flex gap-3 items-center h-9">
<div className={cc(
'flex flex-wrap items-center gap-x-1.5 sm:gap-x-3 gap-y-1',
'h-9',
)}>
<Link
href={backPath}
className="flex gap-1.5 items-center"

View File

@ -15,6 +15,7 @@ export default function PhotoGrid({
animateOnFirstLoadOnly,
staggerOnFirstLoadOnly = true,
showMorePath,
additionalTile,
small,
}: {
photos: Photo[]
@ -26,6 +27,7 @@ export default function PhotoGrid({
animateOnFirstLoadOnly?: boolean
staggerOnFirstLoadOnly?: boolean
showMorePath?: string
additionalTile?: JSX.Element
small?: boolean
}) {
return (
@ -34,7 +36,7 @@ export default function PhotoGrid({
className={cc(
'grid gap-1',
small
? 'grid-cols-4 xs:grid-cols-6'
? 'grid-cols-3 xs:grid-cols-6'
: 'grid-cols-2 sm:grid-cols-4 md:grid-cols-3 lg:grid-cols-4',
'items-center',
)}
@ -51,7 +53,7 @@ export default function PhotoGrid({
tag={tag}
camera={camera}
selected={photo.id === selectedPhoto?.id}
/>)}
/>).concat(additionalTile ?? [])}
/>
{showMorePath &&
<MorePhotos path={showMorePath} />}

View File

@ -0,0 +1,51 @@
import { cc } from '@/utility/css';
import { Photo } from '.';
import PhotoGrid from './PhotoGrid';
import Link from 'next/link';
export default function PhotoLightbox({
count,
photos,
maxPhotosToShow = 6,
moreLink,
}: {
count: number
photos: Photo[]
maxPhotosToShow?: number
moreLink: string
}) {
const photoCountToShow = maxPhotosToShow < count
? maxPhotosToShow - 1
: maxPhotosToShow;
const countNotShown = count - photoCountToShow;
const showOverageTile = countNotShown > 0;
return (
<div className={cc(
'border dark:border-gray-800 p-1.5 lg:p-2 rounded-md',
'bg-gray-50 dark:bg-gray-950',
)}>
<PhotoGrid
photos={photos.slice(0, photoCountToShow)}
animate={false}
additionalTile={showOverageTile
? <Link
href={moreLink}
className={cc(
'flex flex-col items-center justify-center',
'gap-0.5 lg:gap-1',
)}
>
<div className="text-[1.1rem] lg:text-[1.5rem]">
+{countNotShown}
</div>
<div className="text-dim">More</div>
</Link>
: undefined}
small
/>
</div>
);
}

View File

@ -154,7 +154,7 @@ export const translatePhotoId = (id: string) =>
export const titleForPhoto = (photo: Photo) =>
photo.title || 'Untitled';
const photoLabelForCount = (count: number) =>
export const photoLabelForCount = (count: number) =>
count === 1 ? 'Photo' : 'Photos';
export const photoQuantityText = (count: number, includeParentheses = true) =>

View File

@ -4,14 +4,16 @@ import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
import Link from 'next/link';
import { PATH_ADMIN_TAGS } from '@/site/paths';
import FieldSetWithStatus from '@/components/FieldSetWithStatus';
import { useMemo, useState } from 'react';
import { ReactNode, useMemo, useState } from 'react';
import { renamePhotoTagGloballyAction } from '@/photo/actions';
import { parameterize } from '@/utility/string';
export default function TagForm({
tag,
children,
}: {
tag: string
children?: ReactNode
}) {
const [updatedTagRaw, setUpdatedTagRaw] = useState(tag);
@ -49,6 +51,7 @@ export default function TagForm({
hidden
readOnly
/>
{children}
<div className="flex gap-3">
<Link
className="button"