diff --git a/src/admin/AdminNav.tsx b/src/admin/AdminNav.tsx
index b86d91ac..a87a15d9 100644
--- a/src/admin/AdminNav.tsx
+++ b/src/admin/AdminNav.tsx
@@ -5,18 +5,15 @@ import {
getUniqueTagsCached,
} from '@/photo/cache';
import {
- PATH_ADMIN_OUTDATED,
PATH_ADMIN_PHOTOS,
PATH_ADMIN_TAGS,
PATH_ADMIN_UPLOADS,
} from '@/site/paths';
import AdminNavClient from './AdminNavClient';
-import { OUTDATED_THRESHOLD } from '@/photo';
export default async function AdminNav() {
const [
countPhotos,
- countPhotosOutdated,
countUploads,
countTags,
mostRecentPhotoUpdateTime,
@@ -24,12 +21,6 @@ export default async function AdminNav() {
getPhotosMetaCached({ hidden: 'include' })
.then(({ count }) => count)
.catch(() => 0),
- getPhotosMetaCached({
- hidden: 'include',
- takenBefore: OUTDATED_THRESHOLD,
- })
- .then(({ count }) => count)
- .catch(() => 0),
getStorageUploadUrlsNoStore()
.then(urls => urls.length)
.catch(e => {
@@ -47,13 +38,6 @@ export default async function AdminNav() {
count: countPhotos,
}];
- // Outdated Photos
- if (countPhotosOutdated > 0) { items.push({
- label: 'Outdated',
- href: PATH_ADMIN_OUTDATED,
- count: countPhotosOutdated,
- }); }
-
// Uploads
if (countUploads > 0) { items.push({
label: 'Uploads',
diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx
index 6baa955d..9951ac69 100644
--- a/src/app/admin/layout.tsx
+++ b/src/app/admin/layout.tsx
@@ -6,7 +6,7 @@ export default async function AdminLayout({
children: React.ReactNode
}) {
return (
-
+
diff --git a/src/app/admin/outdated/page.tsx b/src/app/admin/outdated/page.tsx
index fe8994b2..526dfbf1 100644
--- a/src/app/admin/outdated/page.tsx
+++ b/src/app/admin/outdated/page.tsx
@@ -1,4 +1,3 @@
-import SiteGrid from '@/components/SiteGrid';
import { AI_TEXT_GENERATION_ENABLED } from '@/site/config';
import { getPhotos } from '@/photo/db/query';
import AdminPhotosTable from '@/admin/AdminPhotosTable';
@@ -6,6 +5,8 @@ import { OUTDATED_THRESHOLD } from '@/photo';
import LoaderButton from '@/components/primitives/LoaderButton';
import IconGrSync from '@/site/IconGrSync';
import Banner from '@/components/Banner';
+import AdminChildPage from '@/components/AdminChildPage';
+import { PATH_ADMIN_PHOTOS } from '@/site/paths';
const UPDATE_BATCH_SIZE = 5;
@@ -18,36 +19,44 @@ export default async function AdminPhotosPage() {
}).catch(() => []);
return (
-
-
-
- These photos {'('}uploaded before
- {' '}
- {new Date(OUTDATED_THRESHOLD).toLocaleDateString()}{')'}
- {' '}
- may have: missing EXIF fields, inaccurate blur data,
- {' '}
- undesired privacy settings,
- {' '}
- and missing AI-generated text.
-
-
- }
- hideTextOnMobile={false}
- className="primary"
- >
- Sync oldest {UPDATE_BATCH_SIZE} photos
-
-
-
+
}
+ hideTextOnMobile={false}
+ className="primary"
+ >
+
+ Sync oldest {UPDATE_BATCH_SIZE} photos
+
+
+ Sync oldest
+
+ }
+ >
+
+
+
+ These photos {'('}uploaded before
+ {' '}
+ {new Date(OUTDATED_THRESHOLD).toLocaleDateString()}{')'}
+ {' '}
+ may have: missing EXIF fields, inaccurate blur data,
+ {' '}
+ undesired privacy settings,
+ {' '}
+ and missing AI-generated text.
- }
- />
+
+
+
+
);
}
diff --git a/src/app/admin/photos/page.tsx b/src/app/admin/photos/page.tsx
index 542c0d65..b62a20f4 100644
--- a/src/app/admin/photos/page.tsx
+++ b/src/app/admin/photos/page.tsx
@@ -10,6 +10,10 @@ import AdminPhotosTable from '@/admin/AdminPhotosTable';
import AdminPhotosTableInfinite from
'@/admin/AdminPhotosTableInfinite';
import { getPhotosMetaCached } from '@/photo/cache';
+import { IoInformationCircleOutline } from 'react-icons/io5';
+import PathLoaderButton from '@/components/primitives/PathLoaderButton';
+import { PATH_ADMIN_OUTDATED } from '@/site/paths';
+import { OUTDATED_THRESHOLD } from '@/photo';
const DEBUG_PHOTO_BLOBS = false;
@@ -20,6 +24,7 @@ export default async function AdminPhotosPage() {
const [
photos,
photosCount,
+ photosCountOutdated,
blobPhotoUrls,
] = await Promise.all([
getPhotos({
@@ -30,6 +35,12 @@ export default async function AdminPhotosPage() {
getPhotosMetaCached({ hidden: 'include'})
.then(({ count }) => count)
.catch(() => 0),
+ getPhotosMetaCached({
+ hidden: 'include',
+ takenBefore: OUTDATED_THRESHOLD,
+ })
+ .then(({ count }) => count)
+ .catch(() => 0),
DEBUG_PHOTO_BLOBS
? getStoragePhotoUrlsNoStore()
: [],
@@ -39,14 +50,28 @@ export default async function AdminPhotosPage() {
- {
- 'use server';
- // Update upload count in admin nav
- revalidatePath('/admin', 'layout');
- }}
- />
+
+
+
{
+ 'use server';
+ // Update upload count in admin nav
+ revalidatePath('/admin', 'layout');
+ }}
+ />
+
+ {photosCountOutdated > 0 &&
}
+ title={`${photosCountOutdated} Outdated Photos`}
+ hideTextOnMobile={false}
+ >
+ {photosCountOutdated}
+ }
+
{blobPhotoUrls.length > 0 &&
}
aria-disabled={loading}
onClick={() => inputRef.current?.click()}
diff --git a/src/components/primitives/PathLoaderButton.tsx b/src/components/primitives/PathLoaderButton.tsx
index 14f7bc4e..ec212bb2 100644
--- a/src/components/primitives/PathLoaderButton.tsx
+++ b/src/components/primitives/PathLoaderButton.tsx
@@ -8,6 +8,7 @@ import LoaderButton from '@/components/primitives/LoaderButton';
export default function PathLoaderButton({
path,
icon,
+ title,
prefetch,
loaderDelay = 100,
shouldScroll = true,
@@ -21,6 +22,7 @@ export default function PathLoaderButton({
}: {
path: string
icon?: ReactNode
+ title?: string
prefetch?: boolean
loaderDelay?: number
shouldScroll?: boolean
@@ -58,6 +60,7 @@ export default function PathLoaderButton({
return (
{
startTransition(() => {
diff --git a/src/site/globals.css b/src/site/globals.css
index 5e117b9b..50eaa560 100644
--- a/src/site/globals.css
+++ b/src/site/globals.css
@@ -99,6 +99,7 @@
text-invert
bg-gray-900 dark:bg-gray-100
disabled:text-dim
+ font-medium
disabled:bg-gray-100 dark:disabled:bg-gray-900
disabled:border-gray-200 disabled:dark:border-gray-700
border-gray-900 dark:border-gray-100