feat: Auto-save components, soft delete, tags, compact WCO header

- Auto-save rendered Vue components to DB on render_vue_component
- Soft delete (archive) instead of hard delete for components
- Tags support for component categorization
- Gallery limited to 10 most recent items per section
- Upsert with ON CONFLICT for component saves
- PUT endpoint for partial component updates
- Collapsible toolbar with animated toggle button
- Window Controls Overlay support for PWA titlebar
- Compact header mode (32px) with hidden dot toggle
- Dynamic theme-color meta sync for Windows titlebar
This commit is contained in:
2026-02-15 02:54:27 -06:00
parent 8154bac63f
commit 9f9f335439
10 changed files with 401 additions and 84 deletions

View File

@@ -38,13 +38,15 @@ const editIcon = ref('')
const editOrder = ref(99)
const filteredCanvases = computed(() => {
const list = showArchived.value ? store.canvases : store.activeCanvasesList
if (!searchQuery.value) return list
const q = searchQuery.value.toLowerCase()
return list.filter(c =>
c.name.toLowerCase().includes(q) ||
(c.description && c.description.toLowerCase().includes(q))
)
let list = showArchived.value ? store.canvases : store.activeCanvasesList
if (searchQuery.value) {
const q = searchQuery.value.toLowerCase()
list = list.filter(c =>
c.name.toLowerCase().includes(q) ||
(c.description && c.description.toLowerCase().includes(q))
)
}
return list.slice(0, 10)
})
const filteredSnapshots = computed(() => {
@@ -168,7 +170,7 @@ async function loadComponent(comp: VueComponentDefinition) {
async function fetchComponents() {
try {
savedComponents.value = await componentsApi.getAll()
savedComponents.value = await componentsApi.getAll({ limit: 10 })
} catch {
savedComponents.value = []
}
@@ -432,10 +434,14 @@ onMounted(() => {
<div class="card-content">
<div class="card-name">{{ comp.name }}</div>
<div class="card-desc card-id">{{ comp.id }}</div>
<div v-if="comp.tags?.length" class="card-tags">
<span v-for="tag in comp.tags" :key="tag" class="tag-pill">{{ tag }}</span>
</div>
</div>
<div class="card-meta">
<span class="card-badge component">componente</span>
<span v-if="comp.status === 'archived'" class="card-badge archived-badge">Archivado</span>
</div>
<!-- Loading overlay -->
@@ -955,4 +961,20 @@ onMounted(() => {
.new-btn.cancel:hover {
background: var(--border-color);
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
margin-top: 0.375rem;
}
.tag-pill {
padding: 0.0625rem 0.375rem;
background: rgba(99, 102, 241, 0.1);
color: #818cf8;
border-radius: 999px;
font-size: 0.625rem;
font-weight: 500;
}
</style>