diff --git a/README.md b/README.md index 71517a12..3b531952 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ https://photos.sambecker.com 1. Click [Deploy](https://vercel.com/new/clone?demo-title=Photo+Blog&demo-description=Store+photos+with+original+camera+data&demo-url=https%3A%2F%2Fphotos.sambecker.com&demo-image=https%3A%2F%2Fphotos.sambecker.com%2Ftemplate-image-tight&project-name=Photo+Blog&repository-name=exif-photo-blog&repository-url=https%3A%2F%2Fgithub.com%2Fsambecker%2Fexif-photo-blog&from=templates&skippable-integrations=1&teamCreateStatus=hidden&stores=%5B%7B%22type%22%3A%22postgres%22%7D%2C%7B%22type%22%3A%22blob%22%7D%5D) 2. Add required storage ([Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres/quickstart#create-a-postgres-database) + [Vercel Blob](https://vercel.com/docs/storage/vercel-blob/quickstart#create-a-blob-store)) as part of template installation 3. Configure environment variable for production domain in project settings - - `NEXT_PUBLIC_SITE_DOMAIN` (e.g., photos.domain.com—used in permalinks and seen in top-right nav) + - `NEXT_PUBLIC_SITE_DOMAIN` (e.g., photos.domain.com—used in absolute urls and seen in navigation if no explicit nav title is set) ### 2. Setup Auth @@ -105,9 +105,10 @@ _⚠️ READ BEFORE PROCEEDING_ Application behavior can be changed by configuring the following environment variables: #### Content -- `NEXT_PUBLIC_META_TITLE` (seen in browser tab) -- `NEXT_PUBLIC_META_DESCRIPTION` (seen in nav, beneath title) -- `NEXT_PUBLIC_NAV_TITLE` (seen in navigation, defaults to domain when not configured) +- `NEXT_PUBLIC_META_TITLE` (seen in search results and browser tab) +- `NEXT_PUBLIC_META_DESCRIPTION` (seen in search results) +- `NEXT_PUBLIC_NAV_TITLE` (defaults to domain when not configured) +- `NEXT_PUBLIC_NAV_CAPTION` (seen in navigation, beneath title) - `NEXT_PUBLIC_PAGE_ABOUT` (seen in grid sidebar—accepts rich formatting tags: ``, ``, ``, ``, ``, `
`) #### Performance diff --git a/src/admin/AdminAppConfigurationClient.tsx b/src/admin/AdminAppConfigurationClient.tsx index 796b507b..56f7842e 100644 --- a/src/admin/AdminAppConfigurationClient.tsx +++ b/src/admin/AdminAppConfigurationClient.tsx @@ -20,7 +20,6 @@ import { labelForStorage } from '@/platforms/storage'; import { HiSparkles } from 'react-icons/hi'; import { testConnectionsAction } from '@/admin/actions'; import ErrorNote from '@/components/ErrorNote'; -import WarningNote from '@/components/WarningNote'; import { RiSpeedMiniLine } from 'react-icons/ri'; import SecretGenerator from '../app/SecretGenerator'; import { PiPaintBrushHousehold } from 'react-icons/pi'; @@ -49,9 +48,11 @@ export default function AdminAppConfigurationClient({ hasAdminUser, // Content hasDomain, - hasTitle, - hasDescription, - hasAbout, + hasNavTitle, + hasNavCaption, + isMetaTitleConfigured, + isMetaDescriptionConfigured, + hasPageAbout, // AI isAiTextGenerationEnabled, aiTextAutoGeneratedFields, @@ -153,20 +154,6 @@ export default function AdminAppConfigurationClient({ {message} ; - const renderWarning = ({ - connection, - message, - }: { - connection?: { provider: string, error: string } - message?: string - }) => - - {connection && <> - {connection.provider} connection error: {`"${connection.error}"`} - } - {message} - ; - return ( - {!hasDomain && - renderWarning({message: - 'Not explicitly setting a domain may cause ' + - 'certain features to behave unexpectedly', - })} - Store in environment variable (seen in top-right nav): + Store in environment variable + (used in explicit share urls, seen in nav if no title is defined): {renderEnvVars(['NEXT_PUBLIC_SITE_DOMAIN'])} Store in environment variable (seen in browser tab): {renderEnvVars(['NEXT_PUBLIC_META_TITLE'])} - - Store in environment variable (seen in nav, under title): - {renderEnvVars(['NEXT_PUBLIC_META_DESCRIPTION'])} - - - Store in environment variable (seen in grid sidebar): - {renderEnvVars(['NEXT_PUBLIC_PAGE_ABOUT'])} - + {!simplifiedView && <> + + Store in environment variable (seen in search results): + {renderEnvVars(['NEXT_PUBLIC_META_DESCRIPTION'])} + + + Store in environment variable (replaces domain in nav): + {renderEnvVars(['NEXT_PUBLIC_NAV_TITLE'])} + + + Store in environment variable (seen in nav, under title): + {renderEnvVars(['NEXT_PUBLIC_NAV_CAPTION'])} + + + Store in environment variable (seen in sidebar): + {renderEnvVars(['NEXT_PUBLIC_PAGE_ABOUT'])} + + } {!simplifiedView && <> 0 && !MATTE_PHOTOS, camerasFirst: ( diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx index ad6b7b05..4802da4c 100644 --- a/src/admin/insights/AdminAppInsightsClient.tsx +++ b/src/admin/insights/AdminAppInsightsClient.tsx @@ -45,6 +45,7 @@ import IconFilmSimulation from '@/components/icons/IconFilmSimulation'; import IconFocalLength from '@/components/icons/IconFocalLength'; import IconTag from '@/components/icons/IconTag'; import IconPhoto from '@/components/icons/IconPhoto'; +import { HiOutlineDocumentText } from 'react-icons/hi'; const DEBUG_COMMIT_SHA = '4cd29ed'; const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes'; @@ -59,8 +60,8 @@ const readmeAnchor = (anchor: string) => README/{anchor} ; -const renderLabeledEnvVar = (label: string, envVar: string, value = '1') => -
+const renderLabeledEnvVar = (label: string, envVar: string, value?: string) => +
{label} @@ -112,6 +113,7 @@ export default function AdminAppInsightsClient({ noAi, noAiRateLimiting, noConfiguredDomain, + noConfiguredMeta, outdatedPhotos, photoMatting, camerasFirst, @@ -277,7 +279,7 @@ export default function AdminAppInsightsClient({ !isExpanded, )} expandContent={<> - Not explicitly setting a domain may cause certain features + Not setting an explicit domain may cause certain features to behave unexpectedly. Domains are stored in {' '} } />} + {(noConfiguredMeta || debug) && } + content="Configure meta" + expandContent={<> + Configure site title (visible in search results and browser tab) + and site description (visible in search results): + {' '} +
+ {renderLabeledEnvVar( + 'Site title', + 'NEXT_PUBLIC_META_TITLE', + )} + {renderLabeledEnvVar( + 'Site description', + 'NEXT_PUBLIC_META_DESCRIPTION', + )} +
+ } + />} {(noStaticOptimization || debug) && See {readmeAnchor('performance')} for cost implications. diff --git a/src/admin/insights/index.ts b/src/admin/insights/index.ts index e803346b..1a3edc9f 100644 --- a/src/admin/insights/index.ts +++ b/src/admin/insights/index.ts @@ -20,6 +20,7 @@ const _INSIGHTS_TEMPLATE = [ 'noAi', 'noAiRateLimiting', 'noConfiguredDomain', + 'noConfiguredMeta', 'photoMatting', 'camerasFirst', 'gridFirst', diff --git a/src/app/Nav.tsx b/src/app/Nav.tsx index 97dc68d9..3962c623 100644 --- a/src/app/Nav.tsx +++ b/src/app/Nav.tsx @@ -17,13 +17,12 @@ import { import AnimateItems from '../components/AnimateItems'; import { GRID_HOMEPAGE_ENABLED, - HAS_DEFINED_SITE_DESCRIPTION, - META_DESCRIPTION, + NAV_CAPTION, } from './config'; import { useRef } from 'react'; import useStickyNav from './useStickyNav'; -const NAV_HEIGHT_CLASS = HAS_DEFINED_SITE_DESCRIPTION +const NAV_HEIGHT_CLASS = NAV_CAPTION ? 'min-h-[4rem] sm:min-h-[5rem]' : 'min-h-[4rem]'; @@ -100,16 +99,16 @@ export default function Nav({ )}>
{renderLink(navTitleOrDomain, PATH_ROOT)}
- {HAS_DEFINED_SITE_DESCRIPTION && + {NAV_CAPTION &&
- {META_DESCRIPTION} + {NAV_CAPTION}
}
] diff --git a/src/app/config.ts b/src/app/config.ts index f731360d..534314a8 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -92,6 +92,11 @@ const SITE_DOMAIN_SHORT = shortenUrl(SITE_DOMAIN); export const NAV_TITLE = process.env.NEXT_PUBLIC_NAV_TITLE; +export const NAV_CAPTION = + process.env.NEXT_PUBLIC_NAV_CAPTION || + // Legacy environment variable + process.env.NEXT_PUBLIC_SITE_DESCRIPTION; + export const META_TITLE = process.env.NEXT_PUBLIC_META_TITLE || // Legacy environment variable @@ -99,10 +104,19 @@ export const META_TITLE = NAV_TITLE || TEMPLATE_TITLE; +export const IS_META_TITLE_CONFIGURED = + Boolean(process.env.NEXT_PUBLIC_META_TITLE) || + // Legacy environment variable + Boolean(process.env.NEXT_PUBLIC_SITE_TITLE) || + Boolean(NAV_TITLE); + +export const IS_META_DESCRIPTION_CONFIGURED = + Boolean(process.env.NEXT_PUBLIC_META_DESCRIPTION) || + Boolean(NAV_CAPTION); + export const META_DESCRIPTION = process.env.NEXT_PUBLIC_META_DESCRIPTION || - // Legacy environment variable - process.env.NEXT_PUBLIC_SITE_DESCRIPTION || + NAV_CAPTION || SITE_DOMAIN; export const NAV_TITLE_OR_DOMAIN = @@ -115,11 +129,6 @@ export const PAGE_ABOUT = // Legacy environment variable process.env.NEXT_PUBLIC_SITE_ABOUT; -export const HAS_DEFINED_SITE_DESCRIPTION = - Boolean(process.env.NEXT_PUBLIC_META_DESCRIPTION) || - // Legacy environment variable - Boolean(process.env.NEXT_PUBLIC_SITE_DESCRIPTION); - // STORAGE // STORAGE: DATABASE @@ -309,11 +318,14 @@ export const APP_CONFIGURATION = { Boolean(process.env.ADMIN_EMAIL) && Boolean(process.env.ADMIN_PASSWORD) ), - // Content + // Domain hasDomain: Boolean(process.env.NEXT_PUBLIC_SITE_DOMAIN), - hasTitle: Boolean(process.env.NEXT_PUBLIC_SITE_TITLE), - hasDescription: HAS_DEFINED_SITE_DESCRIPTION, - hasAbout: Boolean(process.env.NEXT_PUBLIC_SITE_ABOUT), + // Content + hasNavTitle: Boolean(NAV_TITLE), + hasNavCaption: Boolean(NAV_CAPTION), + isMetaTitleConfigured: IS_META_TITLE_CONFIGURED, + isMetaDescriptionConfigured: IS_META_DESCRIPTION_CONFIGURED, + hasPageAbout: Boolean(process.env.NEXT_PUBLIC_SITE_ABOUT), // AI isAiTextGenerationEnabled: AI_TEXT_GENERATION_ENABLED, aiTextAutoGeneratedFields: process.env.AI_TEXT_AUTO_GENERATED_FIELDS