Merge branch 'main' into static
This commit is contained in:
commit
ed840adb91
28
package.json
28
package.json
@ -9,20 +9,20 @@
|
||||
"analyze": "ANALYZE=true next build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.525.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.525.0",
|
||||
"@next/bundle-analyzer": "14.1.0",
|
||||
"@aws-sdk/client-s3": "3.529.1",
|
||||
"@aws-sdk/s3-request-presigner": "3.529.1",
|
||||
"@next/bundle-analyzer": "14.1.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@testing-library/jest-dom": "^6.4.2",
|
||||
"@testing-library/react": "^14.2.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/react": "18.2.61",
|
||||
"@types/react-dom": "18.2.19",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"@types/node": "^20.11.26",
|
||||
"@types/react": "18.2.65",
|
||||
"@types/react-dom": "18.2.21",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"@vercel/blob": "^0.22.1",
|
||||
"@vercel/postgres": "0.7.2",
|
||||
@ -30,16 +30,16 @@
|
||||
"autoprefixer": "10.4.18",
|
||||
"camelcase-keys": "^9.1.3",
|
||||
"clsx": "^2.1.0",
|
||||
"cmdk": "^0.2.1",
|
||||
"date-fns": "^3.3.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"date-fns": "^3.4.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-next": "14.1.1",
|
||||
"eslint-config-next": "14.1.3",
|
||||
"exifr": "^7.1.3",
|
||||
"framer-motion": "^11.0.8",
|
||||
"framer-motion": "^11.0.12",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"nanoid": "^5.0.6",
|
||||
"next": "14.2.0-canary.16",
|
||||
"next": "14.2.0-canary.18",
|
||||
"next-auth": "5.0.0-beta.13",
|
||||
"next-themes": "^0.2.1",
|
||||
"postcss": "8.4.35",
|
||||
@ -49,7 +49,7 @@
|
||||
"sonner": "^1.4.3",
|
||||
"tailwindcss": "3.4.1",
|
||||
"ts-exif-parser": "^0.2.2",
|
||||
"typescript": "5.3.3",
|
||||
"typescript": "5.4.2",
|
||||
"use-debounce": "^10.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
966
pnpm-lock.yaml
generated
966
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,8 @@
|
||||
import PhotoForm from '@/photo/form/PhotoForm';
|
||||
import AdminChildPage from '@/components/AdminChildPage';
|
||||
import { PATH_ADMIN, PATH_ADMIN_UPLOADS } from '@/site/paths';
|
||||
import { PATH_ADMIN } from '@/site/paths';
|
||||
import { extractExifDataFromBlobPath } from '@/photo/server';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { getUniqueTagsCached } from '@/photo/cache';
|
||||
import UploadPageClient from '@/photo/UploadPageClient';
|
||||
|
||||
interface Params {
|
||||
params: { uploadPath: string }
|
||||
@ -20,15 +19,6 @@ export default async function UploadPage({ params: { uploadPath } }: Params) {
|
||||
if (!photoFormExif) { redirect(PATH_ADMIN); }
|
||||
|
||||
return (
|
||||
<AdminChildPage
|
||||
backPath={PATH_ADMIN_UPLOADS}
|
||||
backLabel="Uploads"
|
||||
breadcrumb={blobId}
|
||||
>
|
||||
<PhotoForm
|
||||
initialPhotoForm={photoFormExif}
|
||||
uniqueTags={uniqueTags}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
<UploadPageClient {...{ blobId, photoFormExif, uniqueTags }} />
|
||||
);
|
||||
};
|
||||
|
||||
@ -4,18 +4,21 @@ import { FiArrowLeft } from 'react-icons/fi';
|
||||
import SiteGrid from './SiteGrid';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import Badge from './Badge';
|
||||
import Spinner from './Spinner';
|
||||
|
||||
function AdminChildPage({
|
||||
backPath,
|
||||
backLabel,
|
||||
breadcrumb,
|
||||
accessory,
|
||||
isLoading,
|
||||
children,
|
||||
}: {
|
||||
backPath?: string
|
||||
backLabel?: string
|
||||
breadcrumb?: ReactNode
|
||||
accessory?: ReactNode
|
||||
isLoading?: boolean
|
||||
children: ReactNode,
|
||||
}) {
|
||||
return (
|
||||
@ -42,10 +45,14 @@ function AdminChildPage({
|
||||
{breadcrumb &&
|
||||
<>
|
||||
<span>/</span>
|
||||
<Badge>
|
||||
{breadcrumb}
|
||||
</Badge>
|
||||
<span className={clsx(isLoading && 'opacity-50')}>
|
||||
<Badge>
|
||||
{breadcrumb}
|
||||
</Badge>
|
||||
</span>
|
||||
</>}
|
||||
{isLoading &&
|
||||
<Spinner />}
|
||||
</div>
|
||||
{accessory &&
|
||||
<div>{accessory}</div>}
|
||||
|
||||
@ -10,6 +10,7 @@ interface Props extends HTMLProps<HTMLButtonElement> {
|
||||
icon?: JSX.Element
|
||||
styleAsLink?: boolean
|
||||
spinnerColor?: SpinnerColor
|
||||
onFormStatusChange?: (pending: boolean) => void
|
||||
onFormSubmitToastMessage?: string
|
||||
}
|
||||
|
||||
@ -17,6 +18,7 @@ export default function SubmitButtonWithStatus({
|
||||
icon,
|
||||
styleAsLink,
|
||||
spinnerColor,
|
||||
onFormStatusChange,
|
||||
onFormSubmitToastMessage,
|
||||
children,
|
||||
disabled,
|
||||
@ -24,8 +26,8 @@ export default function SubmitButtonWithStatus({
|
||||
type: _type,
|
||||
...buttonProps
|
||||
}: Props) {
|
||||
|
||||
const { pending } = useFormStatus();
|
||||
|
||||
const pendingPrevious = useRef(pending);
|
||||
|
||||
useEffect(() => {
|
||||
@ -39,6 +41,10 @@ export default function SubmitButtonWithStatus({
|
||||
pendingPrevious.current = pending;
|
||||
}, [pending, onFormSubmitToastMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
onFormStatusChange?.(pending);
|
||||
}, [onFormStatusChange, pending]);
|
||||
|
||||
return (
|
||||
<button
|
||||
type="submit"
|
||||
|
||||
@ -11,6 +11,7 @@ import { areSimpleObjectsEqual } from '@/utility/object';
|
||||
import IconGrSync from '@/site/IconGrSync';
|
||||
import { getExifDataAction } from './actions';
|
||||
import { TagsWithMeta } from '@/tag';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function PhotoEditPageClient({
|
||||
photo,
|
||||
@ -26,6 +27,8 @@ export default function PhotoEditPageClient({
|
||||
seedExifData,
|
||||
);
|
||||
|
||||
const [pending, setIsPending] = useState(false);
|
||||
|
||||
const hasExifDataBeenFound = !areSimpleObjectsEqual(
|
||||
updatedExifData,
|
||||
seedExifData,
|
||||
@ -47,6 +50,7 @@ export default function PhotoEditPageClient({
|
||||
EXIF
|
||||
</SubmitButtonWithStatus>
|
||||
</form>}
|
||||
isLoading={pending}
|
||||
>
|
||||
<PhotoForm
|
||||
type="edit"
|
||||
@ -55,6 +59,7 @@ export default function PhotoEditPageClient({
|
||||
? updatedExifData
|
||||
: undefined}
|
||||
uniqueTags={uniqueTags}
|
||||
onFormStatusChange={setIsPending}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
);
|
||||
|
||||
35
src/photo/UploadPageClient.tsx
Normal file
35
src/photo/UploadPageClient.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
import AdminChildPage from '@/components/AdminChildPage';
|
||||
import { PATH_ADMIN_UPLOADS } from '@/site/paths';
|
||||
import { PhotoFormData } from './form';
|
||||
import { Tags } from '@/tag';
|
||||
import PhotoForm from './form/PhotoForm';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function UploadPageClient({
|
||||
blobId,
|
||||
photoFormExif,
|
||||
uniqueTags,
|
||||
}: {
|
||||
blobId?: string
|
||||
photoFormExif: Partial<PhotoFormData>
|
||||
uniqueTags: Tags
|
||||
}) {
|
||||
const [pending, setIsPending] = useState(false);
|
||||
|
||||
return (
|
||||
<AdminChildPage
|
||||
backPath={PATH_ADMIN_UPLOADS}
|
||||
backLabel="Uploads"
|
||||
breadcrumb={blobId}
|
||||
isLoading={pending}
|
||||
>
|
||||
<PhotoForm
|
||||
initialPhotoForm={photoFormExif}
|
||||
uniqueTags={uniqueTags}
|
||||
onFormStatusChange={setIsPending}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
);
|
||||
}
|
||||
@ -34,12 +34,14 @@ export default function PhotoForm({
|
||||
type = 'create',
|
||||
uniqueTags,
|
||||
debugBlur,
|
||||
onFormStatusChange,
|
||||
}: {
|
||||
initialPhotoForm: Partial<PhotoFormData>
|
||||
updatedExifData?: Partial<PhotoFormData>
|
||||
type?: 'create' | 'edit'
|
||||
uniqueTags?: TagsWithMeta
|
||||
debugBlur?: boolean
|
||||
onFormStatusChange?: (pending: boolean) => void
|
||||
}) {
|
||||
const [formData, setFormData] =
|
||||
useState<Partial<PhotoFormData>>(initialPhotoForm);
|
||||
@ -206,7 +208,10 @@ export default function PhotoForm({
|
||||
>
|
||||
Cancel
|
||||
</Link>
|
||||
<SubmitButtonWithStatus disabled={!isFormValid(formData)}>
|
||||
<SubmitButtonWithStatus
|
||||
disabled={!isFormValid(formData)}
|
||||
onFormStatusChange={onFormStatusChange}
|
||||
>
|
||||
{type === 'create' ? 'Create' : 'Update'}
|
||||
</SubmitButtonWithStatus>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user