Files
agent-ui/frontend/src/components/Toolbar.vue
josedario87 4450d1e034 feat: Add /tools page with centralized tool registry management
- Add ToolsPage for managing MCP tools activation and persistence
- Centralize all tool handlers in services/tools/handlers/
- toolRegistry.ts is now the single source of truth for tool state
- Add tools store for pinned tools (persisted in localStorage)
- Tools can be pinned to stay active across page navigation
- Remove old individual tool files, replaced by centralized handlers
2026-02-13 13:46:55 -06:00

215 lines
7.8 KiB
Vue

<script setup lang="ts">
import { onMounted } from 'vue'
import { RouterLink, useRoute } from 'vue-router'
import { useCanvasStore } from '../stores/canvas'
import { useProjectCanvasStore } from '../stores/projectCanvas'
const route = useRoute()
const canvasStore = useCanvasStore()
const projectCanvasStore = useProjectCanvasStore()
function clearCanvas() {
const container = document.getElementById('canvas-content')
if (container) {
container.innerHTML = `
<div class="canvas-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18"/>
<path d="M9 21V9"/>
</svg>
<p>Canvas listo</p>
<span>Claude Code puede renderizar contenido aquí</span>
</div>
`
}
}
function toggleHistory() {
canvasStore.toggleHistoryPanel()
}
function isCanvasActive(canvasId: string) {
return route.path === `/canvas/${canvasId}`
}
onMounted(() => {
projectCanvasStore.fetchToolbarCanvases()
})
</script>
<template>
<aside class="toolbar">
<!-- Navegacion principal -->
<div class="toolbar-section nav-section">
<RouterLink to="/" class="toolbar-btn" :class="{ active: route.path === '/' }" title="Home">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
</RouterLink>
<RouterLink to="/dynamic/canvas" class="toolbar-btn" :class="{ active: route.path === '/dynamic/canvas' }" title="Dynamic Canvas">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18"/>
<path d="M9 21V9"/>
</svg>
</RouterLink>
<!-- Canvas dinamicos de la toolbar -->
<RouterLink
v-for="canvas in projectCanvasStore.toolbarCanvases"
:key="canvas.id"
:to="`/canvas/${canvas.id}`"
class="toolbar-btn"
:class="{ active: isCanvasActive(canvas.id) }"
:title="canvas.name"
>
<span v-if="canvas.toolbar_icon" class="toolbar-emoji">{{ canvas.toolbar_icon }}</span>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18"/>
<path d="M9 21V9"/>
</svg>
</RouterLink>
</div>
<div class="toolbar-divider"></div>
<!-- Gestion -->
<div class="toolbar-section">
<RouterLink to="/projects" class="toolbar-btn" :class="{ active: route.path === '/projects' }" title="Proyectos">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
</svg>
</RouterLink>
<RouterLink to="/components" class="toolbar-btn" :class="{ active: route.path === '/components' }" title="Componentes">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
<polyline points="3.29 7 12 12 20.71 7"/>
<line x1="12" y1="22" x2="12" y2="12"/>
</svg>
</RouterLink>
<RouterLink to="/themes" class="toolbar-btn" :class="{ active: route.path === '/themes' }" title="Temas">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="13.5" cy="6.5" r="2.5"/>
<circle cx="19" cy="11.5" r="2.5"/>
<circle cx="17" cy="18.5" r="2.5"/>
<circle cx="8.5" cy="17.5" r="2.5"/>
<circle cx="5" cy="10.5" r="2.5"/>
<path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.93 0 1.82-.13 2.67-.36"/>
</svg>
</RouterLink>
<RouterLink to="/database" class="toolbar-btn" :class="{ active: route.path === '/database' }" title="Database">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<ellipse cx="12" cy="5" rx="9" ry="3"/>
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
<path d="M3 12c0 1.66 4 3 9 3s9-1.34 9-3"/>
</svg>
</RouterLink>
<RouterLink to="/source" class="toolbar-btn" :class="{ active: route.path === '/source' }" title="Source Code">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="16 18 22 12 16 6"/>
<polyline points="8 6 2 12 8 18"/>
</svg>
</RouterLink>
<RouterLink to="/terminal" class="toolbar-btn" :class="{ active: route.path === '/terminal' }" title="Terminal">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="4 17 10 11 4 5"/>
<line x1="12" y1="19" x2="20" y2="19"/>
</svg>
</RouterLink>
<RouterLink to="/tools" class="toolbar-btn" :class="{ active: route.path === '/tools' }" title="Tools">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
</svg>
</RouterLink>
</div>
<div class="toolbar-divider"></div>
<!-- Acciones -->
<div class="toolbar-section">
<button class="toolbar-btn" @click="clearCanvas" title="Limpiar canvas">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 6h18"/>
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/>
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
</svg>
</button>
<button class="toolbar-btn" @click="toggleHistory" title="Historial">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 8v4l3 3"/>
<circle cx="12" cy="12" r="10"/>
</svg>
</button>
</div>
</aside>
</template>
<style scoped>
.toolbar {
width: 56px;
background: var(--bg-secondary);
border-right: 1px solid var(--border-color);
padding: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.toolbar-section {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.toolbar-divider {
height: 1px;
background: var(--border-color);
margin: 0.25rem 0;
}
.toolbar-btn {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
border-radius: 8px;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.15s ease;
text-decoration: none;
}
.toolbar-btn:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.toolbar-btn:active {
transform: scale(0.95);
}
.toolbar-btn.active {
background: rgba(99, 102, 241, 0.15);
color: #6366f1;
}
.toolbar-emoji {
font-size: 1.25rem;
line-height: 1;
}
</style>