diff --git a/apps/web/package.json b/apps/web/package.json
index e9102eb..c2a8692 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -10,6 +10,10 @@
"lint": "oxlint"
},
"dependencies": {
+ "@fontsource/caveat": "^5.2.8",
+ "@fontsource/kalam": "^5.2.8",
+ "@fontsource/patrick-hand": "^5.2.8",
+ "@fontsource/shadows-into-light": "^5.2.8",
"@radix-ui/react-slot": "^1.3.0",
"@tanstack/react-router": "^1.170.16",
"class-variance-authority": "^0.7.1",
diff --git a/apps/web/src/components/caption-font-control.tsx b/apps/web/src/components/caption-font-control.tsx
new file mode 100644
index 0000000..8ef360c
--- /dev/null
+++ b/apps/web/src/components/caption-font-control.tsx
@@ -0,0 +1,34 @@
+import { CAPTION_FONTS } from '@/lib/fonts'
+import { useSettingsStore } from '@/stores/settings-store'
+
+export function CaptionFontControl() {
+ const captionFontId = useSettingsStore((state) => state.captionFontId)
+ const setCaptionFont = useSettingsStore((state) => state.setCaptionFont)
+
+ return (
+
+
+
@@ -60,11 +65,13 @@ function CaptionInput({
onChange,
placeholder,
className,
+ fontFamily,
}: {
value: string
onChange: (value: string) => void
placeholder?: string
className?: string
+ fontFamily: string
}) {
return (
onChange(event.target.value)}
placeholder={placeholder}
aria-label="Polaroid caption"
+ style={{ fontFamily }}
className={cn(
- 'font-handwriting w-full border-0 bg-transparent text-center text-neutral-800 placeholder:text-neutral-300 focus:outline-none',
+ 'w-full border-0 bg-transparent text-center text-neutral-800 placeholder:text-neutral-300 focus:outline-none',
className,
)}
/>
diff --git a/apps/web/src/fontsource.d.ts b/apps/web/src/fontsource.d.ts
new file mode 100644
index 0000000..ffd952a
--- /dev/null
+++ b/apps/web/src/fontsource.d.ts
@@ -0,0 +1,3 @@
+// @fontsource packages ship CSS with no type declarations; declare them so
+// side-effect imports satisfy `noUncheckedSideEffectImports`.
+declare module '@fontsource/*'
diff --git a/apps/web/src/lib/fonts.ts b/apps/web/src/lib/fonts.ts
new file mode 100644
index 0000000..f0fe892
--- /dev/null
+++ b/apps/web/src/lib/fonts.ts
@@ -0,0 +1,25 @@
+export interface CaptionFont {
+ id: string
+ label: string
+ /** CSS font-family stack applied to caption text. */
+ stack: string
+}
+
+export const CAPTION_FONTS: CaptionFont[] = [
+ { id: 'caveat', label: 'Caveat', stack: '"Caveat", cursive' },
+ { id: 'patrick-hand', label: 'Patrick Hand', stack: '"Patrick Hand", cursive' },
+ {
+ id: 'shadows-into-light',
+ label: 'Shadows Into Light',
+ stack: '"Shadows Into Light", cursive',
+ },
+ { id: 'kalam', label: 'Kalam', stack: '"Kalam", cursive' },
+]
+
+export const DEFAULT_CAPTION_FONT_ID = CAPTION_FONTS[0].id
+
+export function captionFontStack(id: string): string {
+ return (
+ CAPTION_FONTS.find((font) => font.id === id)?.stack ?? CAPTION_FONTS[0].stack
+ )
+}
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
index 592f518..53bac28 100644
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -4,6 +4,10 @@ import { RouterProvider, createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
import './styles.css'
+import '@fontsource/caveat'
+import '@fontsource/patrick-hand'
+import '@fontsource/shadows-into-light'
+import '@fontsource/kalam'
const router = createRouter({ routeTree })
diff --git a/apps/web/src/stores/settings-store.ts b/apps/web/src/stores/settings-store.ts
index 23d3290..f1d72ae 100644
--- a/apps/web/src/stores/settings-store.ts
+++ b/apps/web/src/stores/settings-store.ts
@@ -1,5 +1,7 @@
import { create } from 'zustand'
+import { DEFAULT_CAPTION_FONT_ID } from '@/lib/fonts'
+
export const MIN_FRAME_PADDING = 6
export const MAX_FRAME_PADDING = 28
@@ -7,9 +9,13 @@ interface SettingsState {
/** White polaroid border width in px (sides/top); the bottom is thicker. */
framePadding: number
setFramePadding: (px: number) => void
+ captionFontId: string
+ setCaptionFont: (id: string) => void
}
export const useSettingsStore = create
((set) => ({
framePadding: 14,
setFramePadding: (px) => set({ framePadding: px }),
+ captionFontId: DEFAULT_CAPTION_FONT_ID,
+ setCaptionFont: (id) => set({ captionFontId: id }),
}))
diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css
index 4f93859..269edc5 100644
--- a/apps/web/src/styles.css
+++ b/apps/web/src/styles.css
@@ -42,7 +42,6 @@
}
@theme inline {
- --font-handwriting: "Caveat", "Segoe Print", "Bradley Hand", cursive;
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 06e6f32..1347897 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,18 @@ importers:
apps/web:
dependencies:
+ '@fontsource/caveat':
+ specifier: ^5.2.8
+ version: 5.2.8
+ '@fontsource/kalam':
+ specifier: ^5.2.8
+ version: 5.2.8
+ '@fontsource/patrick-hand':
+ specifier: ^5.2.8
+ version: 5.2.8
+ '@fontsource/shadows-into-light':
+ specifier: ^5.2.8
+ version: 5.2.8
'@radix-ui/react-slot':
specifier: ^1.3.0
version: 1.3.0(@types/react@19.2.17)(react@19.2.7)
@@ -157,6 +169,18 @@ packages:
'@emnapi/wasi-threads@1.2.2':
resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==}
+ '@fontsource/caveat@5.2.8':
+ resolution: {integrity: sha512-9fUUfFE2IQFKbx+xOcaeQxxmh8iJguEb8z+j1PeueO4UUx+XfT4pRm/B04ZDvFA794/iRxY/IibmP8ZKtIf4rw==}
+
+ '@fontsource/kalam@5.2.8':
+ resolution: {integrity: sha512-9WDYPX1llS28xRjrqAoz3IOLeaBhCtL3HCtNanYnF1fthFPmSD5aESL6s7C1SJxAlxq/qzTlpIpw4S1W9+q3OA==}
+
+ '@fontsource/patrick-hand@5.2.8':
+ resolution: {integrity: sha512-FZx34VLuiF+Pjv/A/m1bTxjR6hAvmL6vdCp62uypVdgFvSrPrBOxX+vCXVy8lfNVFqvKfm/ghun+aaYVYqfBEg==}
+
+ '@fontsource/shadows-into-light@5.2.8':
+ resolution: {integrity: sha512-ZTiWDiLQmG8kjWEb2o3vicAqpEi02/SziTClaSXRRKpdpXv5w/Jv3kG7EVK9d7wlFm3/4U3hhaFOcIuHznmbSQ==}
+
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -1293,6 +1317,14 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@fontsource/caveat@5.2.8': {}
+
+ '@fontsource/kalam@5.2.8': {}
+
+ '@fontsource/patrick-hand@5.2.8': {}
+
+ '@fontsource/shadows-into-light@5.2.8': {}
+
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5