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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user