Skip to content

Commit 340f028

Browse files
committed
Merge branch 'upstream' into feat-og-image-config-gen
2 parents 6525d78 + 89f837f commit 340f028

File tree

35 files changed

+4785
-5505
lines changed

35 files changed

+4785
-5505
lines changed

Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ RUN sh ./scripts/preinstall.sh
2020
# Install all dependencies
2121
RUN pnpm install --frozen-lockfile
2222

23+
# Copy zeroperl.wasm to web public directory before build.
24+
# @uswriting/exiftool depends on @6over3/zeroperl-ts which loads zeroperl.wasm via fetch("./zeroperl.wasm")
25+
# relative to the current page URL, so it must be available under both root and /photos/ paths.
26+
RUN mkdir -p apps/web/public/photos && \
27+
find node_modules -name "zeroperl.wasm" -path "*/esm/*" -exec cp {} apps/web/public/ \; -exec cp {} apps/web/public/photos/ \; -quit
28+
2329
ARG S3_ACCESS_KEY_ID
2430
ARG S3_SECRET_ACCESS_KEY
2531
ARG GIT_TOKEN

apps/docs/package.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,46 +26,46 @@
2626
"@types/mdast": "^4.0.4",
2727
"clsx": "2.1.1",
2828
"cmdk": "1.1.1",
29-
"lucide-react": "^0.562.0",
29+
"lucide-react": "^0.564.0",
3030
"mdast": "^3.0.0",
31-
"motion": "12.25.0",
31+
"motion": "12.34.0",
3232
"next-themes": "^0.4.6",
33-
"react": "^19.2.3",
34-
"react-dom": "^19.2.3",
33+
"react": "^19.2.4",
34+
"react-dom": "^19.2.4",
3535
"remark-frontmatter": "^5.0.0",
3636
"remark-gfm": "^4.0.1",
3737
"remark-mdx": "^3.1.1",
3838
"remark-parse": "^11.0.0",
3939
"tailwind-scrollbar-hide": "^4.0.0",
4040
"unified": "^11.0.5",
41-
"unist-util-visit": "^5.0.0"
41+
"unist-util-visit": "^5.1.0"
4242
},
4343
"devDependencies": {
44-
"@eslint/js": "^9.39.2",
45-
"@shikijs/rehype": "^3.21.0",
44+
"@eslint/js": "^10.0.1",
45+
"@shikijs/rehype": "^3.22.0",
4646
"@tailwindcss/postcss": "catalog:",
4747
"@tailwindcss/typography": "catalog:",
4848
"@types/glob": "^9.0.0",
4949
"@types/mdx": "^2.0.13",
50-
"@types/react": "^19.2.8",
51-
"@types/react-dom": "^19.2.3",
50+
"@types/react": "catalog:",
51+
"@types/react-dom": "catalog:",
5252
"@types/remark-heading-id": "^1.0.0",
53-
"@vitejs/plugin-react": "^5.1.2",
54-
"code-inspector-plugin": "1.3.4",
55-
"eslint": "^9.39.2",
53+
"@vitejs/plugin-react": "^5.1.4",
54+
"code-inspector-plugin": "1.4.2",
55+
"eslint": "^10.0.0",
5656
"eslint-plugin-react-hooks": "^7.0.1",
57-
"eslint-plugin-react-refresh": "^0.4.26",
58-
"glob": "^13.0.0",
59-
"globals": "^16.5.0",
60-
"shiki": "^3.21.0",
57+
"eslint-plugin-react-refresh": "^0.5.0",
58+
"glob": "^13.0.3",
59+
"globals": "^17.3.0",
60+
"shiki": "^3.22.0",
6161
"tailwind-scrollbar": "catalog:",
6262
"tailwindcss": "catalog:",
6363
"tailwindcss-animate": "catalog:",
6464
"tailwindcss-safe-area": "catalog:",
6565
"tailwindcss-uikit-colors": "catalog:",
6666
"tsx": "^4.21.0",
6767
"typescript": "~5.9.3",
68-
"typescript-eslint": "^8.52.0",
68+
"typescript-eslint": "^8.55.0",
6969
"vite": "8.0.0-beta.0"
7070
}
7171
}

apps/ssr/package.json

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"name": "@afilmory/ssr",
33
"version": "1.0.0",
4-
"description": "",
4+
"description": "Next.js SSR host and SEO for the gallery",
5+
"license": "SEE LICENSE IN LICENSE.md",
56
"author": "Innei",
67
"type": "module",
78
"main": "index.js",
@@ -24,13 +25,13 @@
2425
"@t3-oss/env-nextjs": "0.13.10",
2526
"clsx": "2.1.1",
2627
"drizzle-orm": "0.45.1",
27-
"es-toolkit": "1.43.0",
28+
"es-toolkit": "1.44.0",
2829
"linkedom": "0.18.12",
29-
"pg": "8.16.3",
30+
"pg": "8.18.0",
3031
"postgres": "3.4.8",
3132
"prop-types": "15.8.1",
32-
"react": "19.2.3",
33-
"react-dom": "19.2.3",
33+
"react": "19.2.4",
34+
"react-dom": "19.2.4",
3435
"react-responsive-masonry": "2.7.1",
3536
"react-use": "17.6.0",
3637
"tailwind-merge": "3.4.0",
@@ -44,21 +45,21 @@
4445
"@iconify-json/mingcute": "catalog:",
4546
"@tailwindcss/postcss": "catalog:",
4647
"@tailwindcss/typography": "catalog:",
47-
"@types/node": "24.10.1",
48+
"@types/node": "25.2.3",
4849
"@types/pg": "8.16.0",
49-
"@types/react": "19.2.8",
50-
"@types/react-dom": "19.2.3",
50+
"@types/react": "catalog:",
51+
"@types/react-dom": "catalog:",
5152
"concurrently": "9.2.1",
5253
"cross-env": "10.1.0",
5354
"dotenv-expand": "catalog:",
5455
"drizzle-kit": "0.31.8",
55-
"next": "16.1.1",
56+
"next": "16.1.6",
5657
"postcss": "8.5.6",
5758
"tailwind-scrollbar": "catalog:",
5859
"tailwindcss": "catalog:",
5960
"tailwindcss-animate": "catalog:",
6061
"tailwindcss-safe-area": "catalog:",
6162
"tailwindcss-uikit-colors": "catalog:"
6263
},
63-
"packageManager": "pnpm@10.26.2"
64-
}
64+
"packageManager": "pnpm@10.29.3"
65+
}

apps/ssr/src/app/og/[photoId]/route.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1+
import { hostname } from 'node:os'
2+
13
import type { NextRequest } from 'next/server'
24

5+
function getDefaultCoreApiBase(): string {
6+
// In Docker, HOSTNAME is set to the container ID, and localhost may not resolve correctly (IPv6 issues).
7+
// Use os.hostname() which is resolvable within the Docker network.
8+
const isDocker = process.env.HOSTNAME && /^[a-f0-9]{12,64}$/.test(process.env.HOSTNAME)
9+
const host = isDocker ? hostname() : 'localhost'
10+
return `http://${host}:3000`
11+
}
12+
313
const CORE_API_BASE =
414
process.env.CORE_API_URL ??
515
process.env.NEXT_PUBLIC_CORE_API_URL ??
616
process.env.API_BASE_URL ??
7-
'http://localhost:3000'
17+
getDefaultCoreApiBase()
818

919
const FORWARDED_HEADER_KEYS = ['cookie', 'authorization', 'x-forwarded-host', 'x-forwarded-proto', 'host']
1020

apps/web/package.json

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
{
22
"name": "@afilmory/web",
33
"version": "0.0.1",
4+
"description": "Photo gallery SPA",
45
"repository": {
56
"type": "git",
67
"url": "https://github.com/Afilmory/Afilmory"
78
},
9+
"license": "SEE LICENSE IN LICENSE.md",
810
"type": "module",
911
"scripts": {
1012
"analyze": "analyzer=1 vite build",
@@ -34,69 +36,69 @@
3436
"@radix-ui/react-dropdown-menu": "2.1.16",
3537
"@react-hook/window-size": "3.1.1",
3638
"@t3-oss/env-core": "catalog:",
37-
"@tanstack/react-query": "5.90.16",
39+
"@tanstack/react-query": "5.90.21",
3840
"@tanstack/react-virtual": "3.13.18",
3941
"@use-gesture/react": "10.3.1",
4042
"@uswriting/exiftool": "1.0.9",
4143
"blurhash": "2.0.5",
4244
"clsx": "2.1.1",
4345
"consola": "3.4.2",
44-
"dotenv": "17.2.3",
45-
"es-toolkit": "1.43.0",
46+
"dotenv": "17.3.1",
47+
"es-toolkit": "1.44.0",
4648
"file-type": "^21.3.0",
4749
"foxact": "0.2.51",
48-
"heic-to": "1.3.0",
49-
"i18next": "25.7.4",
50-
"i18next-browser-languagedetector": "8.2.0",
51-
"immer": "11.1.3",
52-
"jotai": "2.16.1",
53-
"maplibre-gl": "^5.15.0",
50+
"heic-to": "1.4.2",
51+
"i18next": "25.8.7",
52+
"i18next-browser-languagedetector": "8.2.1",
53+
"immer": "11.1.4",
54+
"jotai": "2.17.1",
55+
"maplibre-gl": "^5.18.0",
5456
"masonic": "4.1.0",
55-
"motion": "12.25.0",
57+
"motion": "12.34.0",
5658
"ofetch": "1.5.1",
57-
"react": "19.2.3",
59+
"react": "19.2.4",
5860
"react-blurhash": "0.3.0",
59-
"react-dom": "19.2.3",
60-
"react-error-boundary": "6.0.3",
61+
"react-dom": "19.2.4",
62+
"react-error-boundary": "6.1.0",
6163
"react-freeze": "1.0.4",
62-
"react-i18next": "16.5.1",
64+
"react-i18next": "16.5.4",
6365
"react-image-gallery": "1.4.0",
64-
"react-intersection-observer": "10.0.0",
66+
"react-intersection-observer": "10.0.2",
6567
"react-map-gl": "^8.1.0",
6668
"react-remove-scroll": "2.7.2",
6769
"react-responsive-masonry": "2.7.1",
68-
"react-router": "7.12.0",
70+
"react-router": "7.13.0",
6971
"react-scan": "0.4.3",
7072
"react-use-measure": "2.1.7",
7173
"react-zoom-pan-pinch": "3.7.0",
7274
"sonner": "2.0.7",
73-
"swiper": "12.0.3",
74-
"swr": "2.3.8",
75+
"swiper": "12.1.0",
76+
"swr": "2.4.0",
7577
"tailwind-merge": "3.4.0",
7678
"tailwind-variants": "catalog:",
7779
"thumbhash": "0.1.1",
7880
"tiff": "^7.1.3",
7981
"usehooks-ts": "3.1.1",
8082
"vaul": "1.1.2",
8183
"zod": "catalog:",
82-
"zustand": "5.0.9"
84+
"zustand": "5.0.11"
8385
},
8486
"devDependencies": {
8587
"@egoist/tailwindcss-icons": "catalog:",
86-
"@iconify-json/lucide": "1.2.83",
88+
"@iconify-json/lucide": "1.2.90",
8789
"@iconify-json/mingcute": "catalog:",
88-
"@iconify-json/simple-icons": "1.2.65",
90+
"@iconify-json/simple-icons": "1.2.70",
8991
"@tailwindcss/postcss": "catalog:",
9092
"@tailwindcss/typography": "catalog:",
9193
"@tailwindcss/vite": "4.1.18",
92-
"@types/node": "24.10.1",
93-
"@types/react": "19.2.8",
94-
"@types/react-dom": "19.2.3",
95-
"@vitejs/plugin-react": "^5.1.2",
94+
"@types/node": "25.2.3",
95+
"@types/react": "catalog:",
96+
"@types/react-dom": "catalog:",
97+
"@vitejs/plugin-react": "^5.1.4",
9698
"ast-kit": "2.2.0",
9799
"babel-plugin-react-compiler": "1.0.0",
98-
"code-inspector-plugin": "1.3.4",
99-
"daisyui": "5.5.14",
100+
"code-inspector-plugin": "1.4.2",
101+
"daisyui": "5.5.18",
100102
"execa": "9.6.1",
101103
"kolorist": "1.8.0",
102104
"linkedom": "0.18.12",
@@ -110,10 +112,11 @@
110112
"tailwindcss-animate": "catalog:",
111113
"tailwindcss-safe-area": "catalog:",
112114
"tailwindcss-uikit-colors": "catalog:",
113-
"unplugin-ast": "0.15.4",
115+
"unplugin-ast": "0.16.0",
116+
"vite": "8.0.0-beta.0",
114117
"vite-plugin-html": "3.2.2",
115118
"vite-plugin-pwa": "1.2.0",
116119
"vite-plugin-route-builder": "0.5.0-alpha.1"
117120
},
118-
"packageManager": "pnpm@10.26.2"
119-
}
121+
"packageManager": "pnpm@10.29.3"
122+
}

apps/web/plugins/vite/feed-sitemap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function generateSitemap(photos: PhotoManifestItem[], config: SiteConfig): strin
6767
.map((photo) => {
6868
const lastmod = new Date(photo.lastModified || photo.dateTaken).toISOString()
6969
return ` <url>
70-
<loc>${config.url}/${photo.id}</loc>
70+
<loc>${config.url}/photos/${encodeURIComponent(photo.id)}</loc>
7171
<lastmod>${lastmod}</lastmod>
7272
<changefreq>monthly</changefreq>
7373
<priority>0.8</priority>

apps/web/src/atoms/viewer.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { atom } from 'jotai'
2+
3+
import { jotaiStore } from '~/lib/jotai'
4+
5+
// Source of truth for viewer state, synced with URL
6+
export interface ViewerState {
7+
isOpen: boolean
8+
photoId: string | null
9+
// Internal state not synced with URL
10+
triggerElement: HTMLElement | null
11+
}
12+
13+
export const viewerAtom = atom<ViewerState>({
14+
isOpen: false,
15+
photoId: null,
16+
triggerElement: null,
17+
})
18+
19+
// Helper to get viewer state from store
20+
export const getViewer = () => jotaiStore.get(viewerAtom)
21+
22+
// Helper to set viewer state - supports both direct value and updater function
23+
export const setViewer = (valueOrUpdater: ViewerState | ((prev: ViewerState) => ViewerState)) => {
24+
if (typeof valueOrUpdater === 'function') {
25+
const prev = jotaiStore.get(viewerAtom)
26+
jotaiStore.set(viewerAtom, valueOrUpdater(prev))
27+
} else {
28+
jotaiStore.set(viewerAtom, valueOrUpdater)
29+
}
30+
}

apps/web/src/components/ui/number/SlidingNumber.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { clsxm, Spring } from '@afilmory/utils'
44
import type { MotionValue, SpringOptions, UseInViewOptions } from 'motion/react'
5-
import { m as motion, useInView, useSpring, useTransform } from 'motion/react'
5+
import { m as motion, useInView, useReducedMotion, useSpring, useTransform } from 'motion/react'
66
import * as React from 'react'
77
import useMeasure from 'react-use-measure'
88

@@ -16,7 +16,12 @@ type SlidingNumberRollerProps = {
1616
function SlidingNumberRoller({ prevValue, value, place, transition }: SlidingNumberRollerProps) {
1717
const startNumber = Math.floor(prevValue / place) % 10
1818
const targetNumber = Math.floor(value / place) % 10
19-
const animatedValue = useSpring(startNumber, transition)
19+
const shouldReduceMotion = useReducedMotion()
20+
21+
const animatedValue = useSpring(
22+
shouldReduceMotion ? targetNumber : startNumber,
23+
shouldReduceMotion ? { duration: 0 } : transition,
24+
)
2025

2126
React.useEffect(() => {
2227
animatedValue.set(targetNumber)

0 commit comments

Comments
 (0)