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 { PhotoSetAttributes } from '../photo';
|
||||||
import ShareModal from '@/components/ShareModal';
|
import ShareModal from '@/share/ShareModal';
|
||||||
import CameraOGTile from './CameraOGTile';
|
import CameraOGTile from './CameraOGTile';
|
||||||
import { Camera } from '.';
|
import { Camera } from '.';
|
||||||
import { shareTextForCamera } from './meta';
|
import { shareTextForCamera } from './meta';
|
||||||
@ -16,7 +16,6 @@ export default function CameraShareModal({
|
|||||||
return (
|
return (
|
||||||
<ShareModal
|
<ShareModal
|
||||||
pathShare={absolutePathForCamera(camera)}
|
pathShare={absolutePathForCamera(camera)}
|
||||||
pathClose={pathForCamera(camera)}
|
|
||||||
socialText={shareTextForCamera(camera, photos)}
|
socialText={shareTextForCamera(camera, photos)}
|
||||||
>
|
>
|
||||||
<CameraOGTile {...{ camera, photos, count, dateRange }} />
|
<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 { PhotoSetAttributes } from '../photo';
|
||||||
import ShareModal from '@/components/ShareModal';
|
import ShareModal from '@/share/ShareModal';
|
||||||
import FocalLengthOGTile from './FocalLengthOGTile';
|
import FocalLengthOGTile from './FocalLengthOGTile';
|
||||||
import { shareTextFocalLength } from '.';
|
import { shareTextFocalLength } from '.';
|
||||||
|
|
||||||
@ -15,7 +15,6 @@ export default function FocalLengthShareModal({
|
|||||||
return (
|
return (
|
||||||
<ShareModal
|
<ShareModal
|
||||||
pathShare={absolutePathForFocalLength(focal)}
|
pathShare={absolutePathForFocalLength(focal)}
|
||||||
pathClose={pathForFocalLength(focal)}
|
|
||||||
socialText={shareTextFocalLength(focal)}
|
socialText={shareTextFocalLength(focal)}
|
||||||
>
|
>
|
||||||
<FocalLengthOGTile {...{ focal, photos, count, dateRange }} />
|
<FocalLengthOGTile {...{ focal, photos, count, dateRange }} />
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
dateRangeForPhotos,
|
dateRangeForPhotos,
|
||||||
titleForPhoto,
|
titleForPhoto,
|
||||||
} from '.';
|
} from '.';
|
||||||
import ShareButton from '@/components/ShareButton';
|
import ShareButton from '@/share/ShareButton';
|
||||||
import AnimateItems from '@/components/AnimateItems';
|
import AnimateItems from '@/components/AnimateItems';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
|
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
|
||||||
@ -140,8 +140,15 @@ export default function PhotoHeader({
|
|||||||
{entityDescription}
|
{entityDescription}
|
||||||
{sharePath &&
|
{sharePath &&
|
||||||
<ShareButton
|
<ShareButton
|
||||||
|
photos={photos}
|
||||||
|
tag={tag}
|
||||||
|
camera={camera}
|
||||||
|
simulation={simulation}
|
||||||
|
focal={focal}
|
||||||
|
count={count}
|
||||||
|
dateRange={dateRange}
|
||||||
className="translate-y-[1.5px]"
|
className="translate-y-[1.5px]"
|
||||||
path={sharePath}
|
prefetch
|
||||||
dim
|
dim
|
||||||
/>}
|
/>}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -15,10 +15,9 @@ import Link from 'next/link';
|
|||||||
import {
|
import {
|
||||||
pathForFocalLength,
|
pathForFocalLength,
|
||||||
pathForPhoto,
|
pathForPhoto,
|
||||||
pathForPhotoShare,
|
|
||||||
} from '@/site/paths';
|
} from '@/site/paths';
|
||||||
import PhotoTags from '@/tag/PhotoTags';
|
import PhotoTags from '@/tag/PhotoTags';
|
||||||
import ShareButton from '@/components/ShareButton';
|
import ShareButton from '@/share/ShareButton';
|
||||||
import DownloadButton from '@/components/DownloadButton';
|
import DownloadButton from '@/components/DownloadButton';
|
||||||
import PhotoCamera from '../camera/PhotoCamera';
|
import PhotoCamera from '../camera/PhotoCamera';
|
||||||
import { cameraFromPhoto } from '@/camera';
|
import { cameraFromPhoto } from '@/camera';
|
||||||
@ -54,7 +53,6 @@ export default function PhotoLarge({
|
|||||||
shouldShareCamera,
|
shouldShareCamera,
|
||||||
shouldShareSimulation,
|
shouldShareSimulation,
|
||||||
shouldShareFocalLength,
|
shouldShareFocalLength,
|
||||||
shouldScrollOnShare,
|
|
||||||
includeFavoriteInAdminMenu,
|
includeFavoriteInAdminMenu,
|
||||||
onVisible,
|
onVisible,
|
||||||
}: {
|
}: {
|
||||||
@ -258,17 +256,14 @@ export default function PhotoLarge({
|
|||||||
)}>
|
)}>
|
||||||
{shouldShare &&
|
{shouldShare &&
|
||||||
<ShareButton
|
<ShareButton
|
||||||
path={pathForPhotoShare({
|
photo={photo}
|
||||||
photo,
|
tag={shouldShareTag ? primaryTag : undefined}
|
||||||
tag: shouldShareTag ? primaryTag : undefined,
|
camera={shouldShareCamera ? camera : undefined}
|
||||||
camera: shouldShareCamera ? camera : undefined,
|
// eslint-disable-next-line max-len
|
||||||
// eslint-disable-next-line max-len
|
simulation={shouldShareSimulation? photo.filmSimulation : undefined}
|
||||||
simulation: shouldShareSimulation ? photo.filmSimulation : undefined,
|
// eslint-disable-next-line max-len
|
||||||
// eslint-disable-next-line max-len
|
focal={shouldShareFocalLength ? photo.focalLength : undefined}
|
||||||
focal: shouldShareFocalLength ? photo.focalLength : undefined,
|
|
||||||
})}
|
|
||||||
prefetch={prefetchRelatedLinks}
|
prefetch={prefetchRelatedLinks}
|
||||||
shouldScroll={shouldScrollOnShare}
|
|
||||||
/>}
|
/>}
|
||||||
{ALLOW_PUBLIC_DOWNLOADS &&
|
{ALLOW_PUBLIC_DOWNLOADS &&
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import PhotoOGTile from '@/photo/PhotoOGTile';
|
import PhotoOGTile from '@/photo/PhotoOGTile';
|
||||||
import { absolutePathForPhoto, pathForPhoto } from '@/site/paths';
|
import { absolutePathForPhoto } from '@/site/paths';
|
||||||
import { Photo, PhotoSetCategory } from '.';
|
import { Photo, PhotoSetCategory } from '.';
|
||||||
import ShareModal from '@/components/ShareModal';
|
import ShareModal from '@/share/ShareModal';
|
||||||
|
|
||||||
export default function PhotoShareModal(props: {
|
export default function PhotoShareModal(props: {
|
||||||
photo: Photo
|
photo: Photo
|
||||||
@ -9,7 +9,6 @@ export default function PhotoShareModal(props: {
|
|||||||
return (
|
return (
|
||||||
<ShareModal
|
<ShareModal
|
||||||
pathShare={absolutePathForPhoto(props)}
|
pathShare={absolutePathForPhoto(props)}
|
||||||
pathClose={pathForPhoto(props)}
|
|
||||||
socialText="Check out this photo"
|
socialText="Check out this photo"
|
||||||
>
|
>
|
||||||
<PhotoOGTile photo={props.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 { PiXLogo } from 'react-icons/pi';
|
||||||
import { SHOW_SOCIAL } from '@/site/config';
|
import { SHOW_SOCIAL } from '@/site/config';
|
||||||
import { generateXPostText } from '@/utility/social';
|
import { generateXPostText } from '@/utility/social';
|
||||||
|
import { useAppState } from '@/state/AppState';
|
||||||
|
|
||||||
export default function ShareModal({
|
export default function ShareModal({
|
||||||
title,
|
title,
|
||||||
pathShare,
|
pathShare,
|
||||||
pathClose,
|
|
||||||
socialText,
|
socialText,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
title?: string
|
title?: string
|
||||||
pathShare: string
|
pathShare: string
|
||||||
pathClose: string
|
|
||||||
socialText: string
|
socialText: string
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}) {
|
}) {
|
||||||
|
const { setShareModalProps } = useAppState();
|
||||||
|
|
||||||
const renderIcon = (
|
const renderIcon = (
|
||||||
icon: JSX.Element,
|
icon: JSX.Element,
|
||||||
action: () => void,
|
action: () => void,
|
||||||
@ -44,7 +45,7 @@ export default function ShareModal({
|
|||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal onClosePath={pathClose}>
|
<Modal onClose={() => setShareModalProps?.(undefined)}>
|
||||||
<div className="space-y-3 md:space-y-4 w-full">
|
<div className="space-y-3 md:space-y-4 w-full">
|
||||||
{title &&
|
{title &&
|
||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
@ -1,6 +1,37 @@
|
|||||||
import { Photo, PhotoSetAttributes, PhotoSetCategory } from '@/photo';
|
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'> & {
|
export type ShareModalProps = Omit<PhotoSetAttributes, 'photos'> & {
|
||||||
photo?: Photo
|
photo?: Photo
|
||||||
photos?: Photo[]
|
photos?: Photo[]
|
||||||
} & PhotoSetCategory;
|
} & 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 {
|
import { absolutePathForFilmSimulation } from '@/site/paths';
|
||||||
absolutePathForFilmSimulation,
|
|
||||||
pathForFilmSimulation,
|
|
||||||
} from '@/site/paths';
|
|
||||||
import { PhotoSetAttributes } from '../photo';
|
import { PhotoSetAttributes } from '../photo';
|
||||||
import ShareModal from '@/components/ShareModal';
|
import ShareModal from '@/share/ShareModal';
|
||||||
import FilmSimulationOGTile from './FilmSimulationOGTile';
|
import FilmSimulationOGTile from './FilmSimulationOGTile';
|
||||||
import { FilmSimulation, shareTextForFilmSimulation } from '.';
|
import { FilmSimulation, shareTextForFilmSimulation } from '.';
|
||||||
|
|
||||||
@ -18,7 +15,6 @@ export default function FilmSimulationShareModal({
|
|||||||
return (
|
return (
|
||||||
<ShareModal
|
<ShareModal
|
||||||
pathShare={absolutePathForFilmSimulation(simulation)}
|
pathShare={absolutePathForFilmSimulation(simulation)}
|
||||||
pathClose={pathForFilmSimulation(simulation)}
|
|
||||||
socialText={shareTextForFilmSimulation(simulation)}
|
socialText={shareTextForFilmSimulation(simulation)}
|
||||||
>
|
>
|
||||||
<FilmSimulationOGTile {...{ simulation, photos, count, dateRange }} />
|
<FilmSimulationOGTile {...{ simulation, photos, count, dateRange }} />
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { AnimationConfig } from '@/components/AnimateItems';
|
|||||||
import { ShareModalProps } from '@/share';
|
import { ShareModalProps } from '@/share';
|
||||||
|
|
||||||
export interface AppStateContext {
|
export interface AppStateContext {
|
||||||
// GLOBAL
|
// CORE
|
||||||
previousPathname?: string
|
previousPathname?: string
|
||||||
hasLoaded?: boolean
|
hasLoaded?: boolean
|
||||||
setHasLoaded?: Dispatch<SetStateAction<boolean>>
|
setHasLoaded?: Dispatch<SetStateAction<boolean>>
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { getAuthAction } from '@/auth/actions';
|
|||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { HIGH_DENSITY_GRID, MATTE_PHOTOS } from '@/site/config';
|
import { HIGH_DENSITY_GRID, MATTE_PHOTOS } from '@/site/config';
|
||||||
import { getPhotosHiddenMetaCachedAction } from '@/photo/actions';
|
import { getPhotosHiddenMetaCachedAction } from '@/photo/actions';
|
||||||
|
import { ShareModalProps } from '@/share';
|
||||||
|
|
||||||
export default function AppStateProvider({
|
export default function AppStateProvider({
|
||||||
children,
|
children,
|
||||||
@ -25,8 +26,11 @@ export default function AppStateProvider({
|
|||||||
useState<AnimationConfig>();
|
useState<AnimationConfig>();
|
||||||
const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] =
|
const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] =
|
||||||
useState(true);
|
useState(true);
|
||||||
|
// MODAL
|
||||||
const [isCommandKOpen, setIsCommandKOpen] =
|
const [isCommandKOpen, setIsCommandKOpen] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
const [shareModalProps, setShareModalProps] =
|
||||||
|
useState<ShareModalProps>();
|
||||||
// ADMIN
|
// ADMIN
|
||||||
const [userEmail, setUserEmail] =
|
const [userEmail, setUserEmail] =
|
||||||
useState<string>();
|
useState<string>();
|
||||||
@ -89,8 +93,11 @@ export default function AppStateProvider({
|
|||||||
clearNextPhotoAnimation: () => setNextPhotoAnimation?.(undefined),
|
clearNextPhotoAnimation: () => setNextPhotoAnimation?.(undefined),
|
||||||
shouldRespondToKeyboardCommands,
|
shouldRespondToKeyboardCommands,
|
||||||
setShouldRespondToKeyboardCommands,
|
setShouldRespondToKeyboardCommands,
|
||||||
|
// MODAL
|
||||||
isCommandKOpen,
|
isCommandKOpen,
|
||||||
setIsCommandKOpen,
|
setIsCommandKOpen,
|
||||||
|
shareModalProps,
|
||||||
|
setShareModalProps,
|
||||||
// ADMIN
|
// ADMIN
|
||||||
userEmail,
|
userEmail,
|
||||||
setUserEmail,
|
setUserEmail,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { absolutePathForTag, pathForTag } from '@/site/paths';
|
import { absolutePathForTag } from '@/site/paths';
|
||||||
import { PhotoSetAttributes } from '../photo';
|
import { PhotoSetAttributes } from '../photo';
|
||||||
import ShareModal from '@/components/ShareModal';
|
import ShareModal from '@/share/ShareModal';
|
||||||
import TagOGTile from './TagOGTile';
|
import TagOGTile from './TagOGTile';
|
||||||
import { shareTextForTag } from '.';
|
import { shareTextForTag } from '.';
|
||||||
|
|
||||||
@ -15,7 +15,6 @@ export default function TagShareModal({
|
|||||||
return (
|
return (
|
||||||
<ShareModal
|
<ShareModal
|
||||||
pathShare={absolutePathForTag(tag)}
|
pathShare={absolutePathForTag(tag)}
|
||||||
pathClose={pathForTag(tag)}
|
|
||||||
socialText={shareTextForTag(tag)}
|
socialText={shareTextForTag(tag)}
|
||||||
>
|
>
|
||||||
<TagOGTile {...{ tag, photos, count, dateRange }} />
|
<TagOGTile {...{ tag, photos, count, dateRange }} />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user