import { db } from '../db' import { jsonResponse, errorResponse, corsHeaders } from '../utils/cors' function parseTheme(row: any) { return { ...row, is_default: !!row.is_default, is_system: !!row.is_system, variables: JSON.parse(row.variables), metadata: row.metadata ? JSON.parse(row.metadata) : null } } export async function handleThemes(req: Request) { if (req.method === 'GET') { const rows = db.query('SELECT * FROM themes ORDER BY is_system DESC, is_default DESC, name ASC').all() const themes = (rows as any[]).map(parseTheme) return jsonResponse(themes) } if (req.method === 'POST') { const body = await req.json() const id = body.id || `theme-${Date.now()}` const stmt = db.prepare(` INSERT OR REPLACE INTO themes (id, name, description, is_default, is_system, variables, metadata, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) `) stmt.run( id, body.name, body.description || '', body.is_default ? 1 : 0, body.is_system ? 1 : 0, JSON.stringify(body.variables), JSON.stringify(body.metadata || {}) ) return jsonResponse({ success: true, id }) } return null } export function handleActiveTheme() { const row = db.query('SELECT * FROM themes WHERE is_default = 1 LIMIT 1').get() as any if (!row) { return errorResponse('No active theme', 404) } return jsonResponse(parseTheme(row)) } export function handleDesignTokens() { const row = db.query('SELECT variables FROM themes WHERE is_default = 1 LIMIT 1').get() as { variables: string } | null const tokens = row ? JSON.parse(row.variables) : {} return jsonResponse({ version: '1.0.0', description: 'Design tokens for Agent UI components. Use these CSS variables for consistent styling.', usage: 'Use var(--token-name) in CSS, e.g., var(--bg-primary)', tokens, guidelines: { backgrounds: 'Use bg-primary for main areas, bg-secondary for cards/panels, bg-tertiary for nested elements', text: 'Use text-primary for headings, text-secondary for body, text-muted for hints', accent: 'Use accent for interactive elements, accent-hover for hover states, accent-muted for backgrounds', semantic: 'Use success/warning/error/info for status indicators with their -bg variants for backgrounds', spacing: 'Use radius-sm (4px) for small elements, radius-md (8px) for cards, radius-lg (12px) for modals', effects: 'Use transition-fast for micro-interactions, shadow-md for elevated elements' }, examples: { button: 'background: var(--accent); color: var(--accent-text); border-radius: var(--radius-md); transition: var(--transition-fast);', card: 'background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);', input: 'background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: var(--radius-md);', badge: 'background: var(--accent-muted); color: var(--accent); padding: 0.25rem 0.5rem; border-radius: var(--radius-full);' } }) } export async function handleThemeById(req: Request, id: string, action?: string) { // POST /api/themes/:id/default - Set as default if (action === 'default' && req.method === 'POST') { db.run('UPDATE themes SET is_default = 0') db.run('UPDATE themes SET is_default = 1 WHERE id = ?', [id]) return jsonResponse({ success: true }) } // PUT /api/themes/:id - Update theme if (req.method === 'PUT' && !action) { const theme = db.query('SELECT * FROM themes WHERE id = ?').get(id) as any if (!theme) { return errorResponse('Theme not found', 404) } const body = await req.json() const updates: string[] = [] const values: any[] = [] if (body.name !== undefined) { updates.push('name = ?'); values.push(body.name) } if (body.description !== undefined) { updates.push('description = ?'); values.push(body.description) } if (body.variables !== undefined) { updates.push('variables = ?'); values.push(JSON.stringify(body.variables)) } if (body.metadata !== undefined) { updates.push('metadata = ?'); values.push(JSON.stringify(body.metadata)) } if (updates.length > 0) { updates.push('updated_at = CURRENT_TIMESTAMP') values.push(id) const sql = `UPDATE themes SET ${updates.join(', ')} WHERE id = ?` db.run(sql, values) } return jsonResponse({ success: true, id }) } // GET /api/themes/:id - Get theme if (req.method === 'GET' && !action) { const row = db.query('SELECT * FROM themes WHERE id = ?').get(id) as any if (!row) { return errorResponse('Theme not found', 404) } return jsonResponse(parseTheme(row)) } // DELETE /api/themes/:id - Delete theme if (req.method === 'DELETE' && !action) { const theme = db.query('SELECT is_system FROM themes WHERE id = ?').get(id) as { is_system: number } | null if (theme?.is_system) { return errorResponse('Cannot delete system theme', 403) } db.run('DELETE FROM themes WHERE id = ?', [id]) return jsonResponse({ success: true }) } return null } export function handleThemeExport(id: string) { const row = db.query('SELECT * FROM themes WHERE id = ?').get(id) as any if (!row) { return errorResponse('Theme not found', 404) } const exportData = { name: row.name, description: row.description, variables: JSON.parse(row.variables), metadata: { ...(row.metadata ? JSON.parse(row.metadata) : {}), exported_at: new Date().toISOString() } } return new Response(JSON.stringify(exportData, null, 2), { headers: { ...corsHeaders, 'Content-Type': 'application/json', 'Content-Disposition': `attachment; filename="${row.name.toLowerCase().replace(/\s+/g, '-')}-theme.json"` } }) }