diff --git a/app/layout.tsx b/app/layout.tsx index e3e1fd25..028efaf4 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -11,6 +11,7 @@ import { HTML_LANG, NAV_CAPTION, SITE_FEEDS_ENABLED, + ADMIN_DEBUG_TOOLS_ENABLED, } from '@/app/config'; import AppStateProvider from '@/state/AppStateProvider'; import ToasterWithThemes from '@/toast/ToasterWithThemes'; @@ -91,7 +92,7 @@ export default function RootLayout({ // Center on large screens '3xl:flex flex-col items-center', )}> - + diff --git a/src/cmdk/CommandK.tsx b/src/cmdk/CommandK.tsx index bb93e721..baa00697 100644 --- a/src/cmdk/CommandK.tsx +++ b/src/cmdk/CommandK.tsx @@ -1,7 +1,6 @@ import CommandKClient from './CommandKClient'; import { getPhotosMetaCached } from '@/photo/cache'; import { photoQuantityText } from '@/photo'; -import { ADMIN_DEBUG_TOOLS_ENABLED } from '../app/config'; import { getDataForCategoriesCached } from '@/category/cache'; import { getAppText } from '@/i18n/state/server'; @@ -21,7 +20,6 @@ export default async function CommandK() { return ( ); diff --git a/src/cmdk/CommandKClient.tsx b/src/cmdk/CommandKClient.tsx index c674ca01..b080b304 100644 --- a/src/cmdk/CommandKClient.tsx +++ b/src/cmdk/CommandKClient.tsx @@ -122,10 +122,8 @@ export default function CommandKClient({ recipes, films, focalLengths, - showDebugTools, footer, }: { - showDebugTools?: boolean footer?: string } & PhotoSetCategories) { const pathname = usePathname(); @@ -146,6 +144,7 @@ export default function CommandKClient({ isGridHighDensity, areZoomControlsShown, arePhotosMatted, + areAdminDebugToolsEnabled, shouldShowBaselineGrid, shouldDebugImageFallbacks, shouldDebugInsights, @@ -406,7 +405,7 @@ export default function CommandKClient({ }], }]; - if (isUserSignedIn && showDebugTools) { + if (isUserSignedIn && areAdminDebugToolsEnabled) { clientSections.push({ heading: 'Debug Tools', accessory: , @@ -537,7 +536,7 @@ export default function CommandKClient({ annotation: , path: PATH_ADMIN_CONFIGURATION, }); - if (showDebugTools) { + if (areAdminDebugToolsEnabled) { adminSection.items.push({ label: 'Baseline Overview', annotation: , diff --git a/src/components/image/ImageWithFallback.tsx b/src/components/image/ImageWithFallback.tsx index 4056f8c4..7ff45e0d 100644 --- a/src/components/image/ImageWithFallback.tsx +++ b/src/components/image/ImageWithFallback.tsx @@ -10,6 +10,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; export default function ImageWithFallback({ className, classNameImage = 'object-cover h-full', + debug, priority, blurDataURL, blurCompatibilityLevel = 'low', @@ -17,8 +18,12 @@ export default function ImageWithFallback({ }: ImageProps & { blurCompatibilityLevel?: 'none' | 'low' | 'high' classNameImage?: string + debug?: boolean }) { - const { shouldDebugImageFallbacks } = useAppState(); + const { + shouldDebugImageFallbacks, + areAdminDebugToolsEnabled, + } = useAppState(); const [wasCached, setWasCached] = useState(true); const [isLoading, setIsLoading] = useState(true); @@ -39,10 +44,28 @@ export default function ImageWithFallback({ ); }, []); + const shouldDebugFallback = areAdminDebugToolsEnabled && debug; + + const debugFallbackStyles = useCallback(() => { + const stylesMap = refFallback.current?.computedStyleMap(); + const styles = stylesMap + ? Array.from(stylesMap.entries()).reduce((acc, [key, value]) => { + acc[key] = value.toString(); + return acc; + }, {} as Record) : {}; + const opacity = (stylesMap?.get('opacity') as CSSUnitValue)?.value; + return { + styles, + opacity, + classList: refFallback.current?.classList, + }; + }, []); + + const outerTimeout = useRef(undefined); + const innerTimeout = useRef(undefined); useEffect(() => { if (!isLoading && !didError) { - let innerTimeout: NodeJS.Timeout; - const timeout = setTimeout(() => { + outerTimeout.current = setTimeout(() => { if (refFallback.current) { const fallbackOpacity = (refFallback .current @@ -54,22 +77,32 @@ export default function ImageWithFallback({ if (fallbackOpacity === 0) { // Image has loaded and fallback is already hidden setHideFallback(true); + if (shouldDebugFallback) { + console.log('Hide fallback: 01', debugFallbackStyles()); + } } else { // Image has loaded but fallback is still visible // Delay hiding fallback to avoid abrupt transition - innerTimeout = setTimeout(() =>{ - console.log('Delayed hide fallback'); + innerTimeout.current = setTimeout(() =>{ setHideFallback(true); + if (shouldDebugFallback) { + console.log('Hide fallback: 02', debugFallbackStyles()); + } }, 1000); } } }, 1000); return () => { - clearTimeout(timeout); - clearTimeout(innerTimeout); + clearTimeout(outerTimeout.current); + clearTimeout(innerTimeout.current); }; } - }, [isLoading, didError]); + }, [ + isLoading, + didError, + shouldDebugFallback, + debugFallbackStyles, + ]); const showFallback = !wasCached && diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index f48273d4..52b7c335 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -78,6 +78,7 @@ export default function PhotoLarge({ includeFavoriteInAdminMenu, onVisible, showAdminKeyCommands, + debugImageFallback, }: { photo: Photo className?: string @@ -104,6 +105,7 @@ export default function PhotoLarge({ includeFavoriteInAdminMenu?: boolean onVisible?: () => void showAdminKeyCommands?: boolean + debugImageFallback?: boolean }) { const ref = useRef(null); const refZoomControls = useRef(null); @@ -224,6 +226,7 @@ export default function PhotoLarge({ blurDataURL={photo.blurData} blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)} priority={priority} + debug={debugImageFallback} />
)} itemKeys={photos.map(photo => photo.id)} /> diff --git a/src/state/AppState.ts b/src/state/AppState.ts index 70411577..3a5225a1 100644 --- a/src/state/AppState.ts +++ b/src/state/AppState.ts @@ -64,6 +64,7 @@ export type AppStateContextType = { setUploadState?: (uploadState: Partial) => void resetUploadState?: () => void // DEBUG + areAdminDebugToolsEnabled?: boolean isGridHighDensity?: boolean setIsGridHighDensity?: Dispatch> areZoomControlsShown?: boolean diff --git a/src/state/AppStateProvider.tsx b/src/state/AppStateProvider.tsx index 4a352f71..5002199a 100644 --- a/src/state/AppStateProvider.tsx +++ b/src/state/AppStateProvider.tsx @@ -30,8 +30,10 @@ import { toastSuccess } from '@/toast'; export default function AppStateProvider({ children, + areAdminDebugToolsEnabled, }: { children: ReactNode + areAdminDebugToolsEnabled?: boolean }) { const router = useRouter(); @@ -243,6 +245,7 @@ export default function AppStateProvider({ setUploadState, resetUploadState, // DEBUG + areAdminDebugToolsEnabled, isGridHighDensity, setIsGridHighDensity, areZoomControlsShown,