diff --git a/src/admin/AdminUploadsTable.tsx b/src/admin/AdminUploadsTable.tsx
index d27077f8..e80588df 100644
--- a/src/admin/AdminUploadsTable.tsx
+++ b/src/admin/AdminUploadsTable.tsx
@@ -1,18 +1,7 @@
'use client';
-import Spinner from '@/components/Spinner';
-import {
- getIdFromStorageUrl,
- getExtensionFromStorageUrl,
-} from '@/platforms/storage';
-import { clsx } from 'clsx/lite';
-import { FaRegCircleCheck } from 'react-icons/fa6';
-import { pathForAdminUploadUrl } from '@/app/paths';
-import AddButton from './AddButton';
import { UrlAddStatus } from './AdminUploadsClient';
-import ResponsiveDate from '@/components/ResponsiveDate';
-import DeleteBlobButton from './DeleteUploadButton';
-import ImageMedium from '@/components/image/ImageMedium';
+import AdminUploadsTableRow from './AdminUploadsTableRow';
export default function AdminUploadsTable({
isAdding,
@@ -28,89 +17,22 @@ export default function AdminUploadsTable({
setIsDeleting?: (isDeleting: boolean) => void
}) {
const isComplete = urlAddStatuses.every(({ status }) => status === 'added');
-
return (
- {urlAddStatuses.map(({ url, status, statusMessage, uploadedAt, size }) =>
-
-
-
-
-
-
-
- {uploadedAt
- ?
- : '—'}
-
-
- {isAdding || isComplete
- ? status === 'added'
- ? 'Added'
- : status === 'adding'
- ? statusMessage ?? 'Adding ...'
- : 'Waiting'
- : size
- // eslint-disable-next-line max-len
- ? `${size} ${getExtensionFromStorageUrl(url)?.toUpperCase()}`
- : getExtensionFromStorageUrl(url)?.toUpperCase()}
-
-
-
- {isAdding || isComplete
- ? <>
- {status === 'added'
- ?
- : status === 'adding' &&
- }
- >
- : <>
-
- setIsDeleting?.(true)}
- onDelete={() => {
- setIsDeleting?.(false);
- setUrlAddStatuses?.(urlAddStatuses
- .filter(({ url: urlToRemove }) =>
- urlToRemove !== url));
- }}
- isLoading={isDeleting}
- />
- >}
-
-
-
)}
+ {urlAddStatuses.map(status =>
+
,
+ )}
);
}
diff --git a/src/admin/AdminUploadsTableRow.tsx b/src/admin/AdminUploadsTableRow.tsx
new file mode 100644
index 00000000..ee1a9a8e
--- /dev/null
+++ b/src/admin/AdminUploadsTableRow.tsx
@@ -0,0 +1,131 @@
+import ImageMedium from '@/components/image/ImageMedium';
+import { UrlAddStatus } from './AdminUploadsClient';
+import {
+ getExtensionFromStorageUrl,
+ getIdFromStorageUrl,
+} from '@/platforms/storage';
+import clsx from 'clsx/lite';
+import ResponsiveDate from '@/components/ResponsiveDate';
+import Spinner from '@/components/Spinner';
+import { FaRegCircleCheck } from 'react-icons/fa6';
+import AddButton from './AddButton';
+import { pathForAdminUploadUrl } from '@/app/paths';
+import DeleteBlobButton from './DeleteUploadButton';
+import { useEffect, useRef } from 'react';
+import { isElementEntirelyInViewport } from '@/utility/dom';
+
+export default function AdminUploadsTableRow({
+ url,
+ status,
+ statusMessage,
+ uploadedAt,
+ size,
+ isAdding,
+ isDeleting,
+ isComplete,
+ setIsDeleting,
+ urlAddStatuses,
+ setUrlAddStatuses,
+}: UrlAddStatus & {
+ isAdding?: boolean
+ isDeleting?: boolean
+ isComplete?: boolean
+ setIsDeleting?: (isDeleting: boolean) => void
+ urlAddStatuses: UrlAddStatus[]
+ setUrlAddStatuses?: (urlAddStatuses: UrlAddStatus[]) => void
+}) {
+ const ref = useRef(null);
+
+ useEffect(() => {
+ if (
+ status === 'adding' &&
+ !isElementEntirelyInViewport(ref.current)
+ ) {
+ window.scrollTo({
+ top: (ref.current?.offsetTop ?? 0) - 16,
+ behavior: 'smooth',
+ });
+ }
+ }, [status]);
+
+ return (
+
+
+
+
+
+
+
+ {uploadedAt
+ ?
+ : '—'}
+
+
+ {isAdding || isComplete
+ ? status === 'added'
+ ? 'Added'
+ : status === 'adding'
+ ? statusMessage ?? 'Adding ...'
+ : 'Waiting'
+ : size
+ ? `${size} ${getExtensionFromStorageUrl(url)?.toUpperCase()}`
+ : getExtensionFromStorageUrl(url)?.toUpperCase()}
+
+
+
+ {isAdding || isComplete
+ ? <>
+ {status === 'added'
+ ?
+ : status === 'adding' &&
+ }
+ >
+ : <>
+
+ setIsDeleting?.(true)}
+ onDelete={() => {
+ setIsDeleting?.(false);
+ setUrlAddStatuses?.(urlAddStatuses
+ .filter(({ url: urlToRemove }) =>
+ urlToRemove !== url));
+ }}
+ isLoading={isDeleting}
+ />
+ >}
+
+
+
+ );
+}