@@ -65,7 +65,7 @@ export default function AdminInfoPage({
{title}
- {title === 'App Insights' && insightIndicatorStatus &&
+ {title === 'App Insights' && insightsIndicatorStatus &&
runAuthenticatedAdminServerAction(async () => {
@@ -17,7 +17,7 @@ export const getAdminDataAction = async () =>
countHiddenPhotos,
countTags,
countUploads,
- shouldShowInsightsIndicator,
+ insightsIndicatorStatus,
] = await Promise.all([
getPhotosMetaCached()
.then(({ count }) => count)
@@ -34,7 +34,7 @@ export const getAdminDataAction = async () =>
console.error(`Error getting blob upload urls: ${e}`);
return 0;
}),
- getShouldShowInsightsIndicator(),
+ getInsightsIndicatorStatus(),
]);
return {
@@ -42,7 +42,7 @@ export const getAdminDataAction = async () =>
countHiddenPhotos,
countTags,
countUploads,
- shouldShowInsightsIndicator,
+ insightsIndicatorStatus,
};
});
diff --git a/src/admin/insights/AdminAppInsights.tsx b/src/admin/insights/AdminAppInsights.tsx
index 122eee33..36077d9d 100644
--- a/src/admin/insights/AdminAppInsights.tsx
+++ b/src/admin/insights/AdminAppInsights.tsx
@@ -11,11 +11,13 @@ import {
GRID_HOMEPAGE_ENABLED,
HAS_STATIC_OPTIMIZATION,
MATTE_PHOTOS,
+ SHOW_SIDEBAR_CAMERAS_FIRST,
} from '@/app/config';
import { getGitHubMetaForCurrentApp, getSignificantInsights } from '.';
import { getOutdatedPhotosCount } from '@/photo/db/query';
const BASIC_PHOTO_INSTALLATION_COUNT = 32;
+const TAG_COUNT_THRESHOLD = 12;
export default async function AdminAppInsights() {
const [
@@ -63,6 +65,10 @@ export default async function AdminAppInsights() {
noConfiguredDomain,
outdatedPhotos,
photoMatting: photosCountPortrait > 0 && !MATTE_PHOTOS,
+ camerasFirst: (
+ tags.length > TAG_COUNT_THRESHOLD &&
+ !SHOW_SIDEBAR_CAMERAS_FIRST
+ ),
gridFirst: (
photosCount >= BASIC_PHOTO_INSTALLATION_COUNT &&
!GRID_HOMEPAGE_ENABLED
diff --git a/src/admin/insights/AdminAppInsightsClient.tsx b/src/admin/insights/AdminAppInsightsClient.tsx
index 855c0599..973b4285 100644
--- a/src/admin/insights/AdminAppInsightsClient.tsx
+++ b/src/admin/insights/AdminAppInsightsClient.tsx
@@ -7,6 +7,7 @@ import PhotoFilmSimulationIcon from '@/simulation/PhotoFilmSimulationIcon';
import { FaCamera } from 'react-icons/fa';
import { FaTag } from 'react-icons/fa';
import { FaCircleInfo, FaRegCalendar } from 'react-icons/fa6';
+import { HiMiniArrowsUpDown } from 'react-icons/hi2';
import { HiOutlinePhotograph } from 'react-icons/hi';
import { MdAspectRatio } from 'react-icons/md';
import { PiWarningBold } from 'react-icons/pi';
@@ -107,6 +108,7 @@ export default function AdminAppInsightsClient({
noConfiguredDomain,
outdatedPhotos,
photoMatting,
+ camerasFirst,
gridFirst,
noStaticOptimization,
} = insights;
@@ -271,7 +273,10 @@ export default function AdminAppInsightsClient({
Not explicitly setting a domain may cause certain features
to behave unexpectedly. Domains are stored in
{' '}
- .
+
>}
/>}
{(noStaticOptimization || debug) &&
Enable automatic AI text generation
{' '}
- by setting .
+ by setting
{' '}
Further instruction and cost considerations in
{' '}
@@ -331,7 +339,28 @@ export default function AdminAppInsightsClient({
{' '}
portrait and landscape photos appear more consistent
{' '}
- .
+
+ >}
+ />}
+ {(camerasFirst || debug) && }
+ content="Move cameras above tags in sidebar"
+ expandContent={<>
+ Now that you have more than a few tags, consider
+ showing cameras first in the sidebar by setting
+ {' '}
+
>}
/>}
{(gridFirst || debug) && {
switch (size) {
@@ -39,7 +39,7 @@ export default function InsightsIndicatorDot({
bottom !== undefined ||
left !== undefined
) && 'absolute',
- (colorOverride ?? insightIndicatorStatus) === 'blue'
+ (colorOverride ?? insightsIndicatorStatus) === 'blue'
? 'text-blue-500'
: 'text-amber-500',
className,
diff --git a/src/admin/insights/index.ts b/src/admin/insights/index.ts
index 9b9b6e34..2a23fffd 100644
--- a/src/admin/insights/index.ts
+++ b/src/admin/insights/index.ts
@@ -10,41 +10,39 @@ import {
import { PhotoDateRange } from '@/photo';
import { getGitHubMeta } from '@/platforms/github';
-type AdminAppInsightCode =
- 'noFork' |
- 'forkBehind';
+const AdminAppInsightCode = [
+ 'noFork',
+ 'forkBehind',
+] as const;
+type AdminAppInsightCode = typeof AdminAppInsightCode[number];
-type AdminAppInsightRecommendation =
- 'noAi' |
- 'noAiRateLimiting' |
- 'noConfiguredDomain' |
- 'photoMatting' |
- 'gridFirst' |
- 'noStaticOptimization';
+const _INSIGHTS_TEMPLATE = [
+ 'noAi',
+ 'noAiRateLimiting',
+ 'noConfiguredDomain',
+ 'photoMatting',
+ 'camerasFirst',
+ 'gridFirst',
+ 'noStaticOptimization',
+] as const;
+type AdminAppInsightRecommendation = typeof _INSIGHTS_TEMPLATE[number];
-type AdminAppInsightLibrary =
- 'outdatedPhotos';
+const _INSIGHTS_LIBRARY = [
+ 'outdatedPhotos',
+] as const;
+type AdminAppInsightLibrary = typeof _INSIGHTS_LIBRARY[number];
export type AdminAppInsight =
AdminAppInsightCode |
AdminAppInsightRecommendation |
AdminAppInsightLibrary;
-const RECOMMENDATIONS: AdminAppInsightRecommendation[] = [
- 'noAi',
- 'noAiRateLimiting',
- 'noConfiguredDomain',
- 'photoMatting',
- 'gridFirst',
- 'noStaticOptimization',
-];
-
export type AdminAppInsights = Record
-export type InsightIndicatorStatus = 'blue' | 'yellow' | undefined;
+export type InsightsIndicatorStatus = 'blue' | 'yellow' | undefined;
export const hasTemplateRecommendations = (insights: AdminAppInsights) =>
- RECOMMENDATIONS.some(insight => insights[insight]);
+ _INSIGHTS_TEMPLATE.some(insight => insights[insight]);
export interface PhotoStats {
photosCount: number
@@ -87,3 +85,20 @@ export const getSignificantInsights = ({
outdatedPhotos: Boolean(photosCountOutdated),
};
};
+
+export const indicatorStatusForSignificantInsights = (
+ insights: Awaited>,
+) => {
+ const {
+ forkBehind,
+ noAiRateLimiting,
+ noConfiguredDomain,
+ outdatedPhotos,
+ } = insights;
+
+ if (noAiRateLimiting || noConfiguredDomain) {
+ return 'yellow';
+ } else if (forkBehind || outdatedPhotos) {
+ return 'blue';
+ }
+};
diff --git a/src/admin/insights/server.ts b/src/admin/insights/server.ts
index 5090b12f..3b453def 100644
--- a/src/admin/insights/server.ts
+++ b/src/admin/insights/server.ts
@@ -1,8 +1,11 @@
import { getOutdatedPhotosCount } from '@/photo/db/query';
-import { getSignificantInsights } from '.';
+import {
+ getSignificantInsights,
+ indicatorStatusForSignificantInsights,
+} from '.';
import { getGitHubMetaForCurrentApp } from '.';
-export const getShouldShowInsightsIndicator = async () => {
+export const getInsightsIndicatorStatus = async () => {
const [
codeMeta,
photosCountOutdated,
@@ -11,19 +14,10 @@ export const getShouldShowInsightsIndicator = async () => {
getOutdatedPhotosCount(),
]);
- const {
- forkBehind,
- noAiRateLimiting,
- noConfiguredDomain,
- outdatedPhotos,
- } = getSignificantInsights({
+ const significantInsights = getSignificantInsights({
codeMeta,
photosCountOutdated,
});
- if (noAiRateLimiting || noConfiguredDomain) {
- return 'yellow';
- } else if (forkBehind || outdatedPhotos) {
- return 'blue';
- }
+ return indicatorStatusForSignificantInsights(significantInsights);
};
diff --git a/src/app/config.ts b/src/app/config.ts
index 4fb01969..0fca306c 100644
--- a/src/app/config.ts
+++ b/src/app/config.ts
@@ -221,6 +221,8 @@ export const SHOW_RECIPES =
process.env.NEXT_PUBLIC_HIDE_RECIPES !== '1';
export const SHOW_REPO_LINK =
process.env.NEXT_PUBLIC_HIDE_REPO_LINK !== '1';
+export const SHOW_SIDEBAR_CAMERAS_FIRST =
+ process.env.NEXT_PUBLIC_CAMERAS_FIRST === '1';
// GRID
@@ -317,6 +319,7 @@ export const APP_CONFIGURATION = {
showFilmSimulations: SHOW_FILM_SIMULATIONS,
showRecipes: SHOW_RECIPES,
showRepoLink: SHOW_REPO_LINK,
+ showSidebarCamerasFirst: SHOW_SIDEBAR_CAMERAS_FIRST,
// Grid
isGridHomepageEnabled: GRID_HOMEPAGE_ENABLED,
gridAspectRatio: GRID_ASPECT_RATIO,
diff --git a/src/components/EnvVar.tsx b/src/components/EnvVar.tsx
index b96ecf3b..44bd1158 100644
--- a/src/components/EnvVar.tsx
+++ b/src/components/EnvVar.tsx
@@ -34,13 +34,18 @@ export default function EnvVar({
{variable}{value && ` = ${value}`}
{includeCopyButton &&
- }
- {trailingContent}
+
+
+ }
+ {trailingContent &&
+
+ {trailingContent}
+ }
);
diff --git a/src/components/cmdk/CommandKClient.tsx b/src/components/cmdk/CommandKClient.tsx
index 3bf4bd5d..e249b48f 100644
--- a/src/components/cmdk/CommandKClient.tsx
+++ b/src/components/cmdk/CommandKClient.tsx
@@ -108,7 +108,7 @@ export default function CommandKClient({
tagsCount,
selectedPhotoIds,
setSelectedPhotoIds,
- insightIndicatorStatus,
+ insightsIndicatorStatus,
isGridHighDensity,
areZoomControlsShown,
arePhotosMatted,
@@ -365,7 +365,7 @@ export default function CommandKClient({
adminSection.items.push({
label:
{SITE_ABOUT &&
]}
/>}
- {tags.length > 0 &&
}
- items={tagsIncludingHidden.map(({ tag, count }) => {
- switch (tag) {
- case TAG_FAVS:
- return
;
- case TAG_HIDDEN:
- return
;
- default:
- return
;
- }
- })}
- />}
- {cameras.length > 0 &&
}
- items={cameras
- .sort(sortCamerasWithCount)
- .map(({ cameraKey, camera, count }) =>
-
)}
- />}
- {simulations.length > 0 &&
}
- items={simulations
- .sort(sortFilmSimulationsWithCount)
- .map(({ simulation, count }) =>
-
)}
- />}
- {photosCount > 0 && start
- ?
- :
}
+ {SHOW_SIDEBAR_CAMERAS_FIRST
+ ? <>{camerasContent}{tagsContent}>
+ : <>{tagsContent}{camerasContent}>}
+ {filmsContent}
+ {photoStatsContent}
);
}
diff --git a/src/state/AppState.ts b/src/state/AppState.ts
index daa77591..1da924ec 100644
--- a/src/state/AppState.ts
+++ b/src/state/AppState.ts
@@ -7,7 +7,7 @@ import {
} from 'react';
import { AnimationConfig } from '@/components/AnimateItems';
import { ShareModalProps } from '@/share';
-import { InsightIndicatorStatus } from '@/admin/insights';
+import { InsightsIndicatorStatus } from '@/admin/insights';
import { INITIAL_UPLOAD_STATE, UploadState } from '@/admin/upload';
export interface AppStateContext {
@@ -52,8 +52,8 @@ export interface AppStateContext {
setSelectedPhotoIds?: Dispatch