Refine photo matte implementation
This commit is contained in:
parent
a76fa30331
commit
577371e28f
@ -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_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_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_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_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_GEO_PRIVACY = 1` disables collection/display of location-based data
|
||||||
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order
|
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order
|
||||||
|
|||||||
@ -70,13 +70,13 @@ export default function CommandKClient({
|
|||||||
isUserSignedIn,
|
isUserSignedIn,
|
||||||
setUserEmail,
|
setUserEmail,
|
||||||
isCommandKOpen: isOpen,
|
isCommandKOpen: isOpen,
|
||||||
matteSetting,
|
arePhotosMatted,
|
||||||
setMatteSetting,
|
|
||||||
shouldShowBaselineGrid,
|
shouldShowBaselineGrid,
|
||||||
shouldDebugBlur,
|
shouldDebugBlur,
|
||||||
setIsCommandKOpen: setIsOpen,
|
setIsCommandKOpen: setIsOpen,
|
||||||
setShouldRespondToKeyboardCommands,
|
setShouldRespondToKeyboardCommands,
|
||||||
setShouldShowBaselineGrid,
|
setShouldShowBaselineGrid,
|
||||||
|
setArePhotosMatted,
|
||||||
setShouldDebugBlur,
|
setShouldDebugBlur,
|
||||||
} = useAppState();
|
} = useAppState();
|
||||||
|
|
||||||
@ -199,15 +199,9 @@ export default function CommandKClient({
|
|||||||
heading: 'Debug Tools',
|
heading: 'Debug Tools',
|
||||||
accessory: <RiToolsFill size={16} className="translate-x-[-1px]" />,
|
accessory: <RiToolsFill size={16} className="translate-x-[-1px]" />,
|
||||||
items: [{
|
items: [{
|
||||||
label: 'Toggle Matte Setting',
|
label: 'Toggle Photo Matting',
|
||||||
action: () => setMatteSetting?.(prev => {
|
action: () => setArePhotosMatted?.(prev => !prev),
|
||||||
if (!prev) {
|
annotation: arePhotosMatted ? <FaCheck size={12} /> : undefined,
|
||||||
return 'light';
|
|
||||||
} else if (prev === 'light') {
|
|
||||||
return 'dark';
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
annotation: Boolean(matteSetting) ? <FaCheck size={12} /> : undefined,
|
|
||||||
}, {
|
}, {
|
||||||
label: 'Toggle Blur Debug',
|
label: 'Toggle Blur Debug',
|
||||||
action: () => setShouldDebugBlur?.(prev => !prev),
|
action: () => setShouldDebugBlur?.(prev => !prev),
|
||||||
|
|||||||
@ -75,8 +75,9 @@ export default function ImageBlurFallback(props: ImageProps & {
|
|||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'@container',
|
'@container',
|
||||||
'absolute inset-0',
|
'absolute inset-0',
|
||||||
'bg-main overflow-hidden',
|
'overflow-hidden',
|
||||||
'transition-opacity duration-300 ease-in',
|
'transition-opacity duration-300 ease-in',
|
||||||
|
!(BLUR_ENABLED && props.blurDataURL) && 'bg-main',
|
||||||
(isLoading || shouldDebugBlur) ? 'opacity-100' : 'opacity-0',
|
(isLoading || shouldDebugBlur) ? 'opacity-100' : 'opacity-0',
|
||||||
)}>
|
)}>
|
||||||
{(BLUR_ENABLED && props.blurDataURL)
|
{(BLUR_ENABLED && props.blurDataURL)
|
||||||
|
|||||||
@ -69,7 +69,7 @@ export default function PhotoLarge({
|
|||||||
|
|
||||||
useOnVisible(ref, onVisible);
|
useOnVisible(ref, onVisible);
|
||||||
|
|
||||||
const { matteSetting } = useAppState();
|
const { arePhotosMatted } = useAppState();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SiteGrid
|
<SiteGrid
|
||||||
@ -79,21 +79,22 @@ export default function PhotoLarge({
|
|||||||
href={pathForPhoto(photo)}
|
href={pathForPhoto(photo)}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'active:brightness-75',
|
'active:brightness-75',
|
||||||
Boolean(matteSetting) &&
|
arePhotosMatted &&
|
||||||
'flex items-center justify-center aspect-[3/2]',
|
'flex items-center aspect-[3/2] bg-gray-100',
|
||||||
matteSetting === 'light' && 'bg-invert',
|
|
||||||
matteSetting === 'dark' && 'bg-dim',
|
|
||||||
)}
|
)}
|
||||||
prefetch={prefetch}
|
prefetch={prefetch}
|
||||||
>
|
>
|
||||||
|
<div className={clsx(
|
||||||
|
arePhotosMatted &&
|
||||||
|
'flex items-center justify-center w-full',
|
||||||
|
arePhotosMatted && photo.aspectRatio >= 1
|
||||||
|
? 'h-[80%]'
|
||||||
|
: 'h-[90%]',
|
||||||
|
)}>
|
||||||
<ImageLarge
|
<ImageLarge
|
||||||
className={clsx(Boolean(matteSetting) &&
|
className={clsx(arePhotosMatted && 'h-full')}
|
||||||
'flex items-center justify-center h-full')}
|
imgClassName={clsx(arePhotosMatted &&
|
||||||
imgClassName={clsx(
|
'object-contain w-full h-full')}
|
||||||
Boolean(matteSetting) && 'object-scale-down',
|
|
||||||
Boolean(matteSetting) &&
|
|
||||||
photo.aspectRatio >= 1 ? 'max-h-[80%]' : 'max-h-[90%]'
|
|
||||||
)}
|
|
||||||
alt={altTextForPhoto(photo)}
|
alt={altTextForPhoto(photo)}
|
||||||
src={photo.url}
|
src={photo.url}
|
||||||
aspectRatio={photo.aspectRatio}
|
aspectRatio={photo.aspectRatio}
|
||||||
@ -101,6 +102,7 @@ export default function PhotoLarge({
|
|||||||
blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)}
|
blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)}
|
||||||
priority={priority}
|
priority={priority}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</Link>}
|
</Link>}
|
||||||
contentSide={
|
contentSide={
|
||||||
<DivDebugBaselineGrid className={clsx(
|
<DivDebugBaselineGrid className={clsx(
|
||||||
|
|||||||
@ -44,7 +44,7 @@ export default function SiteChecklistClient({
|
|||||||
isStaticallyOptimized,
|
isStaticallyOptimized,
|
||||||
arePagesStaticallyOptimized,
|
arePagesStaticallyOptimized,
|
||||||
areOGImagesStaticallyOptimized,
|
areOGImagesStaticallyOptimized,
|
||||||
matteSetting,
|
arePhotosMatted,
|
||||||
isBlurEnabled,
|
isBlurEnabled,
|
||||||
isGeoPrivacyEnabled,
|
isGeoPrivacyEnabled,
|
||||||
isPriorityOrderEnabled,
|
isPriorityOrderEnabled,
|
||||||
@ -123,9 +123,9 @@ export default function SiteChecklistClient({
|
|||||||
>
|
>
|
||||||
<span className="inline-flex items-center gap-1">
|
<span className="inline-flex items-center gap-1">
|
||||||
<span className={clsx(
|
<span className={clsx(
|
||||||
'text-xs font-medium tracking-wide',
|
'text-[11px] font-medium tracking-wide',
|
||||||
'px-0.5 py-0.5',
|
'px-0.5 py-[0.5px]',
|
||||||
'rounded-sm',
|
'rounded-[5px]',
|
||||||
'bg-gray-100 dark:bg-gray-800',
|
'bg-gray-100 dark:bg-gray-800',
|
||||||
)}>
|
)}>
|
||||||
`{variable}`
|
`{variable}`
|
||||||
@ -135,7 +135,7 @@ export default function SiteChecklistClient({
|
|||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
const renderEnvVars = (variables: string[]) =>
|
const renderEnvVars = (variables: string[]) =>
|
||||||
<div className="py-1 space-y-1">
|
<div className="py-0.5">
|
||||||
{variables.map(envVar => renderEnvVar(envVar))}
|
{variables.map(envVar => renderEnvVar(envVar))}
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
@ -370,26 +370,24 @@ export default function SiteChecklistClient({
|
|||||||
{renderSubStatus(
|
{renderSubStatus(
|
||||||
arePagesStaticallyOptimized ? 'checked' : 'optional',
|
arePagesStaticallyOptimized ? 'checked' : 'optional',
|
||||||
renderEnvVars(['NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES']),
|
renderEnvVars(['NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES']),
|
||||||
'translate-y-[4.5px]',
|
'translate-y-[3.5px]',
|
||||||
)}
|
)}
|
||||||
{renderSubStatus(
|
{renderSubStatus(
|
||||||
areOGImagesStaticallyOptimized ? 'checked' : 'optional',
|
areOGImagesStaticallyOptimized ? 'checked' : 'optional',
|
||||||
renderEnvVars(['NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES']),
|
renderEnvVars(['NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES']),
|
||||||
'translate-y-[4.5px]',
|
'translate-y-[3.5px]',
|
||||||
)}
|
)}
|
||||||
</ChecklistRow>
|
</ChecklistRow>
|
||||||
<ChecklistRow
|
<ChecklistRow
|
||||||
title={'Photo Matte' + (matteSetting
|
title="Photo Matting"
|
||||||
? `: ${matteSetting?.toLocaleUpperCase()}`
|
status={arePhotosMatted}
|
||||||
: '')}
|
|
||||||
status={Boolean(matteSetting)}
|
|
||||||
isPending={isPendingPage}
|
isPending={isPendingPage}
|
||||||
optional
|
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:
|
of each photo, and enable a surrounding border:
|
||||||
{renderEnvVars(['NEXT_PUBLIC_MATTE_SETTING'])}
|
{renderEnvVars(['NEXT_PUBLIC_MATTE_PHOTOS'])}
|
||||||
</ChecklistRow>
|
</ChecklistRow>
|
||||||
<ChecklistRow
|
<ChecklistRow
|
||||||
title="Image Blur"
|
title="Image Blur"
|
||||||
|
|||||||
@ -114,12 +114,8 @@ export const STATICALLY_OPTIMIZED_PAGES =
|
|||||||
process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES === '1';
|
process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_PAGES === '1';
|
||||||
export const STATICALLY_OPTIMIZED_OG_IMAGES =
|
export const STATICALLY_OPTIMIZED_OG_IMAGES =
|
||||||
process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES === '1';
|
process.env.NEXT_PUBLIC_STATICALLY_OPTIMIZE_OG_IMAGES === '1';
|
||||||
export const MATTE_SETTING =
|
export const MATTE_PHOTOS =
|
||||||
process.env.NEXT_PUBLIC_MATTE_SETTING === 'light'
|
process.env.NEXT_PUBLIC_MATTE_PHOTOS === '1';
|
||||||
? 'light'
|
|
||||||
: process.env.NEXT_PUBLIC_MATTE_SETTING === 'dark'
|
|
||||||
? 'dark'
|
|
||||||
: undefined;
|
|
||||||
export const BLUR_ENABLED =
|
export const BLUR_ENABLED =
|
||||||
process.env.NEXT_PUBLIC_BLUR_DISABLED !== '1';
|
process.env.NEXT_PUBLIC_BLUR_DISABLED !== '1';
|
||||||
export const GEO_PRIVACY_ENABLED =
|
export const GEO_PRIVACY_ENABLED =
|
||||||
@ -183,7 +179,7 @@ export const CONFIG_CHECKLIST_STATUS = {
|
|||||||
),
|
),
|
||||||
arePagesStaticallyOptimized: STATICALLY_OPTIMIZED_PAGES,
|
arePagesStaticallyOptimized: STATICALLY_OPTIMIZED_PAGES,
|
||||||
areOGImagesStaticallyOptimized: STATICALLY_OPTIMIZED_OG_IMAGES,
|
areOGImagesStaticallyOptimized: STATICALLY_OPTIMIZED_OG_IMAGES,
|
||||||
matteSetting: MATTE_SETTING,
|
arePhotosMatted: MATTE_PHOTOS,
|
||||||
isBlurEnabled: BLUR_ENABLED,
|
isBlurEnabled: BLUR_ENABLED,
|
||||||
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
|
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
|
||||||
isAiTextGenerationEnabled: AI_TEXT_GENERATION_ENABLED,
|
isAiTextGenerationEnabled: AI_TEXT_GENERATION_ENABLED,
|
||||||
|
|||||||
@ -162,10 +162,6 @@
|
|||||||
@apply
|
@apply
|
||||||
bg-gray-900 dark:bg-gray-100
|
bg-gray-900 dark:bg-gray-100
|
||||||
}
|
}
|
||||||
.bg-dim {
|
|
||||||
@apply
|
|
||||||
bg-gray-200/40 dark:bg-gray-800/40
|
|
||||||
}
|
|
||||||
/* Utilities: Baseline Grid */
|
/* Utilities: Baseline Grid */
|
||||||
.space-y-baseline {
|
.space-y-baseline {
|
||||||
@apply
|
@apply
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import { Dispatch, SetStateAction, createContext, useContext } from 'react';
|
import { Dispatch, SetStateAction, createContext, useContext } from 'react';
|
||||||
import { AnimationConfig } from '@/components/AnimateItems';
|
import { AnimationConfig } from '@/components/AnimateItems';
|
||||||
|
|
||||||
export type MatteSetting = 'light' | 'dark' | undefined;
|
|
||||||
|
|
||||||
export interface AppStateContext {
|
export interface AppStateContext {
|
||||||
previousPathname?: string
|
previousPathname?: string
|
||||||
hasLoaded?: boolean
|
hasLoaded?: boolean
|
||||||
matteSetting?: MatteSetting
|
arePhotosMatted?: boolean
|
||||||
setMatteSetting?: Dispatch<SetStateAction<MatteSetting>>
|
setArePhotosMatted?: Dispatch<SetStateAction<boolean>>
|
||||||
swrTimestamp?: number
|
swrTimestamp?: number
|
||||||
invalidateSwr?: () => void
|
invalidateSwr?: () => void
|
||||||
userEmail?: string
|
userEmail?: string
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect, ReactNode, useCallback } from 'react';
|
import { useState, useEffect, ReactNode, useCallback } from 'react';
|
||||||
import { AppStateContext, MatteSetting } from './AppState';
|
import { AppStateContext } from './AppState';
|
||||||
import { AnimationConfig } from '@/components/AnimateItems';
|
import { AnimationConfig } from '@/components/AnimateItems';
|
||||||
import usePathnames from '@/utility/usePathnames';
|
import usePathnames from '@/utility/usePathnames';
|
||||||
import { getAuthAction } from '@/auth/actions';
|
import { getAuthAction } from '@/auth/actions';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { MATTE_SETTING } from '@/site/config';
|
import { MATTE_PHOTOS } from '@/site/config';
|
||||||
|
|
||||||
export default function AppStateProvider({
|
export default function AppStateProvider({
|
||||||
children,
|
children,
|
||||||
@ -17,8 +17,8 @@ export default function AppStateProvider({
|
|||||||
|
|
||||||
const [hasLoaded, setHasLoaded] =
|
const [hasLoaded, setHasLoaded] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [matteSetting, setMatteSetting] =
|
const [arePhotosMatted, setArePhotosMatted] =
|
||||||
useState<MatteSetting>(MATTE_SETTING);
|
useState(MATTE_PHOTOS);
|
||||||
const [swrTimestamp, setSwrTimestamp] =
|
const [swrTimestamp, setSwrTimestamp] =
|
||||||
useState(Date.now());
|
useState(Date.now());
|
||||||
const [userEmail, setUserEmail] =
|
const [userEmail, setUserEmail] =
|
||||||
@ -53,8 +53,8 @@ export default function AppStateProvider({
|
|||||||
value={{
|
value={{
|
||||||
previousPathname,
|
previousPathname,
|
||||||
hasLoaded,
|
hasLoaded,
|
||||||
matteSetting,
|
arePhotosMatted,
|
||||||
setMatteSetting,
|
setArePhotosMatted,
|
||||||
swrTimestamp,
|
swrTimestamp,
|
||||||
invalidateSwr,
|
invalidateSwr,
|
||||||
setHasLoaded,
|
setHasLoaded,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user