- Rename 'Colors' card heading to 'Custom'
- Add 'Publish Theme' button that opens a dialog to publish kind 36767 events
- Query and display user's published themes in the grid after presets
- Clicking a user theme enters editor mode, showing 'Update Theme' alongside
'Publish Theme' to update the existing event in place
- Exit editor mode when selecting a builtin theme or preset
When changing a color via the inline color picker in ThemeSelector,
the handler was passing bare CoreThemeColors to applyCustomTheme(),
which replaced the entire customTheme config and dropped the font
and background fields. Now spreads the existing customTheme before
applying the new colors, matching the pattern used by FontPicker
and BackgroundPicker.
When visiting a profile that has theme colors but no font tag,
the effective font was undefined, which removed the font override
entirely — letting the visitor's custom font bleed through. Now
profiles without an f tag explicitly default to Inter.
When viewing your own profile and your custom theme differs from the
published one, the palette button now opens a dropdown with 'Update
Profile Theme' and 'Delete Profile Theme' options instead of directly
opening the update dialog. The initial share scenario (no published
theme yet) keeps the single-click tooltip behavior.
The profile page useEffect cleanup was restoring the user's theme from
stale closure values captured before Copy Theme was clicked. Use a ref
to always read the latest ownTheme/ownCustomTheme/configuredThemes at
cleanup time so the newly copied theme is correctly restored.
Instead of a standalone link that redirected to /settings/theme?import=,
the Copy Theme action is now a menu item inside the palette icon dropdown
on other users' profiles. It immediately applies the profile's theme as
the user's custom app theme (including font and background), and if
autoShareTheme is enabled, auto-publishes a kind 16767 event too.
Remove nostr from useEffect dependencies (replacing with a ref) so the
subscription is not torn down and re-opened on every render cycle.
Add a seenIds Set to guard against the same event ID firing multiple
notifications even if the relay delivers it more than once.
Delete the separate config/schema.ts that duplicated every Zod schema.
DittoConfigSchema is now simply AppConfigSchema.partial().strict(),
defined in src/lib/schemas.ts alongside everything else. vite.config.ts
imports it directly via a relative path.
Read an optional ditto.json (or CONFIG_FILE env) at build time, validate
it with Zod, and inject the result via Vite's define. At runtime the
build-time values are merged between the hardcoded defaults and user
localStorage, giving precedence: user > build-time > hardcoded.
Extract canonical Zod schemas into config/schema.ts (no path aliases)
so they can be imported from both vite.config.ts and runtime code.
Move AppConfigSchema out of AppProvider into src/lib/schemas.ts to
eliminate duplication.
Every place that previously read builtinThemes directly for light/dark
mode now calls resolveThemeConfig(), which checks config.themes first
and falls back to builtinThemes. This ensures configured themes are
actually used for colors, fonts, and backgrounds in all code paths:
AppProvider, useTheme, ThemeSelector, ThemeBuilderPage, ProfilePage.
Allow self-hosters to override the builtin light/dark themes by setting
a themes field in AppConfig with full ThemeConfig objects (colors, fonts,
backgrounds) for each mode.
When switching to builtin themes (Light/Dark/System), setTheme doesn't
clear customTheme, so the FontPicker and BackgroundPicker were still
showing the previous preset's font/background. Now they check that the
active theme is 'custom' before displaying the current selection.
Use primitive fontFamily/fontUrl strings as effect dependencies instead
of the font object reference, matching the same fix applied to
background handling.
Use primitive bgUrl/bgMode strings as effect dependencies instead of
the background object reference, ensuring React detects the change
when switching between presets with and without backgrounds.