Recolour the whole UI from Settings — 12 palette colour pickers with live preview, presets (Ember/Frost/Verdant/Amethyst), and reset to the default Blackflame. Overrides persist in app_settings (key 'theme') via a hex-validated /api/theme route and apply to :root on boot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
22 lines
848 B
JavaScript
22 lines
848 B
JavaScript
import { Router } from 'express';
|
|
import { z } from 'zod';
|
|
import { asyncWrap } from '../errors.js';
|
|
import { requireOwner } from '../cap.js';
|
|
import { validate } from '../validate.js';
|
|
import * as settings from '../../db/repos/app_settings.js';
|
|
export const router = Router();
|
|
|
|
// Theme = a small map of palette-var overrides, e.g. { accent: '#ff4f2e' }.
|
|
// Keys are short slugs (mapped to --<key> on the client); values must be hex,
|
|
// so a saved theme can never inject arbitrary CSS.
|
|
const themeSchema = z.record(
|
|
z.string().regex(/^[a-z0-9-]{1,24}$/),
|
|
z.string().regex(/^#[0-9a-fA-F]{3,8}$/)
|
|
);
|
|
|
|
router.get('/', asyncWrap(async (_req, res) => res.json(await settings.get('theme', {}))));
|
|
|
|
router.put('/', requireOwner, validate({ body: themeSchema }), asyncWrap(async (req, res) => {
|
|
res.json(await settings.set('theme', req.body));
|
|
}));
|