Refactor link prefetching

This commit is contained in:
Sam Becker 2024-04-18 19:13:10 -05:00
parent 52de4718cb
commit f49e0678c9
7 changed files with 82 additions and 67 deletions

View File

@ -11,7 +11,7 @@
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "3.556.0", "@aws-sdk/client-s3": "3.556.0",
"@aws-sdk/s3-request-presigner": "3.556.0", "@aws-sdk/s3-request-presigner": "3.556.0",
"@next/bundle-analyzer": "14.2.1", "@next/bundle-analyzer": "14.2.2",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
@ -25,9 +25,9 @@
"@typescript-eslint/parser": "^7.7.0", "@typescript-eslint/parser": "^7.7.0",
"@upstash/ratelimit": "^1.1.1", "@upstash/ratelimit": "^1.1.1",
"@vercel/analytics": "^1.2.2", "@vercel/analytics": "^1.2.2",
"@vercel/blob": "^0.23.0", "@vercel/blob": "^0.23.2",
"@vercel/kv": "^1.0.1", "@vercel/kv": "^1.0.1",
"@vercel/postgres": "0.8.0", "@vercel/postgres": "^0.8.0",
"@vercel/speed-insights": "^1.0.10", "@vercel/speed-insights": "^1.0.10",
"ai": "^3.0.23", "ai": "^3.0.23",
"autoprefixer": "10.4.19", "autoprefixer": "10.4.19",
@ -36,16 +36,16 @@
"cmdk": "^1.0.0", "cmdk": "^1.0.0",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-next": "14.2.1", "eslint-config-next": "14.2.2",
"exifr": "^7.1.3", "exifr": "^7.1.3",
"framer-motion": "^11.1.3", "framer-motion": "^11.1.5",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0", "jest-environment-jsdom": "^29.7.0",
"nanoid": "^5.0.7", "nanoid": "^5.0.7",
"next": "14.3.0-canary.8", "next": "14.3.0-canary.8",
"next-auth": "5.0.0-beta.15", "next-auth": "5.0.0-beta.15",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"openai": "^4.37.1", "openai": "^4.38.0",
"postcss": "8.4.38", "postcss": "8.4.38",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",

68
pnpm-lock.yaml generated
View File

@ -15,8 +15,8 @@ importers:
specifier: 3.556.0 specifier: 3.556.0
version: 3.556.0 version: 3.556.0
'@next/bundle-analyzer': '@next/bundle-analyzer':
specifier: 14.2.1 specifier: 14.2.2
version: 14.2.1(bufferutil@4.0.8)(utf-8-validate@6.0.3) version: 14.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)
'@radix-ui/react-dropdown-menu': '@radix-ui/react-dropdown-menu':
specifier: ^2.0.6 specifier: ^2.0.6
version: 2.0.6(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 2.0.6(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@ -57,13 +57,13 @@ importers:
specifier: ^1.2.2 specifier: ^1.2.2
version: 1.2.2(next@14.3.0-canary.8(@babel/core@7.23.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0) version: 1.2.2(next@14.3.0-canary.8(@babel/core@7.23.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)
'@vercel/blob': '@vercel/blob':
specifier: ^0.23.0 specifier: ^0.23.2
version: 0.23.0 version: 0.23.2
'@vercel/kv': '@vercel/kv':
specifier: ^1.0.1 specifier: ^1.0.1
version: 1.0.1 version: 1.0.1
'@vercel/postgres': '@vercel/postgres':
specifier: 0.8.0 specifier: ^0.8.0
version: 0.8.0 version: 0.8.0
'@vercel/speed-insights': '@vercel/speed-insights':
specifier: ^1.0.10 specifier: ^1.0.10
@ -90,14 +90,14 @@ importers:
specifier: 8.57.0 specifier: 8.57.0
version: 8.57.0 version: 8.57.0
eslint-config-next: eslint-config-next:
specifier: 14.2.1 specifier: 14.2.2
version: 14.2.1(eslint@8.57.0)(typescript@5.4.5) version: 14.2.2(eslint@8.57.0)(typescript@5.4.5)
exifr: exifr:
specifier: ^7.1.3 specifier: ^7.1.3
version: 7.1.3 version: 7.1.3
framer-motion: framer-motion:
specifier: ^11.1.3 specifier: ^11.1.5
version: 11.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 11.1.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
jest: jest:
specifier: ^29.7.0 specifier: ^29.7.0
version: 29.7.0(@types/node@20.12.7) version: 29.7.0(@types/node@20.12.7)
@ -117,8 +117,8 @@ importers:
specifier: ^0.3.0 specifier: ^0.3.0
version: 0.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 0.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
openai: openai:
specifier: ^4.37.1 specifier: ^4.38.0
version: 4.37.1 version: 4.38.0
postcss: postcss:
specifier: 8.4.38 specifier: 8.4.38
version: 8.4.38 version: 8.4.38
@ -688,14 +688,14 @@ packages:
'@neondatabase/serverless@0.7.2': '@neondatabase/serverless@0.7.2':
resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==} resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==}
'@next/bundle-analyzer@14.2.1': '@next/bundle-analyzer@14.2.2':
resolution: {integrity: sha512-Qwy3Mu/dfnu4rs2xzCy7gKZlwzZzYtiq/rjPcK/7xq3BHSyLthkHf1NAF8NNfjVTouDwo2KchisHrmAamUNWWw==} resolution: {integrity: sha512-Zp2xG3VTPHUquOcBaRtrr0/n7mqnjKUmprGcJXPEKGgP5rAsLymIfWKm3jIVWIw5Eb4fNOfX4v+L+qiSvs+OJw==}
'@next/env@14.3.0-canary.8': '@next/env@14.3.0-canary.8':
resolution: {integrity: sha512-vkUEnZHkrSnJjC9t9U1aQf/SQ0wR0t1jjbLBgYWgJPesQLGnhogmMm2ScROdKTB6iVjz6IiLtjOdgWTKGIgkSg==} resolution: {integrity: sha512-vkUEnZHkrSnJjC9t9U1aQf/SQ0wR0t1jjbLBgYWgJPesQLGnhogmMm2ScROdKTB6iVjz6IiLtjOdgWTKGIgkSg==}
'@next/eslint-plugin-next@14.2.1': '@next/eslint-plugin-next@14.2.2':
resolution: {integrity: sha512-Fp+mthEBjkn8r9qd6o4JgxKp0IDEzW0VYHD8ZC05xS5/lFNwHKuOdr2kVhWG7BQCO9L6eeepshM1Wbs2T+LgSg==} resolution: {integrity: sha512-q+Ec2648JtBpKiu/FSJm8HAsFXlNvioHeBCbTP12T1SGcHYwhqHULSfQgFkPgHDu3kzNp2Kem4J54bK4rPQ5SQ==}
'@next/swc-darwin-arm64@14.3.0-canary.8': '@next/swc-darwin-arm64@14.3.0-canary.8':
resolution: {integrity: sha512-dnWrvcTS0sYJpOTU/p98x7M8lpRKiIF+gQ164yyKNVC57vDh0zbSIKweQjvlLCeFVGli0QjboDrUV/j3UMbqxg==} resolution: {integrity: sha512-dnWrvcTS0sYJpOTU/p98x7M8lpRKiIF+gQ164yyKNVC57vDh0zbSIKweQjvlLCeFVGli0QjboDrUV/j3UMbqxg==}
@ -1498,8 +1498,8 @@ packages:
react: react:
optional: true optional: true
'@vercel/blob@0.23.0': '@vercel/blob@0.23.2':
resolution: {integrity: sha512-FLXiy4SCXJ39gov5qnw7I5YPQq3NBUh5z+swcPw6lBdWN4YQoOho6cVMVncsu1Hc8kemth6ZaTZAnWrNRtbaZw==} resolution: {integrity: sha512-wejIdxb/CJkQpV18/TgGDuQFzZ2BCV+T2F786bmtt7LytmJmfhH8wHuJ70odOyvmiO3RIL57ht5GLZmeV8jqiA==}
engines: {node: '>=16.14'} engines: {node: '>=16.14'}
'@vercel/kv@1.0.1': '@vercel/kv@1.0.1':
@ -2150,8 +2150,8 @@ packages:
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
hasBin: true hasBin: true
eslint-config-next@14.2.1: eslint-config-next@14.2.2:
resolution: {integrity: sha512-BgD0kPCWMlqoItRf3xe9fG0MqwObKfVch+f2ccwDpZiCJA8ghkz2wrASH+bI6nLZzGcOJOpMm1v1Q1euhfpt4Q==} resolution: {integrity: sha512-12/uFc0KX+wUs7EDpOUGKMXBXZJiBVGdK5/m/QgXOCg2mQ0bQWoKSWNrCeOg7Vum6Kw1d1TW453W6xh+GbHquw==}
peerDependencies: peerDependencies:
eslint: ^7.23.0 || ^8.0.0 eslint: ^7.23.0 || ^8.0.0
typescript: '>=3.3.1' typescript: '>=3.3.1'
@ -2352,8 +2352,8 @@ packages:
fraction.js@4.3.7: fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
framer-motion@11.1.3: framer-motion@11.1.5:
resolution: {integrity: sha512-/t74b1WQu+mpZtra6xFSfsRfdTymJjNYgFudVIsUmoOWjznr3x5o9HbrX7Jt9655OCA2Js0W79bMZEKE7owp9w==} resolution: {integrity: sha512-ogK5fc0GBUT3AjzMXPx7f74m5V1ByRqkKQARBVHpdkYTNDxb/WriANYD+5JBo1wklQQJ1HayDZtmofQLqZFcbw==}
peerDependencies: peerDependencies:
'@emotion/is-prop-valid': '*' '@emotion/is-prop-valid': '*'
react: ^18.0.0 react: ^18.0.0
@ -3206,8 +3206,8 @@ packages:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'} engines: {node: '>=6'}
openai@4.37.1: openai@4.38.0:
resolution: {integrity: sha512-YVuhylpDeTNCWgsfhZe38+c4dDWZuW9VgzNY/sdYiNt6K9pvijroyYENp8YGEUHnuIAKtsLneZX9Qb/iB5XHkw==} resolution: {integrity: sha512-q1w04cRm+7CgUAGDXqt+OMa89zXBffHrEK0FcVDRhD+zL1S1aAatu4iYO5sIxR2QFEP//i8CM3QaxGVTNajxuw==}
hasBin: true hasBin: true
opener@1.5.2: opener@1.5.2:
@ -3279,8 +3279,8 @@ packages:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'} engines: {node: '>=4.0.0'}
pg-protocol@1.6.0: pg-protocol@1.6.1:
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==}
pg-types@2.2.0: pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
@ -5148,7 +5148,7 @@ snapshots:
dependencies: dependencies:
'@types/pg': 8.6.6 '@types/pg': 8.6.6
'@next/bundle-analyzer@14.2.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)': '@next/bundle-analyzer@14.2.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)':
dependencies: dependencies:
webpack-bundle-analyzer: 4.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.3) webpack-bundle-analyzer: 4.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)
transitivePeerDependencies: transitivePeerDependencies:
@ -5157,7 +5157,7 @@ snapshots:
'@next/env@14.3.0-canary.8': {} '@next/env@14.3.0-canary.8': {}
'@next/eslint-plugin-next@14.2.1': '@next/eslint-plugin-next@14.2.2':
dependencies: dependencies:
glob: 10.3.10 glob: 10.3.10
@ -5940,7 +5940,7 @@ snapshots:
'@types/pg@8.6.6': '@types/pg@8.6.6':
dependencies: dependencies:
'@types/node': 20.12.7 '@types/node': 20.12.7
pg-protocol: 1.6.0 pg-protocol: 1.6.1
pg-types: 2.2.0 pg-types: 2.2.0
'@types/prop-types@15.7.11': {} '@types/prop-types@15.7.11': {}
@ -6117,7 +6117,7 @@ snapshots:
next: 14.3.0-canary.8(@babel/core@7.23.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 14.3.0-canary.8(@babel/core@7.23.9)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0 react: 18.2.0
'@vercel/blob@0.23.0': '@vercel/blob@0.23.2':
dependencies: dependencies:
async-retry: 1.3.3 async-retry: 1.3.3
bytes: 3.1.2 bytes: 3.1.2
@ -6845,9 +6845,9 @@ snapshots:
optionalDependencies: optionalDependencies:
source-map: 0.6.1 source-map: 0.6.1
eslint-config-next@14.2.1(eslint@8.57.0)(typescript@5.4.5): eslint-config-next@14.2.2(eslint@8.57.0)(typescript@5.4.5):
dependencies: dependencies:
'@next/eslint-plugin-next': 14.2.1 '@next/eslint-plugin-next': 14.2.2
'@rushstack/eslint-patch': 1.7.2 '@rushstack/eslint-patch': 1.7.2
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
eslint: 8.57.0 eslint: 8.57.0
@ -7160,7 +7160,7 @@ snapshots:
fraction.js@4.3.7: {} fraction.js@4.3.7: {}
framer-motion@11.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): framer-motion@11.1.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
tslib: 2.6.2 tslib: 2.6.2
optionalDependencies: optionalDependencies:
@ -8166,7 +8166,7 @@ snapshots:
dependencies: dependencies:
mimic-fn: 2.1.0 mimic-fn: 2.1.0
openai@4.37.1: openai@4.38.0:
dependencies: dependencies:
'@types/node': 18.19.24 '@types/node': 18.19.24
'@types/node-fetch': 2.6.11 '@types/node-fetch': 2.6.11
@ -8246,7 +8246,7 @@ snapshots:
pg-int8@1.0.1: {} pg-int8@1.0.1: {}
pg-protocol@1.6.0: {} pg-protocol@1.6.1: {}
pg-types@2.2.0: pg-types@2.2.0:
dependencies: dependencies:

View File

@ -3,7 +3,6 @@ import {
altTextForPhoto, altTextForPhoto,
shouldShowCameraDataForPhoto, shouldShowCameraDataForPhoto,
shouldShowExifDataForPhoto, shouldShowExifDataForPhoto,
titleForPhoto,
} from '.'; } from '.';
import SiteGrid from '@/components/SiteGrid'; import SiteGrid from '@/components/SiteGrid';
import ImageLarge from '@/components/ImageLarge'; import ImageLarge from '@/components/ImageLarge';
@ -19,6 +18,7 @@ import { sortTags } from '@/tag';
import AdminPhotoMenu from '@/admin/AdminPhotoMenu'; import AdminPhotoMenu from '@/admin/AdminPhotoMenu';
import { Suspense } from 'react'; import { Suspense } from 'react';
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid'; import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
import PhotoLink from './PhotoLink';
export default function PhotoLarge({ export default function PhotoLarge({
photo, photo,
@ -81,14 +81,11 @@ export default function PhotoLarge({
{/* Meta */} {/* Meta */}
<div className="pr-2 md:pr-0"> <div className="pr-2 md:pr-0">
<div className="md:relative flex gap-2 items-start"> <div className="md:relative flex gap-2 items-start">
<div className="flex-grow"> <PhotoLink
<Link photo={photo}
href={pathForPhoto(photo)} className="font-bold uppercase flex-grow"
className="font-bold uppercase" prefetch={prefetch}
> />
{titleForPhoto(photo)}
</Link>
</div>
<Suspense> <Suspense>
<div className="absolute right-0 translate-y-[-4px] z-10"> <div className="absolute right-0 translate-y-[-4px] z-10">
<AdminPhotoMenu photo={photo} /> <AdminPhotoMenu photo={photo} />
@ -106,9 +103,14 @@ export default function PhotoLarge({
<PhotoCamera <PhotoCamera
camera={camera} camera={camera}
contrast="medium" contrast="medium"
prefetch={prefetchRelatedLinks}
/>} />}
{showTagsContent && {showTagsContent &&
<PhotoTags tags={tags} contrast="medium" />} <PhotoTags
tags={tags}
contrast="medium"
prefetch={prefetchRelatedLinks}
/>}
</div>} </div>}
</div> </div>
</div> </div>
@ -138,6 +140,7 @@ export default function PhotoLarge({
{showSimulation && photo.filmSimulation && {showSimulation && photo.filmSimulation &&
<PhotoFilmSimulation <PhotoFilmSimulation
simulation={photo.filmSimulation} simulation={photo.filmSimulation}
prefetch={prefetchRelatedLinks}
/>} />}
</>} </>}
<div className={clsx( <div className={clsx(

View File

@ -1,13 +1,14 @@
'use client'; 'use client';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Photo } from '@/photo'; import { Photo, titleForPhoto } from '@/photo';
import Link from 'next/link'; import Link from 'next/link';
import { AnimationConfig } from '../components/AnimateItems'; import { AnimationConfig } from '../components/AnimateItems';
import { useAppState } from '@/state/AppState'; import { useAppState } from '@/state/AppState';
import { pathForPhoto } from '@/site/paths'; import { pathForPhoto } from '@/site/paths';
import { Camera } from '@/camera'; import { Camera } from '@/camera';
import { FilmSimulation } from '@/simulation'; import { FilmSimulation } from '@/simulation';
import { clsx } from 'clsx/lite';
export default function PhotoLink({ export default function PhotoLink({
photo, photo,
@ -16,6 +17,7 @@ export default function PhotoLink({
simulation, simulation,
prefetch, prefetch,
nextPhotoAnimation, nextPhotoAnimation,
className,
children, children,
}: { }: {
photo?: Photo photo?: Photo
@ -24,7 +26,8 @@ export default function PhotoLink({
simulation?: FilmSimulation simulation?: FilmSimulation
prefetch?: boolean prefetch?: boolean
nextPhotoAnimation?: AnimationConfig nextPhotoAnimation?: AnimationConfig
children: ReactNode className?: string
children?: ReactNode
}) { }) {
const { setNextPhotoAnimation } = useAppState(); const { setNextPhotoAnimation } = useAppState();
@ -38,12 +41,16 @@ export default function PhotoLink({
setNextPhotoAnimation?.(nextPhotoAnimation); setNextPhotoAnimation?.(nextPhotoAnimation);
} }
}} }}
className={className}
scroll={false} scroll={false}
> >
{children} {children ?? titleForPhoto(photo)}
</Link> </Link>
: <span className="text-gray-300 dark:text-gray-700 cursor-default"> : <span className={clsx(
{children} 'text-gray-300 dark:text-gray-700 cursor-default',
className,
)}>
{children ?? (photo ? titleForPhoto(photo) : undefined)}
</span> </span>
); );
}; };

View File

@ -301,9 +301,7 @@ const safelyQueryPhotos = async <T>(
): Promise<T> => { ): Promise<T> => {
let result: T; let result: T;
if (debugMessage) { const start = new Date();
console.log(`Executing sql query: ${debugMessage}`);
}
try { try {
result = await callback(); result = await callback();
@ -337,6 +335,12 @@ const safelyQueryPhotos = async <T>(
} }
} }
if (debugMessage) {
const time =
(((new Date()).getTime() - start.getTime()) / 1000).toFixed(2);
console.log(`Executing sql query: ${debugMessage} (${time} seconds)`);
}
return result; return result;
}; };
@ -412,8 +416,7 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
values.push(limit, offset); values.push(limit, offset);
return safelyQueryPhotos(async () => { return safelyQueryPhotos(async () => {
const client = await db.connect(); return db.query(sql.join(' '), values);
return client.query(sql.join(' '), values);
}, sql.join(' ')) }, sql.join(' '))
.then(({ rows }) => rows.map(parsePhotoFromDb)); .then(({ rows }) => rows.map(parsePhotoFromDb));
}; };
@ -427,8 +430,7 @@ export const getPhotosNearId = async (
: 'ORDER BY taken_at DESC'; : 'ORDER BY taken_at DESC';
return safelyQueryPhotos(async () => { return safelyQueryPhotos(async () => {
const client = await db.connect(); return db.query(
return client.query(
` `
WITH twi AS ( WITH twi AS (
SELECT *, row_number() SELECT *, row_number()
@ -444,7 +446,7 @@ export const getPhotosNearId = async (
`, `,
[id, limit] [id, limit]
); );
}, 'getPhotosNearId') }, `getPhotosNearId: ${id}`)
.then(({ rows }) => { .then(({ rows }) => {
const photos = rows.map(parsePhotoFromDb); const photos = rows.map(parsePhotoFromDb);
return { return {

View File

@ -22,8 +22,10 @@ const SITE_DOMAIN =
VERCEL_PROJECT_URL; VERCEL_PROJECT_URL;
// Used primarily for absolute references such as OG images // Used primarily for absolute references such as OG images
export const BASE_URL = makeUrlAbsolute(VERCEL_ENV === 'production' export const BASE_URL = makeUrlAbsolute((
? SITE_DOMAIN process.env.NODE_ENV === 'production' &&
VERCEL_ENV !== 'preview'
) ? SITE_DOMAIN
: VERCEL_ENV === 'preview' : VERCEL_ENV === 'preview'
? VERCEL_BRANCH_URL || VERCEL_DEPLOYMENT_URL ? VERCEL_BRANCH_URL || VERCEL_DEPLOYMENT_URL
: 'http://localhost:3000')?.toLocaleLowerCase(); : 'http://localhost:3000')?.toLocaleLowerCase();

View File

@ -6,6 +6,7 @@ import { EntityLinkExternalProps } from '@/components/primitives/EntityLink';
export default function PhotoTags({ export default function PhotoTags({
tags, tags,
contrast, contrast,
prefetch,
}: { }: {
tags: string[] tags: string[]
} & EntityLinkExternalProps) { } & EntityLinkExternalProps) {
@ -14,8 +15,8 @@ export default function PhotoTags({
{tags.map(tag => {tags.map(tag =>
<> <>
{isTagFavs(tag) {isTagFavs(tag)
? <FavsTag key={tag} {...{ contrast }} /> ? <FavsTag key={tag} {...{ contrast, prefetch }} />
: <PhotoTag key={tag} {...{ tag, contrast }} />} : <PhotoTag key={tag} {...{ tag, contrast, prefetch }} />}
</>)} </>)}
</div> </div>
); );