Show raw lens content next to photos

This commit is contained in:
Sam Becker 2025-03-15 14:05:12 -05:00
parent bac0c51f75
commit bfe00c9565
7 changed files with 89 additions and 11 deletions

View File

@ -5,6 +5,7 @@ import { Camera } from '@/camera';
import { FilmSimulation } from '@/simulation';
import { parameterize } from '@/utility/string';
import { TAG_HIDDEN } from '@/tag';
import { Lens } from '@/lens';
// Core paths
export const PATH_ROOT = '/';
@ -23,9 +24,10 @@ export const PATH_FEED_INFERRED = GRID_HOMEPAGE_ENABLED ? PATH_FEED : PATH
export const PREFIX_PHOTO = '/p';
export const PREFIX_TAG = '/tag';
export const PREFIX_CAMERA = '/shot-on';
export const PREFIX_LENS = '/lens';
export const PREFIX_RECIPE = '/recipe';
export const PREFIX_FILM_SIMULATION = '/film';
export const PREFIX_FOCAL_LENGTH = '/focal';
export const PREFIX_RECIPE = '/recipe';
// Dynamic paths
const PATH_PHOTO_DYNAMIC = `${PREFIX_PHOTO}/[photoId]`;
@ -113,6 +115,7 @@ export const pathForPhoto = ({
photo,
tag,
camera,
lens,
simulation,
focal,
recipe,
@ -123,13 +126,15 @@ export const pathForPhoto = ({
? `${pathForTag(tag)}/${getPhotoId(photo)}`
: camera
? `${pathForCamera(camera)}/${getPhotoId(photo)}`
: simulation
? `${pathForFilmSimulation(simulation)}/${getPhotoId(photo)}`
: recipe
? `${pathForRecipe(recipe)}/${getPhotoId(photo)}`
: focal
? `${pathForFocalLength(focal)}/${getPhotoId(photo)}`
: `${PREFIX_PHOTO}/${getPhotoId(photo)}`;
: lens
? `${pathForLens(lens)}/${getPhotoId(photo)}`
: simulation
? `${pathForFilmSimulation(simulation)}/${getPhotoId(photo)}`
: recipe
? `${pathForRecipe(recipe)}/${getPhotoId(photo)}`
: focal
? `${pathForFocalLength(focal)}/${getPhotoId(photo)}`
: `${PREFIX_PHOTO}/${getPhotoId(photo)}`;
export const pathForTag = (tag: string) =>
`${PREFIX_TAG}/${tag}`;
@ -140,6 +145,9 @@ export const pathForCamera = ({ make, model }: Camera) =>
export const pathForFilmSimulation = (simulation: FilmSimulation) =>
`${PREFIX_FILM_SIMULATION}/${simulation}`;
export const pathForLens = ({ make, model }: Lens) =>
`${PREFIX_LENS}/${parameterize(make, true)}/${parameterize(model, true)}`;
export const pathForFocalLength = (focal: number) =>
`${PREFIX_FOCAL_LENGTH}/${focal}mm`;

View File

@ -3,6 +3,8 @@ import { parameterize } from '@/utility/string';
const CAMERA_PLACEHOLDER: Camera = { make: 'Camera', model: 'Model' };
const CAMERA_MAKE_APPLE = 'apple';
export type Camera = {
make: string
model: string
@ -57,7 +59,7 @@ export const cameraFromPhoto = (
: fallback ?? CAMERA_PLACEHOLDER;
const isCameraMakeApple = (make?: string) =>
make?.toLocaleLowerCase() === 'apple';
make?.toLocaleLowerCase() === CAMERA_MAKE_APPLE;
export const isCameraApple = ({ make }: Camera) =>
isCameraMakeApple(make);

34
src/lens/PhotoLens.tsx Normal file
View File

@ -0,0 +1,34 @@
import { pathForLens } from '@/app/paths';
import { Lens, formatLensText } from '.';
import EntityLink, {
EntityLinkExternalProps,
} from '@/components/primitives/EntityLink';
import { TbCone } from 'react-icons/tb';
export default function PhotoLens({
lens,
type,
badged,
contrast,
prefetch,
countOnHover,
className,
}: {
lens: Lens
hideAppleIcon?: boolean
countOnHover?: number
} & EntityLinkExternalProps) {
return (
<EntityLink
label={formatLensText(lens)}
href={pathForLens(lens)}
icon={<TbCone className="rotate-[270deg] translate-x-[-1px]" />}
type={type}
className={className}
badged={badged}
contrast={contrast}
prefetch={prefetch}
hoverEntity={countOnHover}
/>
);
}

View File

@ -3,6 +3,8 @@ import { parameterize } from '@/utility/string';
const LENS_PLACEHOLDER: Lens = { make: 'Lens', model: 'Model' };
const LENS_MAKE_APPLE = 'apple';
export type Lens = {
make: string
model: string
@ -45,3 +47,12 @@ export const lensFromPhoto = (
photo?.lensMake && photo?.lensModel
? { make: photo.lensMake, model: photo.lensModel }
: fallback ?? LENS_PLACEHOLDER;
const isLensMakeApple = (make?: string) =>
make?.toLocaleLowerCase() === LENS_MAKE_APPLE;
export const isLensApple = ({ make }: Lens) =>
isLensMakeApple(make);
export const formatLensText = ({ make, model }: Lens, short = true) =>
short ? model : `${make} ${model}`;

View File

@ -6,6 +6,7 @@ import {
doesPhotoNeedBlurCompatibility,
shouldShowCameraDataForPhoto,
shouldShowExifDataForPhoto,
shouldShowLensDataForPhoto,
titleForPhoto,
} from '.';
import SiteGrid from '@/components/SiteGrid';
@ -45,6 +46,8 @@ import { AnimatePresence } from 'framer-motion';
import useRecipeOverlay from '../recipe/useRecipeOverlay';
import PhotoRecipeOverlay from '@/recipe/PhotoRecipeOverlay';
import PhotoRecipe from '@/recipe/PhotoRecipe';
import PhotoLens from '@/lens/PhotoLens';
import { lensFromPhoto } from '@/lens';
export default function PhotoLarge({
photo,
@ -57,6 +60,7 @@ export default function PhotoLarge({
showTitle = true,
showTitleAsH1,
showCamera = true,
showLens = true,
showSimulation = true,
showRecipe = true,
showZoomControls: showZoomControlsProp = true,
@ -80,6 +84,7 @@ export default function PhotoLarge({
showTitle?: boolean
showTitleAsH1?: boolean
showCamera?: boolean
showLens?: boolean
showSimulation?: boolean
showRecipe?: boolean
showZoomControls?: boolean
@ -121,10 +126,11 @@ export default function PhotoLarge({
const tags = sortTags(photo.tags, primaryTag);
const camera = cameraFromPhoto(photo);
const lens = lensFromPhoto(photo);
const { recipeTitle: recipe } = photo;
const showCameraContent = showCamera && shouldShowCameraDataForPhoto(photo);
const showLensContent = showLens && shouldShowLensDataForPhoto(photo);
const showRecipeContent = showRecipe && recipe;
const showTagsContent = tags.length > 0;
const showExifContent = shouldShowExifDataForPhoto(photo);
@ -284,6 +290,15 @@ export default function PhotoLarge({
contrast="medium"
prefetch={prefetchRelatedLinks}
/>}
{showLensContent &&
<>
<br />
<PhotoLens
lens={lens}
contrast="medium"
prefetch={prefetchRelatedLinks}
/>
</>}
{showRecipeContent &&
<PhotoRecipe
recipe={recipe}

View File

@ -298,6 +298,10 @@ const photoHasCameraData = (photo: Photo) =>
Boolean(photo.make) &&
Boolean(photo.model);
const photoHasLensData = (photo: Photo) =>
Boolean(photo.lensMake) &&
Boolean(photo.lensModel);
const photoHasExifData = (photo: Photo) =>
Boolean(photo.focalLength) ||
Boolean(photo.focalLengthIn35MmFormat) ||
@ -309,6 +313,9 @@ const photoHasExifData = (photo: Photo) =>
export const shouldShowCameraDataForPhoto = (photo: Photo) =>
SHOW_EXIF_DATA && photoHasCameraData(photo);
export const shouldShowLensDataForPhoto = (photo: Photo) =>
SHOW_EXIF_DATA && photoHasLensData(photo);
export const shouldShowExifDataForPhoto = (photo: Photo) =>
SHOW_EXIF_DATA && photoHasExifData(photo);

View File

@ -10,10 +10,10 @@ import { Recipes } from '@/recipe';
const CATEGORY_KEYS = [
'tags',
'cameras',
'lenses',
'recipes',
'films',
'focal-lengths',
'lenses',
] as const;
type CategoryKey = (typeof CATEGORY_KEYS)[number];
@ -23,6 +23,7 @@ type CategoryKeys = CategoryKey[];
export const DEFAULT_CATEGORY_KEYS: CategoryKeys = [
'tags',
'cameras',
'lenses',
'recipes',
'films',
];