diff --git a/src/app/(auth-state)/admin/photos/page.tsx b/src/app/(auth-state)/admin/photos/page.tsx index 02a54941..43409cb1 100644 --- a/src/app/(auth-state)/admin/photos/page.tsx +++ b/src/app/(auth-state)/admin/photos/page.tsx @@ -12,7 +12,7 @@ import { pathForAdminPhotoEdit, } from '@/site/paths'; import { titleForPhoto } from '@/photo'; -import MorePhotos from '@/components/MorePhotos'; +import MorePhotos from '@/photo/MorePhotos'; import { getBlobPhotoUrlsCached, getPhotosCached, diff --git a/src/app/(auth-state)/layout.tsx b/src/app/(auth-state)/layout.tsx index f98f925d..1093e968 100644 --- a/src/app/(auth-state)/layout.tsx +++ b/src/app/(auth-state)/layout.tsx @@ -1,4 +1,4 @@ -import FooterAuth from '@/components/FooterAuth'; +import FooterAuth from '@/site/FooterAuth'; import PageContentContainer from '@/components/PageContentContainer'; import { SessionProvider } from 'next-auth/react'; diff --git a/src/app/(static)/film/page.tsx b/src/app/(static)/film/page.tsx new file mode 100644 index 00000000..c9ca28cc --- /dev/null +++ b/src/app/(static)/film/page.tsx @@ -0,0 +1,14 @@ +import { FILM_SIMULATION_FORM_INPUT_OPTIONS } from '@/vendors/fujifilm'; +import PhotoFujifilmSimulation from + '@/vendors/fujifilm/PhotoFujifilmSimulation'; + +export default function FilmPage() { + return ( +
+ {FILM_SIMULATION_FORM_INPUT_OPTIONS.map(({ value }) => +
+ +
)} +
+ ); +} diff --git a/src/app/(static)/layout.tsx b/src/app/(static)/layout.tsx index abfc0e8b..f4fa896f 100644 --- a/src/app/(static)/layout.tsx +++ b/src/app/(static)/layout.tsx @@ -1,4 +1,4 @@ -import FooterStatic from '@/components/FooterStatic'; +import FooterStatic from '@/site/FooterStatic'; import PageContentContainer from '@/components/PageContentContainer'; export default function RootLayout({ diff --git a/src/app/(static)/og/page.tsx b/src/app/(static)/og/page.tsx index 13ddc5bd..11ad9f75 100644 --- a/src/app/(static)/og/page.tsx +++ b/src/app/(static)/og/page.tsx @@ -1,5 +1,5 @@ import { getPhotosCached, getPhotosCountCached } from '@/cache'; -import MorePhotos from '@/components/MorePhotos'; +import MorePhotos from '@/photo/MorePhotos'; import StaggeredOgPhotos from '@/photo/StaggeredOgPhotos'; import { PaginationParams, diff --git a/src/app/(static)/page.tsx b/src/app/(static)/page.tsx index 6d3959ee..129c7799 100644 --- a/src/app/(static)/page.tsx +++ b/src/app/(static)/page.tsx @@ -1,6 +1,6 @@ import { getPhotosCached, getPhotosCountCached } from '@/cache'; import AnimateItems from '@/components/AnimateItems'; -import MorePhotos from '@/components/MorePhotos'; +import MorePhotos from '@/photo/MorePhotos'; import SiteGrid from '@/components/SiteGrid'; import { generateOgImageMetaForPhotos } from '@/photo'; import PhotoLarge from '@/photo/PhotoLarge'; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 197c834a..fdbbcd7c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,7 +5,7 @@ import { Metadata } from 'next'; import { BASE_URL, SITE_DESCRIPTION, SITE_TITLE } from '@/site/config'; import StateProvider from '@/state/AppStateProvider'; import ThemeProviderClient from '@/site/ThemeProviderClient'; -import Nav from '@/components/Nav'; +import Nav from '@/site/Nav'; import ToasterWithThemes from '@/components/ToasterWithThemes'; import PhotoEscapeHandler from '@/photo/PhotoEscapeHandler'; diff --git a/src/components/IconPathButton.tsx b/src/components/IconPathButton.tsx index 7c6d64f0..7f5b923e 100644 --- a/src/components/IconPathButton.tsx +++ b/src/components/IconPathButton.tsx @@ -60,8 +60,8 @@ export default function IconPathButton({ className={cc( 'translate-y-[-0.5px]', 'active:translate-y-[1px]', - 'text-gray-500 active:text-gray-600', - 'dark:text-gray-400 dark:active:text-gray-300', + 'text-medium', + 'active:text-gray-600 dark:active:text-gray-300', )} spinnerColor={spinnerColor ?? 'text'} /> diff --git a/src/components/InfoBlock.tsx b/src/components/InfoBlock.tsx index 8fc31593..982c0e78 100644 --- a/src/components/InfoBlock.tsx +++ b/src/components/InfoBlock.tsx @@ -30,7 +30,7 @@ export default function InfoBlock({
{children}
diff --git a/src/components/OGTile.tsx b/src/components/OGTile.tsx index 868a9b8e..da11f0a7 100644 --- a/src/components/OGTile.tsx +++ b/src/components/OGTile.tsx @@ -121,7 +121,7 @@ export default function OGTile({
{title}
-
+
{description}
diff --git a/src/components/RepoLink.tsx b/src/components/RepoLink.tsx index 6aa86c31..329c6908 100644 --- a/src/components/RepoLink.tsx +++ b/src/components/RepoLink.tsx @@ -17,7 +17,7 @@ export default function RepoLink() { 'hover:underline', )} > - + exif-photo-blog diff --git a/src/components/MorePhotos.tsx b/src/photo/MorePhotos.tsx similarity index 96% rename from src/components/MorePhotos.tsx rename to src/photo/MorePhotos.tsx index dadcd616..c7902d5d 100644 --- a/src/components/MorePhotos.tsx +++ b/src/photo/MorePhotos.tsx @@ -2,7 +2,7 @@ import { useRouter } from 'next/navigation'; import { useCallback, useEffect, useRef, useTransition } from 'react'; -import Spinner from './Spinner'; +import Spinner from '../components/Spinner'; export default function MorePhotos({ path, diff --git a/src/photo/PhotoGrid.tsx b/src/photo/PhotoGrid.tsx index bba6a5c6..4607ed48 100644 --- a/src/photo/PhotoGrid.tsx +++ b/src/photo/PhotoGrid.tsx @@ -3,7 +3,7 @@ import PhotoSmall from './PhotoSmall'; import { cc } from '@/utility/css'; import AnimateItems from '@/components/AnimateItems'; import { Camera } from '@/camera'; -import MorePhotos from '@/components/MorePhotos'; +import MorePhotos from '@/photo/MorePhotos'; export default function PhotoGrid({ photos, diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index e12c1a30..6babea86 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -75,22 +75,24 @@ export default function PhotoLarge({ } {showCamera && photoHasCameraData(photo) && -
+
-   - + {photo.filmSimulation && + <> +
+ + }
} )} {renderMiniGrid(<> {photoHasExifData(photo) && -
    +
    • {photo.focalLengthFormatted} {photo.focalLengthIn35MmFormatFormatted && @@ -118,8 +120,7 @@ export default function PhotoLarge({ )}>
      {photo.takenAtNaiveFormatted}
      diff --git a/src/photo/PhotosEmptyState.tsx b/src/photo/PhotosEmptyState.tsx index ac9fadd0..c17dd053 100644 --- a/src/photo/PhotosEmptyState.tsx +++ b/src/photo/PhotosEmptyState.tsx @@ -12,7 +12,7 @@ export default function PhotosEmptyState() { contentMain={
      `{variable}` @@ -261,7 +261,7 @@ export default function SiteChecklistClient({ Check
      } -
      +
      Changes to environment variables require a redeploy or reboot of local dev server
      diff --git a/src/photo/ViewSwitcher.tsx b/src/site/ViewSwitcher.tsx similarity index 91% rename from src/photo/ViewSwitcher.tsx rename to src/site/ViewSwitcher.tsx index 2f82744f..02a7969b 100644 --- a/src/photo/ViewSwitcher.tsx +++ b/src/site/ViewSwitcher.tsx @@ -1,7 +1,7 @@ import Switcher from '@/components/Switcher'; import SwitcherItem from '@/components/SwitcherItem'; -import IconFullFrame from '@/icons/IconFullFrame'; -import IconGrid from '@/icons/IconGrid'; +import IconFullFrame from '@/site/IconFullFrame'; +import IconGrid from '@/site/IconGrid'; import { PATH_GRID } from '@/site/paths'; import { BiLockAlt } from 'react-icons/bi'; diff --git a/src/site/globals.css b/src/site/globals.css index 5118a39d..71026ab4 100644 --- a/src/site/globals.css +++ b/src/site/globals.css @@ -14,7 +14,7 @@ label { @apply font-sans font-medium block uppercase text-xs - text-gray-500 dark:text-gray-400 + text-medium tracking-wider } button, .button, @@ -46,7 +46,7 @@ } input[type=file] { @apply - block font-mono w-full text-gray-500 dark:text-gray-400 + block font-mono w-full text-medium file:bg-white dark:file:bg-gray-950 file:mr-2 file:my-2 file:px-4 file:py-1.5 file:rounded-md file:border-solid file:border @@ -95,7 +95,7 @@ } button.primary.disabled, .button.primary.disabled { @apply - text-extra-dim + text-medium } /* Toasts */ .toaster [data-sonner-toast] { @@ -112,14 +112,14 @@ @apply text-gray-100 dark:text-gray-900 } + .text-medium { + @apply + text-gray-500 dark:text-gray-400 + } .text-dim { @apply text-gray-400 dark:text-gray-500 } - .text-extra-dim { - @apply - text-gray-500 dark:text-gray-400 - } .text-icon { @apply text-gray-800 dark:text-gray-200 diff --git a/src/vendors/fujifilm/PhotoFujifilmSimulation.tsx b/src/vendors/fujifilm/PhotoFujifilmSimulation.tsx index 7b20a7d8..4805e9b9 100644 --- a/src/vendors/fujifilm/PhotoFujifilmSimulation.tsx +++ b/src/vendors/fujifilm/PhotoFujifilmSimulation.tsx @@ -1,44 +1,30 @@ /* eslint-disable max-len */ -import { FujifilmSimulation, getLabelForFilmSimulation } from '@/vendors/fujifilm'; +import { cc } from '@/utility/css'; +import { + FujifilmSimulation, + getLabelForFilmSimulation, +} from '@/vendors/fujifilm'; +import PhotoFujifilmSimulationIcon from './PhotoFujifilmSimulationIcon'; -export default function PhotoFilmSimulation({ +export default function PhotoFujifilmSimulation({ simulation, }: { simulation: FujifilmSimulation; }) { - const contentForSimulation = () => { - switch (simulation) { - default: - return ( - <> - - - - - - - - - - - ); - } - }; - + const { small, medium, large } = getLabelForFilmSimulation(simulation); return ( - - {contentForSimulation()} - + + + + {small} + {medium} ); } diff --git a/src/vendors/fujifilm/PhotoFujifilmSimulationIcon.tsx b/src/vendors/fujifilm/PhotoFujifilmSimulationIcon.tsx new file mode 100644 index 00000000..ebb5977c --- /dev/null +++ b/src/vendors/fujifilm/PhotoFujifilmSimulationIcon.tsx @@ -0,0 +1,142 @@ +/* eslint-disable max-len */ +import { + FujifilmSimulation, + getLabelForFilmSimulation, +} from '@/vendors/fujifilm'; + +export default function PhotoFujifilmSimulationIcon({ + simulation, +}: { + simulation: FujifilmSimulation; +}) { + const contentForSimulation = (): JSX.Element => { + switch (simulation) { + case 'monochrome': return <> + + + ; + case 'monochrome-ye': return <> + + + + ; + case 'monochrome-r': return <> + + + + ; + case 'monochrome-g': return <> + + + + ; + case 'sepia': return <> + + + + ; + case 'acros': return <> + + + ; + case 'acros-ye': return <> + + + + ; + case 'acros-r': return <> + + + + ; + case 'acros-g': return <> + + + + ; + case 'provia': return <> + + + + ; + case 'portrait': return <> + + + ; + case 'portrait-saturation': return <> + + + + ; + case 'portrait-skin-tone': return <> + + + ; + case 'portrait-sharpness': return <> + + + + ; + case 'portrait-ex': return <> + + + + ; + case 'velvia': return <> + + + ; + case 'pro-neg-std': return <> + + + + ; + case 'pro-neg-hi': return <> + + + + ; + case 'classic-chrome': return <> + + + + ; + case 'eterna': return <> + + + ; + case 'classic-neg': return <> + + + + ; + case 'eterna-bleach-bypass': return <> + + + + ; + case 'nostalgic-neg': return <> + + + + ; + case 'reala': return <> + + + ; + } + }; + + return ( + + {contentForSimulation()} + + ); +} diff --git a/src/vendors/fujifilm/index.ts b/src/vendors/fujifilm/index.ts index 9656952d..edef8813 100644 --- a/src/vendors/fujifilm/index.ts +++ b/src/vendors/fujifilm/index.ts @@ -86,43 +86,149 @@ const getFujifilmMode = ( } }; -const FILM_SIMULATION_LABELS: Record = { - 'monochrome': 'Monochrome', - 'monochrome-ye': 'Monochrome + Yellow Filter', - 'monochrome-r': 'Monochrome + Red Filter', - 'monochrome-g': 'Monochrome + Green Filter', - 'sepia': 'Sepia', - 'acros': 'ACROS', - 'acros-ye': 'ACROS + Yellow Filter', - 'acros-r': 'ACROS + Red Filter', - 'acros-g': 'ACROS + Green Filter', - 'provia': 'PROVIA / Standard', - 'portrait': 'Studio Portrait', - 'portrait-saturation': 'Studio Portrait + Enhanced Saturation', - 'portrait-skin-tone': 'ASTIA / Soft', - 'portrait-sharpness': 'Studio Portrait + Enhanced Sharpness', - 'portrait-ex': 'Studio Portrait Ex', - 'velvia': 'Velvia / Vivid', - 'pro-neg-std': 'PRO Neg. Std', - 'pro-neg-hi': 'PRO Neg. Hi', - 'classic-chrome': 'Classic Chrome', - 'eterna': 'ETERNA / Cinema', - 'classic-neg': 'Classic Neg.', - 'eterna-bleach-bypass': 'ETERNA Bleach Bypass', - 'nostalgic-neg': 'Nostalgic Neg.', - 'reala': 'REALA ACE', +interface FujifilmSimulationLabel { + small: string + medium: string + large: string +} + +const FILM_SIMULATION_LABELS: Record< + FujifilmSimulation, + FujifilmSimulationLabel +> = { + 'monochrome': { + small: 'Monochrome', + medium: 'Monochrome', + large: 'Monochrome', + }, + 'monochrome-ye': { + small: 'Monochrome+Ye', + medium: 'Monochrome+Ye', + large: 'Monochrome + Yellow Filter', + }, + 'monochrome-r': { + small: 'Monochrome+R', + medium: 'Monochrome+R', + large: 'Monochrome + Red Filter', + }, + 'monochrome-g': { + small: 'Monochrome+G', + medium: 'Monochrome+G', + large: 'Monochrome + Green Filter', + }, + 'sepia': { + small: 'Sepia', + medium: 'Sepia', + large: 'Sepia', + }, + 'acros': { + small: 'ACROS', + medium: 'ACROS', + large: 'ACROS', + }, + 'acros-ye': { + small: 'ACROS+Ye', + medium: 'ACROS+Ye', + large: 'ACROS + Yellow Filter', + }, + 'acros-r': { + small: 'ACROS+R', + medium: 'ACROS+R', + large: 'ACROS + Red Filter', + }, + 'acros-g': { + small: 'ACROS+G', + medium: 'ACROS+G', + large: 'ACROS + Green Filter', + }, + 'provia': { + small: 'PROVIA', + medium: 'PROVIA/Std', + large: 'PROVIA / Standard', + }, + 'portrait': { + small: 'Portrait', + medium: 'Portrait', + large: 'Studio Portrait', + }, + 'portrait-saturation': { + small: 'Portrait+Sat.', + medium: 'Portrait+Sat.', + large: 'Studio Portrait + Enhanced Saturation', + }, + 'portrait-skin-tone': { + small: 'ASTIA', + medium: 'ASTIA/Soft', + large: 'ASTIA / Soft', + }, + 'portrait-sharpness': { + small: 'Portrait+Sharp.', + medium: 'Portrait+Sharp.', + large: 'Studio Portrait + Enhanced Sharpness', + }, + 'portrait-ex': { + small: 'Portrait+Ex', + medium: 'Portrait+Ex', + large: 'Studio Portrait + Ex', + }, + 'velvia': { + small: 'Velvia', + medium: 'Velvia/Vivid', + large: 'Velvia / Vivid', + }, + 'pro-neg-std': { + small: 'PRO Neg. Std', + medium: 'PRO Neg. Std', + large: 'PRO Neg. Std', + }, + 'pro-neg-hi': { + small: 'PRO Neg. Hi', + medium: 'PRO Neg. Hi', + large: 'PRO Neg. Hi', + }, + 'classic-chrome': { + small: 'Classic Chrome', + medium: 'Classic Chrome', + large: 'Classic Chrome', + }, + 'eterna': { + small: 'ETERNA', + medium: 'ETERNA/Cinema', + large: 'ETERNA / Cinema', + }, + 'classic-neg': { + small: 'Classic Neg.', + medium: 'Classic Neg.', + large: 'Classic Neg.', + }, + 'eterna-bleach-bypass': { + small: 'ETERNA Bypass', + medium: 'ETERNA Bypass', + large: 'ETERNA Bleach Bypass', + }, + 'nostalgic-neg': { + small: 'Nostalgic Neg.', + medium: 'Nostalgic Neg.', + large: 'Nostalgic Neg.', + }, + 'reala': { + small: 'REALA', + medium: 'REALA ACE', + large: 'REALA ACE', + }, }; export const FILM_SIMULATION_FORM_INPUT_OPTIONS = Object .entries(FILM_SIMULATION_LABELS) .map(([value, label]) => ( - { value, label } as { value: FujifilmSimulation, label: string } + { value, label: label.large } as + { value: FujifilmSimulation, label: string } )) .sort((a, b) => a.label.localeCompare(b.label)); export const getLabelForFilmSimulation = ( simulation: FujifilmSimulation -): string => +) => FILM_SIMULATION_LABELS[simulation]; const parseFujifilmMakerNote = (