Move all share buttons to internal app state
This commit is contained in:
parent
76a6f40e77
commit
375dd9e034
@ -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 }} />
|
||||
|
||||
@ -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
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -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 }} />
|
||||
|
||||
@ -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
|
||||
/>}
|
||||
</>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
46
src/share/ShareButton.tsx
Normal 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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -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(
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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 }} />
|
||||
|
||||
@ -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>>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 }} />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user