Integrate native share sheets

This commit is contained in:
Sam Becker 2025-04-09 21:10:56 -05:00
parent 8997d259f0
commit ad1bb5e95c
10 changed files with 34 additions and 12 deletions

View File

@ -2,7 +2,7 @@ import { absolutePathForCamera } from '@/app/paths';
import { PhotoSetAttributes } from '../category'; import { PhotoSetAttributes } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
import CameraOGTile from './CameraOGTile'; import CameraOGTile from './CameraOGTile';
import { Camera } from '.'; import { Camera, formatCameraText } from '.';
import { shareTextForCamera } from './meta'; import { shareTextForCamera } from './meta';
export default function CameraShareModal({ export default function CameraShareModal({
@ -16,6 +16,7 @@ export default function CameraShareModal({
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForCamera(camera)} pathShare={absolutePathForCamera(camera)}
navigatorTitle={formatCameraText(camera)}
socialText={shareTextForCamera(camera, photos)} socialText={shareTextForCamera(camera, photos)}
> >
<CameraOGTile {...{ camera, photos, count, dateRange }} /> <CameraOGTile {...{ camera, photos, count, dateRange }} />

View File

@ -2,7 +2,7 @@ import { absolutePathForFilm } from '@/app/paths';
import { PhotoSetAttributes } from '../category'; import { PhotoSetAttributes } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
import FilmOGTile from './FilmOGTile'; import FilmOGTile from './FilmOGTile';
import { shareTextForFilm } from '.'; import { labelForFilm, shareTextForFilm } from '.';
export default function FilmShareModal({ export default function FilmShareModal({
film, film,
@ -15,6 +15,7 @@ export default function FilmShareModal({
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForFilm(film)} pathShare={absolutePathForFilm(film)}
navigatorTitle={labelForFilm(film).large}
socialText={shareTextForFilm(film)} socialText={shareTextForFilm(film)}
> >
<FilmOGTile {...{ film, photos, count, dateRange }} /> <FilmOGTile {...{ film, photos, count, dateRange }} />

View File

@ -2,7 +2,7 @@ import { absolutePathForFocalLength } from '@/app/paths';
import { PhotoSetAttributes } from '../category'; import { PhotoSetAttributes } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
import FocalLengthOGTile from './FocalLengthOGTile'; import FocalLengthOGTile from './FocalLengthOGTile';
import { shareTextFocalLength } from '.'; import { formatFocalLengthSafe, shareTextFocalLength } from '.';
export default function FocalLengthShareModal({ export default function FocalLengthShareModal({
focal, focal,
@ -15,6 +15,7 @@ export default function FocalLengthShareModal({
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForFocalLength(focal)} pathShare={absolutePathForFocalLength(focal)}
navigatorTitle={formatFocalLengthSafe(focal)}
socialText={shareTextFocalLength(focal)} socialText={shareTextFocalLength(focal)}
> >
<FocalLengthOGTile {...{ focal, photos, count, dateRange }} /> <FocalLengthOGTile {...{ focal, photos, count, dateRange }} />

View File

@ -19,10 +19,13 @@ export const getFocalLengthFromString = (focalString?: string) => {
return focal ? parseInt(focal, 10) : 0; return focal ? parseInt(focal, 10) : 0;
}; };
export const formatFocalLength = (focal?: number) => focal ? export const formatFocalLength = (focal?: number) => focal
`${focal}mm` ? formatFocalLengthSafe(focal)
: undefined; : undefined;
export const formatFocalLengthSafe = (focal = 0) =>
`${focal}mm`;
export const titleForFocalLength = ( export const titleForFocalLength = (
focal: number, focal: number,
photos: Photo[], photos: Photo[],

View File

@ -1,7 +1,7 @@
import { absolutePathForLens } from '@/app/paths'; import { absolutePathForLens } from '@/app/paths';
import { PhotoSetAttributes } from '../category'; import { PhotoSetAttributes } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
import { Lens } from '.'; import { formatLensText, Lens } from '.';
import { shareTextForLens } from './meta'; import { shareTextForLens } from './meta';
import LensOGTile from './LensOGTile'; import LensOGTile from './LensOGTile';
@ -16,6 +16,7 @@ export default function LensShareModal({
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForLens(lens)} pathShare={absolutePathForLens(lens)}
navigatorTitle={formatLensText(lens)}
socialText={shareTextForLens(lens, photos)} socialText={shareTextForLens(lens, photos)}
> >
<LensOGTile {...{ lens, photos, count, dateRange }} /> <LensOGTile {...{ lens, photos, count, dateRange }} />

View File

@ -1,6 +1,6 @@
import PhotoOGTile from '@/photo/PhotoOGTile'; import PhotoOGTile from '@/photo/PhotoOGTile';
import { absolutePathForPhoto } from '@/app/paths'; import { absolutePathForPhoto } from '@/app/paths';
import { Photo } from '.'; import { Photo, titleForPhoto } from '.';
import { PhotoSetCategory } from '../category'; import { PhotoSetCategory } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
@ -10,6 +10,7 @@ export default function PhotoShareModal(
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForPhoto(props)} pathShare={absolutePathForPhoto(props)}
navigatorTitle={titleForPhoto(props.photo)}
socialText="Check out this photo" socialText="Check out this photo"
> >
<PhotoOGTile {...props} /> <PhotoOGTile {...props} />

View File

@ -30,7 +30,7 @@ export default function PhotoRecipeOverlayButton({
'rounded-md shadow-none', 'rounded-md shadow-none',
'border-[1.5px] border-medium', 'border-[1.5px] border-medium',
'p-0 inline-flex items-center justify-center', 'p-0 inline-flex items-center justify-center',
'size-[17px] md:size-5', 'size-[17px] sm:size-5',
'hover:bg-extra-dim active:bg-dim', 'hover:bg-extra-dim active:bg-dim',
className, className,
)}> )}>

View File

@ -1,7 +1,7 @@
import { absolutePathForRecipe } from '@/app/paths'; import { absolutePathForRecipe } from '@/app/paths';
import { PhotoSetAttributes } from '../category'; import { PhotoSetAttributes } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
import { shareTextForRecipe } from '.'; import { formatRecipe, shareTextForRecipe } from '.';
import RecipeOGTile from './RecipeOGTile'; import RecipeOGTile from './RecipeOGTile';
export default function RecipeShareModal({ export default function RecipeShareModal({
@ -15,6 +15,7 @@ export default function RecipeShareModal({
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForRecipe(recipe)} pathShare={absolutePathForRecipe(recipe)}
navigatorTitle={formatRecipe(recipe)}
socialText={shareTextForRecipe(recipe)} socialText={shareTextForRecipe(recipe)}
> >
<RecipeOGTile {...{ recipe, photos, count, dateRange }} /> <RecipeOGTile {...{ recipe, photos, count, dateRange }} />

View File

@ -12,16 +12,19 @@ import { SHOW_SOCIAL } from '@/app/config';
import { generateXPostText } from '@/utility/social'; import { generateXPostText } from '@/utility/social';
import { useAppState } from '@/state/AppState'; import { useAppState } from '@/state/AppState';
import useOnPathChange from '@/utility/useOnPathChange'; import useOnPathChange from '@/utility/useOnPathChange';
import { IoArrowUp } from 'react-icons/io5';
export default function ShareModal({ export default function ShareModal({
title, title,
pathShare, pathShare,
socialText, socialText,
navigatorTitle,
children, children,
}: { }: {
title?: string title?: string
pathShare: string pathShare: string
socialText: string socialText: string
navigatorTitle: string
children: ReactNode children: ReactNode
}) { }) {
const { const {
@ -41,7 +44,7 @@ export default function ShareModal({
) => ) =>
<div <div
className={clsx( className={clsx(
'py-3 px-3.5', 'py-3 px-3',
embedded ? 'border-l' : 'border rounded-md', embedded ? 'border-l' : 'border rounded-md',
'border-gray-200 bg-gray-50 active:bg-gray-100', 'border-gray-200 bg-gray-50 active:bg-gray-100',
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
@ -76,7 +79,7 @@ export default function ShareModal({
'flex items-center justify-stretch', 'flex items-center justify-stretch',
'border border-gray-200 dark:border-gray-800', 'border border-gray-200 dark:border-gray-800',
)}> )}>
<div className="truncate p-2 w-full"> <div className="truncate p-2 w-full [direction:rtl] text-left">
{shortenUrl(pathShare)} {shortenUrl(pathShare)}
</div> </div>
{renderIcon( {renderIcon(
@ -88,6 +91,15 @@ export default function ShareModal({
true, true,
)} )}
</div> </div>
{typeof navigator !== 'undefined' && navigator.share &&
renderIcon(
<IoArrowUp size={18} />,
() => navigator.share({
title: navigatorTitle,
url: pathShare,
})
.catch(() => console.log('Share canceled')),
)}
{SHOW_SOCIAL && {SHOW_SOCIAL &&
renderIcon( renderIcon(
<PiXLogo size={18} />, <PiXLogo size={18} />,

View File

@ -2,7 +2,7 @@ import { absolutePathForTag } from '@/app/paths';
import { PhotoSetAttributes } from '../category'; import { PhotoSetAttributes } from '../category';
import ShareModal from '@/share/ShareModal'; import ShareModal from '@/share/ShareModal';
import TagOGTile from './TagOGTile'; import TagOGTile from './TagOGTile';
import { shareTextForTag } from '.'; import { formatTag, shareTextForTag } from '.';
export default function TagShareModal({ export default function TagShareModal({
tag, tag,
@ -15,6 +15,7 @@ export default function TagShareModal({
return ( return (
<ShareModal <ShareModal
pathShare={absolutePathForTag(tag)} pathShare={absolutePathForTag(tag)}
navigatorTitle={formatTag(tag)}
socialText={shareTextForTag(tag)} socialText={shareTextForTag(tag)}
> >
<TagOGTile {...{ tag, photos, count, dateRange }} /> <TagOGTile {...{ tag, photos, count, dateRange }} />