feat: Add additional theme management MCP tools
- list_themes: List all available themes (system + custom) - switch_theme: Change active theme by name or ID - set_default_theme: Set a theme as the default startup theme - delete_theme: Remove custom themes (protects system themes) - reset_theme: Discard unsaved changes - export_theme: Export theme as JSON for backup/sharing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,13 @@ export const THEME_TOOLS = [
|
|||||||
'get_design_tokens',
|
'get_design_tokens',
|
||||||
'get_active_theme',
|
'get_active_theme',
|
||||||
'set_theme_variable',
|
'set_theme_variable',
|
||||||
'save_theme'
|
'save_theme',
|
||||||
|
'list_themes',
|
||||||
|
'switch_theme',
|
||||||
|
'set_default_theme',
|
||||||
|
'delete_theme',
|
||||||
|
'reset_theme',
|
||||||
|
'export_theme'
|
||||||
]
|
]
|
||||||
|
|
||||||
export function registerThemeTools() {
|
export function registerThemeTools() {
|
||||||
@@ -205,6 +211,232 @@ export function registerThemeTools() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// list_themes
|
||||||
|
registerTool(
|
||||||
|
'list_themes',
|
||||||
|
'Lista todos los temas disponibles (del sistema y personalizados)',
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {}
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
try {
|
||||||
|
const themeStore = useThemeStore()
|
||||||
|
await themeStore.fetchThemes()
|
||||||
|
|
||||||
|
const themes = themeStore.themes
|
||||||
|
if (themes.length === 0) {
|
||||||
|
return 'No hay temas disponibles'
|
||||||
|
}
|
||||||
|
|
||||||
|
const systemThemes = themes.filter(t => t.is_system)
|
||||||
|
const userThemes = themes.filter(t => !t.is_system)
|
||||||
|
|
||||||
|
let result = `Temas disponibles (${themes.length}):\n\n`
|
||||||
|
|
||||||
|
if (systemThemes.length > 0) {
|
||||||
|
result += `[SISTEMA]\n`
|
||||||
|
result += systemThemes.map(t =>
|
||||||
|
` - ${t.name} (${t.id})${t.is_default ? ' [DEFAULT]' : ''}`
|
||||||
|
).join('\n')
|
||||||
|
result += '\n\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userThemes.length > 0) {
|
||||||
|
result += `[PERSONALIZADOS]\n`
|
||||||
|
result += userThemes.map(t =>
|
||||||
|
` - ${t.name} (${t.id})${t.is_default ? ' [DEFAULT]' : ''}`
|
||||||
|
).join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
} catch (e: any) {
|
||||||
|
return `Error: ${e.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// switch_theme
|
||||||
|
registerTool(
|
||||||
|
'switch_theme',
|
||||||
|
'Cambia al tema especificado por nombre o ID',
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
theme: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Nombre o ID del tema a activar'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ['theme']
|
||||||
|
},
|
||||||
|
async (args: { theme: string }) => {
|
||||||
|
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}`
|
||||||
|
}
|
||||||
|
|
||||||
|
themeStore.selectTheme(theme)
|
||||||
|
return `Tema cambiado a "${theme.name}"\nID: ${theme.id}`
|
||||||
|
} catch (e: any) {
|
||||||
|
return `Error: ${e.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// set_default_theme
|
||||||
|
registerTool(
|
||||||
|
'set_default_theme',
|
||||||
|
'Establece un tema como el default (se cargará automáticamente al iniciar)',
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
theme: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Nombre o ID del tema a establecer como default'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ['theme']
|
||||||
|
},
|
||||||
|
async (args: { theme: string }) => {
|
||||||
|
try {
|
||||||
|
const themeStore = useThemeStore()
|
||||||
|
await themeStore.fetchThemes()
|
||||||
|
|
||||||
|
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}`
|
||||||
|
}
|
||||||
|
|
||||||
|
await themeStore.setDefaultTheme(theme.id)
|
||||||
|
return `Tema "${theme.name}" establecido como default.\nSe cargará automáticamente al iniciar la aplicación.`
|
||||||
|
} catch (e: any) {
|
||||||
|
return `Error: ${e.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// delete_theme
|
||||||
|
registerTool(
|
||||||
|
'delete_theme',
|
||||||
|
'Elimina un tema personalizado (no se pueden eliminar temas del sistema)',
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
theme: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Nombre o ID del tema a eliminar'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ['theme']
|
||||||
|
},
|
||||||
|
async (args: { theme: string }) => {
|
||||||
|
try {
|
||||||
|
const themeStore = useThemeStore()
|
||||||
|
await themeStore.fetchThemes()
|
||||||
|
|
||||||
|
const theme = themeStore.themes.find(t =>
|
||||||
|
t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase()
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!theme) {
|
||||||
|
return `Tema "${args.theme}" no encontrado`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theme.is_system) {
|
||||||
|
return `No se puede eliminar "${theme.name}" porque es un tema del sistema`
|
||||||
|
}
|
||||||
|
|
||||||
|
const success = await themeStore.deleteTheme(theme.id)
|
||||||
|
if (success) {
|
||||||
|
return `Tema "${theme.name}" eliminado correctamente`
|
||||||
|
} else {
|
||||||
|
return `Error al eliminar el tema "${theme.name}"`
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
return `Error: ${e.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// reset_theme
|
||||||
|
registerTool(
|
||||||
|
'reset_theme',
|
||||||
|
'Descarta todos los cambios no guardados y restaura el tema activo original',
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
try {
|
||||||
|
const themeStore = useThemeStore()
|
||||||
|
|
||||||
|
if (!themeStore.previewTheme) {
|
||||||
|
return 'No hay cambios pendientes para descartar'
|
||||||
|
}
|
||||||
|
|
||||||
|
const themeName = themeStore.activeTheme?.name || 'desconocido'
|
||||||
|
themeStore.resetPreview()
|
||||||
|
return `Cambios descartados. Tema "${themeName}" restaurado a su estado original.`
|
||||||
|
} catch (e: any) {
|
||||||
|
return `Error: ${e.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// export_theme
|
||||||
|
registerTool(
|
||||||
|
'export_theme',
|
||||||
|
'Exporta un tema como JSON para respaldo o compartir',
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
theme: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Nombre o ID del tema a exportar. Si no se especifica, exporta el tema activo.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (args: { theme?: string }) => {
|
||||||
|
try {
|
||||||
|
const themeStore = useThemeStore()
|
||||||
|
|
||||||
|
let theme = themeStore.activeTheme
|
||||||
|
|
||||||
|
if (args.theme) {
|
||||||
|
await themeStore.fetchThemes()
|
||||||
|
theme = themeStore.themes.find(t =>
|
||||||
|
t.id === args.theme || t.name.toLowerCase() === args.theme!.toLowerCase()
|
||||||
|
) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!theme) {
|
||||||
|
return args.theme
|
||||||
|
? `Tema "${args.theme}" no encontrado`
|
||||||
|
: 'No hay tema activo para exportar'
|
||||||
|
}
|
||||||
|
|
||||||
|
const exported = themeStore.exportTheme(theme)
|
||||||
|
return `Tema "${theme.name}" exportado:\n\n${exported}`
|
||||||
|
} catch (e: any) {
|
||||||
|
return `Error: ${e.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unregisterThemeTools() {
|
export function unregisterThemeTools() {
|
||||||
|
|||||||
Reference in New Issue
Block a user