feat: Add update_theme functionality with UI support

Backend:
- Add PUT /api/themes/:id endpoint for updating existing themes

Store:
- Add updateTheme method to theme store

MCP:
- Add update_theme tool to modify name, description, or save current variables

UI:
- Add edit button to ThemeListItem (custom themes only)
- Add edit modal with name and description fields
- Support editing from both desktop sidebar and mobile dropdown
This commit is contained in:
2026-02-13 05:50:13 -06:00
parent d5518cb6d1
commit 2e64dceb1e
6 changed files with 263 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ export const THEME_TOOLS = [
'get_active_theme',
'set_theme_variable',
'save_theme',
'update_theme',
'list_themes',
'switch_theme',
'set_default_theme',
@@ -212,6 +213,85 @@ export function registerThemeTools() {
}
)
// update_theme
registerTool(
'update_theme',
'Actualiza un tema existente (nombre, descripción o variables)',
{
type: 'object',
properties: {
theme: {
type: 'string',
description: 'Nombre o ID del tema a actualizar'
},
name: {
type: 'string',
description: 'Nuevo nombre para el tema (opcional)'
},
description: {
type: 'string',
description: 'Nueva descripción para el tema (opcional)'
},
saveCurrentVariables: {
type: 'boolean',
description: 'Si es true, guarda las variables actuales (con los cambios de set_theme_variable) en este tema'
}
},
required: ['theme']
},
async (args: { theme: string; name?: string; description?: string; saveCurrentVariables?: boolean }) => {
try {
const themeStore = useThemeStore()
await themeStore.fetchThemes()
// Find theme by ID or name
const theme = themeStore.themes.find(t =>
t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase()
)
if (!theme) {
const available = themeStore.themes.map(t => t.name).join(', ')
return `Tema "${args.theme}" no encontrado.\nDisponibles: ${available}`
}
if (theme.is_system) {
return `No se puede modificar "${theme.name}" porque es un tema del sistema. Usa save_theme para crear una copia.`
}
// Build update data
const updateData: { name?: string; description?: string; variables?: any } = {}
if (args.name) {
updateData.name = args.name
}
if (args.description !== undefined) {
updateData.description = args.description
}
if (args.saveCurrentVariables) {
const variablesToSave = themeStore.previewTheme || themeStore.activeTheme?.variables
if (variablesToSave) {
updateData.variables = variablesToSave
}
}
if (Object.keys(updateData).length === 0) {
return 'No se especificaron cambios. Usa name, description o saveCurrentVariables.'
}
await themeStore.updateTheme(theme.id, updateData)
const changes = []
if (args.name) changes.push(`nombre: "${args.name}"`)
if (args.description !== undefined) changes.push('descripción actualizada')
if (args.saveCurrentVariables) changes.push('variables guardadas')
return `Tema "${theme.name}" actualizado:\n ${changes.join('\n ')}`
} catch (e: any) {
return `Error al actualizar tema: ${e.message}`
}
}
)
// list_themes
registerTool(
'list_themes',