Refine photo matte implementation

This commit is contained in:
Sam Becker 2024-05-09 19:09:05 -05:00
parent a76fa30331
commit 577371e28f
9 changed files with 53 additions and 68 deletions

View File

@ -96,7 +96,7 @@ Application behavior can be changed by configuring the following environment var
- `NEXT_PUBLIC_PRO_MODE = 1` enables higher quality image storage (results in increased storage usage)
- `NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES = 1` enables static optimization for pages, i.e., renders pages at build time (results in increased project usage)—⚠️ _Experimental_
- `NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES = 1` enables static optimization for OG images, i.e., renders images at build time (results in increased project usage)—⚠️ _Experimental_
- `NEXT_PUBLIC_MATTE_SETTING = light` constrains the size of each photo, and enables a surrounding border (can be set to `light` or `dark`)
- `NEXT_PUBLIC_MATTE_PHOTOS = 1` constrains the size of each photo, and enables a surrounding border (potentially useful for photos with tall aspect ratios)
- `NEXT_PUBLIC_BLUR_DISABLED = 1` prevents image blur data being stored and displayed (potentially useful for limiting Postgres usage)
- `NEXT_PUBLIC_GEO_PRIVACY = 1` disables collection/display of location-based data
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order

View File

@ -70,13 +70,13 @@ export default function CommandKClient({
isUserSignedIn,
setUserEmail,
isCommandKOpen: isOpen,
matteSetting,
setMatteSetting,
arePhotosMatted,
shouldShowBaselineGrid,
shouldDebugBlur,
setIsCommandKOpen: setIsOpen,
setShouldRespondToKeyboardCommands,
setShouldShowBaselineGrid,
setArePhotosMatted,
setShouldDebugBlur,
} = useAppState();
@ -199,15 +199,9 @@ export default function CommandKClient({
heading: 'Debug Tools',
accessory: <RiToolsFill size={16} className="translate-x-[-1px]" />,
items: [{
label: 'Toggle Matte Setting',
action: () => setMatteSetting?.(prev => {
if (!prev) {
return 'light';
} else if (prev === 'light') {
return 'dark';
}
}),
annotation: Boolean(matteSetting) ? <FaCheck size={12} /> : undefined,
label: 'Toggle Photo Matting',
action: () => setArePhotosMatted?.(prev => !prev),
annotation: arePhotosMatted ? <FaCheck size={12} /> : undefined,
}, {
label: 'Toggle Blur Debug',
action: () => setShouldDebugBlur?.(prev => !prev),

View File

@ -75,8 +75,9 @@ export default function ImageBlurFallback(props: ImageProps & {
<div className={clsx(
'@container',
'absolute inset-0',
'bg-main overflow-hidden',
'overflow-hidden',
'transition-opacity duration-300 ease-in',
!(BLUR_ENABLED && props.blurDataURL) && 'bg-main',
(isLoading || shouldDebugBlur) ? 'opacity-100' : 'opacity-0',
)}>
{(BLUR_ENABLED && props.blurDataURL)

View File

@ -69,7 +69,7 @@ export default function PhotoLarge({
useOnVisible(ref, onVisible);
const { matteSetting } = useAppState();
const { arePhotosMatted } = useAppState();
return (
<SiteGrid
@ -79,28 +79,30 @@ export default function PhotoLarge({
href={pathForPhoto(photo)}
className={clsx(
'active:brightness-75',
Boolean(matteSetting) &&
'flex items-center justify-center aspect-[3/2]',
matteSetting === 'light' && 'bg-invert',
matteSetting === 'dark' && 'bg-dim',
arePhotosMatted &&
'flex items-center aspect-[3/2] bg-gray-100',
)}
prefetch={prefetch}
>
<ImageLarge
className={clsx(Boolean(matteSetting) &&
'flex items-center justify-center h-full')}
imgClassName={clsx(
Boolean(matteSetting) && 'object-scale-down',
Boolean(matteSetting) &&
photo.aspectRatio >= 1 ? 'max-h-[80%]' : 'max-h-[90%]'
)}
alt={altTextForPhoto(photo)}
src={photo.url}
aspectRatio={photo.aspectRatio}
blurData={photo.blurData}
blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)}
priority={priority}
/>
<div className={clsx(
arePhotosMatted &&
'flex items-center justify-center w-full',
arePhotosMatted && photo.aspectRatio >= 1
? 'h-[80%]'
: 'h-[90%]',
)}>
<ImageLarge
className={clsx(arePhotosMatted && 'h-full')}
imgClassName={clsx(arePhotosMatted &&
'object-contain w-full h-full')}
alt={altTextForPhoto(photo)}
src={photo.url}
aspectRatio={photo.aspectRatio}
blurData={photo.blurData}
blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)}
priority={priority}
/>
</div>
</Link>}
contentSide={
<DivDebugBaselineGrid className={clsx(

View File

@ -44,7 +44,7 @@ export default function SiteChecklistClient({
isStaticallyOptimized,
arePagesStaticallyOptimized,
areOGImagesStaticallyOptimized,
matteSetting,
arePhotosMatted,
isBlurEnabled,
isGeoPrivacyEnabled,
isPriorityOrderEnabled,
@ -123,9 +123,9 @@ export default function SiteChecklistClient({
>
<span className="inline-flex items-center gap-1">
<span className={clsx(
'text-xs font-medium tracking-wide',
'px-0.5 py-0.5',
'rounded-sm',
'text-[11px] font-medium tracking-wide',
'px-0.5 py-[0.5px]',
'rounded-[5px]',
'bg-gray-100 dark:bg-gray-800',
)}>
`{variable}`
@ -135,7 +135,7 @@ export default function SiteChecklistClient({
</div>;
const renderEnvVars = (variables: string[]) =>
<div className="py-1 space-y-1">
<div className="py-0.5">
{variables.map(envVar => renderEnvVar(envVar))}
</div>;
@ -370,26 +370,24 @@ export default function SiteChecklistClient({
{renderSubStatus(
arePagesStaticallyOptimized ? 'checked' : 'optional',
renderEnvVars(['NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES']),
'translate-y-[4.5px]',
'translate-y-[3.5px]',
)}
{renderSubStatus(
areOGImagesStaticallyOptimized ? 'checked' : 'optional',
renderEnvVars(['NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES']),
'translate-y-[4.5px]',
'translate-y-[3.5px]',
)}
</ChecklistRow>
<ChecklistRow
title={'Photo Matte' + (matteSetting
? `: ${matteSetting?.toLocaleUpperCase()}`
: '')}
status={Boolean(matteSetting)}
title="Photo Matting"
status={arePhotosMatted}
isPending={isPendingPage}
optional
>
Set environment variable to {'"light"'} or {'"dark"'} to
Set environment variable to {'"1"'} to constrain the size
{' '}
constrain the size of each photo, and enable a surrounding border:
{renderEnvVars(['NEXT_PUBLIC_MATTE_SETTING'])}
of each photo, and enable a surrounding border:
{renderEnvVars(['NEXT_PUBLIC_MATTE_PHOTOS'])}
</ChecklistRow>
<ChecklistRow
title="Image Blur"

View File

@ -114,12 +114,8 @@ export const STATICALLY_OPTIMIZED_PAGES =
process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES === '1';
export const STATICALLY_OPTIMIZED_OG_IMAGES =
process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES === '1';
export const MATTE_SETTING =
process.env.NEXT_PUBLIC_MATTE_SETTING === 'light'
? 'light'
: process.env.NEXT_PUBLIC_MATTE_SETTING === 'dark'
? 'dark'
: undefined;
export const MATTE_PHOTOS =
process.env.NEXT_PUBLIC_MATTE_PHOTOS === '1';
export const BLUR_ENABLED =
process.env.NEXT_PUBLIC_BLUR_DISABLED !== '1';
export const GEO_PRIVACY_ENABLED =
@ -183,7 +179,7 @@ export const CONFIG_CHECKLIST_STATUS = {
),
arePagesStaticallyOptimized: STATICALLY_OPTIMIZED_PAGES,
areOGImagesStaticallyOptimized: STATICALLY_OPTIMIZED_OG_IMAGES,
matteSetting: MATTE_SETTING,
arePhotosMatted: MATTE_PHOTOS,
isBlurEnabled: BLUR_ENABLED,
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
isAiTextGenerationEnabled: AI_TEXT_GENERATION_ENABLED,

View File

@ -162,10 +162,6 @@
@apply
bg-gray-900 dark:bg-gray-100
}
.bg-dim {
@apply
bg-gray-200/40 dark:bg-gray-800/40
}
/* Utilities: Baseline Grid */
.space-y-baseline {
@apply

View File

@ -1,13 +1,11 @@
import { Dispatch, SetStateAction, createContext, useContext } from 'react';
import { AnimationConfig } from '@/components/AnimateItems';
export type MatteSetting = 'light' | 'dark' | undefined;
export interface AppStateContext {
previousPathname?: string
hasLoaded?: boolean
matteSetting?: MatteSetting
setMatteSetting?: Dispatch<SetStateAction<MatteSetting>>
arePhotosMatted?: boolean
setArePhotosMatted?: Dispatch<SetStateAction<boolean>>
swrTimestamp?: number
invalidateSwr?: () => void
userEmail?: string

View File

@ -1,12 +1,12 @@
'use client';
import { useState, useEffect, ReactNode, useCallback } from 'react';
import { AppStateContext, MatteSetting } from './AppState';
import { AppStateContext } from './AppState';
import { AnimationConfig } from '@/components/AnimateItems';
import usePathnames from '@/utility/usePathnames';
import { getAuthAction } from '@/auth/actions';
import useSWR from 'swr';
import { MATTE_SETTING } from '@/site/config';
import { MATTE_PHOTOS } from '@/site/config';
export default function AppStateProvider({
children,
@ -17,8 +17,8 @@ export default function AppStateProvider({
const [hasLoaded, setHasLoaded] =
useState(false);
const [matteSetting, setMatteSetting] =
useState<MatteSetting>(MATTE_SETTING);
const [arePhotosMatted, setArePhotosMatted] =
useState(MATTE_PHOTOS);
const [swrTimestamp, setSwrTimestamp] =
useState(Date.now());
const [userEmail, setUserEmail] =
@ -53,8 +53,8 @@ export default function AppStateProvider({
value={{
previousPathname,
hasLoaded,
matteSetting,
setMatteSetting,
arePhotosMatted,
setArePhotosMatted,
swrTimestamp,
invalidateSwr,
setHasLoaded,