Move all share buttons to internal app state

This commit is contained in:
Sam Becker 2025-01-11 15:20:26 -06:00
parent 76a6f40e77
commit 375dd9e034
13 changed files with 116 additions and 70 deletions

View File

@ -1,6 +1,6 @@
import { absolutePathForCamera, pathForCamera } from '@/site/paths';
import { absolutePathForCamera } from '@/site/paths';
import { PhotoSetAttributes } from '../photo';
import ShareModal from '@/components/ShareModal';
import ShareModal from '@/share/ShareModal';
import CameraOGTile from './CameraOGTile';
import { Camera } from '.';
import { shareTextForCamera } from './meta';
@ -16,7 +16,6 @@ export default function CameraShareModal({
return (
<ShareModal
pathShare={absolutePathForCamera(camera)}
pathClose={pathForCamera(camera)}
socialText={shareTextForCamera(camera, photos)}
>
<CameraOGTile {...{ camera, photos, count, dateRange }} />

View File

@ -1,33 +0,0 @@
import { TbPhotoShare } from 'react-icons/tb';
import PathLoaderButton from './primitives/PathLoaderButton';
import { clsx } from 'clsx/lite';
export default function ShareButton({
path,
prefetch,
shouldScroll,
dim,
className,
}: {
path: string
prefetch?: boolean
shouldScroll?: boolean
dim?: boolean
className?: string
}) {
return (
<PathLoaderButton
path={path}
className={clsx(
className,
dim ? 'text-dim' : 'text-medium',
)}
icon={<TbPhotoShare size={16} />}
spinnerColor="dim"
prefetch={prefetch}
shouldScroll={shouldScroll}
styleAs="link"
shouldReplace
/>
);
}

View File

@ -1,6 +1,6 @@
import { absolutePathForFocalLength, pathForFocalLength } from '@/site/paths';
import { absolutePathForFocalLength } from '@/site/paths';
import { PhotoSetAttributes } from '../photo';
import ShareModal from '@/components/ShareModal';
import ShareModal from '@/share/ShareModal';
import FocalLengthOGTile from './FocalLengthOGTile';
import { shareTextFocalLength } from '.';
@ -15,7 +15,6 @@ export default function FocalLengthShareModal({
return (
<ShareModal
pathShare={absolutePathForFocalLength(focal)}
pathClose={pathForFocalLength(focal)}
socialText={shareTextFocalLength(focal)}
>
<FocalLengthOGTile {...{ focal, photos, count, dateRange }} />

View File

@ -8,7 +8,7 @@ import {
dateRangeForPhotos,
titleForPhoto,
} from '.';
import ShareButton from '@/components/ShareButton';
import ShareButton from '@/share/ShareButton';
import AnimateItems from '@/components/AnimateItems';
import { ReactNode } from 'react';
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
@ -140,8 +140,15 @@ export default function PhotoHeader({
{entityDescription}
{sharePath &&
<ShareButton
photos={photos}
tag={tag}
camera={camera}
simulation={simulation}
focal={focal}
count={count}
dateRange={dateRange}
className="translate-y-[1.5px]"
path={sharePath}
prefetch
dim
/>}
</>

View File

@ -15,10 +15,9 @@ import Link from 'next/link';
import {
pathForFocalLength,
pathForPhoto,
pathForPhotoShare,
} from '@/site/paths';
import PhotoTags from '@/tag/PhotoTags';
import ShareButton from '@/components/ShareButton';
import ShareButton from '@/share/ShareButton';
import DownloadButton from '@/components/DownloadButton';
import PhotoCamera from '../camera/PhotoCamera';
import { cameraFromPhoto } from '@/camera';
@ -54,7 +53,6 @@ export default function PhotoLarge({
shouldShareCamera,
shouldShareSimulation,
shouldShareFocalLength,
shouldScrollOnShare,
includeFavoriteInAdminMenu,
onVisible,
}: {
@ -258,17 +256,14 @@ export default function PhotoLarge({
)}>
{shouldShare &&
<ShareButton
path={pathForPhotoShare({
photo,
tag: shouldShareTag ? primaryTag : undefined,
camera: shouldShareCamera ? camera : undefined,
// eslint-disable-next-line max-len
simulation: shouldShareSimulation ? photo.filmSimulation : undefined,
// eslint-disable-next-line max-len
focal: shouldShareFocalLength ? photo.focalLength : undefined,
})}
photo={photo}
tag={shouldShareTag ? primaryTag : undefined}
camera={shouldShareCamera ? camera : undefined}
// eslint-disable-next-line max-len
simulation={shouldShareSimulation? photo.filmSimulation : undefined}
// eslint-disable-next-line max-len
focal={shouldShareFocalLength ? photo.focalLength : undefined}
prefetch={prefetchRelatedLinks}
shouldScroll={shouldScrollOnShare}
/>}
{ALLOW_PUBLIC_DOWNLOADS &&
<DownloadButton

View File

@ -1,7 +1,7 @@
import PhotoOGTile from '@/photo/PhotoOGTile';
import { absolutePathForPhoto, pathForPhoto } from '@/site/paths';
import { absolutePathForPhoto } from '@/site/paths';
import { Photo, PhotoSetCategory } from '.';
import ShareModal from '@/components/ShareModal';
import ShareModal from '@/share/ShareModal';
export default function PhotoShareModal(props: {
photo: Photo
@ -9,7 +9,6 @@ export default function PhotoShareModal(props: {
return (
<ShareModal
pathShare={absolutePathForPhoto(props)}
pathClose={pathForPhoto(props)}
socialText="Check out this photo"
>
<PhotoOGTile photo={props.photo} />

46
src/share/ShareButton.tsx Normal file
View File

@ -0,0 +1,46 @@
'use client';
import { TbPhotoShare } from 'react-icons/tb';
import { clsx } from 'clsx/lite';
import LoaderButton from '@/components/primitives/LoaderButton';
import { useAppState } from '@/state/AppState';
import { getSharePathFromShareModalProps, ShareModalProps } from '.';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
export default function ShareButton({
dim,
prefetch,
className,
...rest
}: {
dim?: boolean
prefetch?: boolean
className?: string
} & ShareModalProps) {
const { setShareModalProps } = useAppState();
const router = useRouter();
const absoluteImagePath = getSharePathFromShareModalProps({ ...rest });
useEffect(() => {
if (prefetch && absoluteImagePath) {
console.log('prefetching', absoluteImagePath);
router.prefetch(absoluteImagePath);
}
}, [prefetch, absoluteImagePath, router]);
return (
<LoaderButton
onClick={() => setShareModalProps?.({ ...rest })}
className={clsx(
className,
dim ? 'text-dim' : 'text-medium',
)}
icon={<TbPhotoShare size={16} />}
spinnerColor="dim"
styleAs="link"
/>
);
}

View File

@ -10,20 +10,21 @@ import { toastSuccess } from '@/toast';
import { PiXLogo } from 'react-icons/pi';
import { SHOW_SOCIAL } from '@/site/config';
import { generateXPostText } from '@/utility/social';
import { useAppState } from '@/state/AppState';
export default function ShareModal({
title,
pathShare,
pathClose,
socialText,
children,
}: {
title?: string
pathShare: string
pathClose: string
socialText: string
children: ReactNode
}) {
const { setShareModalProps } = useAppState();
const renderIcon = (
icon: JSX.Element,
action: () => void,
@ -44,7 +45,7 @@ export default function ShareModal({
</div>;
return (
<Modal onClosePath={pathClose}>
<Modal onClose={() => setShareModalProps?.(undefined)}>
<div className="space-y-3 md:space-y-4 w-full">
{title &&
<div className={clsx(

View File

@ -1,6 +1,37 @@
import { Photo, PhotoSetAttributes, PhotoSetCategory } from '@/photo';
import { absolutePathForPhotoImage } from '@/site/paths';
import { absolutePathForTagImage } from '@/site/paths';
import {
absolutePathForCamera,
absolutePathForFilmSimulation,
} from '@/site/paths';
import { absolutePathForFocalLength } from '@/site/paths';
export type ShareModalProps = Omit<PhotoSetAttributes, 'photos'> & {
photo?: Photo
photos?: Photo[]
} & PhotoSetCategory;
export const getSharePathFromShareModalProps = ({
photo,
tag,
camera,
simulation,
focal,
}: ShareModalProps) => {
if (photo) {
return absolutePathForPhotoImage(photo);
}
if (tag) {
return absolutePathForTagImage(tag);
}
if (camera) {
return absolutePathForCamera(camera);
}
if (simulation) {
return absolutePathForFilmSimulation(simulation);
}
if (focal) {
return absolutePathForFocalLength(focal);
}
};

View File

@ -1,9 +1,6 @@
import {
absolutePathForFilmSimulation,
pathForFilmSimulation,
} from '@/site/paths';
import { absolutePathForFilmSimulation } from '@/site/paths';
import { PhotoSetAttributes } from '../photo';
import ShareModal from '@/components/ShareModal';
import ShareModal from '@/share/ShareModal';
import FilmSimulationOGTile from './FilmSimulationOGTile';
import { FilmSimulation, shareTextForFilmSimulation } from '.';
@ -18,7 +15,6 @@ export default function FilmSimulationShareModal({
return (
<ShareModal
pathShare={absolutePathForFilmSimulation(simulation)}
pathClose={pathForFilmSimulation(simulation)}
socialText={shareTextForFilmSimulation(simulation)}
>
<FilmSimulationOGTile {...{ simulation, photos, count, dateRange }} />

View File

@ -3,7 +3,7 @@ import { AnimationConfig } from '@/components/AnimateItems';
import { ShareModalProps } from '@/share';
export interface AppStateContext {
// GLOBAL
// CORE
previousPathname?: string
hasLoaded?: boolean
setHasLoaded?: Dispatch<SetStateAction<boolean>>

View File

@ -8,6 +8,7 @@ import { getAuthAction } from '@/auth/actions';
import useSWR from 'swr';
import { HIGH_DENSITY_GRID, MATTE_PHOTOS } from '@/site/config';
import { getPhotosHiddenMetaCachedAction } from '@/photo/actions';
import { ShareModalProps } from '@/share';
export default function AppStateProvider({
children,
@ -25,8 +26,11 @@ export default function AppStateProvider({
useState<AnimationConfig>();
const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] =
useState(true);
// MODAL
const [isCommandKOpen, setIsCommandKOpen] =
useState(false);
const [shareModalProps, setShareModalProps] =
useState<ShareModalProps>();
// ADMIN
const [userEmail, setUserEmail] =
useState<string>();
@ -89,8 +93,11 @@ export default function AppStateProvider({
clearNextPhotoAnimation: () => setNextPhotoAnimation?.(undefined),
shouldRespondToKeyboardCommands,
setShouldRespondToKeyboardCommands,
// MODAL
isCommandKOpen,
setIsCommandKOpen,
shareModalProps,
setShareModalProps,
// ADMIN
userEmail,
setUserEmail,

View File

@ -1,6 +1,6 @@
import { absolutePathForTag, pathForTag } from '@/site/paths';
import { absolutePathForTag } from '@/site/paths';
import { PhotoSetAttributes } from '../photo';
import ShareModal from '@/components/ShareModal';
import ShareModal from '@/share/ShareModal';
import TagOGTile from './TagOGTile';
import { shareTextForTag } from '.';
@ -15,7 +15,6 @@ export default function TagShareModal({
return (
<ShareModal
pathShare={absolutePathForTag(tag)}
pathClose={pathForTag(tag)}
socialText={shareTextForTag(tag)}
>
<TagOGTile {...{ tag, photos, count, dateRange }} />