From 4209cabfe1beeee9df738c5056ad0289bc813eda Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sun, 9 Feb 2025 20:50:14 -0600 Subject: [PATCH 01/54] Stub out admin info page --- src/admin/AdminNavClient.tsx | 22 ++++++++++++++++++++++ src/app/admin/info/page.tsx | 3 +++ src/site/paths.ts | 4 ++++ 3 files changed, 29 insertions(+) create mode 100644 src/app/admin/info/page.tsx diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 723afcc9..2a20a336 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -7,8 +7,10 @@ import SiteGrid from '@/components/SiteGrid'; import Spinner from '@/components/Spinner'; import { PATH_ADMIN_CONFIGURATION, + PATH_ADMIN_INFO, checkPathPrefix, isPathAdminConfiguration, + isPathAdminInfo, isPathTopLevelAdmin, } from '@/site/paths'; import { useAppState } from '@/state/AppState'; @@ -18,6 +20,7 @@ import { usePathname } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; import { BiCog } from 'react-icons/bi'; import { FaRegClock } from 'react-icons/fa'; +import { TbInfoSquareRounded } from 'react-icons/tb'; // Updates considered recent if they occurred in past 5 minutes const areTimesRecent = (dates: Date[]) => dates @@ -86,6 +89,25 @@ export default function AdminNavClient({ ({count})} )} + + } + > + + + + Admin Info; +} diff --git a/src/site/paths.ts b/src/site/paths.ts index 8556b115..1b1e1748 100644 --- a/src/site/paths.ts +++ b/src/site/paths.ts @@ -39,6 +39,7 @@ export const PATH_ADMIN_OUTDATED = `${PATH_ADMIN}/outdated`; export const PATH_ADMIN_UPLOADS = `${PATH_ADMIN}/uploads`; export const PATH_ADMIN_TAGS = `${PATH_ADMIN}/tags`; export const PATH_ADMIN_CONFIGURATION = `${PATH_ADMIN}/configuration`; +export const PATH_ADMIN_INFO = `${PATH_ADMIN}/info`; export const PATH_ADMIN_BASELINE = `${PATH_ADMIN}/baseline`; // Debug paths @@ -213,6 +214,9 @@ export const isPathTopLevelAdmin = (pathname?: string) => export const isPathAdminConfiguration = (pathname?: string) => checkPathPrefix(pathname, PATH_ADMIN_CONFIGURATION); +export const isPathAdminInfo = (pathname?: string) => + checkPathPrefix(pathname, PATH_ADMIN_INFO); + export const isPathProtected = (pathname?: string) => checkPathPrefix(pathname, PATH_ADMIN) || checkPathPrefix(pathname, pathForTag(TAG_HIDDEN)) || From aca2ef9c6dd1f10f0f67feed413da07594a07f93 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sun, 9 Feb 2025 20:57:59 -0600 Subject: [PATCH 02/54] Fix grid density misreporting --- src/site/SiteChecklistClient.tsx | 4 ++-- src/site/config.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/site/SiteChecklistClient.tsx b/src/site/SiteChecklistClient.tsx index 3aa5c4d8..37747885 100644 --- a/src/site/SiteChecklistClient.tsx +++ b/src/site/SiteChecklistClient.tsx @@ -79,7 +79,7 @@ export default function SiteChecklistClient({ isGridHomepageEnabled, gridAspectRatio, hasGridAspectRatio, - gridDensity, + hasHighGridDensity, hasGridDensityPreference, // Settings isGeoPrivacyEnabled, @@ -604,7 +604,7 @@ export default function SiteChecklistClient({ {renderEnvVars(['NEXT_PUBLIC_GRID_ASPECT_RATIO'])} diff --git a/src/site/config.ts b/src/site/config.ts index bbcba05f..f1326a22 100644 --- a/src/site/config.ts +++ b/src/site/config.ts @@ -301,7 +301,7 @@ export const CONFIG_CHECKLIST_STATUS = { isGridHomepageEnabled: GRID_HOMEPAGE_ENABLED, gridAspectRatio: GRID_ASPECT_RATIO, hasGridAspectRatio: Boolean(process.env.NEXT_PUBLIC_GRID_ASPECT_RATIO), - gridDensity: HIGH_DENSITY_GRID, + hasHighGridDensity: HIGH_DENSITY_GRID, hasGridDensityPreference: Boolean(process.env.NEXT_PUBLIC_SHOW_LARGE_THUMBNAILS), // Settings From ab153e0dc5226f7b364abf4986abc6d8067992b4 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sun, 9 Feb 2025 23:20:44 -0600 Subject: [PATCH 03/54] Add initial app insights content --- src/admin/AdminInfoPage.tsx | 30 ++++++++++++++++++++++++++ src/admin/AdminNavClient.tsx | 8 +++---- src/app/admin/configuration/page.tsx | 29 +++++++------------------ src/app/admin/info/page.tsx | 3 --- src/app/admin/insights/page.tsx | 28 ++++++++++++++++++++++++ src/components/cmdk/CommandKClient.tsx | 5 +++++ src/site/paths.ts | 6 +++--- 7 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 src/admin/AdminInfoPage.tsx delete mode 100644 src/app/admin/info/page.tsx create mode 100644 src/app/admin/insights/page.tsx diff --git a/src/admin/AdminInfoPage.tsx b/src/admin/AdminInfoPage.tsx new file mode 100644 index 00000000..0af159ee --- /dev/null +++ b/src/admin/AdminInfoPage.tsx @@ -0,0 +1,30 @@ +import Container from '@/components/Container'; +import SiteGrid from '@/components/SiteGrid'; +import { ReactNode } from 'react'; + +export default function AdminInfoPage({ + title, + accessory, + children, +}: { + title: string + accessory?: ReactNode + children: ReactNode +}) { + return ( + +
+
+ {title} +
+ {accessory} +
+ + {children} + + } + /> + ); +} diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 2a20a336..80c77cb7 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -7,10 +7,10 @@ import SiteGrid from '@/components/SiteGrid'; import Spinner from '@/components/Spinner'; import { PATH_ADMIN_CONFIGURATION, - PATH_ADMIN_INFO, + PATH_ADMIN_INSIGHTS, checkPathPrefix, isPathAdminConfiguration, - isPathAdminInfo, + isPathAdminInsights, isPathTopLevelAdmin, } from '@/site/paths'; import { useAppState } from '@/state/AppState'; @@ -91,8 +91,8 @@ export default function AdminNavClient({ } diff --git a/src/app/admin/configuration/page.tsx b/src/app/admin/configuration/page.tsx index ecb28453..a2a99905 100644 --- a/src/app/admin/configuration/page.tsx +++ b/src/app/admin/configuration/page.tsx @@ -1,27 +1,14 @@ import ClearCacheButton from '@/admin/ClearCacheButton'; -import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; -import Container from '@/components/Container'; -import SiteGrid from '@/components/SiteGrid'; -import { IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB } from '@/site/config'; import SiteChecklist from '@/site/SiteChecklist'; +import AdminInfoPage from '@/admin/AdminInfoPage'; -export default async function AdminConfigurationPage() { +export default function AdminConfigurationPage() { return ( - -
-
- App Configuration -
- {(IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT) && - } - -
- - - - } - /> + } + > + + ); } diff --git a/src/app/admin/info/page.tsx b/src/app/admin/info/page.tsx deleted file mode 100644 index cea4e815..00000000 --- a/src/app/admin/info/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function AdminInfoPage() { - return
Admin Info
; -} diff --git a/src/app/admin/insights/page.tsx b/src/app/admin/insights/page.tsx new file mode 100644 index 00000000..cd0cc31a --- /dev/null +++ b/src/app/admin/insights/page.tsx @@ -0,0 +1,28 @@ +import AdminInfoPage from '@/admin/AdminInfoPage'; +import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; +import { dateRangeForPhotos } from '@/photo'; +import { getPhotosMetaCached } from '@/photo/cache'; +import { IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB } from '@/site/config'; + +export default async function AdminInsightsPage() { + const { count, dateRange } = await getPhotosMetaCached(); + + const { start, end } = dateRangeForPhotos(undefined, dateRange); + + return } + > +
+
+ {count} photos +
+ + {start === end + ? start + : <>{end} – {start}} + +
+
; +} diff --git a/src/components/cmdk/CommandKClient.tsx b/src/components/cmdk/CommandKClient.tsx index 63da9be9..75b3abe0 100644 --- a/src/components/cmdk/CommandKClient.tsx +++ b/src/components/cmdk/CommandKClient.tsx @@ -12,6 +12,7 @@ import { import { PATH_ADMIN_BASELINE, PATH_ADMIN_CONFIGURATION, + PATH_ADMIN_INSIGHTS, PATH_ADMIN_PHOTOS, PATH_ADMIN_TAGS, PATH_ADMIN_UPLOADS, @@ -320,6 +321,10 @@ export default function CommandKClient({ label: 'App Config', annotation: , path: PATH_ADMIN_CONFIGURATION, + }, { + label: 'App Insights', + annotation: , + path: PATH_ADMIN_INSIGHTS, }, { label: selectedPhotoIds === undefined ? 'Select Multiple Photos' diff --git a/src/site/paths.ts b/src/site/paths.ts index 1b1e1748..50834d5e 100644 --- a/src/site/paths.ts +++ b/src/site/paths.ts @@ -39,7 +39,7 @@ export const PATH_ADMIN_OUTDATED = `${PATH_ADMIN}/outdated`; export const PATH_ADMIN_UPLOADS = `${PATH_ADMIN}/uploads`; export const PATH_ADMIN_TAGS = `${PATH_ADMIN}/tags`; export const PATH_ADMIN_CONFIGURATION = `${PATH_ADMIN}/configuration`; -export const PATH_ADMIN_INFO = `${PATH_ADMIN}/info`; +export const PATH_ADMIN_INSIGHTS = `${PATH_ADMIN}/insights`; export const PATH_ADMIN_BASELINE = `${PATH_ADMIN}/baseline`; // Debug paths @@ -214,8 +214,8 @@ export const isPathTopLevelAdmin = (pathname?: string) => export const isPathAdminConfiguration = (pathname?: string) => checkPathPrefix(pathname, PATH_ADMIN_CONFIGURATION); -export const isPathAdminInfo = (pathname?: string) => - checkPathPrefix(pathname, PATH_ADMIN_INFO); +export const isPathAdminInsights = (pathname?: string) => + checkPathPrefix(pathname, PATH_ADMIN_INSIGHTS); export const isPathProtected = (pathname?: string) => checkPathPrefix(pathname, PATH_ADMIN) || From befdf2b868b419e607b6f6f252cde7338e300e5e Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sun, 9 Feb 2025 23:24:17 -0600 Subject: [PATCH 04/54] Add more photo library insights --- src/app/admin/insights/page.tsx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/app/admin/insights/page.tsx b/src/app/admin/insights/page.tsx index cd0cc31a..7b7887b3 100644 --- a/src/app/admin/insights/page.tsx +++ b/src/app/admin/insights/page.tsx @@ -1,11 +1,23 @@ import AdminInfoPage from '@/admin/AdminInfoPage'; import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; import { dateRangeForPhotos } from '@/photo'; -import { getPhotosMetaCached } from '@/photo/cache'; +import { + getPhotosMeta, + getUniqueTags, + getUniqueCameras, +} from '@/photo/db/query'; import { IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB } from '@/site/config'; export default async function AdminInsightsPage() { - const { count, dateRange } = await getPhotosMetaCached(); + const [ + { count, dateRange }, + tags, + cameras, + ]= await Promise.all([ + getPhotosMeta(), + getUniqueTags(), + getUniqueCameras(), + ]); const { start, end } = dateRangeForPhotos(undefined, dateRange); @@ -15,9 +27,18 @@ export default async function AdminInsightsPage() { } >
+
+ Photo library +
{count} photos
+
+ {tags.length} tags +
+
+ {cameras.length} cameras +
{start === end ? start From eedd86efaedf669b69a6c4aef74b0dcd11d706c9 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 00:02:31 -0600 Subject: [PATCH 05/54] Update configuration icon --- src/admin/AdminNavClient.tsx | 52 +++++++++++++++++--------------- src/site/SiteChecklistClient.tsx | 4 +-- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 80c77cb7..0eada77f 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -18,8 +18,8 @@ import { clsx } from 'clsx/lite'; import { differenceInMinutes } from 'date-fns'; import { usePathname } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; -import { BiCog } from 'react-icons/bi'; import { FaRegClock } from 'react-icons/fa'; +import { HiOutlineCog } from 'react-icons/hi'; import { TbInfoSquareRounded } from 'react-icons/tb'; // Updates considered recent if they occurred in past 5 minutes @@ -89,38 +89,40 @@ export default function AdminNavClient({ ({count})} )}
- +
+ + } + > + + + + } > - - - - } - > - - +
{shouldShowBanner && }> diff --git a/src/site/SiteChecklistClient.tsx b/src/site/SiteChecklistClient.tsx index 37747885..315bbfc0 100644 --- a/src/site/SiteChecklistClient.tsx +++ b/src/site/SiteChecklistClient.tsx @@ -8,12 +8,12 @@ import { clsx } from 'clsx/lite'; import ChecklistRow from '../components/ChecklistRow'; import { FiExternalLink } from 'react-icons/fi'; import { - BiCog, BiData, BiHide, BiLockAlt, BiPencil, } from 'react-icons/bi'; +import { HiOutlineCog } from 'react-icons/hi'; import Checklist from '@/components/Checklist'; import { ConfigChecklistStatus } from './config'; import StatusIcon from '@/components/StatusIcon'; @@ -616,7 +616,7 @@ export default function SiteChecklistClient({ } + icon={} optional > Date: Mon, 10 Feb 2025 09:18:44 -0600 Subject: [PATCH 06/54] Enable turbo for local development --- package.json | 2 +- src/site/font.ts | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 2e9a2012..aac7942b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "exif-photo-blog", "scripts": { - "dev": "next dev", + "dev": "next dev --turbo", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/src/site/font.ts b/src/site/font.ts index 17b02ad8..81348fef 100644 --- a/src/site/font.ts +++ b/src/site/font.ts @@ -4,21 +4,11 @@ import { cwd } from 'process'; const FONT_FAMILY_IBM_PLEX_MONO = 'IBMPlexMono'; -const getFontData = async () => { - let data; - if (typeof fs !== 'undefined') { - data = fs.readFileSync(path.join( - cwd(), - '/public/fonts/IBMPlexMono-Medium.ttf', - )); - } else { - data = await fetch(new URL( - '/public/fonts/IBMPlexMono-Medium.ttf', - import.meta.url, - )).then(res => res.arrayBuffer()); - } - return data; -}; +const getFontData = async () => + fs.readFileSync(path.join( + cwd(), + '/public/fonts/IBMPlexMono-Medium.ttf', + )); export const getIBMPlexMonoMedium = () => getFontData() .then(data => ({ From cff51a24a23b8b583873289487a1176ebc60a2f3 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 09:48:14 -0600 Subject: [PATCH 07/54] Refactor getFontData --- src/site/font.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/site/font.ts b/src/site/font.ts index 81348fef..9f0f3b78 100644 --- a/src/site/font.ts +++ b/src/site/font.ts @@ -2,19 +2,17 @@ import fs from 'fs'; import path from 'path'; import { cwd } from 'process'; -const FONT_FAMILY_IBM_PLEX_MONO = 'IBMPlexMono'; +const FONT_IBM_PLEX_MONO_FAMILY = 'IBMPlexMono'; +const FONT_IBM_PLEX_MONO_PATH = '/public/fonts/IBMPlexMono-Medium.ttf'; const getFontData = async () => - fs.readFileSync(path.join( - cwd(), - '/public/fonts/IBMPlexMono-Medium.ttf', - )); + fs.readFileSync(path.join(cwd(), FONT_IBM_PLEX_MONO_PATH)); export const getIBMPlexMonoMedium = () => getFontData() .then(data => ({ - fontFamily: FONT_FAMILY_IBM_PLEX_MONO, + fontFamily: FONT_IBM_PLEX_MONO_FAMILY, fonts: [{ - name: FONT_FAMILY_IBM_PLEX_MONO, + name: FONT_IBM_PLEX_MONO_FAMILY, data, weight: 500, style: 'normal', From 2f3cc204bdbd24b2160c3c283b01450aea97bb71 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 09:52:01 -0600 Subject: [PATCH 08/54] Move admin insights into dedicated component --- src/admin/AdminAppInsights.tsx | 42 +++++++++++++++++++++++++++++++++ src/app/admin/insights/page.tsx | 39 ++---------------------------- 2 files changed, 44 insertions(+), 37 deletions(-) create mode 100644 src/admin/AdminAppInsights.tsx diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx new file mode 100644 index 00000000..5148b3de --- /dev/null +++ b/src/admin/AdminAppInsights.tsx @@ -0,0 +1,42 @@ +import { dateRangeForPhotos } from '@/photo'; +import { + getPhotosMeta, + getUniqueCameras, + getUniqueTags, +} from '@/photo/db/query'; + +export default async function AdminAppInsights() { + const [ + { count, dateRange }, + tags, + cameras, + ]= await Promise.all([ + getPhotosMeta(), + getUniqueTags(), + getUniqueCameras(), + ]); + + const { start, end } = dateRangeForPhotos(undefined, dateRange); + + return ( +
+
+ Photo library +
+
+ {count} photos +
+
+ {tags.length} tags +
+
+ {cameras.length} cameras +
+ + {start === end + ? start + : <>{end} – {start}} + +
+ ); +} diff --git a/src/app/admin/insights/page.tsx b/src/app/admin/insights/page.tsx index 7b7887b3..7a4d30f7 100644 --- a/src/app/admin/insights/page.tsx +++ b/src/app/admin/insights/page.tsx @@ -1,49 +1,14 @@ +import AdminAppInsights from '@/admin/AdminAppInsights'; import AdminInfoPage from '@/admin/AdminInfoPage'; import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; -import { dateRangeForPhotos } from '@/photo'; -import { - getPhotosMeta, - getUniqueTags, - getUniqueCameras, -} from '@/photo/db/query'; import { IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB } from '@/site/config'; export default async function AdminInsightsPage() { - const [ - { count, dateRange }, - tags, - cameras, - ]= await Promise.all([ - getPhotosMeta(), - getUniqueTags(), - getUniqueCameras(), - ]); - - const { start, end } = dateRangeForPhotos(undefined, dateRange); - return } > -
-
- Photo library -
-
- {count} photos -
-
- {tags.length} tags -
-
- {cameras.length} cameras -
- - {start === end - ? start - : <>{end} – {start}} - -
+
; } From 979d7f2e418a4bcf638f5525b3c603865abf107f Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 20:14:43 -0600 Subject: [PATCH 09/54] Customize admin insights icon --- src/admin/AdminNavClient.tsx | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 0eada77f..e3488f6b 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -19,8 +19,10 @@ import { differenceInMinutes } from 'date-fns'; import { usePathname } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; import { FaRegClock } from 'react-icons/fa'; +import { FaInfo } from 'react-icons/fa'; import { HiOutlineCog } from 'react-icons/hi'; -import { TbInfoSquareRounded } from 'react-icons/tb'; + +const DEBUG_INDICATOR_SIZE = true; // Updates considered recent if they occurred in past 5 minutes const areTimesRecent = (dates: Date[]) => dates @@ -98,16 +100,22 @@ export default function AdminNavClient({ : 'text-dim'} loader={} > - + + +
- + {DEBUG_INDICATOR_SIZE && } Date: Mon, 10 Feb 2025 20:28:35 -0600 Subject: [PATCH 10/54] Format photo library tile --- src/admin/AdminAppInsights.tsx | 39 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index 5148b3de..74aa0269 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -1,9 +1,10 @@ -import { dateRangeForPhotos } from '@/photo'; +import { dateRangeForPhotos } from '@/photo';; import { getPhotosMeta, getUniqueCameras, getUniqueTags, } from '@/photo/db/query'; +import clsx from 'clsx/lite'; export default async function AdminAppInsights() { const [ @@ -19,24 +20,30 @@ export default async function AdminAppInsights() { const { start, end } = dateRangeForPhotos(undefined, dateRange); return ( -
-
+
+
Photo library
-
- {count} photos +
+
Photos
+
{count}
+
Tags
+
{tags.length}
+
Cameras
+
{cameras.length}
+ + {start === end + ? start + : <>{end} – {start}} +
-
- {tags.length} tags -
-
- {cameras.length} cameras -
- - {start === end - ? start - : <>{end} – {start}} -
); } From e0f795709b68b3ce3cae18f5e6e6fd376d101ed7 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 22:34:04 -0600 Subject: [PATCH 11/54] Refine admin insights formatting --- src/admin/AdminAppInsights.tsx | 38 ++++------------ src/admin/AdminAppInsightsClient.tsx | 44 +++++++++++++++++++ .../github/GitHubForkStatusBadgeClient.tsx | 8 +++- .../github/GitHubForkStatusBadgeServer.tsx | 2 +- src/photo/index.ts | 6 ++- 5 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 src/admin/AdminAppInsightsClient.tsx diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index 74aa0269..52c52db8 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -1,49 +1,27 @@ -import { dateRangeForPhotos } from '@/photo';; import { getPhotosMeta, getUniqueCameras, getUniqueTags, } from '@/photo/db/query'; -import clsx from 'clsx/lite'; +import AdminAppInsightsClient from './AdminAppInsightsClient'; export default async function AdminAppInsights() { const [ { count, dateRange }, tags, cameras, - ]= await Promise.all([ + ] = await Promise.all([ getPhotosMeta(), getUniqueTags(), getUniqueCameras(), ]); - const { start, end } = dateRangeForPhotos(undefined, dateRange); - return ( -
-
- Photo library -
-
-
Photos
-
{count}
-
Tags
-
{tags.length}
-
Cameras
-
{cameras.length}
- - {start === end - ? start - : <>{end} – {start}} - -
-
+ ); } diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx new file mode 100644 index 00000000..64f89b0e --- /dev/null +++ b/src/admin/AdminAppInsightsClient.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; +import clsx from 'clsx/lite'; + +export default function AdminAppInsightsClient({ + photosCount, + tagsCount, + camerasCount, + dateRange, +}: { + photosCount: number + tagsCount: number + camerasCount: number + dateRange?: PhotoDateRange +}) { + const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); + + return ( +
+
+ Photo library +
+
+
Photos
+
{photosCount}
+
Tags
+
{tagsCount}
+
Cameras
+
{camerasCount}
+ + {descriptionWithSpaces} + +
+
+ ); +} diff --git a/src/admin/github/GitHubForkStatusBadgeClient.tsx b/src/admin/github/GitHubForkStatusBadgeClient.tsx index 3bfe8593..7f1e0fd6 100644 --- a/src/admin/github/GitHubForkStatusBadgeClient.tsx +++ b/src/admin/github/GitHubForkStatusBadgeClient.tsx @@ -10,11 +10,17 @@ export default function GitHubForkStatusBadgeClient({ tooltip, }: { label?: ReactNode - style?: 'success' | 'warning' | 'error' | 'mono' + style?: 'info' |'success' | 'warning' | 'error' | 'mono' tooltip?: ReactNode }) { const classNameForStyle = () => { switch (style) { + case 'info': return clsx( + 'text-blue-600 hover:text-blue-600', + 'dark:text-blue-400 dark:hover:text-blue-400', + 'bg-blue-100/40 dark:bg-blue-900/25', + 'border-blue-300/40 dark:border-blue-900/50', + ); case 'success': return clsx( 'text-green-700 hover:text-green-700', 'dark:text-green-400 dark:hover:text-green-400', diff --git a/src/admin/github/GitHubForkStatusBadgeServer.tsx b/src/admin/github/GitHubForkStatusBadgeServer.tsx index 5b7657fe..faf3d99c 100644 --- a/src/admin/github/GitHubForkStatusBadgeServer.tsx +++ b/src/admin/github/GitHubForkStatusBadgeServer.tsx @@ -55,7 +55,7 @@ export default async function GitHubForkStatusBadgeServer() { : null} , style: didError || isBehind === undefined || isBehind - ? 'warning' + ? 'info' : 'mono', }} /> : null; diff --git a/src/photo/index.ts b/src/photo/index.ts index 8a145e02..e58a38db 100644 --- a/src/photo/index.ts +++ b/src/photo/index.ts @@ -273,6 +273,7 @@ export const dateRangeForPhotos = ( let start = ''; let end = ''; let description = ''; + let descriptionWithSpaces = ''; if (explicitDateRange || photos.length > 0) { const photosSorted = sortPhotosByDate(photos); @@ -287,9 +288,12 @@ export const dateRangeForPhotos = ( description = start === end ? start : `${start}–${end}`; + descriptionWithSpaces = start === end + ? start + : `${start} – ${end}`; } - return { start, end, description }; + return { start, end, description, descriptionWithSpaces }; }; const photoHasCameraData = (photo: Photo) => From 6b9ca44d9573e64b560409ed7e89719254b54fb1 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 22:40:14 -0600 Subject: [PATCH 12/54] Refine admin nav spinner position --- src/admin/AdminNavClient.tsx | 4 ++-- src/components/LinkWithLoader.tsx | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index e3488f6b..b08ec7f4 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -98,7 +98,7 @@ export default function AdminNavClient({ className={isPathAdminInsights(pathname) ? 'font-bold' : 'text-dim'} - loader={} + loader={} > } + loader={} > & { loader: ReactNode + debugLoading?: boolean }) { return ( @@ -19,7 +21,7 @@ export default function LinkWithLoader({ )}> {children} - {isLoading && From 2c13e77b1a0da04d7f43833f17ab6f983ff408f9 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Mon, 10 Feb 2025 23:57:51 -0600 Subject: [PATCH 13/54] Bump dependencies --- package.json | 20 +-- pnpm-lock.yaml | 345 ++++++++++++++++++++++++------------------------- 2 files changed, 178 insertions(+), 187 deletions(-) diff --git a/package.json b/package.json index aac7942b..66a658aa 100644 --- a/package.json +++ b/package.json @@ -17,19 +17,19 @@ "@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-visually-hidden": "^1.1.2", "@upstash/ratelimit": "^2.0.5", - "@vercel/analytics": "^1.4.1", + "@vercel/analytics": "^1.5.0", "@vercel/blob": "^0.27.1", "@vercel/kv": "^3.0.0", - "@vercel/speed-insights": "^1.1.0", - "ai": "^4.1.26", + "@vercel/speed-insights": "^1.2.0", + "ai": "^4.1.34", "camelcase-keys": "^9.1.3", "cmdk": "^1.0.4", "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", "exifr": "^7.1.3", - "framer-motion": "^12.4.1", + "framer-motion": "^12.4.2", "nanoid": "^5.0.9", - "next": "15.1.6", + "next": "15.1.7", "next-auth": "5.0.0-beta.25", "next-themes": "^0.4.4", "pg": "^8.13.1", @@ -45,10 +45,10 @@ "viewerjs": "^1.11.7" }, "devDependencies": { - "@next/bundle-analyzer": "15.1.6", + "@next/bundle-analyzer": "15.1.7", "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/forms": "^0.5.10", - "@tailwindcss/postcss": "^4.0.5", + "@tailwindcss/postcss": "^4.0.6", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", @@ -61,11 +61,11 @@ "clsx": "^2.1.1", "cross-fetch": "^4.1.0", "eslint": "9.20.0", - "eslint-config-next": "15.1.6", + "eslint-config-next": "15.1.7", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "postcss": "8.5.1", - "tailwindcss": "4.0.5", + "postcss": "8.5.2", + "tailwindcss": "4.0.6", "ts-node": "^10.9.2", "typescript": "5.7.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9d808fa..84632744 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,8 +33,8 @@ importers: specifier: ^2.0.5 version: 2.0.5(@upstash/redis@1.34.3) '@vercel/analytics': - specifier: ^1.4.1 - version: 1.4.1(next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3)) + specifier: ^1.5.0 + version: 1.5.0(next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3)) '@vercel/blob': specifier: ^0.27.1 version: 0.27.1 @@ -42,11 +42,11 @@ importers: specifier: ^3.0.0 version: 3.0.0 '@vercel/speed-insights': - specifier: ^1.1.0 - version: 1.1.0(next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3)) + specifier: ^1.2.0 + version: 1.2.0(next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3)) ai: - specifier: ^4.1.26 - version: 4.1.26(react@19.0.0)(zod@3.23.8) + specifier: ^4.1.34 + version: 4.1.34(react@19.0.0)(zod@3.23.8) camelcase-keys: specifier: ^9.1.3 version: 9.1.3 @@ -63,17 +63,17 @@ importers: specifier: ^7.1.3 version: 7.1.3 framer-motion: - specifier: ^12.4.1 - version: 12.4.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^12.4.2 + version: 12.4.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) nanoid: specifier: ^5.0.9 version: 5.0.9 next: - specifier: 15.1.6 - version: 15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 15.1.7 + version: 15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + version: 5.0.0-beta.25(next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) next-themes: specifier: ^0.4.4 version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -112,17 +112,17 @@ importers: version: 1.11.7 devDependencies: '@next/bundle-analyzer': - specifier: 15.1.6 - version: 15.1.6 + specifier: 15.1.7 + version: 15.1.7 '@tailwindcss/container-queries': specifier: ^0.1.1 - version: 0.1.1(tailwindcss@4.0.5) + version: 0.1.1(tailwindcss@4.0.6) '@tailwindcss/forms': specifier: ^0.5.10 - version: 0.5.10(tailwindcss@4.0.5) + version: 0.5.10(tailwindcss@4.0.6) '@tailwindcss/postcss': - specifier: ^4.0.5 - version: 4.0.5 + specifier: ^4.0.6 + version: 4.0.6 '@testing-library/dom': specifier: ^10.4.0 version: 10.4.0 @@ -160,8 +160,8 @@ importers: specifier: 9.20.0 version: 9.20.0(jiti@2.4.2) eslint-config-next: - specifier: 15.1.6 - version: 15.1.6(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) + specifier: 15.1.7 + version: 15.1.7(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) jest: specifier: ^29.7.0 version: 29.7.0(@types/node@22.13.1)(ts-node@10.9.2(@types/node@22.13.1)(typescript@5.7.3)) @@ -169,11 +169,11 @@ importers: specifier: ^29.7.0 version: 29.7.0 postcss: - specifier: 8.5.1 - version: 8.5.1 + specifier: 8.5.2 + version: 8.5.2 tailwindcss: - specifier: 4.0.5 - version: 4.0.5 + specifier: 4.0.6 + version: 4.0.6 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.13.1)(typescript@5.7.3) @@ -205,8 +205,8 @@ packages: resolution: {integrity: sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==} engines: {node: '>=18'} - '@ai-sdk/react@1.1.10': - resolution: {integrity: sha512-RTkEVYKq7qO6Ct3XdVTgbaCTyjX+q1HLqb+t2YvZigimzMCQbHkpZCtt2H2Fgpt1UOTqnAAlXjEAgTW3X60Y9g==} + '@ai-sdk/react@1.1.11': + resolution: {integrity: sha512-vfjZ7w2M+Me83HTMMrnnrmXotz39UDCMd27YQSrvt2f1YCLPloVpLhP+Y9TLZeFE/QiiRCrPYLDQm6aQJYJ9PQ==} engines: {node: '>=18'} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc @@ -217,8 +217,8 @@ packages: zod: optional: true - '@ai-sdk/ui-utils@1.1.10': - resolution: {integrity: sha512-x+A1Nfy8RTSatdCe+7nRpHAZVzPFB6H+r+2JKoapSvrwsu9mw2pAbmFgV8Zaj94TsmUdTlO0/j97e63f+yYuWg==} + '@ai-sdk/ui-utils@1.1.11': + resolution: {integrity: sha512-1SC9W4VZLcJtxHRv4Y0aX20EFeaEP6gUvVqoKLBBtMLOgtcZrv/F/HQRjGavGugiwlS3dsVza4X+E78fiwtlTA==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 @@ -866,59 +866,59 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@next/bundle-analyzer@15.1.6': - resolution: {integrity: sha512-hGzQyDqJzFHcHNCyTqM3o05BpVq5tGnRODccZBVJDBf5Miv/26UJPMB0wh9L9j3ylgHC+0/v8BaBnBBek1rC6Q==} + '@next/bundle-analyzer@15.1.7': + resolution: {integrity: sha512-tESiAwTUEpzzxKMLDbQuPHvD+PFDjY+0O3R4T5bpjIo0cr5fvppbbllQbtksQbBEquT55Eu8JmDoOlc9YFv6Kw==} - '@next/env@15.1.6': - resolution: {integrity: sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w==} + '@next/env@15.1.7': + resolution: {integrity: sha512-d9jnRrkuOH7Mhi+LHav2XW91HOgTAWHxjMPkXMGBc9B2b7614P7kjt8tAplRvJpbSt4nbO1lugcT/kAaWzjlLQ==} - '@next/eslint-plugin-next@15.1.6': - resolution: {integrity: sha512-+slMxhTgILUntZDGNgsKEYHUvpn72WP1YTlkmEhS51vnVd7S9jEEy0n9YAMcI21vUG4akTw9voWH02lrClt/yw==} + '@next/eslint-plugin-next@15.1.7': + resolution: {integrity: sha512-kRP7RjSxfTO13NE317ek3mSGzoZlI33nc/i5hs1KaWpK+egs85xg0DJ4p32QEiHnR0mVjuUfhRIun7awqfL7pQ==} - '@next/swc-darwin-arm64@15.1.6': - resolution: {integrity: sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==} + '@next/swc-darwin-arm64@15.1.7': + resolution: {integrity: sha512-hPFwzPJDpA8FGj7IKV3Yf1web3oz2YsR8du4amKw8d+jAOHfYHYFpMkoF6vgSY4W6vB29RtZEklK9ayinGiCmQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.1.6': - resolution: {integrity: sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg==} + '@next/swc-darwin-x64@15.1.7': + resolution: {integrity: sha512-2qoas+fO3OQKkU0PBUfwTiw/EYpN+kdAx62cePRyY1LqKtP09Vp5UcUntfZYajop5fDFTjSxCHfZVRxzi+9FYQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.1.6': - resolution: {integrity: sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg==} + '@next/swc-linux-arm64-gnu@15.1.7': + resolution: {integrity: sha512-sKLLwDX709mPdzxMnRIXLIT9zaX2w0GUlkLYQnKGoXeWUhcvpCrK+yevcwCJPdTdxZEUA0mOXGLdPsGkudGdnA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.1.6': - resolution: {integrity: sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ==} + '@next/swc-linux-arm64-musl@15.1.7': + resolution: {integrity: sha512-zblK1OQbQWdC8fxdX4fpsHDw+VSpBPGEUX4PhSE9hkaWPrWoeIJn+baX53vbsbDRaDKd7bBNcXRovY1hEhFd7w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.1.6': - resolution: {integrity: sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ==} + '@next/swc-linux-x64-gnu@15.1.7': + resolution: {integrity: sha512-GOzXutxuLvLHFDAPsMP2zDBMl1vfUHHpdNpFGhxu90jEzH6nNIgmtw/s1MDwpTOiM+MT5V8+I1hmVFeAUhkbgQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.1.6': - resolution: {integrity: sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ==} + '@next/swc-linux-x64-musl@15.1.7': + resolution: {integrity: sha512-WrZ7jBhR7ATW1z5iEQ0ZJfE2twCNSXbpCSaAunF3BKcVeHFADSI/AW1y5Xt3DzTqPF1FzQlwQTewqetAABhZRQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.1.6': - resolution: {integrity: sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg==} + '@next/swc-win32-arm64-msvc@15.1.7': + resolution: {integrity: sha512-LDnj1f3OVbou1BqvvXVqouJZKcwq++mV2F+oFHptToZtScIEnhNRJAhJzqAtTE2dB31qDYL45xJwrc+bLeKM2Q==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.1.6': - resolution: {integrity: sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ==} + '@next/swc-win32-x64-msvc@15.1.7': + resolution: {integrity: sha512-dC01f1quuf97viOfW05/K8XYv2iuBgAxJZl7mbCKEjMgdQl5JjAKJ0D2qMKZCgPWDeFbFT0Q0nYWwytEW0DWTQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1515,81 +1515,81 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' - '@tailwindcss/node@4.0.5': - resolution: {integrity: sha512-ffTz4DX1cgr4XPuqjhm32YV6Lyx58R1CxAAnSFTamg6wXwfk3oWdb6exgAbGesPzvUgicTO0gwUdQGSsg4nNog==} + '@tailwindcss/node@4.0.6': + resolution: {integrity: sha512-jb6E0WeSq7OQbVYcIJ6LxnZTeC4HjMvbzFBMCrQff4R50HBlo/obmYNk6V2GCUXDeqiXtvtrQgcIbT+/boB03Q==} - '@tailwindcss/oxide-android-arm64@4.0.5': - resolution: {integrity: sha512-kK/ik8aIAKWDIEYDZGUCJcnU1qU5sPoMBlVzPvtsUqiV6cSHcnVRUdkcLwKqTeUowzZtjjRiamELLd9Gb0x5BQ==} + '@tailwindcss/oxide-android-arm64@4.0.6': + resolution: {integrity: sha512-xDbym6bDPW3D2XqQqX3PjqW3CKGe1KXH7Fdkc60sX5ZLVUbzPkFeunQaoP+BuYlLc2cC1FoClrIRYnRzof9Sow==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.0.5': - resolution: {integrity: sha512-vkbXFv0FfAEbrSa5NBjFEE+xi06ha7mxuxjY8LRn7d7/tBGrAZOEJnnsEbB6M1+x2pGRTjjei0XyTIXdVCglJA==} + '@tailwindcss/oxide-darwin-arm64@4.0.6': + resolution: {integrity: sha512-1f71/ju/tvyGl5c2bDkchZHy8p8EK/tDHCxlpYJ1hGNvsYihZNurxVpZ0DefpN7cNc9RTT8DjrRoV8xXZKKRjg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.0.5': - resolution: {integrity: sha512-PedA64rHBXEa4e6abBWE4Yj4gHulfPb5T+rBNnX+WGkjjge5Txa2oS99TLmJ5BPDkXXqz/Ba7oweWIDDG7i5NQ==} + '@tailwindcss/oxide-darwin-x64@4.0.6': + resolution: {integrity: sha512-s/hg/ZPgxFIrGMb0kqyeaqZt505P891buUkSezmrDY6lxv2ixIELAlOcUVTkVh245SeaeEiUVUPiUN37cwoL2g==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.0.5': - resolution: {integrity: sha512-silz3nuZdEYDfic3v/ooVUQChj9hbxDSee43GCQNwr/iD9L4K/JsZtoNqr0w69pUkvWcKINOGOG0r7WqUqkAeg==} + '@tailwindcss/oxide-freebsd-x64@4.0.6': + resolution: {integrity: sha512-Z3Wo8FWZnmio8+xlcbb7JUo/hqRMSmhQw8IGIRoRJ7GmLR0C+25Wq+bEX/135xe/yEle2lFkhu9JBHd4wZYiig==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.5': - resolution: {integrity: sha512-ElneG75XS64B9I2G83A/Hc7EtNVOD5xahs7avq0aeW7mEX6CtMc8m8RCXMn3jGhz8enFE52l6QU0wO7iVkEtXQ==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.6': + resolution: {integrity: sha512-SNSwkkim1myAgmnbHs4EjXsPL7rQbVGtjcok5EaIzkHkCAVK9QBQsWeP2Jm2/JJhq4wdx8tZB9Y7psMzHYWCkA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.0.5': - resolution: {integrity: sha512-8yoXpWTeIFaByUaKy2qRAppznLVaDHP9xYCAbS3FG7+uUwHi8CHE4TcomM7eyamo0U7dbUIDgKMGoAX5s2iVrA==} + '@tailwindcss/oxide-linux-arm64-gnu@4.0.6': + resolution: {integrity: sha512-tJ+mevtSDMQhKlwCCuhsFEFg058kBiSy4TkoeBG921EfrHKmexOaCyFKYhVXy4JtkaeeOcjJnCLasEeqml4i+Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.0.5': - resolution: {integrity: sha512-BDlVSiiJ08GRz9KKnXgaPFs2fkukPF3pym6uK3oWEKW45jKlVGgybLqulcV5nLEqREOuyq4Rn4vnZss4/bbQ/g==} + '@tailwindcss/oxide-linux-arm64-musl@4.0.6': + resolution: {integrity: sha512-IoArz1vfuTR4rALXMUXI/GWWfx2EaO4gFNtBNkDNOYhlTD4NVEwE45nbBoojYiTulajI4c2XH8UmVEVJTOJKxA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.0.5': - resolution: {integrity: sha512-DYgieNDRkTy69bWPgdsc47nAXa74P63P/RetUwYM9vYj5USyOfHCEcqIthkCuYw3dXKBhjgwe697TmL2g2jpAw==} + '@tailwindcss/oxide-linux-x64-gnu@4.0.6': + resolution: {integrity: sha512-QtsUfLkEAeWAC3Owx9Kg+7JdzE+k9drPhwTAXbXugYB9RZUnEWWx5x3q/au6TvUYcL+n0RBqDEO2gucZRvRFgQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.0.5': - resolution: {integrity: sha512-z2RzUvOQl0ZqrZqmCFP53tJbBXQ3UmLD/E6J7+q0e+4VaFnXCcIYTfQbHgI8f3fash+q6gK80Ko/ywEQ+bvv6Q==} + '@tailwindcss/oxide-linux-x64-musl@4.0.6': + resolution: {integrity: sha512-QthvJqIji2KlGNwLcK/PPYo7w1Wsi/8NK0wAtRGbv4eOPdZHkQ9KUk+oCoP20oPO7i2a6X1aBAFQEL7i08nNMA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-win32-arm64-msvc@4.0.5': - resolution: {integrity: sha512-ho1dJ4o5Q8nAOxdMkbfBu5aSqI+/bzQ0jEeHcXaEdEJzf2fSWs3HY7bIKtE6vQS8c4SmSBvls7IhGPuJxNg+2Q==} + '@tailwindcss/oxide-win32-arm64-msvc@4.0.6': + resolution: {integrity: sha512-+oka+dYX8jy9iP00DJ9Y100XsqvbqR5s0yfMZJuPR1H/lDVtDfsZiSix1UFBQ3X1HWxoEEl6iXNJHWd56TocVw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.0.5': - resolution: {integrity: sha512-yjw6JhtyDXr+G0aZrj3L3NlEV7CobSqOdPyfo6G3d91WEZ5b8PyGm86IAreX08Jp9DChGXEd53gWysVpWCTs+w==} + '@tailwindcss/oxide-win32-x64-msvc@4.0.6': + resolution: {integrity: sha512-+o+juAkik4p8Ue/0LiflQXPmVatl6Av3LEZXpBTfg4qkMIbZdhCGWFzHdt2NjoMiLOJCFDddoV6GYaimvK1Olw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.0.5': - resolution: {integrity: sha512-iWGyOCu0TuzvCBisWbGv2K9+7QCfE0ztgtrZOvb9iF7V7ChVkD15Obe3HevZrhjngAc34jDA+OMSuSvkrpTy4A==} + '@tailwindcss/oxide@4.0.6': + resolution: {integrity: sha512-lVyKV2y58UE9CeKVcYykULe9QaE1dtKdxDEdrTPIdbzRgBk6bdxHNAoDqvcqXbIGXubn3VOl1O/CFF77v/EqSA==} engines: {node: '>= 10'} - '@tailwindcss/postcss@4.0.5': - resolution: {integrity: sha512-U7IPb+KMASETtUvISwePM+1h+jLQspXf2ncfX/LmP/4AaH7b7DJQhqXzDCaJQd/MIh54dRUO93i9q4+Xm7dlVg==} + '@tailwindcss/postcss@4.0.6': + resolution: {integrity: sha512-noTaGPHjGCXTCc487TWnfAEN0VMjqDAecssWDOsfxV2hFrcZR0AHthX7IdY/0xHTg/EtpmIPdssddlZ5/B7JnQ==} '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} @@ -1769,8 +1769,8 @@ packages: '@upstash/redis@1.34.3': resolution: {integrity: sha512-VT25TyODGy/8ljl7GADnJoMmtmJ1F8d84UXfGonRRF8fWYJz7+2J6GzW+a6ETGtk4OyuRTt7FRSvFG5GvrfSdQ==} - '@vercel/analytics@1.4.1': - resolution: {integrity: sha512-ekpL4ReX2TH3LnrRZTUKjHHNpNy9S1I7QmS+g/RQXoSUQ8ienzosuX7T9djZ/s8zPhBx1mpHP/Rw5875N+zQIQ==} + '@vercel/analytics@1.5.0': + resolution: {integrity: sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==} peerDependencies: '@remix-run/react': ^2 '@sveltejs/kit': ^1 || ^2 @@ -1803,8 +1803,8 @@ packages: resolution: {integrity: sha512-pKT8fRnfyYk2MgvyB6fn6ipJPCdfZwiKDdw7vB+HL50rjboEBHDVBEcnwfkEpVSp2AjNtoaOUH7zG+bVC/rvSg==} engines: {node: '>=14.6'} - '@vercel/speed-insights@1.1.0': - resolution: {integrity: sha512-rAXxuhhO4mlRGC9noa5F7HLMtGg8YF1zAN6Pjd1Ny4pII4cerhtwSG4vympbCl+pWkH7nBS9kVXRD4FAn54dlg==} + '@vercel/speed-insights@1.2.0': + resolution: {integrity: sha512-y9GVzrUJ2xmgtQlzFP2KhVRoCglwfRQgjyfY607aU0hh0Un6d0OUyrJkjuAlsV18qR4zfoFPs/BiIj9YDS6Wzw==} peerDependencies: '@sveltejs/kit': ^1 || ^2 next: '>= 13' @@ -1885,8 +1885,8 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - ai@4.1.26: - resolution: {integrity: sha512-Mww6mJbGwmMK0qAKR67WfVK1WyaUjfFlPZ2rhUUmDns3WhI+DVgMM7gLmuo0rA+I5qq69g7YE1OCgUwMRKKjMw==} + ai@4.1.34: + resolution: {integrity: sha512-9IB5duz6VbXvjibqNrvKz6++PwE8Ui5UfbOC9/CtcQN5Z9sudUQErss+maj7ptoPysD2NPjj99e0Hp183Cz5LQ==} engines: {node: '>=18'} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc @@ -2378,10 +2378,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enhanced-resolve@5.16.1: - resolution: {integrity: sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==} - engines: {node: '>=10.13.0'} - enhanced-resolve@5.18.1: resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} engines: {node: '>=10.13.0'} @@ -2445,8 +2441,8 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-next@15.1.6: - resolution: {integrity: sha512-Wd1uy6y7nBbXUSg9QAuQ+xYEKli5CgUhLjz1QHW11jLDis5vK5XB3PemL6jEmy7HrdhaRFDz+GTZ/3FoH+EUjg==} + eslint-config-next@15.1.7: + resolution: {integrity: sha512-zXoMnYUIy3XHaAoOhrcYkT9UQWvXqWju2K7NNsmb5wd/7XESDwof61eUdW4QhERr3eJ9Ko/vnXqIrj8kk/drYw==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 typescript: '>=3.3.1' @@ -2646,8 +2642,8 @@ packages: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} - framer-motion@12.4.1: - resolution: {integrity: sha512-5Ijbea3topSZjadQ0hgc/TcWj2ldMZmNREM7RvAhvsThYOA1HHOA8TT1yKvMu1YXP3jWaFwoZ6Vo9Nw+DUZrzA==} + framer-motion@12.4.2: + resolution: {integrity: sha512-pW307cQKjDqEuO1flEoIFf6TkuJRfKr+c7qsHAJhDo4368N/5U8/7WU8J+xhd9+gjmOgJfgp+46evxRRFM39dA==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -3441,8 +3437,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@15.1.6: - resolution: {integrity: sha512-Hch4wzbaX0vKQtalpXvUiw5sYivBy4cm5rzUKrBnUB/y436LGrvOUqYvlSeNVCWFO/770gDlltR9gqZH62ct4Q==} + next@15.1.7: + resolution: {integrity: sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -3661,8 +3657,8 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.1: - resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} + postcss@8.5.2: + resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -4088,8 +4084,8 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tailwindcss@4.0.5: - resolution: {integrity: sha512-DZZIKX3tA23LGTjHdnwlJOTxfICD1cPeykLLsYF1RQBI9QsCR3i0szohJfJDVjr6aNRAIio5WVO7FGB77fRHwg==} + tailwindcss@4.0.6: + resolution: {integrity: sha512-mysewHYJKaXgNOW6pp5xon/emCsfAMnO8WMaGKZZ35fomnR/T5gYnRg2/yRTTrtXiEl1tiVkeRt0eMO6HxEZqw==} tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -4439,17 +4435,17 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/react@1.1.10(react@19.0.0)(zod@3.23.8)': + '@ai-sdk/react@1.1.11(react@19.0.0)(zod@3.23.8)': dependencies: '@ai-sdk/provider-utils': 2.1.6(zod@3.23.8) - '@ai-sdk/ui-utils': 1.1.10(zod@3.23.8) + '@ai-sdk/ui-utils': 1.1.11(zod@3.23.8) swr: 2.3.2(react@19.0.0) throttleit: 2.1.0 optionalDependencies: react: 19.0.0 zod: 3.23.8 - '@ai-sdk/ui-utils@1.1.10(zod@3.23.8)': + '@ai-sdk/ui-utils@1.1.11(zod@3.23.8)': dependencies: '@ai-sdk/provider': 1.0.7 '@ai-sdk/provider-utils': 2.1.6(zod@3.23.8) @@ -5512,41 +5508,41 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@next/bundle-analyzer@15.1.6': + '@next/bundle-analyzer@15.1.7': dependencies: webpack-bundle-analyzer: 4.10.1 transitivePeerDependencies: - bufferutil - utf-8-validate - '@next/env@15.1.6': {} + '@next/env@15.1.7': {} - '@next/eslint-plugin-next@15.1.6': + '@next/eslint-plugin-next@15.1.7': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.1.6': + '@next/swc-darwin-arm64@15.1.7': optional: true - '@next/swc-darwin-x64@15.1.6': + '@next/swc-darwin-x64@15.1.7': optional: true - '@next/swc-linux-arm64-gnu@15.1.6': + '@next/swc-linux-arm64-gnu@15.1.7': optional: true - '@next/swc-linux-arm64-musl@15.1.6': + '@next/swc-linux-arm64-musl@15.1.7': optional: true - '@next/swc-linux-x64-gnu@15.1.6': + '@next/swc-linux-x64-gnu@15.1.7': optional: true - '@next/swc-linux-x64-musl@15.1.6': + '@next/swc-linux-x64-musl@15.1.7': optional: true - '@next/swc-win32-arm64-msvc@15.1.6': + '@next/swc-win32-arm64-msvc@15.1.7': optional: true - '@next/swc-win32-x64-msvc@15.1.6': + '@next/swc-win32-x64-msvc@15.1.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -6223,76 +6219,76 @@ snapshots: dependencies: tslib: 2.8.1 - '@tailwindcss/container-queries@0.1.1(tailwindcss@4.0.5)': + '@tailwindcss/container-queries@0.1.1(tailwindcss@4.0.6)': dependencies: - tailwindcss: 4.0.5 + tailwindcss: 4.0.6 - '@tailwindcss/forms@0.5.10(tailwindcss@4.0.5)': + '@tailwindcss/forms@0.5.10(tailwindcss@4.0.6)': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 4.0.5 + tailwindcss: 4.0.6 - '@tailwindcss/node@4.0.5': + '@tailwindcss/node@4.0.6': dependencies: enhanced-resolve: 5.18.1 jiti: 2.4.2 - tailwindcss: 4.0.5 + tailwindcss: 4.0.6 - '@tailwindcss/oxide-android-arm64@4.0.5': + '@tailwindcss/oxide-android-arm64@4.0.6': optional: true - '@tailwindcss/oxide-darwin-arm64@4.0.5': + '@tailwindcss/oxide-darwin-arm64@4.0.6': optional: true - '@tailwindcss/oxide-darwin-x64@4.0.5': + '@tailwindcss/oxide-darwin-x64@4.0.6': optional: true - '@tailwindcss/oxide-freebsd-x64@4.0.5': + '@tailwindcss/oxide-freebsd-x64@4.0.6': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.5': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.6': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.0.5': + '@tailwindcss/oxide-linux-arm64-gnu@4.0.6': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.0.5': + '@tailwindcss/oxide-linux-arm64-musl@4.0.6': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.0.5': + '@tailwindcss/oxide-linux-x64-gnu@4.0.6': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.0.5': + '@tailwindcss/oxide-linux-x64-musl@4.0.6': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.0.5': + '@tailwindcss/oxide-win32-arm64-msvc@4.0.6': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.0.5': + '@tailwindcss/oxide-win32-x64-msvc@4.0.6': optional: true - '@tailwindcss/oxide@4.0.5': + '@tailwindcss/oxide@4.0.6': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.0.5 - '@tailwindcss/oxide-darwin-arm64': 4.0.5 - '@tailwindcss/oxide-darwin-x64': 4.0.5 - '@tailwindcss/oxide-freebsd-x64': 4.0.5 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.5 - '@tailwindcss/oxide-linux-arm64-gnu': 4.0.5 - '@tailwindcss/oxide-linux-arm64-musl': 4.0.5 - '@tailwindcss/oxide-linux-x64-gnu': 4.0.5 - '@tailwindcss/oxide-linux-x64-musl': 4.0.5 - '@tailwindcss/oxide-win32-arm64-msvc': 4.0.5 - '@tailwindcss/oxide-win32-x64-msvc': 4.0.5 + '@tailwindcss/oxide-android-arm64': 4.0.6 + '@tailwindcss/oxide-darwin-arm64': 4.0.6 + '@tailwindcss/oxide-darwin-x64': 4.0.6 + '@tailwindcss/oxide-freebsd-x64': 4.0.6 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.6 + '@tailwindcss/oxide-linux-arm64-gnu': 4.0.6 + '@tailwindcss/oxide-linux-arm64-musl': 4.0.6 + '@tailwindcss/oxide-linux-x64-gnu': 4.0.6 + '@tailwindcss/oxide-linux-x64-musl': 4.0.6 + '@tailwindcss/oxide-win32-arm64-msvc': 4.0.6 + '@tailwindcss/oxide-win32-x64-msvc': 4.0.6 - '@tailwindcss/postcss@4.0.5': + '@tailwindcss/postcss@4.0.6': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.0.5 - '@tailwindcss/oxide': 4.0.5 + '@tailwindcss/node': 4.0.6 + '@tailwindcss/oxide': 4.0.6 lightningcss: 1.29.1 - postcss: 8.5.1 - tailwindcss: 4.0.5 + postcss: 8.5.2 + tailwindcss: 4.0.6 '@testing-library/dom@10.4.0': dependencies: @@ -6519,9 +6515,9 @@ snapshots: dependencies: crypto-js: 4.2.0 - '@vercel/analytics@1.4.1(next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3))': + '@vercel/analytics@1.5.0(next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3))': optionalDependencies: - next: 15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 svelte: 4.2.17 vue: 3.4.27(typescript@5.7.3) @@ -6538,9 +6534,9 @@ snapshots: dependencies: '@upstash/redis': 1.34.3 - '@vercel/speed-insights@1.1.0(next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3))': + '@vercel/speed-insights@1.2.0(next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(svelte@4.2.17)(vue@3.4.27(typescript@5.7.3))': optionalDependencies: - next: 15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 svelte: 4.2.17 vue: 3.4.27(typescript@5.7.3) @@ -6569,7 +6565,7 @@ snapshots: '@vue/shared': 3.4.27 estree-walker: 2.0.2 magic-string: 0.30.10 - postcss: 8.5.1 + postcss: 8.5.2 source-map-js: 1.2.1 optional: true @@ -6630,12 +6626,12 @@ snapshots: transitivePeerDependencies: - supports-color - ai@4.1.26(react@19.0.0)(zod@3.23.8): + ai@4.1.34(react@19.0.0)(zod@3.23.8): dependencies: '@ai-sdk/provider': 1.0.7 '@ai-sdk/provider-utils': 2.1.6(zod@3.23.8) - '@ai-sdk/react': 1.1.10(react@19.0.0)(zod@3.23.8) - '@ai-sdk/ui-utils': 1.1.10(zod@3.23.8) + '@ai-sdk/react': 1.1.11(react@19.0.0)(zod@3.23.8) + '@ai-sdk/ui-utils': 1.1.11(zod@3.23.8) '@opentelemetry/api': 1.9.0 jsondiffpatch: 0.6.0 optionalDependencies: @@ -7160,11 +7156,6 @@ snapshots: emoji-regex@9.2.2: {} - enhanced-resolve@5.16.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.1 - enhanced-resolve@5.18.1: dependencies: graceful-fs: 4.2.11 @@ -7285,9 +7276,9 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-next@15.1.6(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3): + eslint-config-next@15.1.7(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3): dependencies: - '@next/eslint-plugin-next': 15.1.6 + '@next/eslint-plugin-next': 15.1.7 '@rushstack/eslint-patch': 1.10.3 '@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) '@typescript-eslint/parser': 8.19.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) @@ -7315,7 +7306,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.19.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.20.0(jiti@2.4.2)): dependencies: debug: 4.3.4 - enhanced-resolve: 5.16.1 + enhanced-resolve: 5.18.1 eslint: 9.20.0(jiti@2.4.2) eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.19.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.20.0(jiti@2.4.2)) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.20.0(jiti@2.4.2)) @@ -7591,7 +7582,7 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - framer-motion@12.4.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + framer-motion@12.4.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: motion-dom: 12.0.0 motion-utils: 12.0.0 @@ -8523,10 +8514,10 @@ snapshots: natural-compare@1.4.0: {} - next-auth@5.0.0-beta.25(next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0): + next-auth@5.0.0-beta.25(next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0): dependencies: '@auth/core': 0.37.2 - next: 15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 next-themes@0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): @@ -8534,9 +8525,9 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - next@15.1.6(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + next@15.1.7(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@next/env': 15.1.6 + '@next/env': 15.1.7 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 @@ -8546,14 +8537,14 @@ snapshots: react-dom: 19.0.0(react@19.0.0) styled-jsx: 5.1.6(@babel/core@7.24.5)(react@19.0.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.1.6 - '@next/swc-darwin-x64': 15.1.6 - '@next/swc-linux-arm64-gnu': 15.1.6 - '@next/swc-linux-arm64-musl': 15.1.6 - '@next/swc-linux-x64-gnu': 15.1.6 - '@next/swc-linux-x64-musl': 15.1.6 - '@next/swc-win32-arm64-msvc': 15.1.6 - '@next/swc-win32-x64-msvc': 15.1.6 + '@next/swc-darwin-arm64': 15.1.7 + '@next/swc-darwin-x64': 15.1.7 + '@next/swc-linux-arm64-gnu': 15.1.7 + '@next/swc-linux-arm64-musl': 15.1.7 + '@next/swc-linux-x64-gnu': 15.1.7 + '@next/swc-linux-x64-musl': 15.1.7 + '@next/swc-win32-arm64-msvc': 15.1.7 + '@next/swc-win32-x64-msvc': 15.1.7 '@opentelemetry/api': 1.9.0 sharp: 0.33.5 transitivePeerDependencies: @@ -8756,7 +8747,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.1: + postcss@8.5.2: dependencies: nanoid: 3.3.8 picocolors: 1.1.1 @@ -8958,7 +8949,7 @@ snapshots: htmlparser2: 8.0.2 is-plain-object: 5.0.0 parse-srcset: 1.0.2 - postcss: 8.5.1 + postcss: 8.5.2 sax@1.2.4: {} @@ -9217,7 +9208,7 @@ snapshots: symbol-tree@3.2.4: {} - tailwindcss@4.0.5: {} + tailwindcss@4.0.6: {} tapable@2.2.1: {} From 985f0d0c26f6d2f55f4933d21811de8dd76c9d7e Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 11 Feb 2025 00:04:49 -0600 Subject: [PATCH 14/54] Adjust photo library card --- src/admin/AdminAppInsights.tsx | 10 +++++++++- src/admin/AdminAppInsightsClient.tsx | 20 ++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index 52c52db8..6aea957a 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -1,6 +1,8 @@ import { getPhotosMeta, getUniqueCameras, + getUniqueFilmSimulations, + getUniqueLenses, getUniqueTags, } from '@/photo/db/query'; import AdminAppInsightsClient from './AdminAppInsightsClient'; @@ -10,10 +12,14 @@ export default async function AdminAppInsights() { { count, dateRange }, tags, cameras, + filmSimulations, + lenses, ] = await Promise.all([ - getPhotosMeta(), + getPhotosMeta({ hidden: 'include' }), getUniqueTags(), getUniqueCameras(), + getUniqueFilmSimulations(), + getUniqueLenses(), ]); return ( @@ -21,6 +27,8 @@ export default async function AdminAppInsights() { photosCount={count} tagsCount={tags.length} camerasCount={cameras.length} + filmSimulationsCount={filmSimulations.length} + lensesCount={lenses.length} dateRange={dateRange} /> ); diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 64f89b0e..5029d54c 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -7,11 +7,15 @@ export default function AdminAppInsightsClient({ photosCount, tagsCount, camerasCount, + filmSimulationsCount, + lensesCount, dateRange, }: { photosCount: number tagsCount: number camerasCount: number + filmSimulationsCount: number + lensesCount: number dateRange?: PhotoDateRange }) { const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); @@ -22,19 +26,23 @@ export default function AdminAppInsightsClient({ 'mt-2 mb-6', )}>
- Photo library + Library stats
Photos
{photosCount}
-
Tags
+
Tags
{tagsCount}
-
Cameras
+
Cameras
{camerasCount}
+
Films
+
{filmSimulationsCount}
+
Lenses
+
{lensesCount}
{descriptionWithSpaces} From 1781a5e9c57f938537488a07279b8b2fc453f1e6 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 11 Feb 2025 00:13:23 -0600 Subject: [PATCH 15/54] Add sample template recommendation --- src/admin/AdminAppInsightsClient.tsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 5029d54c..4f868cc4 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -1,7 +1,9 @@ 'use client'; +import Note from '@/components/Note'; import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; import clsx from 'clsx/lite'; +import { FaCodeFork } from 'react-icons/fa6'; export default function AdminAppInsightsClient({ photosCount, @@ -22,16 +24,26 @@ export default function AdminAppInsightsClient({ return (
-
- Library stats +
+ Template Recommendations +
+ } + className="w-[clamp(300px,80%,1000px)] m-auto" + > + Consider forking this repository in order to + receive new features and fixes + +
+ Library Stats
Photos
{photosCount}
From a1746542972865f2d2ca0d457ccb846bfa90ce60 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 11 Feb 2025 18:06:15 -0600 Subject: [PATCH 16/54] Refactor app/site/admin code paths --- __tests__/github.test.ts | 2 +- __tests__/path.test.ts | 2 +- src/admin/AdminAddAllUploads.tsx | 2 +- src/admin/AdminAppConfiguration.tsx | 20 +++ .../AdminAppConfigurationClient.tsx} | 48 +++---- .../AdminAppConfigurationServer.tsx} | 10 +- src/admin/AdminAppInsights.tsx | 28 +++- src/admin/AdminAppInsightsClient.tsx | 126 ++++++++++++------ src/admin/AdminAppMenu.tsx | 2 +- src/admin/AdminBatchEditPanelClient.tsx | 2 +- src/admin/AdminCTA.tsx | 2 +- src/admin/AdminNav.tsx | 2 +- src/admin/AdminNavClient.tsx | 2 +- src/admin/AdminOutdatedClient.tsx | 4 +- src/admin/AdminPhotoMenuClient.tsx | 2 +- src/admin/AdminPhotosClient.tsx | 4 +- src/admin/AdminPhotosTable.tsx | 2 +- src/admin/AdminPhotosTableInfinite.tsx | 2 +- src/admin/AdminTagTable.tsx | 2 +- src/admin/AdminUploadsTable.tsx | 2 +- src/admin/DeleteBlobButton.tsx | 2 +- src/admin/ExifSyncButton.tsx | 2 +- src/admin/PhotoSyncButton.tsx | 2 +- src/admin/actions.ts | 4 +- src/admin/github/GitHubForkStatusBadge.tsx | 2 +- .../github/GitHubForkStatusBadgeServer.tsx | 2 +- src/admin/github/index.ts | 2 +- src/{site => app-core}/CommandK.tsx | 0 src/{site => app-core}/Footer.tsx | 4 +- src/{site => app-core}/IconFeed.tsx | 0 src/{site => app-core}/IconGrSync.tsx | 0 src/{site => app-core}/IconGrid.tsx | 0 src/{site => app-core}/IconSearch.tsx | 0 src/{site => app-core}/Nav.tsx | 4 +- src/{site => app-core}/SecretGenerator.tsx | 0 src/{site => app-core}/ThemeSwitcher.tsx | 0 src/{site => app-core}/ViewSwitcher.tsx | 6 +- src/{site => app-core}/api.ts | 0 src/{site => app-core}/config.ts | 12 +- src/{site => app-core}/font.ts | 0 src/{site => app-core}/paths.ts | 0 src/app/admin/configuration/page.tsx | 6 +- src/app/admin/insights/page.tsx | 5 +- src/app/admin/outdated/page.tsx | 2 +- src/app/admin/photos/[photoId]/edit/page.tsx | 4 +- src/app/admin/tags/[tag]/edit/page.tsx | 2 +- src/app/admin/uploads/[uploadPath]/page.tsx | 4 +- src/app/api/route.ts | 4 +- .../api/storage/presigned-url/[key]/route.ts | 2 +- src/app/film/[simulation]/[photoId]/page.tsx | 2 +- src/app/film/[simulation]/image/route.tsx | 4 +- src/app/film/[simulation]/page.tsx | 4 +- src/app/focal/[focal]/[photoId]/page.tsx | 2 +- src/app/focal/[focal]/image/route.tsx | 4 +- src/app/focal/[focal]/page.tsx | 6 +- src/app/home-image/route.tsx | 2 +- src/app/layout.tsx | 8 +- src/app/p/[photoId]/image/route.tsx | 4 +- src/app/p/[photoId]/page.tsx | 4 +- src/app/page.tsx | 2 +- .../shot-on/[make]/[model]/[photoId]/page.tsx | 2 +- .../shot-on/[make]/[model]/image/route.tsx | 4 +- src/app/shot-on/[make]/[model]/page.tsx | 4 +- src/app/sign-in/page.tsx | 2 +- src/app/tag/[tag]/[photoId]/page.tsx | 2 +- src/app/tag/[tag]/image/route.tsx | 4 +- src/app/tag/[tag]/page.tsx | 6 +- src/app/tag/hidden/[photoId]/page.tsx | 2 +- src/app/tag/hidden/page.tsx | 2 +- src/app/template-image-tight/route.tsx | 2 +- src/app/template-image/route.tsx | 2 +- src/auth/actions.ts | 2 +- src/auth/index.ts | 2 +- src/camera/CameraOGTile.tsx | 2 +- src/camera/CameraShareModal.tsx | 2 +- src/camera/PhotoCamera.tsx | 2 +- src/camera/meta.ts | 2 +- .../{Checklist.tsx => ChecklistGroup.tsx} | 2 +- src/components/Container.tsx | 12 +- src/components/HttpStatusPage.tsx | 2 +- src/components/Modal.tsx | 4 +- src/components/SwitcherItem.tsx | 2 +- src/components/cmdk/CommandKClient.tsx | 4 +- src/components/image/ImageLarge.tsx | 2 +- src/components/image/ImageWithFallback.tsx | 2 +- src/components/image/useImageZoomControls.ts | 2 +- src/focal/FocalLengthOGTile.tsx | 2 +- src/focal/FocalLengthShareModal.tsx | 2 +- src/focal/PhotoFocalLength.tsx | 2 +- src/focal/index.ts | 2 +- src/image-response/HomeImageResponse.tsx | 2 +- src/image-response/PhotoImageResponse.tsx | 2 +- src/image-response/TemplateImageResponse.tsx | 4 +- .../components/ImageCaption.tsx | 2 +- .../components/ImagePhotoGrid.tsx | 2 +- src/middleware.ts | 2 +- src/photo/InfinitePhotoScroll.tsx | 2 +- src/photo/PhotoEditPageClient.tsx | 2 +- src/photo/PhotoEscapeHandler.tsx | 2 +- src/photo/PhotoGrid.tsx | 2 +- src/photo/PhotoGridPage.tsx | 2 +- src/photo/PhotoGridSidebar.tsx | 2 +- src/photo/PhotoLarge.tsx | 4 +- src/photo/PhotoLink.tsx | 2 +- src/photo/PhotoMedium.tsx | 4 +- src/photo/PhotoOGTile.tsx | 2 +- src/photo/PhotoPrevNext.tsx | 2 +- src/photo/PhotoShareModal.tsx | 2 +- src/photo/PhotoSmall.tsx | 4 +- src/photo/PhotoUpload.tsx | 2 +- src/photo/PhotosEmptyState.tsx | 8 +- src/photo/PhotosLargeInfinite.tsx | 2 +- src/photo/StaggeredOgPhotosInfinite.tsx | 2 +- src/photo/UploadPageClient.tsx | 2 +- src/photo/actions.ts | 4 +- src/photo/cache.ts | 2 +- src/photo/data.ts | 2 +- src/photo/db/index.ts | 2 +- src/photo/db/query.ts | 2 +- src/photo/form/PhotoForm.tsx | 4 +- src/photo/form/index.ts | 2 +- src/photo/index.ts | 8 +- src/photo/server.ts | 5 +- src/services/next-image.ts | 2 +- src/services/openai.ts | 2 +- src/services/postgres.ts | 2 +- src/services/storage/index.ts | 4 +- src/services/storage/vercel-blob.ts | 2 +- src/share/ShareModal.tsx | 2 +- src/share/index.ts | 2 +- src/simulation/FilmSimulationOGTile.tsx | 2 +- src/simulation/FilmSimulationShareModal.tsx | 2 +- src/simulation/PhotoFilmSimulation.tsx | 2 +- src/simulation/index.ts | 2 +- src/site/SiteChecklist.tsx | 20 --- src/state/AppStateProvider.tsx | 2 +- src/tag/FavsTag.tsx | 2 +- src/tag/HiddenTag.tsx | 2 +- src/tag/PhotoTag.tsx | 2 +- src/tag/TagForm.tsx | 2 +- src/tag/TagOGTile.tsx | 2 +- src/tag/TagShareModal.tsx | 2 +- src/tag/index.ts | 2 +- src/{site => utility}/useMetaThemeColor.ts | 0 src/utility/vercel.ts | 2 +- 145 files changed, 341 insertions(+), 277 deletions(-) create mode 100644 src/admin/AdminAppConfiguration.tsx rename src/{site/SiteChecklistClient.tsx => admin/AdminAppConfigurationClient.tsx} (96%) rename src/{site/SiteChecklistServer.tsx => admin/AdminAppConfigurationServer.tsx} (51%) rename src/{site => app-core}/CommandK.tsx (100%) rename src/{site => app-core}/Footer.tsx (95%) rename src/{site => app-core}/IconFeed.tsx (100%) rename src/{site => app-core}/IconGrSync.tsx (100%) rename src/{site => app-core}/IconGrid.tsx (100%) rename src/{site => app-core}/IconSearch.tsx (100%) rename src/{site => app-core}/Nav.tsx (96%) rename src/{site => app-core}/SecretGenerator.tsx (100%) rename src/{site => app-core}/ThemeSwitcher.tsx (100%) rename src/{site => app-core}/ViewSwitcher.tsx (93%) rename src/{site => app-core}/api.ts (100%) rename src/{site => app-core}/config.ts (98%) rename src/{site => app-core}/font.ts (100%) rename src/{site => app-core}/paths.ts (100%) rename src/components/{Checklist.tsx => ChecklistGroup.tsx} (97%) delete mode 100644 src/site/SiteChecklist.tsx rename src/{site => utility}/useMetaThemeColor.ts (100%) diff --git a/__tests__/github.test.ts b/__tests__/github.test.ts index 2f7a0442..552ea006 100644 --- a/__tests__/github.test.ts +++ b/__tests__/github.test.ts @@ -1,5 +1,5 @@ import { getGitHubMetaWithFallback, getGitHubPublicFork } from '@/admin/github'; -import { TEMPLATE_BASE_OWNER, TEMPLATE_BASE_REPO } from '@/site/config'; +import { TEMPLATE_BASE_OWNER, TEMPLATE_BASE_REPO } from '@/app-core/config'; describe('GitHub', () => { it('fetches base repo meta', async () => { diff --git a/__tests__/path.test.ts b/__tests__/path.test.ts index 5aeead2f..77f2c737 100644 --- a/__tests__/path.test.ts +++ b/__tests__/path.test.ts @@ -12,7 +12,7 @@ import { isPathProtected, isPathTag, isPathTagPhoto, -} from '@/site/paths'; +} from '@/app-core/paths'; import { TAG_HIDDEN } from '@/tag'; const PHOTO_ID = 'UsKSGcbt'; diff --git a/src/admin/AdminAddAllUploads.tsx b/src/admin/AdminAddAllUploads.tsx index b14f6939..71b31d56 100644 --- a/src/admin/AdminAddAllUploads.tsx +++ b/src/admin/AdminAddAllUploads.tsx @@ -4,7 +4,7 @@ import ErrorNote from '@/components/ErrorNote'; import FieldSetWithStatus from '@/components/FieldSetWithStatus'; import Container from '@/components/Container'; import { addAllUploadsAction } from '@/photo/actions'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS } from '@/app-core/paths'; import { Tags } from '@/tag'; import { generateLocalNaivePostgresString, diff --git a/src/admin/AdminAppConfiguration.tsx b/src/admin/AdminAppConfiguration.tsx new file mode 100644 index 00000000..bc4dbc69 --- /dev/null +++ b/src/admin/AdminAppConfiguration.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react'; +import { APP_CONFIGURATION } from '@/app-core/config'; +import AdminAppConfigurationServer from './AdminAppConfigurationServer'; +import AdminAppConfigurationClient from './AdminAppConfigurationClient'; + +export default function AdminAppConfiguration({ + simplifiedView, +}: { + simplifiedView?: boolean +}) { + return ( + }> + + + ); +} diff --git a/src/site/SiteChecklistClient.tsx b/src/admin/AdminAppConfigurationClient.tsx similarity index 96% rename from src/site/SiteChecklistClient.tsx rename to src/admin/AdminAppConfigurationClient.tsx index 315bbfc0..5dbb6505 100644 --- a/src/site/SiteChecklistClient.tsx +++ b/src/admin/AdminAppConfigurationClient.tsx @@ -14,8 +14,8 @@ import { BiPencil, } from 'react-icons/bi'; import { HiOutlineCog } from 'react-icons/hi'; -import Checklist from '@/components/Checklist'; -import { ConfigChecklistStatus } from './config'; +import ChecklistGroup from '@/components/ChecklistGroup'; +import { ConfigChecklistStatus } from '../app-core/config'; import StatusIcon from '@/components/StatusIcon'; import { labelForStorage } from '@/services/storage'; import { HiSparkles } from 'react-icons/hi'; @@ -24,13 +24,13 @@ import ErrorNote from '@/components/ErrorNote'; import WarningNote from '@/components/WarningNote'; import { RiSpeedMiniLine } from 'react-icons/ri'; import Link from 'next/link'; -import SecretGenerator from './SecretGenerator'; +import SecretGenerator from '../app-core/SecretGenerator'; import CopyButton from '@/components/CopyButton'; import { PiPaintBrushHousehold } from 'react-icons/pi'; import { IoMdGrid } from 'react-icons/io'; import { CgDebug } from 'react-icons/cg'; -export default function SiteChecklistClient({ +export default function AdminAppConfigurationClient({ // Storage hasDatabase, isPostgresSslEnabled, @@ -215,7 +215,7 @@ export default function SiteChecklistClient({ return (
- } > @@ -300,8 +300,8 @@ export default function SiteChecklistClient({ )} )} - - + } > @@ -331,8 +331,8 @@ export default function SiteChecklistClient({ 'ADMIN_PASSWORD', ])} - - + } > @@ -373,9 +373,9 @@ export default function SiteChecklistClient({ Store in environment variable (seen in grid sidebar): {renderEnvVars(['NEXT_PUBLIC_SITE_ABOUT'])} - + {!simplifiedView && <> - } @@ -429,8 +429,8 @@ export default function SiteChecklistClient({ (default: {'"title, tags, semantic"'}): {renderEnvVars(['AI_TEXT_AUTO_GENERATED_FIELDS'])} - - + } optional @@ -490,8 +490,8 @@ export default function SiteChecklistClient({ image blur data being stored and displayed: {renderEnvVars(['NEXT_PUBLIC_BLUR_DISABLED'])} - - + } optional @@ -518,8 +518,8 @@ export default function SiteChecklistClient({ of each photo, and display a surrounding border: {renderEnvVars(['NEXT_PUBLIC_MATTE_PHOTOS'])} - - + } optional @@ -578,8 +578,8 @@ export default function SiteChecklistClient({ Set environment variable to {'"1"'} to hide footer link: {renderEnvVars(['NEXT_PUBLIC_HIDE_REPO_LINK'])} - - + } optional @@ -613,8 +613,8 @@ export default function SiteChecklistClient({ aspect ratio): {renderEnvVars(['NEXT_PUBLIC_SHOW_LARGE_THUMBNAILS'])} - - + } optional @@ -664,9 +664,9 @@ export default function SiteChecklistClient({ keep OG image text bottom aligned (default is {'"top"'}): {renderEnvVars(['NEXT_PUBLIC_OG_TEXT_ALIGNMENT'])} - + {areInternalToolsEnabled && - } optional @@ -698,7 +698,7 @@ export default function SiteChecklistClient({ console output for all sql queries: {renderEnvVars(['ADMIN_SQL_DEBUG'])} - } + } }
diff --git a/src/site/SiteChecklistServer.tsx b/src/admin/AdminAppConfigurationServer.tsx similarity index 51% rename from src/site/SiteChecklistServer.tsx rename to src/admin/AdminAppConfigurationServer.tsx index e50255ab..0f19eb2c 100644 --- a/src/site/SiteChecklistServer.tsx +++ b/src/admin/AdminAppConfigurationServer.tsx @@ -1,8 +1,8 @@ -import SiteChecklistClient from './SiteChecklistClient'; -import { CONFIG_CHECKLIST_STATUS } from '@/site/config'; +import AdminAppConfigurationClient from './AdminAppConfigurationClient'; +import { APP_CONFIGURATION } from '@/app-core/config'; import { testConnectionsAction } from '@/admin/actions'; -export default async function SiteChecklistServer({ +export default async function AdminAppConfigurationServer({ simplifiedView, }: { simplifiedView?: boolean @@ -10,8 +10,8 @@ export default async function SiteChecklistServer({ const connectionErrors = await testConnectionsAction().catch(() => ({})); return ( - diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index 6aea957a..9d489ba3 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -6,7 +6,7 @@ import { getUniqueTags, } from '@/photo/db/query'; import AdminAppInsightsClient from './AdminAppInsightsClient'; - +import { APP_CONFIGURATION, IS_DEVELOPMENT } from '@/app-core/config'; export default async function AdminAppInsights() { const [ { count, dateRange }, @@ -22,14 +22,28 @@ export default async function AdminAppInsights() { getUniqueLenses(), ]); + const { + isAiTextGenerationEnabled, + hasVercelBlobStorage, + } = APP_CONFIGURATION; + return ( ); } diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 4f868cc4..329635d4 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -1,63 +1,103 @@ 'use client'; +import IconGrSync from '@/app-core/IconGrSync'; import Note from '@/components/Note'; +import WarningNote from '@/components/WarningNote'; import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; import clsx from 'clsx/lite'; -import { FaCodeFork } from 'react-icons/fa6'; +import { HiSparkles } from 'react-icons/hi'; + +type Recommendation = + 'fork' | + 'forkBehind' | + 'ai' | + 'aiRateLimiting'; export default function AdminAppInsightsClient({ - photosCount, - tagsCount, - camerasCount, - filmSimulationsCount, - lensesCount, - dateRange, + recommendations: { + fork, + forkBehind, + ai, + aiRateLimiting, + }, + photoStats: { + photosCount, + tagsCount, + camerasCount, + filmSimulationsCount, + lensesCount, + dateRange, + }, + debug, }: { - photosCount: number - tagsCount: number - camerasCount: number - filmSimulationsCount: number - lensesCount: number - dateRange?: PhotoDateRange + recommendations: Record, + photoStats: { + photosCount: number + tagsCount: number + camerasCount: number + filmSimulationsCount: number + lensesCount: number + dateRange?: PhotoDateRange + }, + debug?: boolean, }) { + const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); + const renderTitle = (title: string) => +
+ {title} +
; + return (
-
- Template Recommendations -
- } - className="w-[clamp(300px,80%,1000px)] m-auto" - > - Consider forking this repository in order to - receive new features and fixes - -
- Library Stats -
-
Photos
-
{photosCount}
-
Tags
-
{tagsCount}
-
Cameras
-
{camerasCount}
-
Films
-
{filmSimulationsCount}
-
Lenses
-
{lensesCount}
- - {descriptionWithSpaces} - + {renderTitle('Code Observability')} + {(fork || debug) && + }> + Consider forking this repository in order to + receive new features and fixes + } + {(forkBehind || debug) && + + This fork is 9 commits behind + } + {renderTitle('Template Recommendations')} + {(ai || debug) && }> + Enable AI text generation in the app configuration + } + {(aiRateLimiting || debug) && + Consider enabling rate limiting to mitigate AI abuse + } + {renderTitle('Library Stats')} +
+
Photos
+
{photosCount}
+
Tags
+
{tagsCount}
+
Cameras
+
{camerasCount}
+
Films
+
{filmSimulationsCount}
+
Lenses
+
{lensesCount}
+ + {descriptionWithSpaces} + +
); diff --git a/src/admin/AdminAppMenu.tsx b/src/admin/AdminAppMenu.tsx index 1835ea05..60ffa121 100644 --- a/src/admin/AdminAppMenu.tsx +++ b/src/admin/AdminAppMenu.tsx @@ -1,7 +1,7 @@ 'use client'; import MoreMenu from '@/components/more/MoreMenu'; -import { PATH_ADMIN_CONFIGURATION, PATH_GRID_INFERRED } from '@/site/paths'; +import { PATH_ADMIN_CONFIGURATION, PATH_GRID_INFERRED } from '@/app-core/paths'; import { useAppState } from '@/state/AppState'; import { BiCog } from 'react-icons/bi'; import { ImCheckboxUnchecked } from 'react-icons/im'; diff --git a/src/admin/AdminBatchEditPanelClient.tsx b/src/admin/AdminBatchEditPanelClient.tsx index 91a487bc..e108c6cd 100644 --- a/src/admin/AdminBatchEditPanelClient.tsx +++ b/src/admin/AdminBatchEditPanelClient.tsx @@ -9,7 +9,7 @@ import { IoCloseSharp } from 'react-icons/io5'; import { useState } from 'react'; import { TAG_FAVS, Tags } from '@/tag'; import { usePathname } from 'next/navigation'; -import { PATH_GRID_INFERRED } from '@/site/paths'; +import { PATH_GRID_INFERRED } from '@/app-core/paths'; import PhotoTagFieldset from './PhotoTagFieldset'; import { tagMultiplePhotosAction } from '@/photo/actions'; import { toastSuccess } from '@/toast'; diff --git a/src/admin/AdminCTA.tsx b/src/admin/AdminCTA.tsx index 92fae7b4..74ea1015 100644 --- a/src/admin/AdminCTA.tsx +++ b/src/admin/AdminCTA.tsx @@ -1,7 +1,7 @@ 'use client'; import PhotoUpload from '@/photo/PhotoUpload'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS } from '@/app-core/paths'; import { useAppState } from '@/state/AppState'; import Link from 'next/link'; import { useState } from 'react'; diff --git a/src/admin/AdminNav.tsx b/src/admin/AdminNav.tsx index a87a15d9..aa1110da 100644 --- a/src/admin/AdminNav.tsx +++ b/src/admin/AdminNav.tsx @@ -8,7 +8,7 @@ import { PATH_ADMIN_PHOTOS, PATH_ADMIN_TAGS, PATH_ADMIN_UPLOADS, -} from '@/site/paths'; +} from '@/app-core/paths'; import AdminNavClient from './AdminNavClient'; export default async function AdminNav() { diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index b08ec7f4..2331bcae 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -12,7 +12,7 @@ import { isPathAdminConfiguration, isPathAdminInsights, isPathTopLevelAdmin, -} from '@/site/paths'; +} from '@/app-core/paths'; import { useAppState } from '@/state/AppState'; import { clsx } from 'clsx/lite'; import { differenceInMinutes } from 'date-fns'; diff --git a/src/admin/AdminOutdatedClient.tsx b/src/admin/AdminOutdatedClient.tsx index b09653ac..2ee82d62 100644 --- a/src/admin/AdminOutdatedClient.tsx +++ b/src/admin/AdminOutdatedClient.tsx @@ -3,10 +3,10 @@ import { OUTDATED_THRESHOLD, Photo } from '@/photo'; import AdminPhotosTable from '@/admin/AdminPhotosTable'; import LoaderButton from '@/components/primitives/LoaderButton'; -import IconGrSync from '@/site/IconGrSync'; +import IconGrSync from '@/app-core/IconGrSync'; import Note from '@/components/Note'; import AdminChildPage from '@/components/AdminChildPage'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS } from '@/app-core/paths'; import { useState } from 'react'; import { syncPhotosAction } from '@/photo/actions'; import { useRouter } from 'next/navigation'; diff --git a/src/admin/AdminPhotoMenuClient.tsx b/src/admin/AdminPhotoMenuClient.tsx index e73f0629..2feade73 100644 --- a/src/admin/AdminPhotoMenuClient.tsx +++ b/src/admin/AdminPhotoMenuClient.tsx @@ -1,7 +1,7 @@ 'use client'; import { ComponentProps, useMemo } from 'react'; -import { pathForAdminPhotoEdit, pathForPhoto } from '@/site/paths'; +import { pathForAdminPhotoEdit, pathForPhoto } from '@/app-core/paths'; import { deletePhotoAction, toggleFavoritePhotoAction } from '@/photo/actions'; import { FaRegEdit, FaRegStar, FaStar } from 'react-icons/fa'; import { diff --git a/src/admin/AdminPhotosClient.tsx b/src/admin/AdminPhotosClient.tsx index 073004d1..35015494 100644 --- a/src/admin/AdminPhotosClient.tsx +++ b/src/admin/AdminPhotosClient.tsx @@ -6,11 +6,11 @@ import SiteGrid from '@/components/SiteGrid'; import { AI_TEXT_GENERATION_ENABLED, PRESERVE_ORIGINAL_UPLOADS, -} from '@/site/config'; +} from '@/app-core/config'; import AdminPhotosTable from '@/admin/AdminPhotosTable'; import AdminPhotosTableInfinite from '@/admin/AdminPhotosTableInfinite'; import PathLoaderButton from '@/components/primitives/PathLoaderButton'; -import { PATH_ADMIN_OUTDATED } from '@/site/paths'; +import { PATH_ADMIN_OUTDATED } from '@/app-core/paths'; import { Photo } from '@/photo'; import { StorageListResponse } from '@/services/storage'; import { useState } from 'react'; diff --git a/src/admin/AdminPhotosTable.tsx b/src/admin/AdminPhotosTable.tsx index 357ae9c1..0e8d8ca6 100644 --- a/src/admin/AdminPhotosTable.tsx +++ b/src/admin/AdminPhotosTable.tsx @@ -5,7 +5,7 @@ import AdminTable from './AdminTable'; import { Fragment } from 'react'; import PhotoSmall from '@/photo/PhotoSmall'; import { clsx } from 'clsx/lite'; -import { pathForAdminPhotoEdit, pathForPhoto } from '@/site/paths'; +import { pathForAdminPhotoEdit, pathForPhoto } from '@/app-core/paths'; import Link from 'next/link'; import { AiOutlineEyeInvisible } from 'react-icons/ai'; import PhotoDate from '@/photo/PhotoDate'; diff --git a/src/admin/AdminPhotosTableInfinite.tsx b/src/admin/AdminPhotosTableInfinite.tsx index 3dcc7c9d..65376dfe 100644 --- a/src/admin/AdminPhotosTableInfinite.tsx +++ b/src/admin/AdminPhotosTableInfinite.tsx @@ -1,6 +1,6 @@ 'use client'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS } from '@/app-core/paths'; import InfinitePhotoScroll from '../photo/InfinitePhotoScroll'; import AdminPhotosTable from './AdminPhotosTable'; import { ComponentProps } from 'react'; diff --git a/src/admin/AdminTagTable.tsx b/src/admin/AdminTagTable.tsx index a5bdfc5d..cf93cf99 100644 --- a/src/admin/AdminTagTable.tsx +++ b/src/admin/AdminTagTable.tsx @@ -6,7 +6,7 @@ import DeleteFormButton from '@/admin/DeleteFormButton'; import { photoQuantityText } from '@/photo'; import { Tags, formatTag, sortTagsObject } from '@/tag'; import EditButton from '@/admin/EditButton'; -import { pathForAdminTagEdit } from '@/site/paths'; +import { pathForAdminTagEdit } from '@/app-core/paths'; import { clsx } from 'clsx/lite'; import AdminTagBadge from './AdminTagBadge'; diff --git a/src/admin/AdminUploadsTable.tsx b/src/admin/AdminUploadsTable.tsx index edeb0603..027c4a53 100644 --- a/src/admin/AdminUploadsTable.tsx +++ b/src/admin/AdminUploadsTable.tsx @@ -5,7 +5,7 @@ import Spinner from '@/components/Spinner'; import { getIdFromStorageUrl } from '@/services/storage'; import { clsx } from 'clsx/lite'; import { FaRegCircleCheck } from 'react-icons/fa6'; -import { pathForAdminUploadUrl } from '@/site/paths'; +import { pathForAdminUploadUrl } from '@/app-core/paths'; import AddButton from './AddButton'; import { UrlAddStatus } from './AdminUploadsClient'; import ResponsiveDate from '@/components/ResponsiveDate'; diff --git a/src/admin/DeleteBlobButton.tsx b/src/admin/DeleteBlobButton.tsx index 8e30e030..10d483f0 100644 --- a/src/admin/DeleteBlobButton.tsx +++ b/src/admin/DeleteBlobButton.tsx @@ -3,7 +3,7 @@ import { deleteUploadAction } from '@/photo/actions'; import DeleteButton from './DeleteButton'; import { useRouter } from 'next/navigation'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS } from '@/app-core/paths'; import { useState } from 'react'; export default function DeleteUploadButton({ diff --git a/src/admin/ExifSyncButton.tsx b/src/admin/ExifSyncButton.tsx index 517bcbe5..f968e5d2 100644 --- a/src/admin/ExifSyncButton.tsx +++ b/src/admin/ExifSyncButton.tsx @@ -4,7 +4,7 @@ import LoaderButton from '@/components/primitives/LoaderButton'; import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; import { getExifDataAction } from '@/photo/actions'; import { PhotoFormData } from '@/photo/form'; -import IconGrSync from '@/site/IconGrSync'; +import IconGrSync from '@/app-core/IconGrSync'; import { clsx } from 'clsx/lite'; import { ComponentProps, useState } from 'react'; diff --git a/src/admin/PhotoSyncButton.tsx b/src/admin/PhotoSyncButton.tsx index ea410d82..07e0709d 100644 --- a/src/admin/PhotoSyncButton.tsx +++ b/src/admin/PhotoSyncButton.tsx @@ -1,6 +1,6 @@ import LoaderButton from '@/components/primitives/LoaderButton'; import { syncPhotoAction } from '@/photo/actions'; -import IconGrSync from '@/site/IconGrSync'; +import IconGrSync from '@/app-core/IconGrSync'; import { toastSuccess } from '@/toast'; import { ComponentProps, useState } from 'react'; diff --git a/src/admin/actions.ts b/src/admin/actions.ts index e2ddd1ae..ee366c7a 100644 --- a/src/admin/actions.ts +++ b/src/admin/actions.ts @@ -5,7 +5,7 @@ import { testKvConnection } from '@/services/kv'; import { testOpenAiConnection } from '@/services/openai'; import { testDatabaseConnection } from '@/services/postgres'; import { testStorageConnection } from '@/services/storage'; -import { CONFIG_CHECKLIST_STATUS } from '@/site/config'; +import { APP_CONFIGURATION } from '@/app-core/config'; const scanForError = ( shouldCheck: boolean, @@ -24,7 +24,7 @@ export const testConnectionsAction = async () => hasStorageProvider, hasVercelKv, isAiTextGenerationEnabled, - } = CONFIG_CHECKLIST_STATUS; + } = APP_CONFIGURATION; const [ databaseError, diff --git a/src/admin/github/GitHubForkStatusBadge.tsx b/src/admin/github/GitHubForkStatusBadge.tsx index 0af8dbbb..6faf63ef 100644 --- a/src/admin/github/GitHubForkStatusBadge.tsx +++ b/src/admin/github/GitHubForkStatusBadge.tsx @@ -1,7 +1,7 @@ import { Suspense } from 'react'; import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient'; import GitHubForkStatusBadgeServer from './GitHubForkStatusBadgeServer'; -import { IS_DEVELOPMENT } from '@/site/config'; +import { IS_DEVELOPMENT } from '@/app-core/config'; export default function GitHubForkStatusBadge() { return IS_DEVELOPMENT diff --git a/src/admin/github/GitHubForkStatusBadgeServer.tsx b/src/admin/github/GitHubForkStatusBadgeServer.tsx index faf3d99c..f1bb8f02 100644 --- a/src/admin/github/GitHubForkStatusBadgeServer.tsx +++ b/src/admin/github/GitHubForkStatusBadgeServer.tsx @@ -4,7 +4,7 @@ import { VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_SLUG, VERCEL_GIT_COMMIT_SHA, -} from '@/site/config'; +} from '@/app-core/config'; import { getGitHubMetaWithFallback, getGitHubRepoUrl } from '.'; export default async function GitHubForkStatusBadgeServer() { diff --git a/src/admin/github/index.ts b/src/admin/github/index.ts index f04491d5..f6625b05 100644 --- a/src/admin/github/index.ts +++ b/src/admin/github/index.ts @@ -2,7 +2,7 @@ import { TEMPLATE_BASE_OWNER, TEMPLATE_BASE_REPO, TEMPLATE_BASE_BRANCH, -} from '@/site/config'; +} from '@/app-core/config'; const DEFAULT_BRANCH = 'main'; const FALLBACK_TEXT = 'Unknown'; diff --git a/src/site/CommandK.tsx b/src/app-core/CommandK.tsx similarity index 100% rename from src/site/CommandK.tsx rename to src/app-core/CommandK.tsx diff --git a/src/site/Footer.tsx b/src/app-core/Footer.tsx similarity index 95% rename from src/site/Footer.tsx rename to src/app-core/Footer.tsx index 12bcfe30..2fab4de5 100644 --- a/src/site/Footer.tsx +++ b/src/app-core/Footer.tsx @@ -2,9 +2,9 @@ import { clsx } from 'clsx/lite'; import SiteGrid from '../components/SiteGrid'; -import ThemeSwitcher from '@/site/ThemeSwitcher'; +import ThemeSwitcher from '@/app-core/ThemeSwitcher'; import Link from 'next/link'; -import { SHOW_REPO_LINK } from '@/site/config'; +import { SHOW_REPO_LINK } from '@/app-core/config'; import RepoLink from '../components/RepoLink'; import { usePathname } from 'next/navigation'; import { PATH_ADMIN_PHOTOS, isPathAdmin, isPathSignIn } from './paths'; diff --git a/src/site/IconFeed.tsx b/src/app-core/IconFeed.tsx similarity index 100% rename from src/site/IconFeed.tsx rename to src/app-core/IconFeed.tsx diff --git a/src/site/IconGrSync.tsx b/src/app-core/IconGrSync.tsx similarity index 100% rename from src/site/IconGrSync.tsx rename to src/app-core/IconGrSync.tsx diff --git a/src/site/IconGrid.tsx b/src/app-core/IconGrid.tsx similarity index 100% rename from src/site/IconGrid.tsx rename to src/app-core/IconGrid.tsx diff --git a/src/site/IconSearch.tsx b/src/app-core/IconSearch.tsx similarity index 100% rename from src/site/IconSearch.tsx rename to src/app-core/IconSearch.tsx diff --git a/src/site/Nav.tsx b/src/app-core/Nav.tsx similarity index 96% rename from src/site/Nav.tsx rename to src/app-core/Nav.tsx index 6f3bf2e0..07715a4c 100644 --- a/src/site/Nav.tsx +++ b/src/app-core/Nav.tsx @@ -4,7 +4,7 @@ import { clsx } from 'clsx/lite'; import { usePathname } from 'next/navigation'; import Link from 'next/link'; import SiteGrid from '../components/SiteGrid'; -import ViewSwitcher, { SwitcherSelection } from '@/site/ViewSwitcher'; +import ViewSwitcher, { SwitcherSelection } from '@/app-core/ViewSwitcher'; import { PATH_ROOT, isPathAdmin, @@ -12,7 +12,7 @@ import { isPathGrid, isPathProtected, isPathSignIn, -} from '@/site/paths'; +} from '@/app-core/paths'; import AnimateItems from '../components/AnimateItems'; import { useAppState } from '@/state/AppState'; import { diff --git a/src/site/SecretGenerator.tsx b/src/app-core/SecretGenerator.tsx similarity index 100% rename from src/site/SecretGenerator.tsx rename to src/app-core/SecretGenerator.tsx diff --git a/src/site/ThemeSwitcher.tsx b/src/app-core/ThemeSwitcher.tsx similarity index 100% rename from src/site/ThemeSwitcher.tsx rename to src/app-core/ThemeSwitcher.tsx diff --git a/src/site/ViewSwitcher.tsx b/src/app-core/ViewSwitcher.tsx similarity index 93% rename from src/site/ViewSwitcher.tsx rename to src/app-core/ViewSwitcher.tsx index 3d5a2baf..ab39720e 100644 --- a/src/site/ViewSwitcher.tsx +++ b/src/app-core/ViewSwitcher.tsx @@ -1,12 +1,12 @@ import Switcher from '@/components/Switcher'; import SwitcherItem from '@/components/SwitcherItem'; -import IconFeed from '@/site/IconFeed'; -import IconGrid from '@/site/IconGrid'; +import IconFeed from '@/app-core/IconFeed'; +import IconGrid from '@/app-core/IconGrid'; import { PATH_ADMIN_PHOTOS, PATH_FEED_INFERRED, PATH_GRID_INFERRED, -} from '@/site/paths'; +} from '@/app-core/paths'; import { BiLockAlt } from 'react-icons/bi'; import IconSearch from './IconSearch'; import { useAppState } from '@/state/AppState'; diff --git a/src/site/api.ts b/src/app-core/api.ts similarity index 100% rename from src/site/api.ts rename to src/app-core/api.ts diff --git a/src/site/config.ts b/src/app-core/config.ts similarity index 98% rename from src/site/config.ts rename to src/app-core/config.ts index f1326a22..449e0fe8 100644 --- a/src/site/config.ts +++ b/src/app-core/config.ts @@ -232,7 +232,7 @@ export const ADMIN_DEBUG_TOOLS_ENABLED = process.env.ADMIN_DEBUG_TOOLS === '1'; export const ADMIN_DB_OPTIMIZE_ENABLED = process.env.ADMIN_DB_OPTIMIZE === '1'; export const ADMIN_SQL_DEBUG_ENABLED = process.env.ADMIN_SQL_DEBUG === '1'; -export const CONFIG_CHECKLIST_STATUS = { +export const APP_CONFIGURATION = { // Storage hasDatabase: HAS_DATABASE, isPostgresSslEnabled: POSTGRES_SSL_ENABLED, @@ -326,11 +326,11 @@ export const CONFIG_CHECKLIST_STATUS = { commitUrl: VERCEL_GIT_COMMIT_URL, }; -export type ConfigChecklistStatus = typeof CONFIG_CHECKLIST_STATUS; +export type ConfigChecklistStatus = typeof APP_CONFIGURATION; export const IS_SITE_READY = - CONFIG_CHECKLIST_STATUS.hasDatabase && - CONFIG_CHECKLIST_STATUS.hasStorageProvider && - CONFIG_CHECKLIST_STATUS.hasAuthSecret && - CONFIG_CHECKLIST_STATUS.hasAdminUser; + APP_CONFIGURATION.hasDatabase && + APP_CONFIGURATION.hasStorageProvider && + APP_CONFIGURATION.hasAuthSecret && + APP_CONFIGURATION.hasAdminUser; \ No newline at end of file diff --git a/src/site/font.ts b/src/app-core/font.ts similarity index 100% rename from src/site/font.ts rename to src/app-core/font.ts diff --git a/src/site/paths.ts b/src/app-core/paths.ts similarity index 100% rename from src/site/paths.ts rename to src/app-core/paths.ts diff --git a/src/app/admin/configuration/page.tsx b/src/app/admin/configuration/page.tsx index a2a99905..59d27f49 100644 --- a/src/app/admin/configuration/page.tsx +++ b/src/app/admin/configuration/page.tsx @@ -1,14 +1,14 @@ import ClearCacheButton from '@/admin/ClearCacheButton'; -import SiteChecklist from '@/site/SiteChecklist'; +import AdminAppConfiguration from '@/admin/AdminAppConfiguration'; import AdminInfoPage from '@/admin/AdminInfoPage'; -export default function AdminConfigurationPage() { +export default function AdminAppConfigurationPage() { return ( } > - + ); } diff --git a/src/app/admin/insights/page.tsx b/src/app/admin/insights/page.tsx index 7a4d30f7..152ad524 100644 --- a/src/app/admin/insights/page.tsx +++ b/src/app/admin/insights/page.tsx @@ -1,7 +1,10 @@ import AdminAppInsights from '@/admin/AdminAppInsights'; import AdminInfoPage from '@/admin/AdminInfoPage'; import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; -import { IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB } from '@/site/config'; +import { + IS_DEVELOPMENT, + IS_VERCEL_GIT_PROVIDER_GITHUB, +} from '@/app-core/config'; export default async function AdminInsightsPage() { return Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined; diff --git a/src/app/film/[simulation]/page.tsx b/src/app/film/[simulation]/page.tsx index 0199457c..262d78fd 100644 --- a/src/app/film/[simulation]/page.tsx +++ b/src/app/film/[simulation]/page.tsx @@ -2,9 +2,9 @@ import { INFINITE_SCROLL_GRID_INITIAL } from '@/photo'; import { getUniqueFilmSimulations } from '@/photo/db/query'; import { FilmSimulation, generateMetaForFilmSimulation } from '@/simulation'; import FilmSimulationOverview from '@/simulation/FilmSimulationOverview'; -import { IS_PRODUCTION } from '@/site/config'; +import { IS_PRODUCTION } from '@/app-core/config'; import { getPhotosFilmSimulationDataCached } from '@/simulation/data'; -import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/site/config'; +import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/app-core/config'; import { Metadata } from 'next/types'; import { cache } from 'react'; diff --git a/src/app/focal/[focal]/[photoId]/page.tsx b/src/app/focal/[focal]/[photoId]/page.tsx index 1ca40aa1..85c4dc06 100644 --- a/src/app/focal/[focal]/[photoId]/page.tsx +++ b/src/app/focal/[focal]/[photoId]/page.tsx @@ -9,7 +9,7 @@ import { PATH_ROOT, absolutePathForPhoto, absolutePathForPhotoImage, -} from '@/site/paths'; +} from '@/app-core/paths'; import PhotoDetailPage from '@/photo/PhotoDetailPage'; import { getPhotosNearIdCached } from '@/photo/cache'; import { cache } from 'react'; diff --git a/src/app/focal/[focal]/image/route.tsx b/src/app/focal/[focal]/image/route.tsx index 44cc1558..79682cb0 100644 --- a/src/app/focal/[focal]/image/route.tsx +++ b/src/app/focal/[focal]/image/route.tsx @@ -3,7 +3,7 @@ import { IMAGE_OG_DIMENSION_SMALL, MAX_PHOTOS_TO_SHOW_PER_TAG, } from '@/image-response'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import FocalLengthImageResponse from @@ -14,7 +14,7 @@ import { getUniqueFocalLengths } from '@/photo/db/query'; import { STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES, IS_PRODUCTION, -} from '@/site/config'; +} from '@/app-core/config'; export let generateStaticParams: (() => Promise<{ focal: string }[]>) | undefined = undefined; diff --git a/src/app/focal/[focal]/page.tsx b/src/app/focal/[focal]/page.tsx index ed8d78a6..2d01680a 100644 --- a/src/app/focal/[focal]/page.tsx +++ b/src/app/focal/[focal]/page.tsx @@ -2,10 +2,10 @@ import { generateMetaForFocalLength, getFocalLengthFromString } from '@/focal'; import FocalLengthOverview from '@/focal/FocalLengthOverview'; import { getPhotosFocalLengthDataCached } from '@/focal/data'; import { INFINITE_SCROLL_GRID_INITIAL } from '@/photo'; -import { IS_PRODUCTION } from '@/site/config'; +import { IS_PRODUCTION } from '@/app-core/config'; import { getUniqueFocalLengths } from '@/photo/db/query'; -import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/site/config'; -import { PATH_ROOT } from '@/site/paths'; +import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/app-core/config'; +import { PATH_ROOT } from '@/app-core/paths'; import type { Metadata } from 'next'; import { redirect } from 'next/navigation'; import { cache } from 'react'; diff --git a/src/app/home-image/route.tsx b/src/app/home-image/route.tsx index 7cb7acf7..fa820f94 100644 --- a/src/app/home-image/route.tsx +++ b/src/app/home-image/route.tsx @@ -4,7 +4,7 @@ import { MAX_PHOTOS_TO_SHOW_OG, } from '@/image-response'; import HomeImageResponse from '@/image-response/HomeImageResponse'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { isNextImageReadyBasedOnPhotos } from '@/photo'; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index fbebb074..2e0d809b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -7,15 +7,15 @@ import { SITE_DESCRIPTION, SITE_DOMAIN_OR_TITLE, SITE_TITLE, -} from '@/site/config'; +} from '@/app-core/config'; import AppStateProvider from '@/state/AppStateProvider'; import ToasterWithThemes from '@/toast/ToasterWithThemes'; import PhotoEscapeHandler from '@/photo/PhotoEscapeHandler'; import { Metadata } from 'next/types'; import { ThemeProvider } from 'next-themes'; -import Nav from '@/site/Nav'; -import Footer from '@/site/Footer'; -import CommandK from '@/site/CommandK'; +import Nav from '@/app-core/Nav'; +import Footer from '@/app-core/Footer'; +import CommandK from '@/app-core/CommandK'; import SwrConfigClient from '../state/SwrConfigClient'; import AdminBatchEditPanel from '@/admin/AdminBatchEditPanel'; import ShareModals from '@/share/ShareModals'; diff --git a/src/app/p/[photoId]/image/route.tsx b/src/app/p/[photoId]/image/route.tsx index 73bf45ac..07be4e8f 100644 --- a/src/app/p/[photoId]/image/route.tsx +++ b/src/app/p/[photoId]/image/route.tsx @@ -1,13 +1,13 @@ import { getPhotoCached } from '@/photo/cache'; import { IMAGE_OG_DIMENSION } from '@/image-response'; import PhotoImageResponse from '@/image-response/PhotoImageResponse'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { IS_PRODUCTION, STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES, -} from '@/site/config'; +} from '@/app-core/config'; import { getPhotoIds } from '@/photo/db/query'; import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; import { isNextImageReadyBasedOnPhotos } from '@/photo'; diff --git a/src/app/p/[photoId]/page.tsx b/src/app/p/[photoId]/page.tsx index a84aa724..6097fbf1 100644 --- a/src/app/p/[photoId]/page.tsx +++ b/src/app/p/[photoId]/page.tsx @@ -9,10 +9,10 @@ import { PATH_ROOT, absolutePathForPhoto, absolutePathForPhotoImage, -} from '@/site/paths'; +} from '@/app-core/paths'; import PhotoDetailPage from '@/photo/PhotoDetailPage'; import { getPhotosNearIdCached } from '@/photo/cache'; -import { IS_PRODUCTION, STATICALLY_OPTIMIZED_PHOTOS } from '@/site/config'; +import { IS_PRODUCTION, STATICALLY_OPTIMIZED_PHOTOS } from '@/app-core/config'; import { getPhotoIds } from '@/photo/db/query'; import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; import { cache } from 'react'; diff --git a/src/app/page.tsx b/src/app/page.tsx index fb6a9f22..e74c5467 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,7 +7,7 @@ import PhotosEmptyState from '@/photo/PhotosEmptyState'; import { Metadata } from 'next/types'; import { cache } from 'react'; import { getPhotos, getPhotosMeta } from '@/photo/db/query'; -import { GRID_HOMEPAGE_ENABLED } from '@/site/config'; +import { GRID_HOMEPAGE_ENABLED } from '@/app-core/config'; import { getPhotoSidebarData } from '@/photo/data'; import PhotoGridPage from '@/photo/PhotoGridPage'; import PhotoFeedPage from '@/photo/PhotoFeedPage'; diff --git a/src/app/shot-on/[make]/[model]/[photoId]/page.tsx b/src/app/shot-on/[make]/[model]/[photoId]/page.tsx index 74972892..169e80f2 100644 --- a/src/app/shot-on/[make]/[model]/[photoId]/page.tsx +++ b/src/app/shot-on/[make]/[model]/[photoId]/page.tsx @@ -9,7 +9,7 @@ import { PATH_ROOT, absolutePathForPhoto, absolutePathForPhotoImage, -} from '@/site/paths'; +} from '@/app-core/paths'; import PhotoDetailPage from '@/photo/PhotoDetailPage'; import { getPhotosMetaCached, diff --git a/src/app/shot-on/[make]/[model]/image/route.tsx b/src/app/shot-on/[make]/[model]/image/route.tsx index fce1c7ac..b073b7f9 100644 --- a/src/app/shot-on/[make]/[model]/image/route.tsx +++ b/src/app/shot-on/[make]/[model]/image/route.tsx @@ -5,7 +5,7 @@ import { MAX_PHOTOS_TO_SHOW_PER_TAG, } from '@/image-response'; import CameraImageResponse from '@/image-response/CameraImageResponse'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; @@ -13,7 +13,7 @@ import { getUniqueCameras } from '@/photo/db/query'; import { STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES, IS_PRODUCTION, -} from '@/site/config'; +} from '@/app-core/config'; export let generateStaticParams: (() => Promise<{ camera: Camera }[]>) | undefined = undefined; diff --git a/src/app/shot-on/[make]/[model]/page.tsx b/src/app/shot-on/[make]/[model]/page.tsx index 2a776ee7..40ba15df 100644 --- a/src/app/shot-on/[make]/[model]/page.tsx +++ b/src/app/shot-on/[make]/[model]/page.tsx @@ -5,8 +5,8 @@ import { INFINITE_SCROLL_GRID_INITIAL } from '@/photo'; import { getPhotosCameraDataCached } from '@/camera/data'; import CameraOverview from '@/camera/CameraOverview'; import { cache } from 'react'; -import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/site/config'; -import { IS_PRODUCTION } from '@/site/config'; +import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/app-core/config'; +import { IS_PRODUCTION } from '@/app-core/config'; import { getUniqueCameras } from '@/photo/db/query'; const getPhotosCameraDataCachedCached = cache(( diff --git a/src/app/sign-in/page.tsx b/src/app/sign-in/page.tsx index 7fc5053c..f4a93638 100644 --- a/src/app/sign-in/page.tsx +++ b/src/app/sign-in/page.tsx @@ -1,6 +1,6 @@ import { auth } from '@/auth'; import SignInForm from '@/auth/SignInForm'; -import { PATH_ADMIN } from '@/site/paths'; +import { PATH_ADMIN } from '@/app-core/paths'; import { clsx } from 'clsx/lite'; import { redirect } from 'next/navigation'; diff --git a/src/app/tag/[tag]/[photoId]/page.tsx b/src/app/tag/[tag]/[photoId]/page.tsx index 186049dc..9120e9b8 100644 --- a/src/app/tag/[tag]/[photoId]/page.tsx +++ b/src/app/tag/[tag]/[photoId]/page.tsx @@ -9,7 +9,7 @@ import { PATH_ROOT, absolutePathForPhoto, absolutePathForPhotoImage, -} from '@/site/paths'; +} from '@/app-core/paths'; import PhotoDetailPage from '@/photo/PhotoDetailPage'; import { getPhotosNearIdCached } from '@/photo/cache'; import { cache } from 'react'; diff --git a/src/app/tag/[tag]/image/route.tsx b/src/app/tag/[tag]/image/route.tsx index 80e11bb1..a2dcb221 100644 --- a/src/app/tag/[tag]/image/route.tsx +++ b/src/app/tag/[tag]/image/route.tsx @@ -4,7 +4,7 @@ import { MAX_PHOTOS_TO_SHOW_PER_TAG, } from '@/image-response'; import TagImageResponse from '@/image-response/TagImageResponse'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; @@ -12,7 +12,7 @@ import { getUniqueTags } from '@/photo/db/query'; import { STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES, IS_PRODUCTION, -} from '@/site/config'; +} from '@/app-core/config'; export let generateStaticParams: (() => Promise<{ tag: string }[]>) | undefined = undefined; diff --git a/src/app/tag/[tag]/page.tsx b/src/app/tag/[tag]/page.tsx index 0e19f3a7..732e7b04 100644 --- a/src/app/tag/[tag]/page.tsx +++ b/src/app/tag/[tag]/page.tsx @@ -1,8 +1,8 @@ import { INFINITE_SCROLL_GRID_INITIAL } from '@/photo'; import { getUniqueTags } from '@/photo/db/query'; -import { IS_PRODUCTION } from '@/site/config'; -import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/site/config'; -import { PATH_ROOT } from '@/site/paths'; +import { IS_PRODUCTION } from '@/app-core/config'; +import { STATICALLY_OPTIMIZED_PHOTO_CATEGORIES } from '@/app-core/config'; +import { PATH_ROOT } from '@/app-core/paths'; import { generateMetaForTag } from '@/tag'; import TagOverview from '@/tag/TagOverview'; import { getPhotosTagDataCached } from '@/tag/data'; diff --git a/src/app/tag/hidden/[photoId]/page.tsx b/src/app/tag/hidden/[photoId]/page.tsx index 94956d58..d890a95b 100644 --- a/src/app/tag/hidden/[photoId]/page.tsx +++ b/src/app/tag/hidden/[photoId]/page.tsx @@ -8,7 +8,7 @@ import { getPhotosNearIdCached, } from '@/photo/cache'; import { getPhotosMeta } from '@/photo/db/query'; -import { PATH_ROOT, absolutePathForPhoto } from '@/site/paths'; +import { PATH_ROOT, absolutePathForPhoto } from '@/app-core/paths'; import { TAG_HIDDEN } from '@/tag'; import { Metadata } from 'next'; import { redirect } from 'next/navigation'; diff --git a/src/app/tag/hidden/page.tsx b/src/app/tag/hidden/page.tsx index cb890821..cf5a353d 100644 --- a/src/app/tag/hidden/page.tsx +++ b/src/app/tag/hidden/page.tsx @@ -4,7 +4,7 @@ import SiteGrid from '@/components/SiteGrid'; import PhotoGrid from '@/photo/PhotoGrid'; import { getPhotosNoStore } from '@/photo/cache'; import { getPhotosMeta } from '@/photo/db/query'; -import { absolutePathForTag } from '@/site/paths'; +import { absolutePathForTag } from '@/app-core/paths'; import { TAG_HIDDEN, descriptionForTaggedPhotos, titleForTag } from '@/tag'; import HiddenHeader from '@/tag/HiddenHeader'; import { Metadata } from 'next'; diff --git a/src/app/template-image-tight/route.tsx b/src/app/template-image-tight/route.tsx index 2f3816f1..8fb805a4 100644 --- a/src/app/template-image-tight/route.tsx +++ b/src/app/template-image-tight/route.tsx @@ -5,7 +5,7 @@ import { } from '@/image-response'; import TemplateImageResponse from '@/image-response/TemplateImageResponse'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { isNextImageReadyBasedOnPhotos } from '@/photo'; diff --git a/src/app/template-image/route.tsx b/src/app/template-image/route.tsx index 1b2c280b..181defdb 100644 --- a/src/app/template-image/route.tsx +++ b/src/app/template-image/route.tsx @@ -5,7 +5,7 @@ import { } from '@/image-response'; import TemplateImageResponse from '@/image-response/TemplateImageResponse'; -import { getIBMPlexMonoMedium } from '@/site/font'; +import { getIBMPlexMonoMedium } from '@/app-core/font'; import { ImageResponse } from 'next/og'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { isNextImageReadyBasedOnPhotos } from '@/photo'; diff --git a/src/auth/actions.ts b/src/auth/actions.ts index 72c04dea..d3791893 100644 --- a/src/auth/actions.ts +++ b/src/auth/actions.ts @@ -10,7 +10,7 @@ import { signIn, signOut, } from '@/auth'; -import { PATH_ADMIN_PHOTOS, PATH_ROOT } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS, PATH_ROOT } from '@/app-core/paths'; import type { Session } from 'next-auth'; import { redirect } from 'next/navigation'; diff --git a/src/auth/index.ts b/src/auth/index.ts index 9dab1b80..83ec6da7 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -1,4 +1,4 @@ -import { isPathProtected } from '@/site/paths'; +import { isPathProtected } from '@/app-core/paths'; import NextAuth, { User } from 'next-auth'; import Credentials from 'next-auth/providers/credentials'; diff --git a/src/camera/CameraOGTile.tsx b/src/camera/CameraOGTile.tsx index 225758fa..184b8399 100644 --- a/src/camera/CameraOGTile.tsx +++ b/src/camera/CameraOGTile.tsx @@ -1,5 +1,5 @@ import { Photo, PhotoDateRange } from '@/photo'; -import { absolutePathForCameraImage, pathForCamera } from '@/site/paths'; +import { absolutePathForCameraImage, pathForCamera } from '@/app-core/paths'; import OGTile from '@/components/OGTile'; import { Camera } from '.'; import { descriptionForCameraPhotos, titleForCamera } from './meta'; diff --git a/src/camera/CameraShareModal.tsx b/src/camera/CameraShareModal.tsx index 8d640ab1..6e85b7ef 100644 --- a/src/camera/CameraShareModal.tsx +++ b/src/camera/CameraShareModal.tsx @@ -1,4 +1,4 @@ -import { absolutePathForCamera } from '@/site/paths'; +import { absolutePathForCamera } from '@/app-core/paths'; import { PhotoSetAttributes } from '../photo'; import ShareModal from '@/share/ShareModal'; import CameraOGTile from './CameraOGTile'; diff --git a/src/camera/PhotoCamera.tsx b/src/camera/PhotoCamera.tsx index c097b099..845de6d5 100644 --- a/src/camera/PhotoCamera.tsx +++ b/src/camera/PhotoCamera.tsx @@ -1,5 +1,5 @@ import { AiFillApple } from 'react-icons/ai'; -import { pathForCamera } from '@/site/paths'; +import { pathForCamera } from '@/app-core/paths'; import { IoMdCamera } from 'react-icons/io'; import { Camera, formatCameraText, isCameraApple } from '.'; import EntityLink, { diff --git a/src/camera/meta.ts b/src/camera/meta.ts index ff13db16..5c85cd2a 100644 --- a/src/camera/meta.ts +++ b/src/camera/meta.ts @@ -8,7 +8,7 @@ import { Camera, cameraFromPhoto, formatCameraText } from '.'; import { absolutePathForCamera, absolutePathForCameraImage, -} from '@/site/paths'; +} from '@/app-core/paths'; // Meta functions moved to separate file to avoid // dependencies (camelcase-keys) found in photo/index.ts diff --git a/src/components/Checklist.tsx b/src/components/ChecklistGroup.tsx similarity index 97% rename from src/components/Checklist.tsx rename to src/components/ChecklistGroup.tsx index ec62c3bb..2cf3a751 100644 --- a/src/components/Checklist.tsx +++ b/src/components/ChecklistGroup.tsx @@ -5,7 +5,7 @@ import Badge from './Badge'; import ResponsiveText from './primitives/ResponsiveText'; import { parameterize } from '@/utility/string'; -export default function Checklist({ +export default function ChecklistGroup({ title, titleShort, icon, diff --git a/src/components/Container.tsx b/src/components/Container.tsx index 54d640f1..3c35c85e 100644 --- a/src/components/Container.tsx +++ b/src/components/Container.tsx @@ -25,13 +25,13 @@ export default function Container({ switch (color) { case 'gray': return [ 'text-medium', - 'bg-gray-50 border-gray-200', - 'dark:bg-gray-900/40 dark:border-gray-800', + 'bg-gray-50 dark:bg-gray-900/40', + 'border-gray-200 dark:border-gray-800', ]; case 'blue': return [ - 'text-main', - 'bg-blue-50/50 border-blue-200', - 'dark:bg-blue-950/30 dark:border-blue-600/50', + 'text-blue-900 dark:text-blue-300', + 'bg-blue-50/50 dark:bg-blue-950/30', + 'border-blue-200 dark:border-blue-600/30', ]; case 'red': return [ 'text-red-600 dark:text-red-500/90', @@ -41,7 +41,7 @@ export default function Container({ case 'yellow': return [ 'text-amber-700 dark:text-amber-500/90', 'bg-amber-50/50 dark:bg-amber-950/30', - 'border-amber-200/80 dark:border-amber-800/30', + 'border-amber-600/30 dark:border-amber-800/30', ]; } }; diff --git a/src/components/HttpStatusPage.tsx b/src/components/HttpStatusPage.tsx index 0abe6ec0..4e9dba0d 100644 --- a/src/components/HttpStatusPage.tsx +++ b/src/components/HttpStatusPage.tsx @@ -1,7 +1,7 @@ import { ReactNode } from 'react'; import SiteGrid from './SiteGrid'; import { clsx } from 'clsx/lite'; -import { PATH_ROOT } from '@/site/paths'; +import { PATH_ROOT } from '@/app-core/paths'; import Link from 'next/link'; export default function HttpStatusPage({ diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 0b89594f..f4b9eca2 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -6,9 +6,9 @@ import { clsx } from 'clsx/lite'; import useClickInsideOutside from '@/utility/useClickInsideOutside'; import { useRouter } from 'next/navigation'; import AnimateItems from './AnimateItems'; -import { PATH_ROOT } from '@/site/paths'; +import { PATH_ROOT } from '@/app-core/paths'; import usePrefersReducedMotion from '@/utility/usePrefersReducedMotion'; -import useMetaThemeColor from '@/site/useMetaThemeColor'; +import useMetaThemeColor from '@/utility/useMetaThemeColor'; import useEscapeHandler from '@/utility/useEscapeHandler'; export default function Modal({ diff --git a/src/components/SwitcherItem.tsx b/src/components/SwitcherItem.tsx index 41a3a9ea..3967f9ce 100644 --- a/src/components/SwitcherItem.tsx +++ b/src/components/SwitcherItem.tsx @@ -1,5 +1,5 @@ import { clsx } from 'clsx/lite'; -import { SHOULD_PREFETCH_ALL_LINKS } from '@/site/config'; +import { SHOULD_PREFETCH_ALL_LINKS } from '@/app-core/config'; import { JSX } from 'react'; import Spinner from './Spinner'; import LinkWithLoader from './LinkWithLoader'; diff --git a/src/components/cmdk/CommandKClient.tsx b/src/components/cmdk/CommandKClient.tsx index 75b3abe0..5e9c1707 100644 --- a/src/components/cmdk/CommandKClient.tsx +++ b/src/components/cmdk/CommandKClient.tsx @@ -22,7 +22,7 @@ import { PATH_SIGN_IN, pathForPhoto, pathForTag, -} from '../../site/paths'; +} from '../../app-core/paths'; import Modal from '../Modal'; import { clsx } from 'clsx/lite'; import { useDebounce } from 'use-debounce'; @@ -46,7 +46,7 @@ import { Tags, addHiddenToTags, formatTag } from '@/tag'; import { FaTag } from 'react-icons/fa'; import { formatCount, formatCountDescriptive } from '@/utility/string'; import CommandKItem from './CommandKItem'; -import { GRID_HOMEPAGE_ENABLED } from '@/site/config'; +import { GRID_HOMEPAGE_ENABLED } from '@/app-core/config'; import { DialogDescription, DialogTitle } from '@radix-ui/react-dialog'; import * as VisuallyHidden from '@radix-ui/react-visually-hidden'; diff --git a/src/components/image/ImageLarge.tsx b/src/components/image/ImageLarge.tsx index 3b14025e..4a9ee82f 100644 --- a/src/components/image/ImageLarge.tsx +++ b/src/components/image/ImageLarge.tsx @@ -1,4 +1,4 @@ -import { IMAGE_QUALITY } from '@/site/config'; +import { IMAGE_QUALITY } from '@/app-core/config'; import { IMAGE_WIDTH_LARGE, ImageProps } from '.'; import ImageWithFallback from './ImageWithFallback'; diff --git a/src/components/image/ImageWithFallback.tsx b/src/components/image/ImageWithFallback.tsx index 23457add..91ae5935 100644 --- a/src/components/image/ImageWithFallback.tsx +++ b/src/components/image/ImageWithFallback.tsx @@ -1,7 +1,7 @@ 'use client'; /* eslint-disable jsx-a11y/alt-text */ -import { BLUR_ENABLED } from '@/site/config'; +import { BLUR_ENABLED } from '@/app-core/config'; import { useAppState } from '@/state/AppState'; import { clsx} from 'clsx/lite'; import Image, { ImageProps } from 'next/image'; diff --git a/src/components/image/useImageZoomControls.ts b/src/components/image/useImageZoomControls.ts index 6c192250..09479415 100644 --- a/src/components/image/useImageZoomControls.ts +++ b/src/components/image/useImageZoomControls.ts @@ -1,4 +1,4 @@ -import useMetaThemeColor from '@/site/useMetaThemeColor'; +import useMetaThemeColor from '@/utility/useMetaThemeColor'; import { useAppState } from '@/state/AppState'; import useKeydownHandler from '@/utility/useKeydownHandler'; import { RefObject, useCallback, useEffect, useRef, useState } from 'react'; diff --git a/src/focal/FocalLengthOGTile.tsx b/src/focal/FocalLengthOGTile.tsx index 29e9af83..b7fc7782 100644 --- a/src/focal/FocalLengthOGTile.tsx +++ b/src/focal/FocalLengthOGTile.tsx @@ -2,7 +2,7 @@ import { Photo, PhotoDateRange } from '@/photo'; import { absolutePathForFocalLengthImage, pathForFocalLength, -} from '@/site/paths'; +} from '@/app-core/paths'; import OGTile from '@/components/OGTile'; import { descriptionForFocalLengthPhotos, titleForFocalLength } from '.'; diff --git a/src/focal/FocalLengthShareModal.tsx b/src/focal/FocalLengthShareModal.tsx index 5e7ee3e1..62d89cf2 100644 --- a/src/focal/FocalLengthShareModal.tsx +++ b/src/focal/FocalLengthShareModal.tsx @@ -1,4 +1,4 @@ -import { absolutePathForFocalLength } from '@/site/paths'; +import { absolutePathForFocalLength } from '@/app-core/paths'; import { PhotoSetAttributes } from '../photo'; import ShareModal from '@/share/ShareModal'; import FocalLengthOGTile from './FocalLengthOGTile'; diff --git a/src/focal/PhotoFocalLength.tsx b/src/focal/PhotoFocalLength.tsx index b242e43b..c457e291 100644 --- a/src/focal/PhotoFocalLength.tsx +++ b/src/focal/PhotoFocalLength.tsx @@ -1,4 +1,4 @@ -import { pathForFocalLength } from '@/site/paths'; +import { pathForFocalLength } from '@/app-core/paths'; import EntityLink, { EntityLinkExternalProps, } from '@/components/primitives/EntityLink'; diff --git a/src/focal/index.ts b/src/focal/index.ts index 6486f2c6..617bf113 100644 --- a/src/focal/index.ts +++ b/src/focal/index.ts @@ -7,7 +7,7 @@ import { import { absolutePathForFocalLength, absolutePathForFocalLengthImage, -} from '@/site/paths'; +} from '@/app-core/paths'; export type FocalLengths = { focal: number diff --git a/src/image-response/HomeImageResponse.tsx b/src/image-response/HomeImageResponse.tsx index 755d6708..d563f898 100644 --- a/src/image-response/HomeImageResponse.tsx +++ b/src/image-response/HomeImageResponse.tsx @@ -1,4 +1,4 @@ -import { SITE_DOMAIN_OR_TITLE } from '@/site/config'; +import { SITE_DOMAIN_OR_TITLE } from '@/app-core/config'; import { Photo } from '../photo'; import ImageCaption from './components/ImageCaption'; import ImageContainer from './components/ImageContainer'; diff --git a/src/image-response/PhotoImageResponse.tsx b/src/image-response/PhotoImageResponse.tsx index c636527f..22c9202e 100644 --- a/src/image-response/PhotoImageResponse.tsx +++ b/src/image-response/PhotoImageResponse.tsx @@ -3,7 +3,7 @@ import { AiFillApple } from 'react-icons/ai'; import ImageCaption from './components/ImageCaption'; import ImagePhotoGrid from './components/ImagePhotoGrid'; import ImageContainer from './components/ImageContainer'; -import { OG_TEXT_BOTTOM_ALIGNMENT } from '@/site/config'; +import { OG_TEXT_BOTTOM_ALIGNMENT } from '@/app-core/config'; import { NextImageSize } from '@/services/next-image'; import { cameraFromPhoto, formatCameraText } from '@/camera'; diff --git a/src/image-response/TemplateImageResponse.tsx b/src/image-response/TemplateImageResponse.tsx index a4ba9090..1954d722 100644 --- a/src/image-response/TemplateImageResponse.tsx +++ b/src/image-response/TemplateImageResponse.tsx @@ -1,6 +1,6 @@ import { Photo } from '../photo'; -import IconFeed from '@/site/IconFeed'; -import IconGrid from '@/site/IconGrid'; +import IconFeed from '@/app-core/IconFeed'; +import IconGrid from '@/app-core/IconGrid'; import ImagePhotoGrid from './components/ImagePhotoGrid'; import { NextImageSize } from '@/services/next-image'; diff --git a/src/image-response/components/ImageCaption.tsx b/src/image-response/components/ImageCaption.tsx index f025b837..8b52f32d 100644 --- a/src/image-response/components/ImageCaption.tsx +++ b/src/image-response/components/ImageCaption.tsx @@ -1,4 +1,4 @@ -import { OG_TEXT_BOTTOM_ALIGNMENT } from '@/site/config'; +import { OG_TEXT_BOTTOM_ALIGNMENT } from '@/app-core/config'; import { ReactNode } from 'react'; const GRADIENT_STOPS = 'rgba(0,0,0,0), rgba(0,0,0,0.3), rgba(0,0,0,0.7)'; diff --git a/src/image-response/components/ImagePhotoGrid.tsx b/src/image-response/components/ImagePhotoGrid.tsx index 57c570bd..758e4ff9 100644 --- a/src/image-response/components/ImagePhotoGrid.tsx +++ b/src/image-response/components/ImagePhotoGrid.tsx @@ -5,7 +5,7 @@ import { NextImageSize, getNextImageUrlForRequest, } from '@/services/next-image'; -import { IS_PREVIEW } from '@/site/config'; +import { IS_PREVIEW } from '@/app-core/config'; export default function ImagePhotoGrid({ photos, diff --git a/src/middleware.ts b/src/middleware.ts index ac78095a..a2534203 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -8,7 +8,7 @@ import { PATH_OG_SAMPLE, PREFIX_PHOTO, PREFIX_TAG, -} from './site/paths'; +} from './app-core/paths'; export default function middleware(req: NextRequest, res:NextResponse) { const pathname = req.nextUrl.pathname; diff --git a/src/photo/InfinitePhotoScroll.tsx b/src/photo/InfinitePhotoScroll.tsx index a42d41bf..71ddaedd 100644 --- a/src/photo/InfinitePhotoScroll.tsx +++ b/src/photo/InfinitePhotoScroll.tsx @@ -16,7 +16,7 @@ import { clsx } from 'clsx/lite'; import { useAppState } from '@/state/AppState'; import { GetPhotosOptions } from './db'; import useVisible from '@/utility/useVisible'; -import { ADMIN_DB_OPTIMIZE_ENABLED } from '@/site/config'; +import { ADMIN_DB_OPTIMIZE_ENABLED } from '@/app-core/config'; export type RevalidatePhoto = ( photoId: string, diff --git a/src/photo/PhotoEditPageClient.tsx b/src/photo/PhotoEditPageClient.tsx index 33b7bcec..e94af7de 100644 --- a/src/photo/PhotoEditPageClient.tsx +++ b/src/photo/PhotoEditPageClient.tsx @@ -2,7 +2,7 @@ import AdminChildPage from '@/components/AdminChildPage'; import { Photo } from '.'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS } from '@/app-core/paths'; import { PhotoFormData, convertPhotoToFormData } from './form'; import PhotoForm from './form/PhotoForm'; import { Tags } from '@/tag'; diff --git a/src/photo/PhotoEscapeHandler.tsx b/src/photo/PhotoEscapeHandler.tsx index cccc353c..86d7809a 100644 --- a/src/photo/PhotoEscapeHandler.tsx +++ b/src/photo/PhotoEscapeHandler.tsx @@ -1,6 +1,6 @@ 'use client'; -import { getEscapePath } from '@/site/paths'; +import { getEscapePath } from '@/app-core/paths'; import { useRouter, usePathname } from 'next/navigation'; import { useCallback } from 'react'; import useEscapeHandler from '../utility/useEscapeHandler'; diff --git a/src/photo/PhotoGrid.tsx b/src/photo/PhotoGrid.tsx index 98e86bd5..b69cd133 100644 --- a/src/photo/PhotoGrid.tsx +++ b/src/photo/PhotoGrid.tsx @@ -4,7 +4,7 @@ import { Photo, PhotoSetCategory } from '.'; import PhotoMedium from './PhotoMedium'; import { clsx } from 'clsx/lite'; import AnimateItems from '@/components/AnimateItems'; -import { GRID_ASPECT_RATIO } from '@/site/config'; +import { GRID_ASPECT_RATIO } from '@/app-core/config'; import { useAppState } from '@/state/AppState'; import SelectTileOverlay from '@/components/SelectTileOverlay'; import { JSX } from 'react'; diff --git a/src/photo/PhotoGridPage.tsx b/src/photo/PhotoGridPage.tsx index a3c40c22..2ec0d14d 100644 --- a/src/photo/PhotoGridPage.tsx +++ b/src/photo/PhotoGridPage.tsx @@ -4,7 +4,7 @@ import { Tags } from '@/tag'; import { Photo } from '.'; import { Cameras } from '@/camera'; import { FilmSimulations } from '@/simulation'; -import { PATH_GRID_INFERRED } from '@/site/paths'; +import { PATH_GRID_INFERRED } from '@/app-core/paths'; import PhotoGridSidebar from './PhotoGridSidebar'; import PhotoGridContainer from './PhotoGridContainer'; import { useEffect } from 'react'; diff --git a/src/photo/PhotoGridSidebar.tsx b/src/photo/PhotoGridSidebar.tsx index a7b1c412..5362c21e 100644 --- a/src/photo/PhotoGridSidebar.tsx +++ b/src/photo/PhotoGridSidebar.tsx @@ -15,7 +15,7 @@ import FavsTag from '../tag/FavsTag'; import { useAppState } from '@/state/AppState'; import { useMemo } from 'react'; import HiddenTag from '@/tag/HiddenTag'; -import { SITE_ABOUT } from '@/site/config'; +import { SITE_ABOUT } from '@/app-core/config'; import { htmlHasBrParagraphBreaks, safelyParseFormattedHtml, diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index f5754fa5..f45eadd9 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -15,7 +15,7 @@ import Link from 'next/link'; import { pathForFocalLength, pathForPhoto, -} from '@/site/paths'; +} from '@/app-core/paths'; import PhotoTags from '@/tag/PhotoTags'; import ShareButton from '@/share/ShareButton'; import DownloadButton from '@/components/DownloadButton'; @@ -29,7 +29,7 @@ import { SHOULD_PREFETCH_ALL_LINKS, ALLOW_PUBLIC_DOWNLOADS, SHOW_TAKEN_AT_TIME, -} from '@/site/config'; +} from '@/app-core/config'; import AdminPhotoMenuClient from '@/admin/AdminPhotoMenuClient'; import { RevalidatePhoto } from './InfinitePhotoScroll'; import { useRef } from 'react'; diff --git a/src/photo/PhotoLink.tsx b/src/photo/PhotoLink.tsx index 72269e2b..d17ff63b 100644 --- a/src/photo/PhotoLink.tsx +++ b/src/photo/PhotoLink.tsx @@ -5,7 +5,7 @@ import { Photo, PhotoSetCategory, titleForPhoto } from '@/photo'; import Link from 'next/link'; import { AnimationConfig } from '../components/AnimateItems'; import { useAppState } from '@/state/AppState'; -import { pathForPhoto } from '@/site/paths'; +import { pathForPhoto } from '@/app-core/paths'; import { clsx } from 'clsx/lite'; export default function PhotoLink({ diff --git a/src/photo/PhotoMedium.tsx b/src/photo/PhotoMedium.tsx index bd6e0a1a..a659213c 100644 --- a/src/photo/PhotoMedium.tsx +++ b/src/photo/PhotoMedium.tsx @@ -8,8 +8,8 @@ import { } from '.'; import ImageMedium from '@/components/image/ImageMedium'; import { clsx } from 'clsx/lite'; -import { pathForPhoto } from '@/site/paths'; -import { SHOULD_PREFETCH_ALL_LINKS } from '@/site/config'; +import { pathForPhoto } from '@/app-core/paths'; +import { SHOULD_PREFETCH_ALL_LINKS } from '@/app-core/config'; import { useRef } from 'react'; import useVisible from '@/utility/useVisible'; import LinkWithStatus from '@/components/LinkWithStatus'; diff --git a/src/photo/PhotoOGTile.tsx b/src/photo/PhotoOGTile.tsx index 913c97d8..58498834 100644 --- a/src/photo/PhotoOGTile.tsx +++ b/src/photo/PhotoOGTile.tsx @@ -4,7 +4,7 @@ import { descriptionForPhoto, titleForPhoto, } from '@/photo'; -import { absolutePathForPhotoImage, pathForPhoto } from '@/site/paths'; +import { absolutePathForPhotoImage, pathForPhoto } from '@/app-core/paths'; import OGTile from '@/components/OGTile'; export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed'; diff --git a/src/photo/PhotoPrevNext.tsx b/src/photo/PhotoPrevNext.tsx index fb69ba74..0808cf1c 100644 --- a/src/photo/PhotoPrevNext.tsx +++ b/src/photo/PhotoPrevNext.tsx @@ -9,7 +9,7 @@ import { } from '@/photo'; import PhotoLink from './PhotoLink'; import { useRouter } from 'next/navigation'; -import { pathForPhoto } from '@/site/paths'; +import { pathForPhoto } from '@/app-core/paths'; import { useAppState } from '@/state/AppState'; import { AnimationConfig } from '@/components/AnimateItems'; import { clsx } from 'clsx/lite'; diff --git a/src/photo/PhotoShareModal.tsx b/src/photo/PhotoShareModal.tsx index 047b5b0e..851dcb4e 100644 --- a/src/photo/PhotoShareModal.tsx +++ b/src/photo/PhotoShareModal.tsx @@ -1,5 +1,5 @@ import PhotoOGTile from '@/photo/PhotoOGTile'; -import { absolutePathForPhoto } from '@/site/paths'; +import { absolutePathForPhoto } from '@/app-core/paths'; import { Photo, PhotoSetCategory } from '.'; import ShareModal from '@/share/ShareModal'; diff --git a/src/photo/PhotoSmall.tsx b/src/photo/PhotoSmall.tsx index 2c5291c8..dec8780c 100644 --- a/src/photo/PhotoSmall.tsx +++ b/src/photo/PhotoSmall.tsx @@ -7,8 +7,8 @@ import { import ImageSmall from '@/components/image/ImageSmall'; import Link from 'next/link'; import { clsx } from 'clsx/lite'; -import { pathForPhoto } from '@/site/paths'; -import { SHOULD_PREFETCH_ALL_LINKS } from '@/site/config'; +import { pathForPhoto } from '@/app-core/paths'; +import { SHOULD_PREFETCH_ALL_LINKS } from '@/app-core/config'; import { useRef } from 'react'; import useVisible from '@/utility/useVisible'; diff --git a/src/photo/PhotoUpload.tsx b/src/photo/PhotoUpload.tsx index 836d5d13..338e584a 100644 --- a/src/photo/PhotoUpload.tsx +++ b/src/photo/PhotoUpload.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import { uploadPhotoFromClient } from '@/services/storage'; import { useRouter } from 'next/navigation'; -import { PATH_ADMIN_UPLOADS, pathForAdminUploadUrl } from '@/site/paths'; +import { PATH_ADMIN_UPLOADS, pathForAdminUploadUrl } from '@/app-core/paths'; import ImageInput from '../components/ImageInput'; import { clsx } from 'clsx/lite'; diff --git a/src/photo/PhotosEmptyState.tsx b/src/photo/PhotosEmptyState.tsx index c3b36166..7386b2b0 100644 --- a/src/photo/PhotosEmptyState.tsx +++ b/src/photo/PhotosEmptyState.tsx @@ -1,9 +1,9 @@ import AdminCTA from '@/admin/AdminCTA'; import Container from '@/components/Container'; import SiteGrid from '@/components/SiteGrid'; -import { IS_SITE_READY } from '@/site/config'; -import { PATH_ADMIN_CONFIGURATION } from '@/site/paths'; -import SiteChecklist from '@/site/SiteChecklist'; +import { IS_SITE_READY } from '@/app-core/config'; +import { PATH_ADMIN_CONFIGURATION } from '@/app-core/paths'; +import AdminAppConfiguration from '@/admin/AdminAppConfiguration'; import { clsx } from 'clsx/lite'; import Link from 'next/link'; import { HiOutlinePhotograph } from 'react-icons/hi'; @@ -27,7 +27,7 @@ export default function PhotosEmptyState() { {!IS_SITE_READY ? 'Finish Setup' : 'Setup Complete!'}
{!IS_SITE_READY - ? + ? :
diff --git a/src/photo/PhotosLargeInfinite.tsx b/src/photo/PhotosLargeInfinite.tsx index 8309d6a0..1b2b72b9 100644 --- a/src/photo/PhotosLargeInfinite.tsx +++ b/src/photo/PhotosLargeInfinite.tsx @@ -1,6 +1,6 @@ 'use client'; -import { PATH_FEED_INFERRED } from '@/site/paths'; +import { PATH_FEED_INFERRED } from '@/app-core/paths'; import InfinitePhotoScroll from './InfinitePhotoScroll'; import PhotosLarge from './PhotosLarge'; diff --git a/src/photo/StaggeredOgPhotosInfinite.tsx b/src/photo/StaggeredOgPhotosInfinite.tsx index f568bbc3..2d9de205 100644 --- a/src/photo/StaggeredOgPhotosInfinite.tsx +++ b/src/photo/StaggeredOgPhotosInfinite.tsx @@ -1,6 +1,6 @@ 'use client'; -import { PATH_OG } from '@/site/paths'; +import { PATH_OG } from '@/app-core/paths'; import InfinitePhotoScroll from './InfinitePhotoScroll'; import StaggeredOgPhotos from './StaggeredOgPhotos'; diff --git a/src/photo/UploadPageClient.tsx b/src/photo/UploadPageClient.tsx index 27e612d8..e8355af3 100644 --- a/src/photo/UploadPageClient.tsx +++ b/src/photo/UploadPageClient.tsx @@ -1,7 +1,7 @@ 'use client'; import AdminChildPage from '@/components/AdminChildPage'; -import { PATH_ADMIN_UPLOADS } from '@/site/paths'; +import { PATH_ADMIN_UPLOADS } from '@/app-core/paths'; import { PhotoFormData, generateTakenAtFields } from './form'; import PhotoForm from './form/PhotoForm'; import { Tags } from '@/tag'; diff --git a/src/photo/actions.ts b/src/photo/actions.ts index 86bc203a..ed728cd3 100644 --- a/src/photo/actions.ts +++ b/src/photo/actions.ts @@ -33,7 +33,7 @@ import { PATH_ADMIN_TAGS, PATH_ROOT, pathForPhoto, -} from '@/site/paths'; +} from '@/app-core/paths'; import { blurImageFromUrl, extractImageDataFromBlobPath } from './server'; import { TAG_FAVS, isTagFavs } from '@/tag'; import { convertPhotoToPhotoDbInsert, Photo } from '.'; @@ -44,7 +44,7 @@ import { AI_TEXT_AUTO_GENERATED_FIELDS, AI_TEXT_GENERATION_ENABLED, BLUR_ENABLED, -} from '@/site/config'; +} from '@/app-core/config'; import { generateAiImageQueries } from './ai/server'; import { createStreamableValue } from 'ai/rsc'; import { convertUploadToPhoto } from './storage'; diff --git a/src/photo/cache.ts b/src/photo/cache.ts index 6452d8f6..4d3c3fa8 100644 --- a/src/photo/cache.ts +++ b/src/photo/cache.ts @@ -31,7 +31,7 @@ import { PREFIX_FILM_SIMULATION, PREFIX_TAG, pathForPhoto, -} from '@/site/paths'; +} from '@/app-core/paths'; import { createLensKey } from '@/lens'; // Table key diff --git a/src/photo/data.ts b/src/photo/data.ts index fa674b4a..47837a3f 100644 --- a/src/photo/data.ts +++ b/src/photo/data.ts @@ -8,7 +8,7 @@ import { getUniqueFilmSimulations, getUniqueTags, } from '@/photo/db/query'; -import { SHOW_FILM_SIMULATIONS } from '@/site/config'; +import { SHOW_FILM_SIMULATIONS } from '@/app-core/config'; import { sortTagsObject } from '@/tag'; export const getPhotoSidebarData = () => [ diff --git a/src/photo/db/index.ts b/src/photo/db/index.ts index e150a538..72ba97a8 100644 --- a/src/photo/db/index.ts +++ b/src/photo/db/index.ts @@ -1,4 +1,4 @@ -import { PRIORITY_ORDER_ENABLED } from '@/site/config'; +import { PRIORITY_ORDER_ENABLED } from '@/app-core/config'; import { parameterize } from '@/utility/string'; import { PhotoSetCategory } from '..'; diff --git a/src/photo/db/query.ts b/src/photo/db/query.ts index f4177276..8936060a 100644 --- a/src/photo/db/query.ts +++ b/src/photo/db/query.ts @@ -14,7 +14,7 @@ import { import { Cameras, createCameraKey } from '@/camera'; import { Tags } from '@/tag'; import { FilmSimulation, FilmSimulations } from '@/simulation'; -import { ADMIN_SQL_DEBUG_ENABLED } from '@/site/config'; +import { ADMIN_SQL_DEBUG_ENABLED } from '@/app-core/config'; import { GetPhotosOptions, getLimitAndOffsetFromOptions, diff --git a/src/photo/form/PhotoForm.tsx b/src/photo/form/PhotoForm.tsx index 5b480509..d132021a 100644 --- a/src/photo/form/PhotoForm.tsx +++ b/src/photo/form/PhotoForm.tsx @@ -15,7 +15,7 @@ import { createPhotoAction, updatePhotoAction } from '../actions'; import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; import Link from 'next/link'; import { clsx } from 'clsx/lite'; -import { PATH_ADMIN_PHOTOS, PATH_ADMIN_UPLOADS } from '@/site/paths'; +import { PATH_ADMIN_PHOTOS, PATH_ADMIN_UPLOADS } from '@/app-core/paths'; import { toastSuccess, toastWarning } from '@/toast'; import { getDimensionsFromSize } from '@/utility/size'; import ImageWithFallback from '@/components/image/ImageWithFallback'; @@ -27,7 +27,7 @@ import usePreventNavigation from '@/utility/usePreventNavigation'; import { useAppState } from '@/state/AppState'; import UpdateBlurDataButton from '../UpdateBlurDataButton'; import { getNextImageUrlForManipulation } from '@/services/next-image'; -import { BLUR_ENABLED, IS_PREVIEW } from '@/site/config'; +import { BLUR_ENABLED, IS_PREVIEW } from '@/app-core/config'; import { PhotoDbInsert } from '..'; import ErrorNote from '@/components/ErrorNote'; diff --git a/src/photo/form/index.ts b/src/photo/form/index.ts index 58711d2d..571b3c2e 100644 --- a/src/photo/form/index.ts +++ b/src/photo/form/index.ts @@ -21,7 +21,7 @@ import { MAKE_FUJIFILM, } from '@/vendors/fujifilm'; import { FilmSimulation } from '@/simulation'; -import { GEO_PRIVACY_ENABLED } from '@/site/config'; +import { GEO_PRIVACY_ENABLED } from '@/app-core/config'; import { TAG_FAVS, getValidationMessageForTags } from '@/tag'; type VirtualFields = 'favorite'; diff --git a/src/photo/index.ts b/src/photo/index.ts index e58a38db..cf4ec16d 100644 --- a/src/photo/index.ts +++ b/src/photo/index.ts @@ -3,8 +3,12 @@ import { formatFocalLength } from '@/focal'; import { Lens } from '@/lens'; import { getNextImageUrlForRequest } from '@/services/next-image'; import { FilmSimulation } from '@/simulation'; -import { HIGH_DENSITY_GRID, IS_PREVIEW, SHOW_EXIF_DATA } from '@/site/config'; -import { ABSOLUTE_PATH_FOR_HOME_IMAGE } from '@/site/paths'; +import { + HIGH_DENSITY_GRID, + IS_PREVIEW, + SHOW_EXIF_DATA, +} from '@/app-core/config'; +import { ABSOLUTE_PATH_FOR_HOME_IMAGE } from '@/app-core/paths'; import { formatDate, formatDateFromPostgresString } from '@/utility/date'; import { formatAperture, diff --git a/src/photo/server.ts b/src/photo/server.ts index 3708395a..4b1d9233 100644 --- a/src/photo/server.ts +++ b/src/photo/server.ts @@ -11,7 +11,10 @@ import { ExifData, ExifParserFactory } from 'ts-exif-parser'; import { PhotoFormData } from './form'; import { FilmSimulation } from '@/simulation'; import sharp, { Sharp } from 'sharp'; -import { GEO_PRIVACY_ENABLED, PRESERVE_ORIGINAL_UPLOADS } from '@/site/config'; +import { + GEO_PRIVACY_ENABLED, + PRESERVE_ORIGINAL_UPLOADS, +} from '@/app-core/config'; const IMAGE_WIDTH_RESIZE = 200; const IMAGE_WIDTH_BLUR = 200; diff --git a/src/services/next-image.ts b/src/services/next-image.ts index 682130d1..93f8e7a2 100644 --- a/src/services/next-image.ts +++ b/src/services/next-image.ts @@ -2,7 +2,7 @@ import { BASE_URL, VERCEL_BYPASS_KEY, VERCEL_BYPASS_SECRET, -} from '@/site/config'; +} from '@/app-core/config'; // Explicity defined next.config.js `imageSizes` type NextCustomSize = 200; diff --git a/src/services/openai.ts b/src/services/openai.ts index 72d33a94..7ef64c83 100644 --- a/src/services/openai.ts +++ b/src/services/openai.ts @@ -3,7 +3,7 @@ import { createStreamableValue } from 'ai/rsc'; import { createOpenAI } from '@ai-sdk/openai'; import { kv } from '@vercel/kv'; import { Ratelimit } from '@upstash/ratelimit'; -import { AI_TEXT_GENERATION_ENABLED, HAS_VERCEL_KV } from '@/site/config'; +import { AI_TEXT_GENERATION_ENABLED, HAS_VERCEL_KV } from '@/app-core/config'; import { removeBase64Prefix } from '@/utility/image'; import { cleanUpAiTextResponse } from '@/photo/ai'; diff --git a/src/services/postgres.ts b/src/services/postgres.ts index 27d1fd3c..439e56ab 100644 --- a/src/services/postgres.ts +++ b/src/services/postgres.ts @@ -1,4 +1,4 @@ -import { POSTGRES_SSL_ENABLED } from '@/site/config'; +import { POSTGRES_SSL_ENABLED } from '@/app-core/config'; import { Pool, QueryResult, QueryResultRow } from 'pg'; const pool = new Pool({ diff --git a/src/services/storage/index.ts b/src/services/storage/index.ts index e773b3b9..364c4ba6 100644 --- a/src/services/storage/index.ts +++ b/src/services/storage/index.ts @@ -19,7 +19,7 @@ import { HAS_AWS_S3_STORAGE, HAS_VERCEL_BLOB_STORAGE, HAS_CLOUDFLARE_R2_STORAGE, -} from '@/site/config'; +} from '@/app-core/config'; import { generateNanoid } from '@/utility/nanoid'; import { CLOUDFLARE_R2_BASE_URL_PUBLIC, @@ -29,7 +29,7 @@ import { cloudflareR2Put, isUrlFromCloudflareR2, } from './cloudflare-r2'; -import { PATH_API_PRESIGNED_URL } from '@/site/paths'; +import { PATH_API_PRESIGNED_URL } from '@/app-core/paths'; export const generateStorageId = () => generateNanoid(16); diff --git a/src/services/storage/vercel-blob.ts b/src/services/storage/vercel-blob.ts index 1955488b..6abfefb5 100644 --- a/src/services/storage/vercel-blob.ts +++ b/src/services/storage/vercel-blob.ts @@ -1,4 +1,4 @@ -import { PATH_API_VERCEL_BLOB_UPLOAD } from '@/site/paths'; +import { PATH_API_VERCEL_BLOB_UPLOAD } from '@/app-core/paths'; import { copy, del, list, put } from '@vercel/blob'; import { upload } from '@vercel/blob/client'; import { fileNameForStorageUrl } from '.'; diff --git a/src/share/ShareModal.tsx b/src/share/ShareModal.tsx index d1768da9..6301a07a 100644 --- a/src/share/ShareModal.tsx +++ b/src/share/ShareModal.tsx @@ -8,7 +8,7 @@ import { JSX, ReactNode, useEffect } from 'react'; import { shortenUrl } from '@/utility/url'; import { toastSuccess } from '@/toast'; import { PiXLogo } from 'react-icons/pi'; -import { SHOW_SOCIAL } from '@/site/config'; +import { SHOW_SOCIAL } from '@/app-core/config'; import { generateXPostText } from '@/utility/social'; import { useAppState } from '@/state/AppState'; import useOnPathChange from '@/utility/useOnPathChange'; diff --git a/src/share/index.ts b/src/share/index.ts index 5642d168..fabc9f01 100644 --- a/src/share/index.ts +++ b/src/share/index.ts @@ -5,7 +5,7 @@ import { absolutePathForFocalLengthImage, absolutePathForPhotoImage, absolutePathForTagImage, -} from '@/site/paths'; +} from '@/app-core/paths'; export type ShareModalProps = Omit & { photo?: Photo diff --git a/src/simulation/FilmSimulationOGTile.tsx b/src/simulation/FilmSimulationOGTile.tsx index 1233a3e4..1f894877 100644 --- a/src/simulation/FilmSimulationOGTile.tsx +++ b/src/simulation/FilmSimulationOGTile.tsx @@ -2,7 +2,7 @@ import { Photo, PhotoDateRange } from '@/photo'; import { absolutePathForFilmSimulationImage, pathForFilmSimulation, -} from '@/site/paths'; +} from '@/app-core/paths'; import OGTile from '@/components/OGTile'; import { FilmSimulation, diff --git a/src/simulation/FilmSimulationShareModal.tsx b/src/simulation/FilmSimulationShareModal.tsx index a1c64012..e8ca9691 100644 --- a/src/simulation/FilmSimulationShareModal.tsx +++ b/src/simulation/FilmSimulationShareModal.tsx @@ -1,4 +1,4 @@ -import { absolutePathForFilmSimulation } from '@/site/paths'; +import { absolutePathForFilmSimulation } from '@/app-core/paths'; import { PhotoSetAttributes } from '../photo'; import ShareModal from '@/share/ShareModal'; import FilmSimulationOGTile from './FilmSimulationOGTile'; diff --git a/src/simulation/PhotoFilmSimulation.tsx b/src/simulation/PhotoFilmSimulation.tsx index bd7ee7dc..f85e5fc4 100644 --- a/src/simulation/PhotoFilmSimulation.tsx +++ b/src/simulation/PhotoFilmSimulation.tsx @@ -1,6 +1,6 @@ import { labelForFilmSimulation } from '@/vendors/fujifilm'; import PhotoFilmSimulationIcon from './PhotoFilmSimulationIcon'; -import { pathForFilmSimulation } from '@/site/paths'; +import { pathForFilmSimulation } from '@/app-core/paths'; import { FilmSimulation } from '.'; import EntityLink, { EntityLinkExternalProps, diff --git a/src/simulation/index.ts b/src/simulation/index.ts index 51b63dbd..5293848d 100644 --- a/src/simulation/index.ts +++ b/src/simulation/index.ts @@ -7,7 +7,7 @@ import { import { absolutePathForFilmSimulation, absolutePathForFilmSimulationImage, -} from '@/site/paths'; +} from '@/app-core/paths'; import { FujifilmSimulation, labelForFilmSimulation, diff --git a/src/site/SiteChecklist.tsx b/src/site/SiteChecklist.tsx deleted file mode 100644 index 935d0f9c..00000000 --- a/src/site/SiteChecklist.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Suspense } from 'react'; -import { CONFIG_CHECKLIST_STATUS } from '@/site/config'; -import SiteChecklistServer from './SiteChecklistServer'; -import SiteChecklistClient from './SiteChecklistClient'; - -export default function SiteChecklist({ - simplifiedView, -}: { - simplifiedView?: boolean -}) { - return ( - }> - - - ); -} diff --git a/src/state/AppStateProvider.tsx b/src/state/AppStateProvider.tsx index 39e7382e..3a675954 100644 --- a/src/state/AppStateProvider.tsx +++ b/src/state/AppStateProvider.tsx @@ -10,7 +10,7 @@ import { HIGH_DENSITY_GRID, MATTE_PHOTOS, SHOW_ZOOM_CONTROLS, -} from '@/site/config'; +} from '@/app-core/config'; import { getPhotosHiddenMetaCachedAction } from '@/photo/actions'; import { ShareModalProps } from '@/share'; import { storeTimezoneCookie } from '@/utility/timezone'; diff --git a/src/tag/FavsTag.tsx b/src/tag/FavsTag.tsx index 60f76ced..d8df8183 100644 --- a/src/tag/FavsTag.tsx +++ b/src/tag/FavsTag.tsx @@ -1,6 +1,6 @@ import { FaStar } from 'react-icons/fa'; import { TAG_FAVS } from '.'; -import { pathForTag } from '@/site/paths'; +import { pathForTag } from '@/app-core/paths'; import { clsx } from 'clsx/lite'; import EntityLink, { EntityLinkExternalProps, diff --git a/src/tag/HiddenTag.tsx b/src/tag/HiddenTag.tsx index 9727abff..c9176bea 100644 --- a/src/tag/HiddenTag.tsx +++ b/src/tag/HiddenTag.tsx @@ -1,5 +1,5 @@ import { TAG_HIDDEN } from '.'; -import { pathForTag } from '@/site/paths'; +import { pathForTag } from '@/app-core/paths'; import EntityLink, { EntityLinkExternalProps, } from '@/components/primitives/EntityLink'; diff --git a/src/tag/PhotoTag.tsx b/src/tag/PhotoTag.tsx index fb4acbf5..8ffd6657 100644 --- a/src/tag/PhotoTag.tsx +++ b/src/tag/PhotoTag.tsx @@ -1,4 +1,4 @@ -import { pathForTag } from '@/site/paths'; +import { pathForTag } from '@/app-core/paths'; import { FaTag } from 'react-icons/fa'; import { formatTag } from '.'; import EntityLink, { diff --git a/src/tag/TagForm.tsx b/src/tag/TagForm.tsx index 30608287..bad08222 100644 --- a/src/tag/TagForm.tsx +++ b/src/tag/TagForm.tsx @@ -2,7 +2,7 @@ import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; import Link from 'next/link'; -import { PATH_ADMIN_TAGS } from '@/site/paths'; +import { PATH_ADMIN_TAGS } from '@/app-core/paths'; import FieldSetWithStatus from '@/components/FieldSetWithStatus'; import { ReactNode, useMemo, useState } from 'react'; import { renamePhotoTagGloballyAction } from '@/photo/actions'; diff --git a/src/tag/TagOGTile.tsx b/src/tag/TagOGTile.tsx index e3295ea8..4026fb05 100644 --- a/src/tag/TagOGTile.tsx +++ b/src/tag/TagOGTile.tsx @@ -1,5 +1,5 @@ import { Photo, PhotoDateRange } from '@/photo'; -import { absolutePathForTagImage, pathForTag } from '@/site/paths'; +import { absolutePathForTagImage, pathForTag } from '@/app-core/paths'; import OGTile from '@/components/OGTile'; import { descriptionForTaggedPhotos, titleForTag } from '.'; diff --git a/src/tag/TagShareModal.tsx b/src/tag/TagShareModal.tsx index 5d7f9250..b0223bf6 100644 --- a/src/tag/TagShareModal.tsx +++ b/src/tag/TagShareModal.tsx @@ -1,4 +1,4 @@ -import { absolutePathForTag } from '@/site/paths'; +import { absolutePathForTag } from '@/app-core/paths'; import { PhotoSetAttributes } from '../photo'; import ShareModal from '@/share/ShareModal'; import TagOGTile from './TagOGTile'; diff --git a/src/tag/index.ts b/src/tag/index.ts index aafa1c72..447ee702 100644 --- a/src/tag/index.ts +++ b/src/tag/index.ts @@ -8,7 +8,7 @@ import { absolutePathForTag, absolutePathForTagImage, getPathComponents, -} from '@/site/paths'; +} from '@/app-core/paths'; import { capitalizeWords, convertStringToArray, diff --git a/src/site/useMetaThemeColor.ts b/src/utility/useMetaThemeColor.ts similarity index 100% rename from src/site/useMetaThemeColor.ts rename to src/utility/useMetaThemeColor.ts diff --git a/src/utility/vercel.ts b/src/utility/vercel.ts index fd788f11..0986f6bc 100644 --- a/src/utility/vercel.ts +++ b/src/utility/vercel.ts @@ -2,7 +2,7 @@ import { IS_PREVIEW, VERCEL_BYPASS_KEY, VERCEL_BYPASS_SECRET, -} from '@/site/config'; +} from '@/app-core/config'; export const fetchWithBypass: typeof fetch = (url, options) => IS_PREVIEW && VERCEL_BYPASS_SECRET From 4af7ac6b13ab2138a9a08735855bfa1fa36540d6 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 11 Feb 2025 18:15:05 -0600 Subject: [PATCH 17/54] Tweak insights spacing --- src/admin/AdminAppInsightsClient.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 329635d4..549fe9c8 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -54,11 +54,11 @@ export default function AdminAppInsightsClient({ return (
{renderTitle('Code Observability')} From 00582985b1cafad602766056a718d5791d4261fb Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 11 Feb 2025 18:18:54 -0600 Subject: [PATCH 18/54] Enable insights debugging in preview --- src/admin/AdminAppInsights.tsx | 4 ++-- src/admin/AdminAppInsightsClient.tsx | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index 9d489ba3..58286cda 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -6,7 +6,7 @@ import { getUniqueTags, } from '@/photo/db/query'; import AdminAppInsightsClient from './AdminAppInsightsClient'; -import { APP_CONFIGURATION, IS_DEVELOPMENT } from '@/app-core/config'; +import { APP_CONFIGURATION } from '@/app-core/config'; export default async function AdminAppInsights() { const [ { count, dateRange }, @@ -43,7 +43,7 @@ export default async function AdminAppInsights() { lensesCount: lenses.length, dateRange, }} - debug={IS_DEVELOPMENT} + debug /> ); } diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 549fe9c8..9c755287 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -64,8 +64,7 @@ export default function AdminAppInsightsClient({ {renderTitle('Code Observability')} {(fork || debug) && }> - Consider forking this repository in order to - receive new features and fixes + Consider forking this repository to receive new features and fixes } {(forkBehind || debug) && From a09040a0d86d6dcefeca413f7888dd539327780f Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 12 Feb 2025 09:35:31 -0600 Subject: [PATCH 19/54] Test insights scorecard --- src/admin/AdminAppInsights.tsx | 1 + src/admin/AdminAppInsightsClient.tsx | 42 ++++++++++++++++++- .../github/GitHubForkStatusBadgeClient.tsx | 5 +-- tailwind.css | 4 ++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index 58286cda..c25fdd3b 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -7,6 +7,7 @@ import { } from '@/photo/db/query'; import AdminAppInsightsClient from './AdminAppInsightsClient'; import { APP_CONFIGURATION } from '@/app-core/config'; + export default async function AdminAppInsights() { const [ { count, dateRange }, diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 9c755287..0e512f85 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -5,7 +5,9 @@ import Note from '@/components/Note'; import WarningNote from '@/components/WarningNote'; import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; import clsx from 'clsx/lite'; +import { ReactNode } from 'react'; import { HiSparkles } from 'react-icons/hi'; +import { PiWarningBold } from 'react-icons/pi'; type Recommendation = 'fork' | @@ -52,15 +54,53 @@ export default function AdminAppInsightsClient({ {title}
; + const renderRow = (icon: ReactNode, children: ReactNode) => +
+
+ {icon} +
+
+ {children} +
+
; + return (
+
+ {renderRow( + , + 'This fork is 9 commits behind', + )} + {renderRow( + , + 'Consider enabling rate limiting to mitigate AI abuse', + )} + {renderRow( + , + // eslint-disable-next-line max-len + 'Consider forking this repository to receive new features and fixes', + )} + {renderRow( + , + 'Enable AI text generation in the app configuration', + )} +
{renderTitle('Code Observability')} {(fork || debug) && }> diff --git a/src/admin/github/GitHubForkStatusBadgeClient.tsx b/src/admin/github/GitHubForkStatusBadgeClient.tsx index 7f1e0fd6..45a79750 100644 --- a/src/admin/github/GitHubForkStatusBadgeClient.tsx +++ b/src/admin/github/GitHubForkStatusBadgeClient.tsx @@ -59,10 +59,7 @@ export default function GitHubForkStatusBadgeClient({ classNameForStyle(), )}> {!label - ? + ? : } {label ?? 'Checking'}
diff --git a/tailwind.css b/tailwind.css index d02e2a8b..7648abc5 100644 --- a/tailwind.css +++ b/tailwind.css @@ -124,6 +124,10 @@ @apply border border-gray-200 dark:border-gray-700 } +@utility divide-main { + @apply + divide-gray-200 dark:divide-gray-700 +} /* Background */ @utility bg-main { @apply From bc2f38e3add9bbe5b7eabb3ae525fe1f308a0ba5 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 12 Feb 2025 20:44:01 -0600 Subject: [PATCH 20/54] Create ScoreCard component --- src/admin/AdminAppInsightsClient.tsx | 72 +++++++++++++--------------- src/components/ScoreCard.tsx | 13 +++++ src/components/ScoreCardRow.tsx | 29 +++++++++++ 3 files changed, 75 insertions(+), 39 deletions(-) create mode 100644 src/components/ScoreCard.tsx create mode 100644 src/components/ScoreCardRow.tsx diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 0e512f85..52fae8fa 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -2,10 +2,11 @@ import IconGrSync from '@/app-core/IconGrSync'; import Note from '@/components/Note'; +import ScoreCard from '@/components/ScoreCard'; +import ScoreCardRow from '@/components/ScoreCardRow'; import WarningNote from '@/components/WarningNote'; import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; import clsx from 'clsx/lite'; -import { ReactNode } from 'react'; import { HiSparkles } from 'react-icons/hi'; import { PiWarningBold } from 'react-icons/pi'; @@ -54,19 +55,6 @@ export default function AdminAppInsightsClient({ {title}
; - const renderRow = (icon: ReactNode, children: ReactNode) => -
-
- {icon} -
-
- {children} -
-
; - return (
-
- {renderRow( - , - 'This fork is 9 commits behind', - )} - {renderRow( - , - 'Consider enabling rate limiting to mitigate AI abuse', - )} - {renderRow( - , - // eslint-disable-next-line max-len - 'Consider forking this repository to receive new features and fixes', - )} - {renderRow( - , - 'Enable AI text generation in the app configuration', - )} -
+ + + } + > + This fork is 9 commits behind + + } + > + Consider enabling rate limiting to mitigate AI abuse + + } + > + Consider forking this repository to receive new features and fixes + + } + > + Enable AI text generation in the app configuration + + {renderTitle('Code Observability')} {(fork || debug) && }> diff --git a/src/components/ScoreCard.tsx b/src/components/ScoreCard.tsx new file mode 100644 index 00000000..c86bfb9d --- /dev/null +++ b/src/components/ScoreCard.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from 'react'; + +export default function ScoreCard({ + children, +}: { + children: ReactNode, +}) { + return ( +
+ {children} +
+ ); +} diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx new file mode 100644 index 00000000..716d4e47 --- /dev/null +++ b/src/components/ScoreCardRow.tsx @@ -0,0 +1,29 @@ +import { clsx } from 'clsx'; +import { ReactNode } from 'react'; +export default function ScoreCardRow({ + icon, + children, + details, +}: { + icon: ReactNode + children: ReactNode + details?: string +}) { + return ( +
+
+ {icon} +
+
+ {children} +
+ {details && + + {details} + } +
+ ); +} From 0494ce8a8631896e88cf77a98ea185b4521cdf00 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 12 Feb 2025 23:09:13 -0600 Subject: [PATCH 21/54] Add insight expand interaction --- src/admin/AdminAppInsightsClient.tsx | 34 ++++++++++++------------ src/components/ScoreCardRow.tsx | 39 ++++++++++++++++++---------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 52fae8fa..2a440976 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -58,7 +58,6 @@ export default function AdminAppInsightsClient({ return (
} - > - This fork is 9 commits behind - + content="This fork is 9 commits behind" + additionalContent="This fork is 9 commits behind" + /> } - > - Consider enabling rate limiting to mitigate AI abuse - + icon={} + content="Consider enabling rate limiting to mitigate AI abuse" + // eslint-disable-next-line max-len + additionalContent="Consider enabling rate limiting to mitigate AI abuse" + /> } - > - Consider forking this repository to receive new features and fixes - + // eslint-disable-next-line max-len + content="Consider forking this repository to receive new features and fixes" + /> } - > - Enable AI text generation in the app configuration - + content="Enable AI text generation in the app configuration" + /> {renderTitle('Code Observability')} {(fork || debug) && diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index 716d4e47..744ef1a8 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -1,29 +1,42 @@ import { clsx } from 'clsx'; -import { ReactNode } from 'react'; +import { ReactNode, useState } from 'react'; +import { FaMinus, FaPlus } from 'react-icons/fa6'; export default function ScoreCardRow({ icon, - children, - details, + content, + additionalContent, }: { icon: ReactNode - children: ReactNode - details?: string + content: ReactNode + additionalContent?: ReactNode }) { + const [isExpanded, setIsExpanded] = useState(false); return (
-
+
{icon}
-
- {children} +
+
+ {content} +
+ {isExpanded && +
+ {additionalContent} +
}
- {details && - - {details} - } + {additionalContent && }
); } From 1f6db2013d355fff7916696036fbdb3c736909cf Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 12 Feb 2025 23:24:07 -0600 Subject: [PATCH 22/54] Introduce more insights content --- src/admin/AdminAppInsightsClient.tsx | 20 ++++++++++++++++---- src/components/ScoreCardRow.tsx | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 2a440976..5808215e 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -8,6 +8,7 @@ import WarningNote from '@/components/WarningNote'; import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; import clsx from 'clsx/lite'; import { HiSparkles } from 'react-icons/hi'; +import { MdLightbulbOutline } from 'react-icons/md'; import { PiWarningBold } from 'react-icons/pi'; type Recommendation = @@ -72,16 +73,27 @@ export default function AdminAppInsightsClient({ /> } content="This fork is 9 commits behind" - additionalContent="This fork is 9 commits behind" + additionalContent={<> + Sync your fork to receive new features and fixes + } /> } - content="Consider enabling rate limiting to mitigate AI abuse" + content="AI enabled without rate limiting" // eslint-disable-next-line max-len - additionalContent="Consider enabling rate limiting to mitigate AI abuse" + additionalContent="Create Vercel KV store and link it to this project in order to enable rate limiting." + /> + } + // eslint-disable-next-line max-len + content="You seem to have several portrait photos—consider enabling photo matting to make images appear more consistent" + additionalContent={<> + Enabled photo matting by setting + `NEXT_PUBLIC_MATTE_PHOTOS = 1` + } /> } @@ -116,7 +128,7 @@ export default function AdminAppInsightsClient({ 'uppercase', )}>
Photos
-
{photosCount}
+
{photosCount}
Tags
{tagsCount}
Cameras
diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index 744ef1a8..ba9f7403 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -16,10 +16,10 @@ export default function ScoreCardRow({ 'flex gap-4', 'px-4 py-2', )}> -
+
{icon}
-
+
{content}
From be61ae61a3bcedff5932ce530f9979e51cb56098 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 12 Feb 2025 23:32:49 -0600 Subject: [PATCH 23/54] Prevent scorecard overflow --- src/admin/AdminAppInsightsClient.tsx | 2 +- src/components/ScoreCardRow.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index 5808215e..e09134b5 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -89,7 +89,7 @@ export default function AdminAppInsightsClient({ } // eslint-disable-next-line max-len - content="You seem to have several portrait photos—consider enabling photo matting to make images appear more consistent" + content="You seem to have several vertical photos—consider enabling matting to make portrait and landscape photos appear more consistent" additionalContent={<> Enabled photo matting by setting `NEXT_PUBLIC_MATTE_PHOTOS = 1` diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index ba9f7403..b7e055dc 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -19,7 +19,7 @@ export default function ScoreCardRow({
{icon}
-
+
{content}
From 556fa62b083bd1a77a880a8214a62d285c47121e Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Thu, 13 Feb 2025 09:17:19 -0600 Subject: [PATCH 24/54] Add app insights to admin menu --- src/admin/AdminAppInsightsIcon.tsx | 30 +++++++++++++++++ src/admin/AdminAppMenu.tsx | 17 ++++++++-- src/admin/AdminNavClient.tsx | 38 ++++++---------------- src/components/primitives/LoaderButton.tsx | 2 +- 4 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 src/admin/AdminAppInsightsIcon.tsx diff --git a/src/admin/AdminAppInsightsIcon.tsx b/src/admin/AdminAppInsightsIcon.tsx new file mode 100644 index 00000000..3e9008e9 --- /dev/null +++ b/src/admin/AdminAppInsightsIcon.tsx @@ -0,0 +1,30 @@ +import clsx from 'clsx/lite'; +import { FaInfo } from 'react-icons/fa'; + +export default function AdminAppInsightsIcon({ + notification = true, +}: { + notification?: boolean, +}) { + return ( + + + + + {notification && } + + ); +} diff --git a/src/admin/AdminAppMenu.tsx b/src/admin/AdminAppMenu.tsx index 60ffa121..0018cefd 100644 --- a/src/admin/AdminAppMenu.tsx +++ b/src/admin/AdminAppMenu.tsx @@ -1,11 +1,16 @@ 'use client'; import MoreMenu from '@/components/more/MoreMenu'; -import { PATH_ADMIN_CONFIGURATION, PATH_GRID_INFERRED } from '@/app-core/paths'; +import { + PATH_ADMIN_CONFIGURATION, + PATH_ADMIN_INSIGHTS, + PATH_GRID_INFERRED, +} from '@/app-core/paths'; import { useAppState } from '@/state/AppState'; import { BiCog } from 'react-icons/bi'; import { ImCheckboxUnchecked } from 'react-icons/im'; import { IoCloseSharp } from 'react-icons/io5'; +import AdminAppInsightsIcon from './AdminAppInsightsIcon'; export default function AdminAppMenu() { const { @@ -18,13 +23,19 @@ export default function AdminAppMenu() { return ( + + , + href: PATH_ADMIN_INSIGHTS, + }, { + label: 'Configuration', icon: , href: PATH_ADMIN_CONFIGURATION, }, { label: isSelecting ? 'Exit Select' - : 'Select Multiple', + : 'Select', icon: isSelecting ? dates @@ -92,31 +90,15 @@ export default function AdminNavClient({ )}
- - } - > - - - - - {DEBUG_INDICATOR_SIZE && } - + } + > + + {(icon || isLoading) && From 89c985497c45c83cb9730d6de8b51c6a56dfbb0d Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Thu, 13 Feb 2025 17:12:45 -0600 Subject: [PATCH 25/54] Refine admin app insights data --- __tests__/github.test.ts | 6 +- src/admin/AdminAppInsights.tsx | 30 ++++- src/admin/AdminAppInsightsClient.tsx | 185 ++++++++++++++++++--------- src/admin/github/index.ts | 28 ++-- src/app-core/config.ts | 29 +++-- src/app/template-url/route.tsx | 23 ++-- src/components/RepoLink.tsx | 5 +- src/components/ScoreCard.tsx | 8 +- src/components/ScoreCardRow.tsx | 15 ++- 9 files changed, 225 insertions(+), 104 deletions(-) diff --git a/__tests__/github.test.ts b/__tests__/github.test.ts index 552ea006..e6277ac4 100644 --- a/__tests__/github.test.ts +++ b/__tests__/github.test.ts @@ -1,11 +1,11 @@ import { getGitHubMetaWithFallback, getGitHubPublicFork } from '@/admin/github'; -import { TEMPLATE_BASE_OWNER, TEMPLATE_BASE_REPO } from '@/app-core/config'; +import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME } from '@/app-core/config'; describe('GitHub', () => { it('fetches base repo meta', async () => { const meta = await getGitHubMetaWithFallback({ - owner: TEMPLATE_BASE_OWNER, - repo: TEMPLATE_BASE_REPO, + owner: TEMPLATE_REPO_OWNER, + repo: TEMPLATE_REPO_NAME, }); expect(meta).toBeDefined(); expect(meta.url).toBeDefined(); diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/AdminAppInsights.tsx index c25fdd3b..8bb2fa57 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/AdminAppInsights.tsx @@ -6,17 +6,32 @@ import { getUniqueTags, } from '@/photo/db/query'; import AdminAppInsightsClient from './AdminAppInsightsClient'; -import { APP_CONFIGURATION } from '@/app-core/config'; +import { + APP_CONFIGURATION, + IS_VERCEL_GIT_PROVIDER_GITHUB, + VERCEL_GIT_BRANCH, + VERCEL_GIT_COMMIT_SHA, + VERCEL_GIT_REPO_OWNER, + VERCEL_GIT_REPO_SLUG, +} from '@/app-core/config'; +import { getGitHubMetaWithFallback } from './github'; + +const owner = VERCEL_GIT_REPO_OWNER; +const repo = VERCEL_GIT_REPO_SLUG; +const branch = VERCEL_GIT_BRANCH; +const commit = VERCEL_GIT_COMMIT_SHA; export default async function AdminAppInsights() { const [ { count, dateRange }, + { count: countHidden }, tags, cameras, filmSimulations, lenses, ] = await Promise.all([ getPhotosMeta({ hidden: 'include' }), + getPhotosMeta({ hidden: 'only' }), getUniqueTags(), getUniqueCameras(), getUniqueFilmSimulations(), @@ -28,16 +43,29 @@ export default async function AdminAppInsights() { hasVercelBlobStorage, } = APP_CONFIGURATION; + const codeMeta = IS_VERCEL_GIT_PROVIDER_GITHUB + ? await getGitHubMetaWithFallback({ + owner, + repo, + branch, + commit, + }) + : undefined; + return ( , + codeMeta?: Awaited> + recommendations: Record photoStats: { photosCount: number + photosCountHidden: number tagsCount: number camerasCount: number filmSimulationsCount: number lensesCount: number dateRange?: PhotoDateRange }, - debug?: boolean, + debug?: boolean }) { const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); const renderTitle = (title: string) =>
{title} @@ -64,19 +82,53 @@ export default function AdminAppInsightsClient({ 'w-full sm:w-[80%] lg:w-[60%]', 'space-y-4 md:space-y-6', )}> + {(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> + {renderTitle('Build details')} + + } + content={
+
+
{codeMeta?.owner ?? TEMPLATE_REPO_OWNER}
+
/
+
{codeMeta?.repo ?? TEMPLATE_REPO_NAME}
+
+
+
+
+ {codeMeta?.branch ?? TEMPLATE_REPO_BRANCH} +
+
+
} + /> + {(codeMeta?.behindBy || debug) && + } + // eslint-disable-next-line max-len + content={`This fork is ${codeMeta?.behindBy ?? 9} commits behind`} + additionalContent={<> + Sync your fork to receive new features and fixes + } + />} + } + icon={} + content={
+
+ {VERCEL_GIT_COMMIT_SHA_SHORT ?? DEBUG_COMMIT_SHA} +
+
+ {codeMeta?.commit ?? DEBUG_COMMIT_MESSAGE} +
+
} + /> +
+ } + {renderTitle('Template recommendations')} - - } - content="This fork is 9 commits behind" - additionalContent={<> - Sync your fork to receive new features and fixes - } - /> - {renderTitle('Code Observability')} - {(fork || debug) && - }> - Consider forking this repository to receive new features and fixes - } - {(forkBehind || debug) && - - This fork is 9 commits behind - } - {renderTitle('Template Recommendations')} - {(ai || debug) && }> - Enable AI text generation in the app configuration - } - {(aiRateLimiting || debug) && - Consider enabling rate limiting to mitigate AI abuse - } {renderTitle('Library Stats')} -
-
Photos
-
{photosCount}
-
Tags
-
{tagsCount}
-
Cameras
-
{camerasCount}
-
Films
-
{filmSimulationsCount}
-
Lenses
-
{lensesCount}
- - {descriptionWithSpaces} - -
+ + } + content={<> + {photosCount} photos + {photosCountHidden > 0 && + ` (${photosCountHidden} hidden)`} + } + /> + } + content={`${tagsCount} tags`} + /> + } + content={`${camerasCount} cameras`} + /> + {filmSimulationsCount && + + + } + content={`${filmSimulationsCount} film simulations`} + />} + } + content={`${lensesCount} lenses`} + /> + } + content={descriptionWithSpaces} + /> +
); diff --git a/src/admin/github/index.ts b/src/admin/github/index.ts index f6625b05..fae49ffd 100644 --- a/src/admin/github/index.ts +++ b/src/admin/github/index.ts @@ -1,7 +1,7 @@ import { - TEMPLATE_BASE_OWNER, - TEMPLATE_BASE_REPO, - TEMPLATE_BASE_BRANCH, + TEMPLATE_REPO_OWNER, + TEMPLATE_REPO_NAME, + TEMPLATE_REPO_BRANCH, } from '@/app-core/config'; const DEFAULT_BRANCH = 'main'; @@ -23,8 +23,8 @@ interface RepoParams { // Website urls export const getGitHubRepoUrl = ({ - owner = TEMPLATE_BASE_OWNER, - repo = TEMPLATE_BASE_REPO, + owner = TEMPLATE_REPO_OWNER, + repo = TEMPLATE_REPO_NAME, }: RepoParams = {}) => `https://github.com/${owner}/${repo}`; @@ -34,13 +34,13 @@ export const getGitHubCompareUrl = ({ branch = DEFAULT_BRANCH, }: RepoParams = {}) => // eslint-disable-next-line max-len - `${getGitHubRepoUrl({ owner, repo })}/compare/${branch}...${TEMPLATE_BASE_OWNER}:${TEMPLATE_BASE_REPO}:${TEMPLATE_BASE_BRANCH}`; + `${getGitHubRepoUrl({ owner, repo })}/compare/${branch}...${TEMPLATE_REPO_OWNER}:${TEMPLATE_REPO_NAME}:${TEMPLATE_REPO_BRANCH}`; // API urls const getGitHubApiRepoUrl = ({ - owner = TEMPLATE_BASE_OWNER, - repo = TEMPLATE_BASE_REPO, + owner = TEMPLATE_REPO_OWNER, + repo = TEMPLATE_REPO_NAME, }: RepoParams = {}) => `https://api.github.com/repos/${owner}/${repo}`; @@ -56,10 +56,10 @@ const getGitHubApiCompareToRepoUrl = ({ branch = DEFAULT_BRANCH, }: RepoParams = {}) => // eslint-disable-next-line max-len - `${getGitHubApiRepoUrl()}/compare/${TEMPLATE_BASE_BRANCH}...${owner}:${repo}:${branch}`; + `${getGitHubApiRepoUrl()}/compare/${TEMPLATE_REPO_BRANCH}...${owner}:${repo}:${branch}`; const getGitHubApiCompareToCommitUrl = ({ commit }: RepoParams = {}) => - `${getGitHubApiRepoUrl()}/compare/${TEMPLATE_BASE_BRANCH}...${commit}`; + `${getGitHubApiRepoUrl()}/compare/${TEMPLATE_REPO_BRANCH}...${commit}`; // Requests @@ -74,7 +74,7 @@ const getIsRepoForkedFromBase = async (params: RepoParams) => { const data = await response.json(); return ( Boolean(data.fork) && - data.source?.full_name === `${TEMPLATE_BASE_OWNER}/${TEMPLATE_BASE_REPO}` + data.source?.full_name === `${TEMPLATE_REPO_OWNER}/${TEMPLATE_REPO_NAME}` ); }; @@ -97,8 +97,8 @@ const getGitHubCommitsBehindFromCommit = async (params?: RepoParams) => { }; const isRepoBaseRepo = ({ owner, repo }: RepoParams) => - owner?.toLowerCase() === TEMPLATE_BASE_OWNER && - repo?.toLowerCase() === TEMPLATE_BASE_REPO; + owner?.toLowerCase() === TEMPLATE_REPO_OWNER && + repo?.toLowerCase() === TEMPLATE_REPO_NAME; export const getGitHubPublicFork = async ( params?: RepoParams, @@ -144,6 +144,7 @@ const getGitHubMeta = async (params: RepoParams) => { : 'This fork is up to date.'; return { + ...params, url, isForkedFromBase, isBaseRepo, @@ -160,6 +161,7 @@ export const getGitHubMetaWithFallback = (params: RepoParams) => .catch(e => { console.error('Error retrieving GitHub meta', { params, error: e }); return { + ...params, url: undefined, isForkedFromBase: false, isBaseRepo: undefined, diff --git a/src/app-core/config.ts b/src/app-core/config.ts index 449e0fe8..03afd8d0 100644 --- a/src/app-core/config.ts +++ b/src/app-core/config.ts @@ -6,17 +6,21 @@ import type { StorageType } from '@/services/storage'; import { makeUrlAbsolute, shortenUrl } from '@/utility/url'; // HARD-CODED GLOBAL CONFIGURATION + export const SHOULD_PREFETCH_ALL_LINKS: boolean | undefined = undefined; -// META / SOURCE / DOMAINS -export const SITE_TITLE = - process.env.NEXT_PUBLIC_SITE_TITLE || - 'Photo Blog'; +// TEMPLATE META -// SOURCE -export const TEMPLATE_BASE_OWNER = 'sambecker'; -export const TEMPLATE_BASE_REPO = 'exif-photo-blog'; -export const TEMPLATE_BASE_BRANCH = 'main'; +export const TEMPLATE_TITLE = 'Photo Blog'; +export const TEMPLATE_DESCRIPTION = 'Store photos with original camera data'; + +// SOURCE CODE + +export const TEMPLATE_REPO_OWNER = 'sambecker'; +export const TEMPLATE_REPO_NAME = 'exif-photo-blog'; +export const TEMPLATE_REPO_BRANCH = 'main'; +// eslint-disable-next-line max-len +export const TEMPLATE_REPO_URL = `https://github.com/${TEMPLATE_REPO_OWNER}/${TEMPLATE_REPO_NAME}`; export const VERCEL_GIT_PROVIDER = process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER; @@ -59,6 +63,12 @@ export const IS_PREVIEW = VERCEL_ENV === 'preview'; export const VERCEL_BYPASS_KEY = 'x-vercel-protection-bypass'; export const VERCEL_BYPASS_SECRET = process.env.VERCEL_AUTOMATION_BYPASS_SECRET; +// SITE META + +export const SITE_TITLE = + process.env.NEXT_PUBLIC_SITE_TITLE || + TEMPLATE_TITLE; + // User-facing domain, potential site title const SITE_DOMAIN = process.env.NEXT_PUBLIC_SITE_DOMAIN || @@ -90,11 +100,14 @@ export const SITE_ABOUT = process.env.NEXT_PUBLIC_SITE_ABOUT; export const HAS_DEFINED_SITE_DESCRIPTION = Boolean(process.env.NEXT_PUBLIC_SITE_DESCRIPTION); +// STORAGE + // STORAGE: DATABASE export const HAS_DATABASE = Boolean(process.env.POSTGRES_URL); export const POSTGRES_SSL_ENABLED = process.env.DISABLE_POSTGRES_SSL === '1' ? false : true; + // STORAGE: VERCEL KV export const HAS_VERCEL_KV = Boolean(process.env.KV_URL); diff --git a/src/app/template-url/route.tsx b/src/app/template-url/route.tsx index 6bf109cd..79599351 100644 --- a/src/app/template-url/route.tsx +++ b/src/app/template-url/route.tsx @@ -1,24 +1,25 @@ /* eslint-disable max-len */ +import { + TEMPLATE_REPO_OWNER, + TEMPLATE_REPO_NAME, + TEMPLATE_DESCRIPTION, + TEMPLATE_TITLE, +} from '@/app-core/config'; import { NextResponse } from 'next/server'; const REQUIRE_ENV_VARS = false; -const TITLE = 'Photo Blog'; -const DESCRIPTION = 'Store photos with original camera data'; -const REPO_TEAM = 'sambecker'; -const REPO_NAME = 'exif-photo-blog'; - export function GET() { const url = new URL('https://vercel.com/new/clone'); - url.searchParams.set('demo-title', TITLE); - url.searchParams.set('demo-description', DESCRIPTION); + url.searchParams.set('demo-title', TEMPLATE_TITLE); + url.searchParams.set('demo-description', TEMPLATE_DESCRIPTION); url.searchParams.set('demo-url', 'https://photos.sambecker.com'); - url.searchParams.set('demo-description', DESCRIPTION); + url.searchParams.set('demo-description', TEMPLATE_DESCRIPTION); url.searchParams.set('demo-image', 'https://photos.sambecker.com/template-image-tight'); - url.searchParams.set('project-name', TITLE); - url.searchParams.set('repository-name', REPO_NAME); - url.searchParams.set('repository-url', `https://github.com/${REPO_TEAM}/${REPO_NAME}`); + url.searchParams.set('project-name', TEMPLATE_TITLE); + url.searchParams.set('repository-name', TEMPLATE_REPO_NAME); + url.searchParams.set('repository-url', `https://github.com/${TEMPLATE_REPO_OWNER}/${TEMPLATE_REPO_NAME}`); url.searchParams.set('from', 'templates'); url.searchParams.set('skippable-integrations', '1'); if (REQUIRE_ENV_VARS) { diff --git a/src/components/RepoLink.tsx b/src/components/RepoLink.tsx index cc0b6469..621c6f82 100644 --- a/src/components/RepoLink.tsx +++ b/src/components/RepoLink.tsx @@ -1,3 +1,4 @@ +import { TEMPLATE_REPO_NAME, TEMPLATE_REPO_URL } from '@/app-core/config'; import { clsx } from 'clsx/lite'; import Link from 'next/link'; import { BiLogoGithub } from 'react-icons/bi'; @@ -9,7 +10,7 @@ export default function RepoLink() { Made with - exif-photo-blog + {TEMPLATE_REPO_NAME} ); diff --git a/src/components/ScoreCard.tsx b/src/components/ScoreCard.tsx index c86bfb9d..d658ee7b 100644 --- a/src/components/ScoreCard.tsx +++ b/src/components/ScoreCard.tsx @@ -1,12 +1,18 @@ +import clsx from 'clsx/lite'; import { ReactNode } from 'react'; export default function ScoreCard({ children, + className, }: { children: ReactNode, + className?: string, }) { return ( -
+
{children}
); diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index b7e055dc..243a4b84 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -1,6 +1,7 @@ import { clsx } from 'clsx'; import { ReactNode, useState } from 'react'; import { FaMinus, FaPlus } from 'react-icons/fa6'; + export default function ScoreCardRow({ icon, content, @@ -11,16 +12,20 @@ export default function ScoreCardRow({ additionalContent?: ReactNode }) { const [isExpanded, setIsExpanded] = useState(false); + return (
-
+
{icon}
-
+
{content}
{isExpanded && @@ -31,7 +36,7 @@ export default function ScoreCardRow({ {additionalContent &&
+ ); } diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/AdminAppInsightsClient.tsx index e3f0d80b..22b8d976 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/AdminAppInsightsClient.tsx @@ -5,7 +5,6 @@ import ScoreCard from '@/components/ScoreCard'; import ScoreCardRow from '@/components/ScoreCardRow'; import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon'; -import clsx from 'clsx/lite'; import { FaCamera } from 'react-icons/fa'; import { FaTag } from 'react-icons/fa'; import { FaRegCalendar } from 'react-icons/fa6'; @@ -66,147 +65,130 @@ export default function AdminAppInsightsClient({ const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); - const renderTitle = (title: string) => -
- {title} -
; - return ( -
-
- {(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> - {renderTitle('Build details')} - - } - content={
-
-
{codeMeta?.owner ?? TEMPLATE_REPO_OWNER}
-
/
-
{codeMeta?.repo ?? TEMPLATE_REPO_NAME}
-
-
-
-
- {codeMeta?.branch ?? TEMPLATE_REPO_BRANCH} -
-
-
} - /> - {(codeMeta?.behindBy || debug) && - } - // eslint-disable-next-line max-len - content={`This fork is ${codeMeta?.behindBy ?? 9} commits behind`} - additionalContent={<> - Sync your fork to receive new features and fixes - } - />} - } - icon={} - content={
-
- {VERCEL_GIT_COMMIT_SHA_SHORT ?? DEBUG_COMMIT_SHA} -
+
+ {(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> + + } + content={
+
+
{codeMeta?.owner ?? TEMPLATE_REPO_OWNER}
+
/
+
{codeMeta?.repo ?? TEMPLATE_REPO_NAME}
+
+
+
- {codeMeta?.commit ?? DEBUG_COMMIT_MESSAGE} + {codeMeta?.branch ?? TEMPLATE_REPO_BRANCH}
-
} - /> - - } - {renderTitle('Template recommendations')} - - } - content="AI enabled without rate limiting" - // eslint-disable-next-line max-len - additionalContent="Create Vercel KV store and link it to this project in order to enable rate limiting." +
+
} /> } - // eslint-disable-next-line max-len - content="You seem to have several vertical photos—consider enabling matting to make portrait and landscape photos appear more consistent" - additionalContent={<> - Enabled photo matting by setting - `NEXT_PUBLIC_MATTE_PHOTOS = 1` - } + // icon={} + icon={} + content={
+
+ {VERCEL_GIT_COMMIT_SHA_SHORT ?? DEBUG_COMMIT_SHA} +
+
+ {codeMeta?.commit ?? DEBUG_COMMIT_MESSAGE} +
+
} /> - } - // eslint-disable-next-line max-len - content="Consider forking this repository to receive new features and fixes" - /> - } - content="Enable AI text generation in the app configuration" - /> - - {renderTitle('Library Stats')} - - } - content={<> - {photosCount} photos - {photosCountHidden > 0 && - ` (${photosCountHidden} hidden)`} - } - /> - } - content={`${tagsCount} tags`} - /> - } - content={`${camerasCount} cameras`} - /> - {filmSimulationsCount && + {(codeMeta?.behindBy || debug) && - - } - content={`${filmSimulationsCount} film simulations`} + icon={} + content={`This fork is ${codeMeta?.behindBy ?? 9} commits behind`} + additionalContent={<> + Sync your fork to receive new features and fixes + } />} - } - content={`${lensesCount} lenses`} - /> - } - content={descriptionWithSpaces} - /> -
+ } + + } + content="AI enabled without rate limiting" + // eslint-disable-next-line max-len + additionalContent="Create Vercel KV store and link it to this project in order to enable rate limiting." + /> + } + // eslint-disable-next-line max-len + content="You seem to have several vertical photos—consider enabling matting to make portrait and landscape photos appear more consistent" + additionalContent={<> + Enabled photo matting by setting + `NEXT_PUBLIC_MATTE_PHOTOS = 1` + } + /> + } + // eslint-disable-next-line max-len + content="Consider forking this repository to receive new features and fixes" + /> + } + content="Enable AI text generation in the app configuration" + /> + + + } + content={<> + {photosCount} photos + {photosCountHidden > 0 && + ` (${photosCountHidden} hidden)`} + } + /> + } + content={`${tagsCount} tags`} + /> + } + content={`${camerasCount} cameras`} + /> + {filmSimulationsCount && + + + } + content={`${filmSimulationsCount} film simulations`} + />} + } + content={`${lensesCount} lenses`} + /> + } + content={descriptionWithSpaces} + /> +
); } diff --git a/src/admin/AdminAppInsightsIcon.tsx b/src/admin/AdminAppInsightsIcon.tsx index 3e9008e9..f346bec6 100644 --- a/src/admin/AdminAppInsightsIcon.tsx +++ b/src/admin/AdminAppInsightsIcon.tsx @@ -2,9 +2,9 @@ import clsx from 'clsx/lite'; import { FaInfo } from 'react-icons/fa'; export default function AdminAppInsightsIcon({ - notification = true, + indicator = 'blue', }: { - notification?: boolean, + indicator?: 'blue' | 'yellow' }) { return ( @@ -19,11 +19,15 @@ export default function AdminAppInsightsIcon({ aria-label="App Configuration" /> - {notification && } ); diff --git a/src/admin/AdminInfoPage.tsx b/src/admin/AdminInfoPage.tsx index 0af159ee..3e046c22 100644 --- a/src/admin/AdminInfoPage.tsx +++ b/src/admin/AdminInfoPage.tsx @@ -22,7 +22,9 @@ export default function AdminInfoPage({ {accessory}
- {children} +
+ {children} +
} /> diff --git a/src/components/ScoreCard.tsx b/src/components/ScoreCard.tsx index d658ee7b..d08c9cb4 100644 --- a/src/components/ScoreCard.tsx +++ b/src/components/ScoreCard.tsx @@ -2,18 +2,30 @@ import clsx from 'clsx/lite'; import { ReactNode } from 'react'; export default function ScoreCard({ + title, children, className, }: { + title?: string, children: ReactNode, className?: string, }) { return ( -
- {children} +
+ {title && +
+ {title} +
} +
+ {children} +
); } diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index 243a4b84..7e4c40da 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -6,10 +6,12 @@ export default function ScoreCardRow({ icon, content, additionalContent, + className, }: { icon: ReactNode content: ReactNode additionalContent?: ReactNode + className?: string }) { const [isExpanded, setIsExpanded] = useState(false); @@ -17,6 +19,7 @@ export default function ScoreCardRow({
Date: Thu, 13 Feb 2025 19:59:09 -0600 Subject: [PATCH 27/54] Consolidate AdminInsights files --- src/admin/AdminAppMenu.tsx | 2 +- src/admin/AdminNavClient.tsx | 2 +- src/admin/{ => insights}/AdminAppInsights.tsx | 2 +- src/admin/{ => insights}/AdminAppInsightsClient.tsx | 11 ++--------- src/admin/{ => insights}/AdminAppInsightsIcon.tsx | 0 src/admin/insights/index.ts | 7 +++++++ src/app/admin/insights/page.tsx | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) rename src/admin/{ => insights}/AdminAppInsights.tsx (97%) rename src/admin/{ => insights}/AdminAppInsightsClient.tsx (97%) rename src/admin/{ => insights}/AdminAppInsightsIcon.tsx (100%) create mode 100644 src/admin/insights/index.ts diff --git a/src/admin/AdminAppMenu.tsx b/src/admin/AdminAppMenu.tsx index 0018cefd..20f51c46 100644 --- a/src/admin/AdminAppMenu.tsx +++ b/src/admin/AdminAppMenu.tsx @@ -10,7 +10,7 @@ import { useAppState } from '@/state/AppState'; import { BiCog } from 'react-icons/bi'; import { ImCheckboxUnchecked } from 'react-icons/im'; import { IoCloseSharp } from 'react-icons/io5'; -import AdminAppInsightsIcon from './AdminAppInsightsIcon'; +import AdminAppInsightsIcon from './insights/AdminAppInsightsIcon'; export default function AdminAppMenu() { const { diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 70334931..3002a54e 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -20,7 +20,7 @@ import { usePathname } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; import { FaRegClock } from 'react-icons/fa'; import { HiOutlineCog } from 'react-icons/hi'; -import AdminAppInsightsIcon from './AdminAppInsightsIcon'; +import AdminAppInsightsIcon from './insights/AdminAppInsightsIcon'; // Updates considered recent if they occurred in past 5 minutes const areTimesRecent = (dates: Date[]) => dates diff --git a/src/admin/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx similarity index 97% rename from src/admin/AdminAppInsights.tsx rename to src/admin/insights/AdminAppInsights.tsx index 8bb2fa57..d56eb6fe 100644 --- a/src/admin/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -14,7 +14,7 @@ import { VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_SLUG, } from '@/app-core/config'; -import { getGitHubMetaWithFallback } from './github'; +import { getGitHubMetaWithFallback } from '../github'; const owner = VERCEL_GIT_REPO_OWNER; const repo = VERCEL_GIT_REPO_SLUG; diff --git a/src/admin/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx similarity index 97% rename from src/admin/AdminAppInsightsClient.tsx rename to src/admin/insights/AdminAppInsightsClient.tsx index 22b8d976..62e73176 100644 --- a/src/admin/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -24,18 +24,11 @@ import { TEMPLATE_REPO_NAME, VERCEL_GIT_COMMIT_SHA_SHORT, } from '@/app-core/config'; +import { AdminAppInsight } from './insights'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; -type Recommendation = - 'fork' | - 'forkBehind' | - 'ai' | - 'aiRateLimiting' | - 'photoMatting' | - 'gridFirst'; - export default function AdminAppInsightsClient({ codeMeta, photoStats: { @@ -50,7 +43,7 @@ export default function AdminAppInsightsClient({ debug, }: { codeMeta?: Awaited> - recommendations: Record + recommendations: Record photoStats: { photosCount: number photosCountHidden: number diff --git a/src/admin/AdminAppInsightsIcon.tsx b/src/admin/insights/AdminAppInsightsIcon.tsx similarity index 100% rename from src/admin/AdminAppInsightsIcon.tsx rename to src/admin/insights/AdminAppInsightsIcon.tsx diff --git a/src/admin/insights/index.ts b/src/admin/insights/index.ts new file mode 100644 index 00000000..f92111a4 --- /dev/null +++ b/src/admin/insights/index.ts @@ -0,0 +1,7 @@ +export type AdminAppInsight = + 'fork' | + 'forkBehind' | + 'ai' | + 'aiRateLimiting' | + 'photoMatting' | + 'gridFirst'; diff --git a/src/app/admin/insights/page.tsx b/src/app/admin/insights/page.tsx index 152ad524..e81b4596 100644 --- a/src/app/admin/insights/page.tsx +++ b/src/app/admin/insights/page.tsx @@ -1,4 +1,4 @@ -import AdminAppInsights from '@/admin/AdminAppInsights'; +import AdminAppInsights from '@/admin/insights/AdminAppInsights'; import AdminInfoPage from '@/admin/AdminInfoPage'; import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; import { From 03ac8be368182a121fd4c3326e668309e4bf24f8 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Thu, 13 Feb 2025 23:03:15 -0600 Subject: [PATCH 28/54] Refine app insight rules --- src/admin/github/index.ts | 27 ++++++++++-- src/admin/insights/AdminAppInsights.tsx | 31 ++++++++------ src/admin/insights/AdminAppInsightsClient.tsx | 41 +++++++++++++++---- src/admin/insights/index.ts | 9 ++-- src/app-core/config.ts | 11 ++--- src/app/layout.tsx | 19 ++++----- src/components/ScoreCardRow.tsx | 2 +- src/photo/db/index.ts | 6 +++ 8 files changed, 100 insertions(+), 46 deletions(-) diff --git a/src/admin/github/index.ts b/src/admin/github/index.ts index fae49ffd..3f9d38e3 100644 --- a/src/admin/github/index.ts +++ b/src/admin/github/index.ts @@ -22,11 +22,23 @@ interface RepoParams { // Website urls +export const getGitHubOwnerUrl = ({ + owner = TEMPLATE_REPO_OWNER, +}: RepoParams = {}) => + `https://github.com/${owner}`; + export const getGitHubRepoUrl = ({ owner = TEMPLATE_REPO_OWNER, repo = TEMPLATE_REPO_NAME, }: RepoParams = {}) => - `https://github.com/${owner}/${repo}`; + `${getGitHubOwnerUrl({ owner })}/${repo}`; + +export const getGitHubBranchUrl = ({ + owner = TEMPLATE_REPO_OWNER, + repo = TEMPLATE_REPO_NAME, + branch = DEFAULT_BRANCH, +}: RepoParams = {}) => + `${getGitHubRepoUrl({ owner, repo })}/tree/${branch}`; export const getGitHubCompareUrl = ({ owner, @@ -112,7 +124,10 @@ export const getGitHubPublicFork = async ( }; const getGitHubMeta = async (params: RepoParams) => { - const url = getGitHubRepoUrl(params); + const urlOwner = getGitHubOwnerUrl(params); + const urlRepo = getGitHubRepoUrl(params); + const urlBranch = getGitHubBranchUrl(params); + const isBaseRepo = isRepoBaseRepo(params); const [ @@ -145,7 +160,9 @@ const getGitHubMeta = async (params: RepoParams) => { return { ...params, - url, + urlOwner, + urlRepo, + urlBranch, isForkedFromBase, isBaseRepo, behindBy, @@ -162,7 +179,9 @@ export const getGitHubMetaWithFallback = (params: RepoParams) => console.error('Error retrieving GitHub meta', { params, error: e }); return { ...params, - url: undefined, + urlOwner: undefined, + urlRepo: undefined, + urlBranch: undefined, isForkedFromBase: false, isBaseRepo: undefined, behindBy: undefined, diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index d56eb6fe..7c75ee7d 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -8,7 +8,11 @@ import { import AdminAppInsightsClient from './AdminAppInsightsClient'; import { APP_CONFIGURATION, + GRID_HOMEPAGE_ENABLED, + HAS_STATIC_OPTIMIZATION, + IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB, + MATTE_PHOTOS, VERCEL_GIT_BRANCH, VERCEL_GIT_COMMIT_SHA, VERCEL_GIT_REPO_OWNER, @@ -23,8 +27,9 @@ const commit = VERCEL_GIT_COMMIT_SHA; export default async function AdminAppInsights() { const [ - { count, dateRange }, - { count: countHidden }, + { count: photosCount, dateRange }, + { count: photosCountHidden }, + { count: photosCountPortrait }, tags, cameras, filmSimulations, @@ -32,6 +37,7 @@ export default async function AdminAppInsights() { ] = await Promise.all([ getPhotosMeta({ hidden: 'include' }), getPhotosMeta({ hidden: 'only' }), + getPhotosMeta({ maximumAspectRatio: 0.9 }), getUniqueTags(), getUniqueCameras(), getUniqueFilmSimulations(), @@ -43,7 +49,7 @@ export default async function AdminAppInsights() { hasVercelBlobStorage, } = APP_CONFIGURATION; - const codeMeta = IS_VERCEL_GIT_PROVIDER_GITHUB + const codeMeta = IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT ? await getGitHubMetaWithFallback({ owner, repo, @@ -56,23 +62,24 @@ export default async function AdminAppInsights() { 0 && !MATTE_PHOTOS, + gridFirst: photosCount > 32 && !GRID_HOMEPAGE_ENABLED, + noStaticOptimization: !HAS_STATIC_OPTIMIZATION, }} photoStats={{ - photosCount: count, - photosCountHidden: countHidden, + photosCount, + photosCountHidden, tagsCount: tags.length, camerasCount: cameras.length, filmSimulationsCount: filmSimulations.length, lensesCount: lenses.length, dateRange, }} - debug + debug={IS_DEVELOPMENT} /> ); } diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 62e73176..38a0b732 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -16,7 +16,7 @@ import { import { MdLightbulbOutline } from 'react-icons/md'; import { PiWarningBold } from 'react-icons/pi'; import { TbCone } from 'react-icons/tb'; -import { getGitHubMetaWithFallback } from './github'; +import { getGitHubMetaWithFallback } from '../github'; import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi'; import { TEMPLATE_REPO_BRANCH, @@ -24,13 +24,17 @@ import { TEMPLATE_REPO_NAME, VERCEL_GIT_COMMIT_SHA_SHORT, } from '@/app-core/config'; -import { AdminAppInsight } from './insights'; +import { AdminAppInsight } from '.'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; export default function AdminAppInsightsClient({ codeMeta, + recommendations: { + noAi, + noAiRateLimiting, + }, photoStats: { photosCount, photosCountHidden, @@ -68,20 +72,33 @@ export default function AdminAppInsightsClient({ className="flex flex-wrap gap-x-4 gap-y-1 overflow-auto" >
-
{codeMeta?.owner ?? TEMPLATE_REPO_OWNER}
+ + {codeMeta?.owner ?? TEMPLATE_REPO_OWNER} +
/
-
{codeMeta?.repo ?? TEMPLATE_REPO_NAME}
+ + {codeMeta?.repo ?? TEMPLATE_REPO_NAME} +
} /> } icon={} content={
@@ -106,7 +123,7 @@ export default function AdminAppInsightsClient({ } - + />} + {(noAi || debug) && } + content="Enable AI text generation to improve photo descriptions" + // eslint-disable-next-line max-len + additionalContent="Create Vercel KV store and link it to this project in order to enable rate limiting." + />} } // eslint-disable-next-line max-len diff --git a/src/admin/insights/index.ts b/src/admin/insights/index.ts index f92111a4..156b5bcf 100644 --- a/src/admin/insights/index.ts +++ b/src/admin/insights/index.ts @@ -1,7 +1,8 @@ export type AdminAppInsight = - 'fork' | + 'noFork' | 'forkBehind' | - 'ai' | - 'aiRateLimiting' | + 'noAi' | + 'noAiRateLimiting' | 'photoMatting' | - 'gridFirst'; + 'gridFirst' | + 'noStaticOptimization'; diff --git a/src/app-core/config.ts b/src/app-core/config.ts index 03afd8d0..5dfe1a30 100644 --- a/src/app-core/config.ts +++ b/src/app-core/config.ts @@ -175,6 +175,11 @@ export const STATICALLY_OPTIMIZED_PHOTO_CATEGORIES = process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORIES === '1'; export const STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES = process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES === '1'; +export const HAS_STATIC_OPTIMIZATION = + STATICALLY_OPTIMIZED_PHOTOS || + STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES || + STATICALLY_OPTIMIZED_PHOTO_CATEGORIES || + STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES; export const PRESERVE_ORIGINAL_UPLOADS = process.env.NEXT_PUBLIC_PRESERVE_ORIGINAL_UPLOADS === '1' || // Legacy environment variable name @@ -285,11 +290,7 @@ export const APP_CONFIGURATION = { hasAiTextAutoGeneratedFields: Boolean(process.env.AI_TEXT_AUTO_GENERATED_FIELDS), // Performance - isStaticallyOptimized: ( - STATICALLY_OPTIMIZED_PHOTOS || - STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES || - STATICALLY_OPTIMIZED_PHOTO_CATEGORIES - ), + isStaticallyOptimized: HAS_STATIC_OPTIMIZATION, arePhotosStaticallyOptimized: STATICALLY_OPTIMIZED_PHOTOS, arePhotoOGImagesStaticallyOptimized: STATICALLY_OPTIMIZED_PHOTO_OG_IMAGES, arePhotoCategoriesStaticallyOptimized: STATICALLY_OPTIMIZED_PHOTO_CATEGORIES, diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2e0d809b..26171370 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -72,11 +72,8 @@ export default function RootLayout({ > - - + +
-
-
- - - - + + + + + +
diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index 7e4c40da..addc539b 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -32,7 +32,7 @@ export default function ScoreCardRow({ {content}
{isExpanded && -
+
{additionalContent}
}
diff --git a/src/photo/db/index.ts b/src/photo/db/index.ts index 72ba97a8..6b0fe754 100644 --- a/src/photo/db/index.ts +++ b/src/photo/db/index.ts @@ -17,6 +17,7 @@ export type GetPhotosOptions = { limit?: number offset?: number query?: string + maximumAspectRatio?: number takenBefore?: Date takenAfterInclusive?: Date updatedBefore?: Date @@ -36,6 +37,7 @@ export const getWheresFromOptions = ( takenAfterInclusive, updatedBefore, query, + maximumAspectRatio, tag, camera, lens, @@ -73,6 +75,10 @@ export const getWheresFromOptions = ( wheres.push(`CONCAT(title, ' ', caption, ' ', semantic_description) ILIKE $${valuesIndex++}`); wheresValues.push(`%${query.toLocaleLowerCase()}%`); } + if (maximumAspectRatio) { + wheres.push(`aspect_ratio <= $${valuesIndex++}`); + wheresValues.push(maximumAspectRatio); + } if (tag) { wheres.push(`$${valuesIndex++}=ANY(tags)`); wheresValues.push(tag); From 0a2b8666bd8175188ecb02afdb06b261b102f025 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Thu, 13 Feb 2025 23:06:15 -0600 Subject: [PATCH 29/54] Fix GitHub badge typo --- src/admin/github/GitHubForkStatusBadgeServer.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/admin/github/GitHubForkStatusBadgeServer.tsx b/src/admin/github/GitHubForkStatusBadgeServer.tsx index f1bb8f02..a9959144 100644 --- a/src/admin/github/GitHubForkStatusBadgeServer.tsx +++ b/src/admin/github/GitHubForkStatusBadgeServer.tsx @@ -14,7 +14,6 @@ export default async function GitHubForkStatusBadgeServer() { const commit = VERCEL_GIT_COMMIT_SHA; const { - url, isForkedFromBase, isBaseRepo, isBehind, @@ -44,7 +43,6 @@ export default async function GitHubForkStatusBadgeServer() { return isForkedFromBase || isBaseRepo ? {description} From c63140b2272e7464f68089da309ddaf293a04c84 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Thu, 13 Feb 2025 23:14:40 -0600 Subject: [PATCH 30/54] Fix commit message reporting --- src/admin/github/index.ts | 1 + src/admin/insights/AdminAppInsightsClient.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/admin/github/index.ts b/src/admin/github/index.ts index 3f9d38e3..077405ef 100644 --- a/src/admin/github/index.ts +++ b/src/admin/github/index.ts @@ -179,6 +179,7 @@ export const getGitHubMetaWithFallback = (params: RepoParams) => console.error('Error retrieving GitHub meta', { params, error: e }); return { ...params, + commitMessage: undefined, urlOwner: undefined, urlRepo: undefined, urlBranch: undefined, diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 38a0b732..9cb35517 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -23,6 +23,7 @@ import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME, VERCEL_GIT_COMMIT_SHA_SHORT, + VERCEL_GIT_COMMIT_MESSAGE, } from '@/app-core/config'; import { AdminAppInsight } from '.'; @@ -105,7 +106,7 @@ export default function AdminAppInsightsClient({ {VERCEL_GIT_COMMIT_SHA_SHORT ?? DEBUG_COMMIT_SHA}
- {codeMeta?.commit ?? DEBUG_COMMIT_MESSAGE} + {VERCEL_GIT_COMMIT_MESSAGE ?? DEBUG_COMMIT_MESSAGE}
} /> From 3582ddb2a3bc710f3c000489e8857eccc1350527 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 08:50:49 -0600 Subject: [PATCH 31/54] Extract env var into component --- src/admin/AdminAppConfigurationClient.tsx | 31 +++------------------- src/admin/insights/AdminAppInsights.tsx | 7 ++++- src/components/EnvVar.tsx | 32 +++++++++++++++++++++++ 3 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 src/components/EnvVar.tsx diff --git a/src/admin/AdminAppConfigurationClient.tsx b/src/admin/AdminAppConfigurationClient.tsx index fbe1f1b1..be6889fc 100644 --- a/src/admin/AdminAppConfigurationClient.tsx +++ b/src/admin/AdminAppConfigurationClient.tsx @@ -25,10 +25,10 @@ import WarningNote from '@/components/WarningNote'; import { RiSpeedMiniLine } from 'react-icons/ri'; import Link from 'next/link'; import SecretGenerator from '../app-core/SecretGenerator'; -import CopyButton from '@/components/CopyButton'; import { PiPaintBrushHousehold } from 'react-icons/pi'; import { IoMdGrid } from 'react-icons/io'; import { CgDebug } from 'react-icons/cg'; +import EnvVar from '@/components/EnvVar'; export default function AdminAppConfigurationClient({ // Storage @@ -131,33 +131,10 @@ export default function AdminAppConfigurationClient({ } ; - const renderEnvVar = ( - variable: string, - minimal?: boolean, - ) => -
- - - `{variable}` - - {!minimal && } - -
; - const renderEnvVars = (variables: string[]) => -
- {variables.map(envVar => renderEnvVar(envVar))} +
+ {variables.map(envVar => + )}
; const renderSubStatus = ( diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index 7c75ee7d..e4fa2a47 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -20,6 +20,8 @@ import { } from '@/app-core/config'; import { getGitHubMetaWithFallback } from '../github'; +const BASIC_PHOTO_INSTALLATION_COUNT = 32; + const owner = VERCEL_GIT_REPO_OWNER; const repo = VERCEL_GIT_REPO_SLUG; const branch = VERCEL_GIT_BRANCH; @@ -67,7 +69,10 @@ export default async function AdminAppInsights() { noAi: !isAiTextGenerationEnabled, noAiRateLimiting: isAiTextGenerationEnabled && !hasVercelBlobStorage, photoMatting: photosCountPortrait > 0 && !MATTE_PHOTOS, - gridFirst: photosCount > 32 && !GRID_HOMEPAGE_ENABLED, + gridFirst: ( + photosCount >= BASIC_PHOTO_INSTALLATION_COUNT && + !GRID_HOMEPAGE_ENABLED + ), noStaticOptimization: !HAS_STATIC_OPTIMIZATION, }} photoStats={{ diff --git a/src/components/EnvVar.tsx b/src/components/EnvVar.tsx new file mode 100644 index 00000000..c4054349 --- /dev/null +++ b/src/components/EnvVar.tsx @@ -0,0 +1,32 @@ +import clsx from 'clsx/lite'; +import CopyButton from './CopyButton'; + +export default function EnvVar({ + variable, + includeCopyButton = true, +}: { + variable: string, + includeCopyButton?: boolean, +}) { + return ( +
+ + + {variable} + + {includeCopyButton && + } + +
+ ); +} From 6da15dfa861f837c165daa25fbd2eb0fd5443fe4 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 08:53:20 -0600 Subject: [PATCH 32/54] Use component in insights --- src/admin/insights/AdminAppInsightsClient.tsx | 3 ++- src/components/EnvVar.tsx | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 9cb35517..b38994c3 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -26,6 +26,7 @@ import { VERCEL_GIT_COMMIT_MESSAGE, } from '@/app-core/config'; import { AdminAppInsight } from '.'; +import EnvVar from '@/components/EnvVar'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; @@ -145,7 +146,7 @@ export default function AdminAppInsightsClient({ content="You seem to have several vertical photos—consider enabling matting to make portrait and landscape photos appear more consistent" additionalContent={<> Enabled photo matting by setting - `NEXT_PUBLIC_MATTE_PHOTOS = 1` + } /> - {variable} + {variable}{value && ` = ${value}`} {includeCopyButton && } From 1cf2bc8dba92e279d8973718db258248ad2ec6ee Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 09:46:13 -0600 Subject: [PATCH 33/54] Refine insights --- src/admin/insights/AdminAppInsightsClient.tsx | 47 ++++++++++++++----- src/components/EnvVar.tsx | 4 +- src/components/ScoreCardRow.tsx | 14 ++++-- tailwind.css | 3 +- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index b38994c3..32fce23c 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -10,7 +10,6 @@ import { FaTag } from 'react-icons/fa'; import { FaRegCalendar } from 'react-icons/fa6'; import { HiOutlinePhotograph, - HiOutlineRefresh, HiSparkles, } from 'react-icons/hi'; import { MdLightbulbOutline } from 'react-icons/md'; @@ -27,6 +26,8 @@ import { } from '@/app-core/config'; import { AdminAppInsight } from '.'; import EnvVar from '@/components/EnvVar'; +import { IoSyncCircle } from 'react-icons/io5'; +import clsx from 'clsx/lite'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; @@ -68,6 +69,37 @@ export default function AdminAppInsightsClient({
{(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> + {(codeMeta?.behindBy || debug) && + } + content={<> + This fork is + {' '} + + {codeMeta?.behindBy ?? 9} commits + + {' '} + behind + } + additionalContent={<> + + Sync your fork + + {' '} + to receive the latest fixes and features + } + />} } content={
} /> - {(codeMeta?.behindBy || debug) && - } - content={`This fork is ${codeMeta?.behindBy ?? 9} commits behind`} - additionalContent={<> - Sync your fork to receive new features and fixes - } - />}
} @@ -132,7 +153,7 @@ export default function AdminAppInsightsClient({ />} content="AI enabled without rate limiting" // eslint-disable-next-line max-len - additionalContent="Create Vercel KV store and link it to this project in order to enable rate limiting." + additionalContent="Create Vercel KV store and link o this project in order to enable rate limiting." />} {(noAi || debug) && } diff --git a/src/components/EnvVar.tsx b/src/components/EnvVar.tsx index 535d6301..5e45c348 100644 --- a/src/components/EnvVar.tsx +++ b/src/components/EnvVar.tsx @@ -20,8 +20,8 @@ export default function EnvVar({ {variable}{value && ` = ${value}`} diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index addc539b..0e8a2a4f 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -1,6 +1,6 @@ -import { clsx } from 'clsx'; +import { clsx } from 'clsx/lite'; import { ReactNode, useState } from 'react'; -import { FaMinus, FaPlus } from 'react-icons/fa6'; +import { LuChevronsDownUp, LuChevronsUpDown } from 'react-icons/lu'; export default function ScoreCardRow({ icon, @@ -39,11 +39,15 @@ export default function ScoreCardRow({ {additionalContent && }
); diff --git a/tailwind.css b/tailwind.css index e35d3666..a4d64d75 100644 --- a/tailwind.css +++ b/tailwind.css @@ -304,8 +304,7 @@ } a, .link { @apply - hover:text-gray-600 - hover:dark:text-gray-400 + hover:text-medium } } From 6884be70390a83104c5b2ea3d6b079b51eb69d7b Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 09:55:21 -0600 Subject: [PATCH 34/54] Add url to insights commit --- .../github/GitHubForkStatusBadgeServer.tsx | 4 +-- src/admin/github/index.ts | 32 +++++++++++++------ src/admin/insights/AdminAppInsightsClient.tsx | 16 ++++++---- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/admin/github/GitHubForkStatusBadgeServer.tsx b/src/admin/github/GitHubForkStatusBadgeServer.tsx index a9959144..ab49eaca 100644 --- a/src/admin/github/GitHubForkStatusBadgeServer.tsx +++ b/src/admin/github/GitHubForkStatusBadgeServer.tsx @@ -5,7 +5,7 @@ import { VERCEL_GIT_REPO_SLUG, VERCEL_GIT_COMMIT_SHA, } from '@/app-core/config'; -import { getGitHubMetaWithFallback, getGitHubRepoUrl } from '.'; +import { getGitHubMetaWithFallback, getGitHubUrlRepo } from '.'; export default async function GitHubForkStatusBadgeServer() { const owner = VERCEL_GIT_REPO_OWNER; @@ -24,7 +24,7 @@ export default async function GitHubForkStatusBadgeServer() { const repoLink = (text: string) => diff --git a/src/admin/github/index.ts b/src/admin/github/index.ts index 077405ef..58208bbc 100644 --- a/src/admin/github/index.ts +++ b/src/admin/github/index.ts @@ -22,31 +22,40 @@ interface RepoParams { // Website urls -export const getGitHubOwnerUrl = ({ +export const getGitHubUrlOwner = ({ owner = TEMPLATE_REPO_OWNER, }: RepoParams = {}) => `https://github.com/${owner}`; -export const getGitHubRepoUrl = ({ +export const getGitHubUrlRepo = ({ owner = TEMPLATE_REPO_OWNER, repo = TEMPLATE_REPO_NAME, }: RepoParams = {}) => - `${getGitHubOwnerUrl({ owner })}/${repo}`; + `${getGitHubUrlOwner({ owner })}/${repo}`; -export const getGitHubBranchUrl = ({ +export const getGitHubUrlBranch = ({ owner = TEMPLATE_REPO_OWNER, repo = TEMPLATE_REPO_NAME, branch = DEFAULT_BRANCH, }: RepoParams = {}) => - `${getGitHubRepoUrl({ owner, repo })}/tree/${branch}`; + `${getGitHubUrlRepo({ owner, repo })}/tree/${branch}`; -export const getGitHubCompareUrl = ({ +export const getGitHubUrlCommit = ({ + owner = TEMPLATE_REPO_OWNER, + repo = TEMPLATE_REPO_NAME, + commit, +}: RepoParams = {}) => + commit + ? `${getGitHubUrlRepo({ owner, repo })}/commit/${commit}` + : undefined; + +export const getGitHubUrlCompare = ({ owner, repo, branch = DEFAULT_BRANCH, }: RepoParams = {}) => // eslint-disable-next-line max-len - `${getGitHubRepoUrl({ owner, repo })}/compare/${branch}...${TEMPLATE_REPO_OWNER}:${TEMPLATE_REPO_NAME}:${TEMPLATE_REPO_BRANCH}`; + `${getGitHubUrlRepo({ owner, repo })}/compare/${branch}...${TEMPLATE_REPO_OWNER}:${TEMPLATE_REPO_NAME}:${TEMPLATE_REPO_BRANCH}`; // API urls @@ -124,9 +133,10 @@ export const getGitHubPublicFork = async ( }; const getGitHubMeta = async (params: RepoParams) => { - const urlOwner = getGitHubOwnerUrl(params); - const urlRepo = getGitHubRepoUrl(params); - const urlBranch = getGitHubBranchUrl(params); + const urlOwner = getGitHubUrlOwner(params); + const urlRepo = getGitHubUrlRepo(params); + const urlBranch = getGitHubUrlBranch(params); + const urlCommit = getGitHubUrlCommit(params); const isBaseRepo = isRepoBaseRepo(params); @@ -163,6 +173,7 @@ const getGitHubMeta = async (params: RepoParams) => { urlOwner, urlRepo, urlBranch, + urlCommit, isForkedFromBase, isBaseRepo, behindBy, @@ -183,6 +194,7 @@ export const getGitHubMetaWithFallback = (params: RepoParams) => urlOwner: undefined, urlRepo: undefined, urlBranch: undefined, + urlCommit: undefined, isForkedFromBase: false, isBaseRepo: undefined, behindBy: undefined, diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 32fce23c..fe197943 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -134,14 +134,18 @@ export default function AdminAppInsightsClient({ /> } - content={} + + } /> } From bceb2346d33887c90afc620dcc5a7cff6dd780fb Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 09:58:30 -0600 Subject: [PATCH 35/54] Tweak git icon placement --- src/admin/insights/AdminAppInsightsClient.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index fe197943..8fcb7a36 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -133,7 +133,10 @@ export default function AdminAppInsightsClient({
} /> } + icon={} content={ Date: Fri, 14 Feb 2025 09:59:08 -0600 Subject: [PATCH 36/54] Adjust blue commit background --- src/admin/insights/AdminAppInsightsClient.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 8fcb7a36..ee7a1082 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -79,7 +79,7 @@ export default function AdminAppInsightsClient({ This fork is {' '} From e1082a8a3d2be0e4c52209e95f21a8005d5ecee6 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 18:06:53 -0600 Subject: [PATCH 37/54] Finalize core insights UX --- src/admin/AdminOutdatedClient.tsx | 1 + src/admin/insights/AdminAppInsights.tsx | 7 +- src/admin/insights/AdminAppInsightsClient.tsx | 260 ++++++++++++------ src/admin/insights/index.ts | 36 +++ src/app-core/config.ts | 3 + src/components/EnvVar.tsx | 1 + src/components/LinkWithStatus.tsx | 2 +- src/components/ScoreCardRow.tsx | 8 +- 8 files changed, 233 insertions(+), 85 deletions(-) diff --git a/src/admin/AdminOutdatedClient.tsx b/src/admin/AdminOutdatedClient.tsx index 2ee82d62..210b025f 100644 --- a/src/admin/AdminOutdatedClient.tsx +++ b/src/admin/AdminOutdatedClient.tsx @@ -67,6 +67,7 @@ export default function AdminOutdatedClient({ } }} isLoading={arePhotoIdsSyncing} + disabled={!updateBatchSize} > {arePhotoIdsSyncing ? 'Syncing' diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index e4fa2a47..c951ce77 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -19,6 +19,7 @@ import { VERCEL_GIT_REPO_SLUG, } from '@/app-core/config'; import { getGitHubMetaWithFallback } from '../github'; +import { OUTDATED_THRESHOLD } from '@/photo'; const BASIC_PHOTO_INSTALLATION_COUNT = 32; @@ -31,6 +32,7 @@ export default async function AdminAppInsights() { const [ { count: photosCount, dateRange }, { count: photosCountHidden }, + { count: photosCountOutdated }, { count: photosCountPortrait }, tags, cameras, @@ -39,6 +41,7 @@ export default async function AdminAppInsights() { ] = await Promise.all([ getPhotosMeta({ hidden: 'include' }), getPhotosMeta({ hidden: 'only' }), + getPhotosMeta({ hidden: 'include', updatedBefore: OUTDATED_THRESHOLD }), getPhotosMeta({ maximumAspectRatio: 0.9 }), getUniqueTags(), getUniqueCameras(), @@ -63,11 +66,12 @@ export default async function AdminAppInsights() { return ( 0 && !MATTE_PHOTOS, gridFirst: ( photosCount >= BASIC_PHOTO_INSTALLATION_COUNT && @@ -78,6 +82,7 @@ export default async function AdminAppInsights() { photoStats={{ photosCount, photosCountHidden, + photosCountOutdated, tagsCount: tags.length, camerasCount: cameras.length, filmSimulationsCount: filmSimulations.length, diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index ee7a1082..47e35a93 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -1,20 +1,16 @@ 'use client'; -import IconGrSync from '@/app-core/IconGrSync'; import ScoreCard from '@/components/ScoreCard'; import ScoreCardRow from '@/components/ScoreCardRow'; -import { dateRangeForPhotos, PhotoDateRange } from '@/photo'; +import { dateRangeForPhotos } from '@/photo'; import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon'; import { FaCamera } from 'react-icons/fa'; import { FaTag } from 'react-icons/fa'; -import { FaRegCalendar } from 'react-icons/fa6'; -import { - HiOutlinePhotograph, - HiSparkles, -} from 'react-icons/hi'; -import { MdLightbulbOutline } from 'react-icons/md'; +import { FaCircleInfo, FaRegCalendar } from 'react-icons/fa6'; +import { HiOutlinePhotograph } from 'react-icons/hi'; +import { MdAspectRatio } from 'react-icons/md'; import { PiWarningBold } from 'react-icons/pi'; -import { TbCone } from 'react-icons/tb'; +import { TbCone, TbSparkles } from 'react-icons/tb'; import { getGitHubMetaWithFallback } from '../github'; import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi'; import { @@ -23,24 +19,40 @@ import { TEMPLATE_REPO_NAME, VERCEL_GIT_COMMIT_SHA_SHORT, VERCEL_GIT_COMMIT_MESSAGE, + TEMPLATE_REPO_URL_FORK, + TEMPLATE_REPO_URL_README, } from '@/app-core/config'; -import { AdminAppInsight } from '.'; +import { AdminAppInsights, hasTemplateRecommendations, PhotoStats } from '.'; import EnvVar from '@/components/EnvVar'; import { IoSyncCircle } from 'react-icons/io5'; import clsx from 'clsx/lite'; +import { PATH_ADMIN_OUTDATED } from '@/app-core/paths'; +import { LiaBroomSolid } from 'react-icons/lia'; +import { IoMdGrid } from 'react-icons/io'; +import { RiSpeedMiniLine } from 'react-icons/ri'; +import LinkWithStatus from '@/components/LinkWithStatus'; + +const readmeAnchor = (anchor: string, text: string) => + + {text} + ; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; +const DEBUG_BEHIND_BY = 9; +const DEBUG_PHOTOS_COUNT_OUTDATED = 7; export default function AdminAppInsightsClient({ codeMeta, - recommendations: { - noAi, - noAiRateLimiting, - }, + insights, photoStats: { photosCount, photosCountHidden, + photosCountOutdated, tagsCount, camerasCount, filmSimulationsCount, @@ -50,18 +62,20 @@ export default function AdminAppInsightsClient({ debug, }: { codeMeta?: Awaited> - recommendations: Record - photoStats: { - photosCount: number - photosCountHidden: number - tagsCount: number - camerasCount: number - filmSimulationsCount: number - lensesCount: number - dateRange?: PhotoDateRange - }, + insights: AdminAppInsights + photoStats: PhotoStats debug?: boolean }) { + const { + noFork, + forkBehind, + noAi, + noAiRateLimiting, + outdatedPhotos, + photoMatting, + gridFirst, + noStaticOptimization, + } = insights; const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); @@ -69,37 +83,63 @@ export default function AdminAppInsightsClient({
{(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> - {(codeMeta?.behindBy || debug) && + {(noFork || debug) && } - content={<> - This fork is - {' '} - - {codeMeta?.behindBy ?? 9} commits - - {' '} - behind - } - additionalContent={<> + content="This template is not forked" + expandContent={<> - Sync your fork + Fork {' '} - to receive the latest fixes and features + original template to receive the latest fixes and features. + {' '} + {readmeAnchor('receiving-updates', 'Additional instructions')} + {' '} + in README. } />} + {(forkBehind || debug) && } + content={<> + This fork is + {' '} + + {codeMeta?.behindBy ?? DEBUG_BEHIND_BY} + {' '} + {(codeMeta?.behindBy ?? DEBUG_BEHIND_BY) === 1 + ? 'commit' + : 'commits'} + + {' '} + behind + } + expandContent={<> + + Sync your fork + + {' '} + to receive the latest fixes and features + } + />} } content={
} - - {(noAiRateLimiting || debug) && + {(noAiRateLimiting || debug) && } + content="AI enabled without rate limiting" + // eslint-disable-next-line max-len + expandContent="Create Vercel KV store and link o this project in order to enable rate limiting." />} - content="AI enabled without rate limiting" - // eslint-disable-next-line max-len - additionalContent="Create Vercel KV store and link o this project in order to enable rate limiting." - />} - {(noAi || debug) && } - content="Enable AI text generation to improve photo descriptions" - // eslint-disable-next-line max-len - additionalContent="Create Vercel KV store and link it to this project in order to enable rate limiting." - />} - } - // eslint-disable-next-line max-len - content="You seem to have several vertical photos—consider enabling matting to make portrait and landscape photos appear more consistent" - additionalContent={<> - Enabled photo matting by setting - - } - /> - } - // eslint-disable-next-line max-len - content="Consider forking this repository to receive new features and fixes" - /> - } - content="Enable AI text generation in the app configuration" - /> - + {(noAi || debug) && } + content="Improve SEO + accessibility with AI" + expandContent={<> +
+ Enable automatic AI text generation + {' '} + by setting environment variable + {' '} + . +
+
+ Further instruction in + {' '} + {readmeAnchor('ai-text-generation', 'README')}. +
+ } + />} + {(photoMatting || debug) && } + content="Vertical photos may benefit from matting" + expandContent={<> + {/* eslint-disable-next-line max-len */} + Enable photo matting to make portrait and landscape photos appear more consistent + + } + />} + {(gridFirst || debug) && } + content="Grid homepage" + expandContent={<> + Enable grid homepage by setting environment variable + {' '} + + } + />} + {(noStaticOptimization || debug) && } + content="Static optimization" + expandContent={<> + {/* eslint-disable-next-line max-len */} + Enable static optimization by setting any of the following environment variables: +
+ + + + +
+ } + />} + } + {(outdatedPhotos || debug) && } + // eslint-disable-next-line max-len + content={`You have ${photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED} outdated ${(photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED) === 1 ? 'photo' : 'photos'}`} + expandContent={<> + + View outdated photos + + {' '} + to update them in batches. + } + />} + +export const hasTemplateRecommendations = (insights: AdminAppInsights) => + RECOMMENDATIONS.some(insight => insights[insight]); + +export interface PhotoStats { + photosCount: number + photosCountHidden: number + photosCountOutdated: number + tagsCount: number + camerasCount: number + filmSimulationsCount: number + lensesCount: number + dateRange?: PhotoDateRange +} + +export const getInsightIndicator = ({ + forkBehind, + noAiRateLimiting, + outdatedPhotos, +}: AdminAppInsights) => + forkBehind || + noAiRateLimiting || + outdatedPhotos; diff --git a/src/app-core/config.ts b/src/app-core/config.ts index 5dfe1a30..7dbdf6c9 100644 --- a/src/app-core/config.ts +++ b/src/app-core/config.ts @@ -21,6 +21,9 @@ export const TEMPLATE_REPO_NAME = 'exif-photo-blog'; export const TEMPLATE_REPO_BRANCH = 'main'; // eslint-disable-next-line max-len export const TEMPLATE_REPO_URL = `https://github.com/${TEMPLATE_REPO_OWNER}/${TEMPLATE_REPO_NAME}`; +export const TEMPLATE_REPO_URL_FORK = `${TEMPLATE_REPO_URL}/fork`; +// eslint-disable-next-line max-len +export const TEMPLATE_REPO_URL_README = `${TEMPLATE_REPO_URL}?tab=readme-ov-file`; export const VERCEL_GIT_PROVIDER = process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER; diff --git a/src/components/EnvVar.tsx b/src/components/EnvVar.tsx index 5e45c348..710d37ee 100644 --- a/src/components/EnvVar.tsx +++ b/src/components/EnvVar.tsx @@ -23,6 +23,7 @@ export default function EnvVar({ 'px-1.5 py-[0.5px]', 'rounded-md', 'bg-gray-100 dark:bg-gray-800', + 'whitespace-nowrap', )}> {variable}{value && ` = ${value}`} diff --git a/src/components/LinkWithStatus.tsx b/src/components/LinkWithStatus.tsx index a2ddf0a9..fa5a2803 100644 --- a/src/components/LinkWithStatus.tsx +++ b/src/components/LinkWithStatus.tsx @@ -89,7 +89,7 @@ export default function LinkWithStatus({ {...props } href={href} className={clsx( - 'relative flex transition-[colors,opacity]', + 'relative inline-flex transition-[colors,opacity]', (loadingClassName || isControlled) ? 'opacity-100' : isLoading ? 'opacity-50' : 'opacity-100', diff --git a/src/components/ScoreCardRow.tsx b/src/components/ScoreCardRow.tsx index 0e8a2a4f..21f0a31a 100644 --- a/src/components/ScoreCardRow.tsx +++ b/src/components/ScoreCardRow.tsx @@ -5,12 +5,12 @@ import { LuChevronsDownUp, LuChevronsUpDown } from 'react-icons/lu'; export default function ScoreCardRow({ icon, content, - additionalContent, + expandContent, className, }: { icon: ReactNode content: ReactNode - additionalContent?: ReactNode + expandContent?: ReactNode className?: string }) { const [isExpanded, setIsExpanded] = useState(false); @@ -33,10 +33,10 @@ export default function ScoreCardRow({
{isExpanded &&
- {additionalContent} + {expandContent}
}
- {additionalContent && } + {expandPath && + {({ isLoading }) => <> {isLoading + ? + : } + } + }
); } From a59164aadb0531c807e32cdf8b6922562debbbfd Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 21:06:34 -0600 Subject: [PATCH 39/54] Remove GitHub status badge --- __tests__/github.test.ts | 11 +-- src/admin/github/GitHubForkStatusBadge.tsx | 15 ---- .../github/GitHubForkStatusBadgeClient.tsx | 68 ------------------- .../github/GitHubForkStatusBadgeServer.tsx | 60 ---------------- src/admin/insights/AdminAppInsights.tsx | 2 +- src/admin/insights/AdminAppInsightsClient.tsx | 2 +- src/app/admin/insights/page.tsx | 11 +-- .../github/index.ts => utility/github.ts} | 10 ++- 8 files changed, 14 insertions(+), 165 deletions(-) delete mode 100644 src/admin/github/GitHubForkStatusBadge.tsx delete mode 100644 src/admin/github/GitHubForkStatusBadgeClient.tsx delete mode 100644 src/admin/github/GitHubForkStatusBadgeServer.tsx rename src/{admin/github/index.ts => utility/github.ts} (96%) diff --git a/__tests__/github.test.ts b/__tests__/github.test.ts index e6277ac4..c443f0f3 100644 --- a/__tests__/github.test.ts +++ b/__tests__/github.test.ts @@ -1,4 +1,7 @@ -import { getGitHubMetaWithFallback, getGitHubPublicFork } from '@/admin/github'; +import { + getGitHubMetaWithFallback, + getGitHubPublicFork, +} from '@/utility/github'; import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME } from '@/app-core/config'; describe('GitHub', () => { @@ -8,7 +11,7 @@ describe('GitHub', () => { repo: TEMPLATE_REPO_NAME, }); expect(meta).toBeDefined(); - expect(meta.url).toBeDefined(); + expect(meta.urlRepo).toBeDefined(); expect(meta.isForkedFromBase).toEqual(false); expect(meta.label).toBeDefined(); expect(meta.description).toBeDefined(); @@ -26,7 +29,7 @@ describe('GitHub', () => { repo: 'nonexistent', }); expect(meta).toBeDefined(); - expect(meta.url).toBeDefined(); + expect(meta.urlRepo).toBeDefined(); expect(meta.isForkedFromBase).toEqual(false); expect(meta.label).toEqual('Unknown'); expect(meta.description).toEqual('Unknown'); @@ -38,7 +41,7 @@ describe('GitHub', () => { repo: 'bad text for a url.com', }); expect(meta).toBeDefined(); - expect(meta.url).toBeDefined(); + expect(meta.urlRepo).toBeDefined(); expect(meta.isForkedFromBase).toEqual(false); expect(meta.label).toEqual('Unknown'); expect(meta.description).toEqual('Unknown'); diff --git a/src/admin/github/GitHubForkStatusBadge.tsx b/src/admin/github/GitHubForkStatusBadge.tsx deleted file mode 100644 index 6faf63ef..00000000 --- a/src/admin/github/GitHubForkStatusBadge.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Suspense } from 'react'; -import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient'; -import GitHubForkStatusBadgeServer from './GitHubForkStatusBadgeServer'; -import { IS_DEVELOPMENT } from '@/app-core/config'; - -export default function GitHubForkStatusBadge() { - return IS_DEVELOPMENT - ? - : - - ; -} diff --git a/src/admin/github/GitHubForkStatusBadgeClient.tsx b/src/admin/github/GitHubForkStatusBadgeClient.tsx deleted file mode 100644 index 45a79750..00000000 --- a/src/admin/github/GitHubForkStatusBadgeClient.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import Spinner from '@/components/Spinner'; -import Tooltip from '@/components/Tooltip'; -import clsx from 'clsx/lite'; -import { ReactNode } from 'react'; -import { BiLogoGithub } from 'react-icons/bi'; - -export default function GitHubForkStatusBadgeClient({ - label, - style = 'mono', - tooltip, -}: { - label?: ReactNode - style?: 'info' |'success' | 'warning' | 'error' | 'mono' - tooltip?: ReactNode -}) { - const classNameForStyle = () => { - switch (style) { - case 'info': return clsx( - 'text-blue-600 hover:text-blue-600', - 'dark:text-blue-400 dark:hover:text-blue-400', - 'bg-blue-100/40 dark:bg-blue-900/25', - 'border-blue-300/40 dark:border-blue-900/50', - ); - case 'success': return clsx( - 'text-green-700 hover:text-green-700', - 'dark:text-green-400 dark:hover:text-green-400', - 'bg-green-100/40 dark:bg-green-900/25', - 'border-green-300/40 dark:border-green-900/50', - ); - case 'warning': return clsx( - 'text-amber-800/90 hover:text-amber-800/90', - 'dark:text-amber-400 dark:hover:text-amber-400', - 'bg-amber-100/40 dark:bg-amber-900/25', - 'border-amber-300/40 dark:border-amber-900/50', - ); - case 'error': return clsx( - 'text-red-700/90 hover:text-red-700/90', - 'dark:text-red-400 dark:hover:text-red-400', - 'bg-red-100/20 dark:bg-red-900/25', - 'border-red-300/40 dark:border-red-900/50', - ); - default: return clsx( - 'text-main', - 'bg-white dark:bg-transparent', - 'border-main', - ); - } - }; - - return ( - -
- {!label - ? - : } - {label ?? 'Checking'} -
-
- ); -} diff --git a/src/admin/github/GitHubForkStatusBadgeServer.tsx b/src/admin/github/GitHubForkStatusBadgeServer.tsx deleted file mode 100644 index ab49eaca..00000000 --- a/src/admin/github/GitHubForkStatusBadgeServer.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient'; -import { - VERCEL_GIT_BRANCH, - VERCEL_GIT_REPO_OWNER, - VERCEL_GIT_REPO_SLUG, - VERCEL_GIT_COMMIT_SHA, -} from '@/app-core/config'; -import { getGitHubMetaWithFallback, getGitHubUrlRepo } from '.'; - -export default async function GitHubForkStatusBadgeServer() { - const owner = VERCEL_GIT_REPO_OWNER; - const repo = VERCEL_GIT_REPO_SLUG; - const branch = VERCEL_GIT_BRANCH; - const commit = VERCEL_GIT_COMMIT_SHA; - - const { - isForkedFromBase, - isBaseRepo, - isBehind, - label, - description, - didError, - } = await getGitHubMetaWithFallback({ owner, repo, branch, commit }); - - const repoLink = (text: string) => - - {text} - ; - - const isBehindContent = <> - {' '} - {repoLink('Sync on GitHub')} for latest updates. - ; - - const didErrorContent = <> - {' '} - Could not connect to {repoLink('GitHub')}. - ; - - return isForkedFromBase || isBaseRepo - ? - {description} - {didError - ? didErrorContent - : isBehind - ? isBehindContent - : null} - , - style: didError || isBehind === undefined || isBehind - ? 'info' - : 'mono', - }} /> - : null; -} diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index c951ce77..b32f1577 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -18,7 +18,7 @@ import { VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_SLUG, } from '@/app-core/config'; -import { getGitHubMetaWithFallback } from '../github'; +import { getGitHubMetaWithFallback } from '../../utility/github'; import { OUTDATED_THRESHOLD } from '@/photo'; const BASIC_PHOTO_INSTALLATION_COUNT = 32; diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 6b78f7bb..d2fe111f 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -11,7 +11,7 @@ import { HiOutlinePhotograph } from 'react-icons/hi'; import { MdAspectRatio } from 'react-icons/md'; import { PiWarningBold } from 'react-icons/pi'; import { TbCone, TbSparkles } from 'react-icons/tb'; -import { getGitHubMetaWithFallback } from '../github'; +import { getGitHubMetaWithFallback } from '../../utility/github'; import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi'; import { TEMPLATE_REPO_BRANCH, diff --git a/src/app/admin/insights/page.tsx b/src/app/admin/insights/page.tsx index e81b4596..0bf5efa4 100644 --- a/src/app/admin/insights/page.tsx +++ b/src/app/admin/insights/page.tsx @@ -1,17 +1,8 @@ import AdminAppInsights from '@/admin/insights/AdminAppInsights'; import AdminInfoPage from '@/admin/AdminInfoPage'; -import GitHubForkStatusBadge from '@/admin/github/GitHubForkStatusBadge'; -import { - IS_DEVELOPMENT, - IS_VERCEL_GIT_PROVIDER_GITHUB, -} from '@/app-core/config'; export default async function AdminInsightsPage() { - return } - > + return ; } diff --git a/src/admin/github/index.ts b/src/utility/github.ts similarity index 96% rename from src/admin/github/index.ts rename to src/utility/github.ts index 58208bbc..c2ed6d75 100644 --- a/src/admin/github/index.ts +++ b/src/utility/github.ts @@ -121,14 +121,12 @@ const isRepoBaseRepo = ({ owner, repo }: RepoParams) => owner?.toLowerCase() === TEMPLATE_REPO_OWNER && repo?.toLowerCase() === TEMPLATE_REPO_NAME; -export const getGitHubPublicFork = async ( - params?: RepoParams, -): Promise => { - const response = await fetch(getGitHubApiForksUrl(params), FETCH_CONFIG); +export const getGitHubPublicFork = async (): Promise => { + const response = await fetch(getGitHubApiForksUrl(), FETCH_CONFIG); const fork = (await response.json())[0]; return { - owner: fork.owner.login, - repo: fork.name, + owner: fork?.owner.login, + repo: fork?.name, }; }; From 6fcdd2b206e149421f6f360f6884c3b2d417c04b Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 14 Feb 2025 21:10:04 -0600 Subject: [PATCH 40/54] Update outdated photos note --- src/admin/AdminOutdatedClient.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/admin/AdminOutdatedClient.tsx b/src/admin/AdminOutdatedClient.tsx index 210b025f..734471b7 100644 --- a/src/admin/AdminOutdatedClient.tsx +++ b/src/admin/AdminOutdatedClient.tsx @@ -79,6 +79,9 @@ export default function AdminOutdatedClient({
+
+ Outdated photos found +
{photos.length} {' '} {photos.length === 1 ? 'photo' : 'photos'} @@ -88,8 +91,7 @@ export default function AdminOutdatedClient({ {' '} may have: missing EXIF fields, inaccurate blur data, {' '} - undesired privacy settings - {hasAiTextGeneration && ', missing AI-generated text'} + undesired privacy settings, or missing AI-generated text
From 59650cf3954615117f022e11a2d482fb84b88268 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 00:10:49 -0600 Subject: [PATCH 41/54] Parallelize GitHub checks --- src/admin/insights/AdminAppInsights.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index b32f1577..1a1b8dc1 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -38,6 +38,7 @@ export default async function AdminAppInsights() { cameras, filmSimulations, lenses, + codeMeta, ] = await Promise.all([ getPhotosMeta({ hidden: 'include' }), getPhotosMeta({ hidden: 'only' }), @@ -47,6 +48,14 @@ export default async function AdminAppInsights() { getUniqueCameras(), getUniqueFilmSimulations(), getUniqueLenses(), + IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT + ? getGitHubMetaWithFallback({ + owner, + repo, + branch, + commit, + }) + : undefined, ]); const { @@ -54,15 +63,6 @@ export default async function AdminAppInsights() { hasVercelBlobStorage, } = APP_CONFIGURATION; - const codeMeta = IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT - ? await getGitHubMetaWithFallback({ - owner, - repo, - branch, - commit, - }) - : undefined; - return ( Date: Sat, 15 Feb 2025 09:47:36 -0600 Subject: [PATCH 42/54] Move branch to own line on mobile --- src/admin/insights/AdminAppInsightsClient.tsx | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index d2fe111f..fb7b7ce3 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -86,6 +86,14 @@ export default function AdminAppInsightsClient({ const { descriptionWithSpaces } = dateRangeForPhotos(undefined, dateRange); + const branchLink = + {codeMeta?.branch ?? TEMPLATE_REPO_BRANCH} + ; + return (
{(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> @@ -167,18 +175,17 @@ export default function AdminAppInsightsClient({ {codeMeta?.repo ?? TEMPLATE_REPO_NAME}
- } /> + } + content={branchLink} + /> Date: Sat, 15 Feb 2025 11:02:58 -0600 Subject: [PATCH 43/54] Refine insights content --- src/admin/insights/AdminAppInsightsClient.tsx | 83 +++++++++---------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index fb7b7ce3..dba002dc 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -36,15 +36,21 @@ const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; const DEBUG_BEHIND_BY = 9; const DEBUG_PHOTOS_COUNT_OUTDATED = 7; -const readmeAnchor = (anchor: string, text: string) => +const renderLink = (text: string, href = '') => {text} ; +const readmeAnchor = (anchor: string) => + renderLink( + `README/${anchor}`, + `${TEMPLATE_REPO_URL_README}#${anchor}`, + ); + const renderLabeledEnvVar = (label: string, envVar: string, value = '1') =>
@@ -106,19 +112,13 @@ export default function AdminAppInsightsClient({ />} content="This template is not forked" expandContent={<> - - Fork - + {renderLink('Fork original template', TEMPLATE_REPO_URL_FORK)} {' '} - original template to receive the latest fixes and features. + to receive the latest fixes and features. {' '} - {readmeAnchor('receiving-updates', 'Additional instructions')} + Additional instructions in {' '} - in README. + {readmeAnchor('receiving-updates')}. } />} {(forkBehind || debug) && } expandContent={<> - - Sync your fork - + {renderLink('Sync your fork', codeMeta?.urlRepo)} {' '} - to receive the latest fixes and features + to receive the latest fixes and features. } />} } content="AI enabled without rate limiting" - // eslint-disable-next-line max-len - expandContent="Create Vercel KV store and link to this project in order prevent abuse by to enabling rate limiting." + expandContent={<> + Create Vercel KV store and link to this project + in order prevent abuse by to enabling rate limiting. + } />} {(noAi || debug) && } content="Improve SEO + accessibility with AI" expandContent={<> -
- Enable automatic AI text generation - {' '} - by setting environment variable - {' '} - . -
-
- Further instruction in - {' '} - {readmeAnchor('ai-text-generation', 'README')}. -
+ Enable automatic AI text generation + {' '} + by setting . + {' '} + Further instruction and cost considerations in + {' '} + {readmeAnchor('ai-text-generation')}. } />} {(photoMatting || debug) && } + icon={} content="Vertical photos may benefit from matting" expandContent={<> - {/* eslint-disable-next-line max-len */} - Enable photo matting to make portrait and landscape photos appear more consistent + Enable photo matting to make + {' '} + portrait and landscape photos appear more consistent + {' '} } />} @@ -251,7 +246,7 @@ export default function AdminAppInsightsClient({ expandContent={<> Now that you have a sufficient amount of photos, you can {' '} - enable grid homepage by setting environment variable + enable grid homepage by setting {' '} } @@ -263,8 +258,9 @@ export default function AdminAppInsightsClient({ />} content="Static optimization" expandContent={<> - {/* eslint-disable-next-line max-len */} - Enable static optimization by setting any of the following environment variables: + Enable static optimization + {' '} + by setting any of the following:
{renderLabeledEnvVar( 'Pre-render photo pages', @@ -282,6 +278,9 @@ export default function AdminAppInsightsClient({ 'Pre-render OG image for each category page', 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', )} + + See {readmeAnchor('performance')} for cost considerations. +
} />} From 55ac1b5bcf779c2c1fe7acf3669e147507ef29ab Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 11:06:42 -0600 Subject: [PATCH 44/54] Tweak insight headers --- src/components/ScoreCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ScoreCard.tsx b/src/components/ScoreCard.tsx index d08c9cb4..c01d7840 100644 --- a/src/components/ScoreCard.tsx +++ b/src/components/ScoreCard.tsx @@ -14,7 +14,7 @@ export default function ScoreCard({
{title &&
From 555e8f65eb5759e0cb3db91b0bdfda8949330b83 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 11:07:28 -0600 Subject: [PATCH 45/54] Debug on preview --- src/admin/insights/AdminAppInsights.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index 1a1b8dc1..140fde37 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -11,6 +11,7 @@ import { GRID_HOMEPAGE_ENABLED, HAS_STATIC_OPTIMIZATION, IS_DEVELOPMENT, + IS_PRODUCTION, IS_VERCEL_GIT_PROVIDER_GITHUB, MATTE_PHOTOS, VERCEL_GIT_BRANCH, @@ -89,7 +90,7 @@ export default async function AdminAppInsights() { lensesCount: lenses.length, dateRange, }} - debug={IS_DEVELOPMENT} + debug={!IS_PRODUCTION} /> ); } From 6ce564973e9f470ba9c861656229230a551a2e90 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 17:09:19 -0600 Subject: [PATCH 46/54] Improve insights layout on mobile --- src/admin/insights/AdminAppInsightsClient.tsx | 70 +++++++++---------- src/components/ScoreCardRow.tsx | 8 ++- tailwind.css | 4 ++ 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index dba002dc..4c041e5e 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -53,7 +53,7 @@ const readmeAnchor = (anchor: string) => const renderLabeledEnvVar = (label: string, envVar: string, value = '1') =>
- + {label} @@ -213,6 +213,39 @@ export default function AdminAppInsightsClient({ in order prevent abuse by to enabling rate limiting. } />} + {(noStaticOptimization || debug) && } + content="Speed up page load times" + expandContent={<> + Dramatically improve load times by enabling static optimization + {' '} + on: +
+ {renderLabeledEnvVar( + 'Photo pages', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS', + )} + {renderLabeledEnvVar( + 'Photo OG images', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES', + )} + {renderLabeledEnvVar( + 'Category pages (tags, cameras, etc.)', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORIES', + )} + {renderLabeledEnvVar( + 'Category OG images', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', + )} + + See {readmeAnchor('performance')} for cost considerations. + +
+ } + />} {(noAi || debug) && } content="Improve SEO + accessibility with AI" @@ -251,39 +284,6 @@ export default function AdminAppInsightsClient({ } />} - {(noStaticOptimization || debug) && } - content="Static optimization" - expandContent={<> - Enable static optimization - {' '} - by setting any of the following: -
- {renderLabeledEnvVar( - 'Pre-render photo pages', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS', - )} - {renderLabeledEnvVar( - 'Pre-render OG image for each photo', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES', - )} - {renderLabeledEnvVar( - 'Pre-render category pages (tags, cameras, etc.)', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORIES', - )} - {renderLabeledEnvVar( - 'Pre-render OG image for each category page', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', - )} - - See {readmeAnchor('performance')} for cost considerations. - -
- } - />} } {(outdatedPhotos || debug) && } // eslint-disable-next-line max-len - content={`You have ${photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED} outdated ${(photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED) === 1 ? 'photo' : 'photos'}`} + content={`${photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED} outdated ${(photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED) === 1 ? 'photo' : 'photos'}`} expandPath={PATH_ADMIN_OUTDATED} />}
-
+
{content}
{isExpanded && -
+
{expandContent}
}
diff --git a/tailwind.css b/tailwind.css index a4d64d75..ee234e00 100644 --- a/tailwind.css +++ b/tailwind.css @@ -141,6 +141,10 @@ @apply bg-white dark:bg-black } +@utility bg-medium { + @apply + bg-gray-200 dark:bg-gray-700 +} @utility bg-dim { @apply bg-gray-100 dark:bg-gray-900/75 From 33fba41a4fa31484763047c39a0afadc49892c6f Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 17:24:28 -0600 Subject: [PATCH 47/54] Update admin icons --- src/admin/AdminAppMenu.tsx | 10 ++++++---- src/admin/AdminNavClient.tsx | 14 ++++++++------ src/admin/insights/AdminAppInsightsIcon.tsx | 19 ++++++------------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/admin/AdminAppMenu.tsx b/src/admin/AdminAppMenu.tsx index 20f51c46..de7e9f4d 100644 --- a/src/admin/AdminAppMenu.tsx +++ b/src/admin/AdminAppMenu.tsx @@ -7,10 +7,10 @@ import { PATH_GRID_INFERRED, } from '@/app-core/paths'; import { useAppState } from '@/state/AppState'; -import { BiCog } from 'react-icons/bi'; import { ImCheckboxUnchecked } from 'react-icons/im'; import { IoCloseSharp } from 'react-icons/io5'; import AdminAppInsightsIcon from './insights/AdminAppInsightsIcon'; +import { LuCog } from 'react-icons/lu'; export default function AdminAppMenu() { const { @@ -24,13 +24,15 @@ export default function AdminAppMenu() { + icon: , href: PATH_ADMIN_INSIGHTS, }, { label: 'Configuration', - icon: , + icon: , href: PATH_ADMIN_CONFIGURATION, }, { label: isSelecting @@ -41,7 +43,7 @@ export default function AdminAppMenu() { className="text-[18px] translate-y-[-0.5px]" /> : , href: PATH_GRID_INFERRED, action: () => { diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 3002a54e..c90063c6 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -19,8 +19,8 @@ import { differenceInMinutes } from 'date-fns'; import { usePathname } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; import { FaRegClock } from 'react-icons/fa'; -import { HiOutlineCog } from 'react-icons/hi'; import AdminAppInsightsIcon from './insights/AdminAppInsightsIcon'; +import { LuCog } from 'react-icons/lu'; // Updates considered recent if they occurred in past 5 minutes const areTimesRecent = (dates: Date[]) => dates @@ -92,10 +92,12 @@ export default function AdminNavClient({
} + className={clsx( + 'translate-y-[-2px]', + isPathAdminInsights(pathname) + ? 'font-bold' + : 'text-dim')} + loader={} > @@ -106,7 +108,7 @@ export default function AdminNavClient({ : 'text-dim'} loader={} > - - - - + {indicator && Date: Sat, 15 Feb 2025 17:34:02 -0600 Subject: [PATCH 48/54] Create /platforms directory --- __tests__/github.test.ts | 2 +- src/admin/insights/AdminAppInsights.tsx | 2 +- src/admin/insights/AdminAppInsightsClient.tsx | 2 +- src/app-core/CommandK.tsx | 2 +- src/app/film-demo/animate/page.tsx | 2 +- src/app/film-demo/page.tsx | 2 +- src/image-response/FilmSimulationImageResponse.tsx | 2 +- src/photo/form/index.ts | 2 +- src/photo/server.ts | 2 +- src/{vendors/fujifilm/index.ts => platforms/fujifilm.ts} | 0 src/{utility => platforms}/github.ts | 0 src/{utility => platforms}/vercel.ts | 0 src/simulation/PhotoFilmSimulation.tsx | 2 +- src/simulation/PhotoFilmSimulationIcon.tsx | 2 +- src/simulation/index.ts | 2 +- 15 files changed, 12 insertions(+), 12 deletions(-) rename src/{vendors/fujifilm/index.ts => platforms/fujifilm.ts} (100%) rename src/{utility => platforms}/github.ts (100%) rename src/{utility => platforms}/vercel.ts (100%) diff --git a/__tests__/github.test.ts b/__tests__/github.test.ts index c443f0f3..4244f2be 100644 --- a/__tests__/github.test.ts +++ b/__tests__/github.test.ts @@ -1,7 +1,7 @@ import { getGitHubMetaWithFallback, getGitHubPublicFork, -} from '@/utility/github'; +} from '@/platforms/github'; import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME } from '@/app-core/config'; describe('GitHub', () => { diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index 140fde37..36fabd54 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -19,7 +19,7 @@ import { VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_SLUG, } from '@/app-core/config'; -import { getGitHubMetaWithFallback } from '../../utility/github'; +import { getGitHubMetaWithFallback } from '../../platforms/github'; import { OUTDATED_THRESHOLD } from '@/photo'; const BASIC_PHOTO_INSTALLATION_COUNT = 32; diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 4c041e5e..3f7e558c 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -11,7 +11,7 @@ import { HiOutlinePhotograph } from 'react-icons/hi'; import { MdAspectRatio } from 'react-icons/md'; import { PiWarningBold } from 'react-icons/pi'; import { TbCone, TbSparkles } from 'react-icons/tb'; -import { getGitHubMetaWithFallback } from '../../utility/github'; +import { getGitHubMetaWithFallback } from '../../platforms/github'; import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi'; import { TEMPLATE_REPO_BRANCH, diff --git a/src/app-core/CommandK.tsx b/src/app-core/CommandK.tsx index b47c2903..0df5f312 100644 --- a/src/app-core/CommandK.tsx +++ b/src/app-core/CommandK.tsx @@ -18,7 +18,7 @@ import { formatCount, formatCountDescriptive } from '@/utility/string'; import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon'; import { IoMdCamera } from 'react-icons/io'; import { ADMIN_DEBUG_TOOLS_ENABLED, SHOW_FILM_SIMULATIONS } from './config'; -import { labelForFilmSimulation } from '@/vendors/fujifilm'; +import { labelForFilmSimulation } from '@/platforms/fujifilm'; import { getUniqueFocalLengths } from '@/photo/db/query'; import { formatFocalLength } from '@/focal'; import { TbCone } from 'react-icons/tb'; diff --git a/src/app/film-demo/animate/page.tsx b/src/app/film-demo/animate/page.tsx index 92cb1f8a..11612df7 100644 --- a/src/app/film-demo/animate/page.tsx +++ b/src/app/film-demo/animate/page.tsx @@ -2,7 +2,7 @@ import SiteGrid from '@/components/SiteGrid'; import { clsx } from 'clsx/lite'; -import { FILM_SIMULATION_FORM_INPUT_OPTIONS } from '@/vendors/fujifilm'; +import { FILM_SIMULATION_FORM_INPUT_OPTIONS } from '@/platforms/fujifilm'; import PhotoFilmSimulation from '@/simulation/PhotoFilmSimulation'; import { useEffect, useState } from 'react'; diff --git a/src/app/film-demo/page.tsx b/src/app/film-demo/page.tsx index cd6a94be..a5e7467c 100644 --- a/src/app/film-demo/page.tsx +++ b/src/app/film-demo/page.tsx @@ -1,4 +1,4 @@ -import { FILM_SIMULATION_FORM_INPUT_OPTIONS } from '@/vendors/fujifilm'; +import { FILM_SIMULATION_FORM_INPUT_OPTIONS } from '@/platforms/fujifilm'; import PhotoFilmSimulation from '@/simulation/PhotoFilmSimulation'; diff --git a/src/image-response/FilmSimulationImageResponse.tsx b/src/image-response/FilmSimulationImageResponse.tsx index 66112674..dd93ac18 100644 --- a/src/image-response/FilmSimulationImageResponse.tsx +++ b/src/image-response/FilmSimulationImageResponse.tsx @@ -4,7 +4,7 @@ import ImagePhotoGrid from './components/ImagePhotoGrid'; import ImageContainer from './components/ImageContainer'; import { labelForFilmSimulation, -} from '@/vendors/fujifilm'; +} from '@/platforms/fujifilm'; import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon'; import { FilmSimulation } from '@/simulation'; diff --git a/src/photo/form/index.ts b/src/photo/form/index.ts index 571b3c2e..a50f95b0 100644 --- a/src/photo/form/index.ts +++ b/src/photo/form/index.ts @@ -19,7 +19,7 @@ import { generateNanoid } from '@/utility/nanoid'; import { FILM_SIMULATION_FORM_INPUT_OPTIONS, MAKE_FUJIFILM, -} from '@/vendors/fujifilm'; +} from '@/platforms/fujifilm'; import { FilmSimulation } from '@/simulation'; import { GEO_PRIVACY_ENABLED } from '@/app-core/config'; import { TAG_FAVS, getValidationMessageForTags } from '@/tag'; diff --git a/src/photo/server.ts b/src/photo/server.ts index 4b1d9233..bd07b560 100644 --- a/src/photo/server.ts +++ b/src/photo/server.ts @@ -6,7 +6,7 @@ import { convertExifToFormData } from '@/photo/form'; import { getFujifilmSimulationFromMakerNote, isExifForFujifilm, -} from '@/vendors/fujifilm'; +} from '@/platforms/fujifilm'; import { ExifData, ExifParserFactory } from 'ts-exif-parser'; import { PhotoFormData } from './form'; import { FilmSimulation } from '@/simulation'; diff --git a/src/vendors/fujifilm/index.ts b/src/platforms/fujifilm.ts similarity index 100% rename from src/vendors/fujifilm/index.ts rename to src/platforms/fujifilm.ts diff --git a/src/utility/github.ts b/src/platforms/github.ts similarity index 100% rename from src/utility/github.ts rename to src/platforms/github.ts diff --git a/src/utility/vercel.ts b/src/platforms/vercel.ts similarity index 100% rename from src/utility/vercel.ts rename to src/platforms/vercel.ts diff --git a/src/simulation/PhotoFilmSimulation.tsx b/src/simulation/PhotoFilmSimulation.tsx index f85e5fc4..e12808c1 100644 --- a/src/simulation/PhotoFilmSimulation.tsx +++ b/src/simulation/PhotoFilmSimulation.tsx @@ -1,4 +1,4 @@ -import { labelForFilmSimulation } from '@/vendors/fujifilm'; +import { labelForFilmSimulation } from '@/platforms/fujifilm'; import PhotoFilmSimulationIcon from './PhotoFilmSimulationIcon'; import { pathForFilmSimulation } from '@/app-core/paths'; import { FilmSimulation } from '.'; diff --git a/src/simulation/PhotoFilmSimulationIcon.tsx b/src/simulation/PhotoFilmSimulationIcon.tsx index 936cf7bd..230d8c96 100644 --- a/src/simulation/PhotoFilmSimulationIcon.tsx +++ b/src/simulation/PhotoFilmSimulationIcon.tsx @@ -1,5 +1,5 @@ /* eslint-disable max-len */ -import { labelForFilmSimulation } from '@/vendors/fujifilm'; +import { labelForFilmSimulation } from '@/platforms/fujifilm'; import { CSSProperties } from 'react'; import { FilmSimulation } from '.'; diff --git a/src/simulation/index.ts b/src/simulation/index.ts index 5293848d..81f747f4 100644 --- a/src/simulation/index.ts +++ b/src/simulation/index.ts @@ -11,7 +11,7 @@ import { import { FujifilmSimulation, labelForFilmSimulation, -} from '@/vendors/fujifilm'; +} from '@/platforms/fujifilm'; export type FilmSimulation = FujifilmSimulation; From 7027e85530e0d74596290e15f8eaec7641b39071 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 17:49:02 -0600 Subject: [PATCH 49/54] Streamline github error handling --- __tests__/github.test.ts | 16 ++-- src/admin/insights/AdminAppInsights.tsx | 4 +- src/admin/insights/AdminAppInsightsClient.tsx | 4 +- src/platforms/github.ts | 74 ++++++------------- 4 files changed, 32 insertions(+), 66 deletions(-) diff --git a/__tests__/github.test.ts b/__tests__/github.test.ts index 4244f2be..6aa8a2a0 100644 --- a/__tests__/github.test.ts +++ b/__tests__/github.test.ts @@ -1,50 +1,44 @@ import { - getGitHubMetaWithFallback, + getGitHubMeta, getGitHubPublicFork, } from '@/platforms/github'; import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME } from '@/app-core/config'; describe('GitHub', () => { it('fetches base repo meta', async () => { - const meta = await getGitHubMetaWithFallback({ + const meta = await getGitHubMeta({ owner: TEMPLATE_REPO_OWNER, repo: TEMPLATE_REPO_NAME, }); expect(meta).toBeDefined(); expect(meta.urlRepo).toBeDefined(); expect(meta.isForkedFromBase).toEqual(false); - expect(meta.label).toBeDefined(); - expect(meta.description).toBeDefined(); expect(meta.isBehind).toEqual(false); expect(meta.isBaseRepo).toBe(true); }); it('fetches fork meta', async () => { const fork = await getGitHubPublicFork(); - const metaFork = await getGitHubMetaWithFallback(fork); + const metaFork = await getGitHubMeta(fork); expect(metaFork.isForkedFromBase).toEqual(true); }); it('handles nonexistent repos', async () => { - const meta = await getGitHubMetaWithFallback({ + const meta = await getGitHubMeta({ owner: 'nonexistent', repo: 'nonexistent', }); expect(meta).toBeDefined(); expect(meta.urlRepo).toBeDefined(); expect(meta.isForkedFromBase).toEqual(false); - expect(meta.label).toEqual('Unknown'); - expect(meta.description).toEqual('Unknown'); expect(meta.isBehind).toBeUndefined(); }); it('handles fetch errors', async () => { - const meta = await getGitHubMetaWithFallback({ + const meta = await getGitHubMeta({ owner: 'gibberish / / *', repo: 'bad text for a url.com', }); expect(meta).toBeDefined(); expect(meta.urlRepo).toBeDefined(); expect(meta.isForkedFromBase).toEqual(false); - expect(meta.label).toEqual('Unknown'); - expect(meta.description).toEqual('Unknown'); expect(meta.isBehind).toBeUndefined(); }); }); diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx index 36fabd54..a5cbb379 100644 --- a/src/admin/insights/AdminAppInsights.tsx +++ b/src/admin/insights/AdminAppInsights.tsx @@ -19,7 +19,7 @@ import { VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_SLUG, } from '@/app-core/config'; -import { getGitHubMetaWithFallback } from '../../platforms/github'; +import { getGitHubMeta } from '../../platforms/github'; import { OUTDATED_THRESHOLD } from '@/photo'; const BASIC_PHOTO_INSTALLATION_COUNT = 32; @@ -50,7 +50,7 @@ export default async function AdminAppInsights() { getUniqueFilmSimulations(), getUniqueLenses(), IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT - ? getGitHubMetaWithFallback({ + ? getGitHubMeta({ owner, repo, branch, diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 3f7e558c..b9b413da 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -11,7 +11,7 @@ import { HiOutlinePhotograph } from 'react-icons/hi'; import { MdAspectRatio } from 'react-icons/md'; import { PiWarningBold } from 'react-icons/pi'; import { TbCone, TbSparkles } from 'react-icons/tb'; -import { getGitHubMetaWithFallback } from '../../platforms/github'; +import { getGitHubMeta } from '../../platforms/github'; import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi'; import { TEMPLATE_REPO_BRANCH, @@ -74,7 +74,7 @@ export default function AdminAppInsightsClient({ }, debug, }: { - codeMeta?: Awaited> + codeMeta?: Awaited> insights: AdminAppInsights photoStats: PhotoStats debug?: boolean diff --git a/src/platforms/github.ts b/src/platforms/github.ts index c2ed6d75..a9b78f1b 100644 --- a/src/platforms/github.ts +++ b/src/platforms/github.ts @@ -5,7 +5,6 @@ import { } from '@/app-core/config'; const DEFAULT_BRANCH = 'main'; -const FALLBACK_TEXT = 'Unknown'; const CACHE_GITHUB_REQUESTS = false; // Cache all results for 2 minutes to avoid rate limiting @@ -130,7 +129,7 @@ export const getGitHubPublicFork = async (): Promise => { }; }; -const getGitHubMeta = async (params: RepoParams) => { +export const getGitHubMeta = async (params: RepoParams) => { const urlOwner = getGitHubUrlOwner(params); const urlRepo = getGitHubUrlRepo(params); const urlBranch = getGitHubUrlBranch(params); @@ -138,33 +137,29 @@ const getGitHubMeta = async (params: RepoParams) => { const isBaseRepo = isRepoBaseRepo(params); - const [ - isForkedFromBase, - behindBy, - ] = await Promise.all([ - getIsRepoForkedFromBase(params), - isBaseRepo && params.commit - ? getGitHubCommitsBehindFromCommit(params) - : getGitHubCommitsBehindFromRepo(params), - ]); + let isForkedFromBase: boolean | undefined; + let isBehind: boolean | undefined; + let behindBy: number | undefined; + let didError: boolean = false; - const isBehind = behindBy === undefined - ? undefined - : behindBy > 0; + try { + const results = await Promise.all([ + getIsRepoForkedFromBase(params), + isBaseRepo && params.commit + ? getGitHubCommitsBehindFromCommit(params) + : getGitHubCommitsBehindFromRepo(params), + ]); - const label = isBehind === undefined - ? FALLBACK_TEXT - : isBehind - ? `${behindBy} Behind` - : 'Synced'; - - const description = isBehind === undefined - ? FALLBACK_TEXT - : isBehind - ? `This fork is ${behindBy} commit${behindBy === 1 ? '' : 's'} behind.` - : isBaseRepo - ? 'This build is up to date.' - : 'This fork is up to date.'; + isForkedFromBase = results[0]; + behindBy = results[1]; + + isBehind = behindBy === undefined + ? undefined + : behindBy > 0; + } catch (error) { + didError = true; + console.error('Error retrieving GitHub meta', { params, error }); + } return { ...params, @@ -176,29 +171,6 @@ const getGitHubMeta = async (params: RepoParams) => { isBaseRepo, behindBy, isBehind, - label, - description, - didError: false, + didError, }; }; - -export const getGitHubMetaWithFallback = (params: RepoParams) => - getGitHubMeta(params) - .catch(e => { - console.error('Error retrieving GitHub meta', { params, error: e }); - return { - ...params, - commitMessage: undefined, - urlOwner: undefined, - urlRepo: undefined, - urlBranch: undefined, - urlCommit: undefined, - isForkedFromBase: false, - isBaseRepo: undefined, - behindBy: undefined, - isBehind: undefined, - label: FALLBACK_TEXT, - description: 'Could not connect to GitHub.', - didError: true, - }; - }); From af40abeb97a9aed7665defdb1a43de2fc3c2c1f6 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 18:16:23 -0600 Subject: [PATCH 50/54] Make links consistent across insights and config --- src/admin/AdminAppConfigurationClient.tsx | 77 ++++++++----------- src/admin/AdminLink.tsx | 38 +++++++++ src/admin/insights/AdminAppInsightsClient.tsx | 35 ++++----- src/admin/insights/AdminAppInsightsIcon.tsx | 2 +- src/components/ChecklistRow.tsx | 2 +- 5 files changed, 88 insertions(+), 66 deletions(-) create mode 100644 src/admin/AdminLink.tsx diff --git a/src/admin/AdminAppConfigurationClient.tsx b/src/admin/AdminAppConfigurationClient.tsx index be6889fc..f29b7f7a 100644 --- a/src/admin/AdminAppConfigurationClient.tsx +++ b/src/admin/AdminAppConfigurationClient.tsx @@ -4,9 +4,7 @@ import { ComponentProps, ReactNode, } from 'react'; -import { clsx } from 'clsx/lite'; import ChecklistRow from '../components/ChecklistRow'; -import { FiExternalLink } from 'react-icons/fi'; import { BiData, BiHide, @@ -29,6 +27,7 @@ import { PiPaintBrushHousehold } from 'react-icons/pi'; import { IoMdGrid } from 'react-icons/io'; import { CgDebug } from 'react-icons/cg'; import EnvVar from '@/components/EnvVar'; +import AdminLink from './AdminLink'; export default function AdminAppConfigurationClient({ // Storage @@ -110,27 +109,6 @@ export default function AdminAppConfigurationClient({ simplifiedView?: boolean isAnalyzingConfiguration?: boolean }) { - const renderLink = (href: string, text: string, external = true) => - <> - - {text} - - {external && - <> -   - - } - ; - const renderEnvVars = (variables: string[]) =>
{variables.map(envVar => @@ -158,7 +136,7 @@ export default function AdminAppConfigurationClient({ renderSubStatus( type, renderEnvVars([variable]), - 'translate-y-[5px]', + 'translate-y-[3px]', ); const renderError = ({ @@ -211,11 +189,13 @@ export default function AdminAppConfigurationClient({ : renderSubStatus('optional', <> Vercel Postgres: {' '} - {renderLink( + + create store + {' '} and connect to project )} @@ -247,11 +227,13 @@ export default function AdminAppConfigurationClient({ : renderSubStatus('optional', <> {labelForStorage('vercel-blob')}: {' '} - {renderLink( + + create store + {' '} and connect to project , @@ -261,20 +243,25 @@ export default function AdminAppConfigurationClient({ : renderSubStatus('optional', <> {labelForStorage('cloudflare-r2')}: {' '} - {renderLink( - 'https://github.com/sambecker/exif-photo-blog#cloudflare-r2', - 'create/configure bucket', - )} + + create/configure bucket + )} {hasAwsS3Storage ? renderSubStatus('checked', 'AWS S3: connected') : renderSubStatus('optional', <> {labelForStorage('aws-s3')}: {' '} - {renderLink( - 'https://github.com/sambecker/exif-photo-blog#aws-s3', - 'create/configure bucket', - )} + + create/configure bucket + )} @@ -385,11 +372,13 @@ export default function AdminAppConfigurationClient({ {kvError && renderError({ connection: { provider: 'Vercel KV', error: kvError}, })} - {renderLink( + + Create Vercel KV store + {' '} and connect to project in order to enable rate limiting diff --git a/src/admin/AdminLink.tsx b/src/admin/AdminLink.tsx new file mode 100644 index 00000000..51e53f84 --- /dev/null +++ b/src/admin/AdminLink.tsx @@ -0,0 +1,38 @@ +import clsx from 'clsx/lite'; +import Link from 'next/link'; +import { ComponentProps } from 'react'; +import { FiExternalLink } from 'react-icons/fi'; +export default function AdminLink({ + href, + className, + children, + externalIcon, + ...props +}: ComponentProps & { + externalIcon?: boolean +}) { + return ( + <> + + {children} + + {externalIcon && + <> +   + + } + + ); +} diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index b9b413da..ce7a21a1 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -30,26 +30,17 @@ import { PATH_ADMIN_OUTDATED } from '@/app-core/paths'; import { LiaBroomSolid } from 'react-icons/lia'; import { IoMdGrid } from 'react-icons/io'; import { RiSpeedMiniLine } from 'react-icons/ri'; +import AdminLink from '../AdminLink'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; const DEBUG_BEHIND_BY = 9; const DEBUG_PHOTOS_COUNT_OUTDATED = 7; -const renderLink = (text: string, href = '') => - - {text} - ; - const readmeAnchor = (anchor: string) => - renderLink( - `README/${anchor}`, - `${TEMPLATE_REPO_URL_README}#${anchor}`, - ); + + README/{anchor} + ; const renderLabeledEnvVar = (label: string, envVar: string, value = '1') =>
@@ -112,7 +103,9 @@ export default function AdminAppInsightsClient({ />} content="This template is not forked" expandContent={<> - {renderLink('Fork original template', TEMPLATE_REPO_URL_FORK)} + + Fork original template + {' '} to receive the latest fixes and features. {' '} @@ -144,7 +137,9 @@ export default function AdminAppInsightsClient({ behind } expandContent={<> - {renderLink('Sync your fork', codeMeta?.urlRepo)} + + Sync your fork + {' '} to receive the latest fixes and features. } @@ -190,7 +185,7 @@ export default function AdminAppInsightsClient({ target="blank" className="flex items-center gap-2" > - + {VERCEL_GIT_COMMIT_SHA_SHORT ?? DEBUG_COMMIT_SHA} @@ -270,18 +265,18 @@ export default function AdminAppInsightsClient({ {' '} portrait and landscape photos appear more consistent {' '} - + . } />} {(gridFirst || debug) && } content="Grid homepage" expandContent={<> - Now that you have a sufficient amount of photos, you can + Now that you have enough photos, consider switching your {' '} - enable grid homepage by setting + default view to grid by setting {' '} - + . } />} } diff --git a/src/admin/insights/AdminAppInsightsIcon.tsx b/src/admin/insights/AdminAppInsightsIcon.tsx index e0fdd86b..dab0effb 100644 --- a/src/admin/insights/AdminAppInsightsIcon.tsx +++ b/src/admin/insights/AdminAppInsightsIcon.tsx @@ -2,7 +2,7 @@ import clsx from 'clsx/lite'; import { LuLightbulb } from 'react-icons/lu'; export default function AdminAppInsightsIcon({ - indicator = 'blue', + indicator, }: { indicator?: 'blue' | 'yellow' }) { diff --git a/src/components/ChecklistRow.tsx b/src/components/ChecklistRow.tsx index dc0954d7..47341bbd 100644 --- a/src/components/ChecklistRow.tsx +++ b/src/components/ChecklistRow.tsx @@ -42,7 +42,7 @@ export default function ChecklistRow({ {experimental && }
-
+
{children}
From 3afafb47a4ec46c17b0e66c8515c1604d66b3b59 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 22:50:10 -0600 Subject: [PATCH 51/54] Fix copy button alignment --- src/admin/insights/AdminAppInsightsClient.tsx | 4 ++-- src/app-core/SecretGenerator.tsx | 4 +--- src/components/CopyButton.tsx | 4 +++- src/components/EnvVar.tsx | 7 ++++++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index ce7a21a1..392d0e17 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -215,7 +215,7 @@ export default function AdminAppInsightsClient({ />} content="Speed up page load times" expandContent={<> - Dramatically improve load times by enabling static optimization + Improve load times by enabling static optimization {' '} on:
@@ -236,7 +236,7 @@ export default function AdminAppInsightsClient({ 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', )} - See {readmeAnchor('performance')} for cost considerations. + See {readmeAnchor('performance')} for cost implications.
} diff --git a/src/app-core/SecretGenerator.tsx b/src/app-core/SecretGenerator.tsx index c85452d6..4f74c706 100644 --- a/src/app-core/SecretGenerator.tsx +++ b/src/app-core/SecretGenerator.tsx @@ -30,9 +30,7 @@ export default function SecretGenerator() { 'flex flex-nowrap items-center gap-2 leading-none -mx-1', )}> {secret ? {secret} : } -
+
diff --git a/src/components/CopyButton.tsx b/src/components/CopyButton.tsx index 7c4fa939..5ba6bacd 100644 --- a/src/components/CopyButton.tsx +++ b/src/components/CopyButton.tsx @@ -7,17 +7,19 @@ export default function CopyButton({ label, text, subtle, + className, }: { label: string text?: string, subtle?: boolean + className?: string }) { return ( } className={clsx( - 'translate-y-[2px]', subtle && 'text-gray-300 dark:text-gray-700', + className, )} onClick={text ? () => { diff --git a/src/components/EnvVar.tsx b/src/components/EnvVar.tsx index 4f26fc82..eeecd836 100644 --- a/src/components/EnvVar.tsx +++ b/src/components/EnvVar.tsx @@ -28,7 +28,12 @@ export default function EnvVar({ {variable}{value && ` = ${value}`} {includeCopyButton && - } + }
); From b9baf65bf9991ccccd2492c8d511956741ff2c25 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sat, 15 Feb 2025 22:54:12 -0600 Subject: [PATCH 52/54] Hide insights when are aren't photos --- src/admin/AdminNav.tsx | 8 +++++++- src/admin/AdminNavClient.tsx | 25 ++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/admin/AdminNav.tsx b/src/admin/AdminNav.tsx index aa1110da..ceef18c9 100644 --- a/src/admin/AdminNav.tsx +++ b/src/admin/AdminNav.tsx @@ -31,6 +31,8 @@ export default async function AdminNav() { getPhotosMostRecentUpdateCached().catch(() => undefined), ]); + const includeInsights = countPhotos > 0; + // Photos const items = [{ label: 'Photos', @@ -53,6 +55,10 @@ export default async function AdminNav() { }); } return ( - + ); } diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index c90063c6..b112dc3e 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -29,6 +29,7 @@ const areTimesRecent = (dates: Date[]) => dates export default function AdminNavClient({ items, mostRecentPhotoUpdateTime, + includeInsights, }: { items: { label: string, @@ -36,6 +37,7 @@ export default function AdminNavClient({ count: number, }[] mostRecentPhotoUpdateTime?: Date + includeInsights?: boolean }) { const pathname = usePathname(); @@ -90,17 +92,18 @@ export default function AdminNavClient({ )}
- } - > - - + {includeInsights && + } + > + + } Date: Sat, 15 Feb 2025 23:18:08 -0600 Subject: [PATCH 53/54] Add insights empty state --- src/admin/AdminEmptyState.tsx | 29 +++ src/admin/insights/AdminAppInsightsClient.tsx | 175 +++++++++--------- 2 files changed, 120 insertions(+), 84 deletions(-) create mode 100644 src/admin/AdminEmptyState.tsx diff --git a/src/admin/AdminEmptyState.tsx b/src/admin/AdminEmptyState.tsx new file mode 100644 index 00000000..3eaef77f --- /dev/null +++ b/src/admin/AdminEmptyState.tsx @@ -0,0 +1,29 @@ +import clsx from 'clsx/lite'; +import { ReactNode } from 'react'; +import { IoInformationCircleOutline } from 'react-icons/io5'; + +export default function AdminEmptyState({ + icon, + children, + includeContainer = true, +}: { + icon?: ReactNode + children: ReactNode + includeContainer?: boolean +}) { + return ( +
+
+ {icon ?? } +
+ {children} +
+ ); +} \ No newline at end of file diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index 392d0e17..7d49248f 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -31,6 +31,7 @@ import { LiaBroomSolid } from 'react-icons/lia'; import { IoMdGrid } from 'react-icons/io'; import { RiSpeedMiniLine } from 'react-icons/ri'; import AdminLink from '../AdminLink'; +import AdminEmptyState from '../AdminEmptyState'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; @@ -93,8 +94,8 @@ export default function AdminAppInsightsClient({ return (
- {(codeMeta?.isBaseRepo || codeMeta?.isForkedFromBase || debug) && <> - + {(codeMeta || debug) && <> + {(noFork || debug) && } - {(hasTemplateRecommendations(insights) || debug) && - - {(noAiRateLimiting || debug) && + {(hasTemplateRecommendations(insights) || debug) + ? <> + {(noAiRateLimiting || debug) && } + content="AI enabled without rate limiting" + expandContent={<> + Create Vercel KV store and link to this project + in order prevent abuse by to enabling rate limiting. + } />} - content="AI enabled without rate limiting" - expandContent={<> - Create Vercel KV store and link to this project - in order prevent abuse by to enabling rate limiting. - } - />} - {(noStaticOptimization || debug) && } + content="Speed up page load times" + expandContent={<> + Improve load times by enabling static optimization + {' '} + on: +
+ {renderLabeledEnvVar( + 'Photo pages', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS', + )} + {renderLabeledEnvVar( + 'Photo OG images', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES', + )} + {renderLabeledEnvVar( + 'Category pages (tags, cameras, etc.)', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORIES', + )} + {renderLabeledEnvVar( + 'Category OG images', + 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', + )} + + See {readmeAnchor('performance')} for cost implications. + +
+ } />} - content="Speed up page load times" - expandContent={<> - Improve load times by enabling static optimization - {' '} - on: -
- {renderLabeledEnvVar( - 'Photo pages', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS', - )} - {renderLabeledEnvVar( - 'Photo OG images', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES', - )} - {renderLabeledEnvVar( - 'Category pages (tags, cameras, etc.)', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORIES', - )} - {renderLabeledEnvVar( - 'Category OG images', - 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', - )} - - See {readmeAnchor('performance')} for cost implications. - -
- } - />} - {(noAi || debug) && } - content="Improve SEO + accessibility with AI" - expandContent={<> - Enable automatic AI text generation - {' '} - by setting . - {' '} - Further instruction and cost considerations in - {' '} - {readmeAnchor('ai-text-generation')}. - } - />} - {(photoMatting || debug) && } + content="Improve SEO + accessibility with AI" + expandContent={<> + Enable automatic AI text generation + {' '} + by setting . + {' '} + Further instruction and cost considerations in + {' '} + {readmeAnchor('ai-text-generation')}. + } />} - content="Vertical photos may benefit from matting" - expandContent={<> - Enable photo matting to make - {' '} - portrait and landscape photos appear more consistent - {' '} - . - } - />} - {(gridFirst || debug) && } - content="Grid homepage" - expandContent={<> - Now that you have enough photos, consider switching your - {' '} - default view to grid by setting - {' '} - . - } - />} -
} + {(photoMatting || debug) && } + content="Vertical photos may benefit from matting" + expandContent={<> + Enable photo matting to make + {' '} + portrait and landscape photos appear more consistent + {' '} + . + } + />} + {(gridFirst || debug) && } + content="Grid homepage" + expandContent={<> + Now that you have enough photos, consider switching your + {' '} + default view to grid by setting + {' '} + {/* eslint-disable-next-line max-len */} + . + } + />} + + : + Nothing to report! + } +
{(outdatedPhotos || debug) && Date: Sat, 15 Feb 2025 23:31:14 -0600 Subject: [PATCH 54/54] Remove commit details from configuration --- src/admin/AdminAppConfigurationClient.tsx | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/admin/AdminAppConfigurationClient.tsx b/src/admin/AdminAppConfigurationClient.tsx index f29b7f7a..51e2322f 100644 --- a/src/admin/AdminAppConfigurationClient.tsx +++ b/src/admin/AdminAppConfigurationClient.tsx @@ -21,7 +21,6 @@ import { testConnectionsAction } from '@/admin/actions'; import ErrorNote from '@/components/ErrorNote'; import WarningNote from '@/components/WarningNote'; import { RiSpeedMiniLine } from 'react-icons/ri'; -import Link from 'next/link'; import SecretGenerator from '../app-core/SecretGenerator'; import { PiPaintBrushHousehold } from 'react-icons/pi'; import { IoMdGrid } from 'react-icons/io'; @@ -93,9 +92,6 @@ export default function AdminAppConfigurationClient({ isAdminSqlDebugEnabled, // Misc baseUrl, - commitSha, - commitMessage, - commitUrl, // Connection status databaseError, storageError, @@ -681,21 +677,6 @@ export default function AdminAppConfigurationClient({ {baseUrl || 'Not Defined'}
-
- Commit -    - {commitSha - ? commitUrl - ? - {commitSha} - - : {commitSha} - : 'Not Found'} -
}