You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
v/src/vcen-edit/comps/SecAttsPanel.svelte

126 lines
5.4 KiB

<script lang="ts">
import { getContext } from 'svelte'
import type { CatalogEditorStore } from '@/vcen-edit/stores/catalog-editor.svelte.js'
import { labelOf } from '@/vcen-edit/lib/label.ts'
import AttDetail from './AttDetail.svelte'
import SidebarTree from './SidebarTree.svelte'
const editor = getContext<CatalogEditorStore>('catalog-editor')
const sel = $derived(editor.selection)
const cat = $derived(editor.cat)
const ctx = $derived(sel.kind === 'sec-atts'
? { objId: sel.objId, secId: sel.secId, sec: editor.findSec(sel.objId, sel.secId), attId: sel.attId }
: null)
let creating = $state(false)
let newAttName = $state('')
let newAttSlug = $state('')
let attSlugError = $state('')
function slugify(text: string): string {
return text.toLowerCase()
.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')
}
function confirmAdd() {
if (!ctx?.sec) return
const slug = newAttSlug.trim()
if (!slug) { attSlugError = 'El ID es obligatorio'; return }
if (editor.isAttSlugTaken(slug)) { attSlugError = 'ID ya existe'; return }
editor.addAtt(ctx.objId, ctx.secId, newAttName.trim() || 'Atributo', slug)
creating = false; newAttName = ''; newAttSlug = ''; attSlugError = ''
}
function cancelAdd() {
creating = false; newAttName = ''; newAttSlug = ''; attSlugError = ''
}
</script>
{#if ctx?.sec}
{@const { objId, secId, sec, attId } = ctx}
<div class="flex h-full">
<SidebarTree title="Atributos" count={sec.atts.length} onAdd={() => { creating = true; newAttName = '' }}>
{#if sec.atts.length === 0 && !creating}
<div class="px-4 py-6 text-center text-gray-700 text-xs italic">
Sin atributos
<button
onclick={() => { creating = true; newAttName = '' }}
class="block mx-auto mt-2 px-3 py-1 rounded border border-dashed border-gray-700
text-gray-600 hover:text-indigo-400 hover:border-indigo-700 transition-colors"
>Añadir atributo</button>
</div>
{:else}
{#each sec.atts as att (att.id)}
{@const isActive = attId === att.id}
<button
onclick={() => editor.select({ kind: 'sec-atts', objId, secId, attId: att.id })}
class="w-full text-left px-4 py-2 flex items-center justify-between
cursor-pointer transition-colors border-l-2
{isActive ? 'bg-gray-800 border-blue-500' : 'border-transparent hover:bg-gray-800'}"
>
<span class="text-sm truncate flex-1 {isActive ? 'text-gray-100' : 'text-gray-300'}">
{labelOf(att.label, cat.lang) || 'Sin nombre'}
</span>
<div class="flex items-center gap-1 shrink-0 ml-2">
<span class="text-xs px-1 py-0.5 rounded bg-gray-800 text-gray-500 border border-gray-700">
{att.value.domain.kind}
</span>
{#if att.rules?.rules?.length}
<span class="text-xs text-blue-400" title="Tiene reglas">⚡</span>
{/if}
</div>
</button>
{/each}
{/if}
{#if creating}
<div class="px-3 py-2 border-t border-gray-800 bg-gray-900/60 flex flex-col gap-1.5 mt-1">
<input
type="text"
bind:value={newAttName}
oninput={e => { if (!newAttSlug || newAttSlug === slugify(newAttName.slice(0,-1))) newAttSlug = slugify(e.currentTarget.value) }}
placeholder="Nombre del atributo"
class="field-input text-xs"
autofocus
/>
<div class="flex items-center gap-1">
<span class="text-[10px] text-gray-600 shrink-0">at:</span>
<input
type="text"
bind:value={newAttSlug}
oninput={() => { attSlugError = '' }}
onkeydown={e => { if (e.key === 'Enter') confirmAdd(); if (e.key === 'Escape') cancelAdd() }}
placeholder="slug-atributo"
class="field-input text-xs font-mono flex-1"
/>
</div>
{#if attSlugError}
<p class="text-[10px] text-red-400">{attSlugError}</p>
{/if}
<div class="flex gap-1">
<button onclick={confirmAdd}
class="flex-1 px-2 py-1 text-xs rounded bg-indigo-600 hover:bg-indigo-500 text-white transition-colors">
Añadir
</button>
<button onclick={cancelAdd}
class="px-2 py-1 text-xs rounded border border-gray-700 text-gray-500 hover:text-gray-300 transition-colors">
✕
</button>
</div>
</div>
{/if}
</SidebarTree>
<!-- Att detail -->
<div class="flex-1 overflow-auto">
{#if attId}
<AttDetail />
{:else}
<div class="flex items-center justify-center h-full text-gray-600 text-sm">
Selecciona un atributo para editarlo
</div>
{/if}
</div>
</div>
{/if}

Powered by TurnKey Linux.