diff --git a/src/vcen-edit/App.svelte b/src/vcen-edit/App.svelte index f536d5f..2b68c07 100644 --- a/src/vcen-edit/App.svelte +++ b/src/vcen-edit/App.svelte @@ -1,78 +1,7 @@ -{#if loading} -
- Cargando... -
-{:else} -
- - -
- {#key activeCat.id} - - {/key} - - {#if saving} -
- Guardando... -
- {/if} -
-
-{/if} \ No newline at end of file + diff --git a/src/vcen-edit/canvas/Editor.svelte b/src/vcen-edit/canvas/Editor.svelte index f2aa05f..9b2ebde 100644 --- a/src/vcen-edit/canvas/Editor.svelte +++ b/src/vcen-edit/canvas/Editor.svelte @@ -1,44 +1,82 @@ + const oncancel = () => void {} -
- -
+ +{#if loading} +
+ Cargando... +
+{:else} +
+ - + {#if saving} +
+ Guardando... +
+ {/if} +
+ +{/if} \ No newline at end of file diff --git a/src/vcen-edit/comps/AttDetail.svelte b/src/vcen-edit/comps/AttDetail.svelte index c2028da..188574d 100644 --- a/src/vcen-edit/comps/AttDetail.svelte +++ b/src/vcen-edit/comps/AttDetail.svelte @@ -5,13 +5,13 @@ import type { EditorGlob } from '@/vcen-edit/lib/editor-glob.svelte.js' import { labelOf } from '@/vcen-edit/lib/label.ts' import type { AttDomain, ObjID, SecID, AttID } from '@/vcen/lib' import RuleList from './RuleList.svelte' -import DeleteButton from './DeleteButton.svelte' +import ButtonDelete from './ButtonDelete.svelte' import { buildEvalCtx, evalRuleSetState } from '@/vcen-edit/lib/rule-eval.ts' import { stateStatus } from '@/vcen-edit/lib/state-badge.ts' import { isValidId } from '@/vcen-edit/lib/validate' -import EntityIdName from './EntityIdName.svelte' +import InputIdName from './InputIdName.svelte' import Panel from './Panel.svelte' -import CountBadge from './CountBadge.svelte' +import BadgeCount from './BadgeCount.svelte' const editor = getContext('catalog-editor') const glob = getContext('editor-glob') @@ -221,10 +221,10 @@ function deleteAtt() { {:else} - {/if} {/snippet} @@ -234,7 +234,7 @@ function deleteAtt() {

{glob.t('vcen.editor.att.sectionId')}

-
{glob.t('vcen.editor.att.sectionRules')} - + {#if att.rules} diff --git a/src/vcen-edit/comps/CountBadge.svelte b/src/vcen-edit/comps/BadgeCount.svelte similarity index 100% rename from src/vcen-edit/comps/CountBadge.svelte rename to src/vcen-edit/comps/BadgeCount.svelte diff --git a/src/vcen-edit/comps/DeleteButton.svelte b/src/vcen-edit/comps/ButtonDelete.svelte similarity index 96% rename from src/vcen-edit/comps/DeleteButton.svelte rename to src/vcen-edit/comps/ButtonDelete.svelte index bae2527..09884f2 100644 --- a/src/vcen-edit/comps/DeleteButton.svelte +++ b/src/vcen-edit/comps/ButtonDelete.svelte @@ -1,7 +1,7 @@ @@ -116,35 +105,58 @@ const MOVE_BTN = 'flex items-center justify-center w-5 h-5 rounded cursor-pointe {glob.t('vcen.editor.sidebar.catSection')}
- - - - - - - + + editor.requestAction(() => editor.select({ kind: 'cat-info' }))} + isActive={sel.kind === 'cat-info'} + icon="info" + iconColor={ICON_COLOR} + label={glob.t('vcen.editor.sidebar.catInfo')} + class="flex items-center gap-1.5 px-3 cursor-pointer select-none transition-colors border-l-2 w-full pl-5 { + sel.kind === 'cat-info' + ? CSS_ITEM_ACTIVE + : CSS_ITEM_INACTIVE}" + /> + + editor.requestAction(() => editor.select({ kind: 'cat-atts' }))} + isActive={sel.kind === 'cat-atts'} + icon="att" + iconColor={ICON_COLOR} + label={glob.t('vcen.editor.sidebar.catAtts')} + class="flex items-center gap-1.5 px-3 cursor-pointer select-none transition-colors border-l-2 w-full pl-5 { + sel.kind === 'cat-atts' + ? CSS_ITEM_ACTIVE + : CSS_ITEM_INACTIVE}" + /> + + editor.requestAction(() => editor.select({ kind: 'cat-meta' }))} + isActive={sel.kind === 'cat-meta'} + icon="meta" + iconColor={ICON_COLOR} + label={glob.t('vcen.editor.sidebar.catMeta')} + class="flex items-center gap-1.5 px-3 cursor-pointer select-none transition-colors border-l-2 w-full pl-5 { + sel.kind === 'cat-meta' + ? CSS_ITEM_ACTIVE + : CSS_ITEM_INACTIVE}" + /> + + editor.requestAction(() => editor.select({ kind: 'cat-opts' }))} + isActive={sel.kind === 'cat-opts'} + icon="opt" + iconColor={ICON_COLOR} + label={glob.t('vcen.editor.sidebar.catOpts')} + class="flex items-center gap-1.5 px-3 cursor-pointer select-none transition-colors border-l-2 w-full pl-5 { + sel.kind === 'cat-opts' + ? CSS_ITEM_ACTIVE + : CSS_ITEM_INACTIVE}" + /> +
- editor.requestAction(() => editor.addObj())} @@ -175,6 +187,7 @@ const MOVE_BTN = 'flex items-center justify-center w-5 h-5 rounded cursor-pointe navigateToObj(obj.id)} icon="obj" + iconColor={ICON_COLOR} isActive={objActive} label={labelOf(obj.label, cat.lang) || glob.t('vcen.editor.sidebar.noName')} state={objState || undefined} @@ -216,6 +229,7 @@ const MOVE_BTN = 'flex items-center justify-center w-5 h-5 rounded cursor-pointe navigateToSec(obj.id, sec.id)} icon="sec" + iconColor={ICON_COLOR} isActive={secActive} label={labelOf(sec.label, cat.lang) || glob.t('vcen.editor.sidebar.noName')} state={secState || undefined} @@ -253,6 +267,7 @@ const MOVE_BTN = 'flex items-center justify-center w-5 h-5 rounded cursor-pointe navigateToView(obj.id, sec.id, view.id)} icon="view" + iconColor={ICON_COLOR} isActive={viewActive} label={getLabelStr(view.label) || view.code || view.id} /> @@ -277,6 +292,7 @@ const MOVE_BTN = 'flex items-center justify-center w-5 h-5 rounded cursor-pointe navigateToHotspot(obj.id, sec.id, view.id, hs.id) } icon="hotspot" + iconColor={ICON_COLOR} isActive={hsActive} label={getLabelStr(hs.label) || hs.id} class="pl-16" diff --git a/src/vcen-edit/comps/Icon.svelte b/src/vcen-edit/comps/Icon.svelte index e4fe6ea..94238cf 100644 --- a/src/vcen-edit/comps/Icon.svelte +++ b/src/vcen-edit/comps/Icon.svelte @@ -7,10 +7,12 @@ let { name, class: cls = '', strokeWidth = 1.5, + color = 'currentColor', }: { name: IconName class?: string strokeWidth?: number + color?: string } = $props() // Contenido interno SVG (viewBox 0 0 24 24, stroke="currentColor") @@ -95,7 +97,7 @@ const ICONS: Record = { /** - * EntityIdName — bloque de identificación normalizado: ID + Nombre. + * InputIdName — bloque de identificación normalizado: ID + Nombre. * - * Agrupa InputEntityID y LingInput (label "Nombre") en el orden canónico. + * Agrupa InputId y LingInput (label "Nombre") en el orden canónico. * Úsalo en todos los formularios de entidad como primer bloque. */ import type { LingRecord, LingString } from '@/ling/lib' import LingInput from '@/ling/svelte/LingInput.svelte' -import InputEntityID from './InputEntityID.svelte' +import InputId from './InputID.svelte' let { // ── ID ────────────────────────────────────────────────────────── @@ -60,7 +60,7 @@ let {
- ('catalog-editor') const glob = getContext('editor-glob') @@ -45,6 +45,6 @@ const ctx = $derived.by(() => { {#if ctx}
- +
{/if} diff --git a/src/vcen-edit/comps/DeleteModal.svelte b/src/vcen-edit/comps/ModalDelete.svelte similarity index 100% rename from src/vcen-edit/comps/DeleteModal.svelte rename to src/vcen-edit/comps/ModalDelete.svelte diff --git a/src/vcen-edit/comps/Panel.svelte b/src/vcen-edit/comps/Panel.svelte index d49c9ad..b1446c0 100644 --- a/src/vcen-edit/comps/Panel.svelte +++ b/src/vcen-edit/comps/Panel.svelte @@ -41,11 +41,11 @@ let {
{#if kind} - {kind} + {kind} {/if}

{title}

{#if subtitle} - {subtitle} + {subtitle} {/if}
diff --git a/src/vcen-edit/comps/CatAttsPanel.svelte b/src/vcen-edit/comps/PanelCatalogoAtts.svelte similarity index 95% rename from src/vcen-edit/comps/CatAttsPanel.svelte rename to src/vcen-edit/comps/PanelCatalogoAtts.svelte index 05fe134..3eb0743 100644 --- a/src/vcen-edit/comps/CatAttsPanel.svelte +++ b/src/vcen-edit/comps/PanelCatalogoAtts.svelte @@ -5,7 +5,7 @@ import type { EditorGlob } from '@/vcen-edit/lib/editor-glob.svelte.js' import { labelOf } from '@/vcen-edit/lib/label.ts' import AttDetail from './AttDetail.svelte' import SidebarTree from './SidebarTree.svelte' -import EditorButton from "@/vcen-edit/comps/EditorButton.svelte"; +import ButtonSidebar from "@/vcen-edit/comps/ButtonSidebar.svelte"; const editor = getContext('catalog-editor') const glob = getContext('editor-glob') @@ -19,13 +19,13 @@ const attId = $derived(sel.kind === 'cat-atts' ? sel.attId : undefined) editor.requestAction(() => editor.addCatAtt())}> {#if atts.length === 0} -
- + editor.requestAction(() => editor.addCatAtt())} > {glob.t('vcen.editor.attsPanel.addAtt')} - +
{:else} diff --git a/src/vcen-edit/comps/CatMetaPanel.svelte b/src/vcen-edit/comps/PanelCatalogoMeta.svelte similarity index 95% rename from src/vcen-edit/comps/CatMetaPanel.svelte rename to src/vcen-edit/comps/PanelCatalogoMeta.svelte index 8e6c806..0465433 100644 --- a/src/vcen-edit/comps/CatMetaPanel.svelte +++ b/src/vcen-edit/comps/PanelCatalogoMeta.svelte @@ -4,7 +4,8 @@ import type { CatalogEditorStore } from '@/vcen-edit/stores/catalog-editor.svelt import type { EditorGlob } from '@/vcen-edit/lib/editor-glob.svelte.js' import LingInput from '@/ling/svelte/LingInput.svelte' import Panel from './Panel.svelte' -import IssueSection from './IssueSection.svelte' +import SectionIssue from './SectionIssue.svelte' +import Tabs from './Tabs.svelte' const editor = getContext('catalog-editor') const glob = getContext('editor-glob') @@ -66,25 +67,16 @@ let catTab = $state<'info' | 'issues'>('info') - -
- {#each [ + {#snippet tabs()} + catTab = t as typeof catTab} tabs={[ { id: 'info', label: 'General' }, { id: 'issues', label: 'Incidencias' }, - ] as t (t.id)} - {@const isActive = catTab === t.id} - - {/each} -
+ ]} /> + {/snippet} {#if catTab === 'issues'}
- -{#if ctx?.hs} - {@const hs = ctx.hs} - {@const view = ctx.view!} +{#if ctx?.hs && ctx.view} + {@const hs = ctx.hs} + {@const view = ctx.view} {glob.t('vcen.editor.common.cancel')} {:else} - { if (ctx) editor.removeHotspot(ctx.objId, ctx.secId, ctx.viewId, ctx.hotspotId) }} + { if (ctx) editor.removeHotspot(ctx.objId, ctx.secId, ctx.viewId, ctx.hotspotId) }} /> {/if} {/snippet} @@ -147,7 +152,7 @@ function getLabelStr(label: any): string {
- patch({ label: v as LingRec })} + onNameUpdate={v => patch({ label: asLingRec(v) })} />
- - patch({ mode: asHotspotMode(e.currentTarget.value) })} class="field-input text-xs"> {#each HOTSPOT_MODES as m (m.value)} - + {/each}
- - {glob.t('vcen.editor.hotspot.targetAtt')} {glob.t('vcen.editor.common.optional')} + patch({ targetAtt: e.currentTarget.value ? toAttId(e.currentTarget.value) : undefined })} placeholder="at:color, sc:exterior/at:llantas…" class="field-input font-mono text-xs" /> @@ -199,15 +204,15 @@ function getLabelStr(label: any): string {
- - {glob.t('vcen.editor.hotspot.posX')} + patch({ posX: parseFloat(e.currentTarget.value) || 0 })} class="field-input text-xs" />
- - {glob.t('vcen.editor.hotspot.posY')} + patch({ posY: parseFloat(e.currentTarget.value) || 0 })} class="field-input text-xs" /> @@ -218,27 +223,27 @@ function getLabelStr(label: any): string {
- +
- patch({ color: e.currentTarget.value })} class="h-7 w-8 rounded border border-gray-700 bg-gray-800 cursor-pointer p-0.5" /> - patch({ color: e.currentTarget.value || undefined })} placeholder="#4f46e5" class="field-input font-mono text-xs flex-1 min-w-0" />
- - {glob.t('vcen.editor.hotspot.radius')} + patch({ radius: parseInt(e.currentTarget.value) || undefined })} placeholder="8" class="field-input text-xs" />
- - {glob.t('vcen.editor.hotspot.zIndex')} + patch({ zIndex: parseInt(e.currentTarget.value) || undefined })} placeholder="1" class="field-input text-xs" /> @@ -247,14 +252,17 @@ function getLabelStr(label: any): string {
- + patch({ tooltip: v && Object.keys(v).length ? v as LingRec : undefined })} + variant="dark" + onUpdate={v => patch({ tooltip: asLingRecOpt(v) })} placeholder="Texto al pasar el cursor…" /> + +
diff --git a/src/vcen-edit/comps/MetaPanel.svelte b/src/vcen-edit/comps/PanelMeta.svelte similarity index 100% rename from src/vcen-edit/comps/MetaPanel.svelte rename to src/vcen-edit/comps/PanelMeta.svelte diff --git a/src/vcen-edit/comps/ObjPanel.svelte b/src/vcen-edit/comps/PanelObject.svelte similarity index 91% rename from src/vcen-edit/comps/ObjPanel.svelte rename to src/vcen-edit/comps/PanelObject.svelte index 0c7e116..2cda7d5 100644 --- a/src/vcen-edit/comps/ObjPanel.svelte +++ b/src/vcen-edit/comps/PanelObject.svelte @@ -7,16 +7,16 @@ import { stateStatus } from '@/vcen-edit/lib/state-badge.ts' import { isValidId } from '@/vcen-edit/lib/validate' import type { LingRecord } from '@/ling/lib' import LingInput from '@/ling/svelte/LingInput.svelte' -import EntityIdName from './EntityIdName.svelte' +import InputIdName from './InputIdName.svelte' import Panel from './Panel.svelte' import RuleList from './RuleList.svelte' -import IssueSection from './IssueSection.svelte' -import ObjAttsPanel from './ObjAttsPanel.svelte' -import MetaPanel from './MetaPanel.svelte' -import VisualPanel from './VisualPanel.svelte' -import DeleteButton from './DeleteButton.svelte' -import PricingSection from './PricingSection.svelte' -import CountBadge from './CountBadge.svelte' +import SectionIssue from './SectionIssue.svelte' +import PanelObjectAtts from './PanelObjectAtts.svelte' +import PanelMeta from './PanelMeta.svelte' +import PanelVisual from './PanelVisual.svelte' +import ButtonDelete from './ButtonDelete.svelte' +import SectionPricing from './SectionPricing.svelte' +import BadgeCount from './BadgeCount.svelte' import Tabs from './Tabs.svelte' import { createEntityTabs, entityTabsArray } from '@/vcen-edit/lib/entity-tabs.svelte.ts' @@ -85,12 +85,12 @@ function cancelNew() { + {glob.t('vcen.editor.sidebar.newSec')} - editor.removeObj(objId)} + confirmTitle={glob.t('vcen.editor.obj.deleteTitle')} + confirmBody={labelOf(obj.label, cat.lang) || obj.id} + confirmWarning={glob.t('vcen.editor.obj.deleteWarn')} + onconfirm={() => editor.removeObj(objId)} /> {/if} {/snippet} @@ -121,7 +121,7 @@ function cancelNew() {

{glob.t('vcen.editor.entity.id')}

- - {:else if tab === 'atts'} - + {:else if tab === 'visual'}
-

{glob.t('vcen.editor.entity.rules')} - +

{#if obj.rules} @@ -216,7 +216,7 @@ function cancelNew() { {glob.t('vcen.editor.entity.issues')} ({obj.issues?.length ?? 0}) - - editor.updateObjMeta(objId, m)} /> diff --git a/src/vcen-edit/comps/ObjAttsPanel.svelte b/src/vcen-edit/comps/PanelObjectAtts.svelte similarity index 95% rename from src/vcen-edit/comps/ObjAttsPanel.svelte rename to src/vcen-edit/comps/PanelObjectAtts.svelte index 7c2e3dd..b16f515 100644 --- a/src/vcen-edit/comps/ObjAttsPanel.svelte +++ b/src/vcen-edit/comps/PanelObjectAtts.svelte @@ -5,7 +5,7 @@ import type { EditorGlob } from '@/vcen-edit/lib/editor-glob.svelte.js' import { labelOf } from '@/vcen-edit/lib/label.ts' import AttDetail from './AttDetail.svelte' import SidebarTree from './SidebarTree.svelte' -import EditorButton from "@/vcen-edit/comps/EditorButton.svelte"; +import ButtonSidebar from "@/vcen-edit/comps/ButtonSidebar.svelte"; const editor = getContext('catalog-editor') const glob = getContext('editor-glob') @@ -23,11 +23,11 @@ const ctx = $derived(sel.kind === 'obj-atts' editor.requestAction(() => editor.addAtt(objId, undefined))}> {#if obj.atts.length === 0}
- editor.requestAction(() => editor.addAtt(objId, undefined))} class="w-full"> {glob.t('vcen.editor.attsPanel.addAtt')} - +
diff --git a/src/vcen-edit/comps/OptDetail.svelte b/src/vcen-edit/comps/PanelOptionDetail.svelte similarity index 90% rename from src/vcen-edit/comps/OptDetail.svelte rename to src/vcen-edit/comps/PanelOptionDetail.svelte index 1dcbafd..a8be3b8 100644 --- a/src/vcen-edit/comps/OptDetail.svelte +++ b/src/vcen-edit/comps/PanelOptionDetail.svelte @@ -7,14 +7,15 @@ import type { LingRecord } from '@/ling/lib' import { labelOf } from '@/vcen-edit/lib/label.ts' import { isValidId } from '@/vcen-edit/lib/validate' import LingInput from '@/ling/svelte/LingInput.svelte' -import EntityIdName from './EntityIdName.svelte' +import InputIdName from './InputIdName.svelte' import Panel from './Panel.svelte' -import DeleteButton from './DeleteButton.svelte' -import PricingSection from './PricingSection.svelte' -import CountBadge from './CountBadge.svelte' -import MetaPanel from './MetaPanel.svelte' -import IssueSection from './IssueSection.svelte' +import ButtonDelete from './ButtonDelete.svelte' +import SectionPricing from './SectionPricing.svelte' +import BadgeCount from './BadgeCount.svelte' +import PanelMeta from './PanelMeta.svelte' +import SectionIssue from './SectionIssue.svelte' import RuleList from './RuleList.svelte' +import Tabs from './Tabs.svelte' const editor = getContext('catalog-editor') const glob = getContext('editor-glob') @@ -92,6 +93,14 @@ const usages = $derived.by(() => { }) const dummyContainer = $derived({ id: opt.id, label: optLabel, atts: [], secs: [] } as any) + +const OPT_TABS = $derived([ + { id: 'general', label: glob.t('vcen.editor.opt.tabs.general') }, + { id: 'usages', label: `${glob.t('vcen.editor.opt.tabs.usages')} (${usages.length})` }, + { id: 'rules', label: glob.t('vcen.editor.opt.tabs.rules') }, + { id: 'issues', label: glob.t('vcen.editor.opt.tabs.issues') }, + { id: 'meta', label: glob.t('vcen.editor.opt.tabs.meta') }, +]) {glob.t('vcen.editor.common.cancel')} {:else} - editor.removeOpt(opt.id)} + editor.removeOpt(opt.id)} /> {/if} {/snippet} {#snippet tabs()} -
- {#each ([ - { id: 'general', label: glob.t('vcen.editor.opt.tabs.general') }, - { id: 'usages', label: `${glob.t('vcen.editor.opt.tabs.usages')} (${usages.length})` }, - { id: 'rules', label: glob.t('vcen.editor.opt.tabs.rules') }, - { id: 'issues', label: glob.t('vcen.editor.opt.tabs.issues') }, - { id: 'meta', label: glob.t('vcen.editor.opt.tabs.meta') }, - ] as { id: typeof tab; label: string }[]) as t (t.id)} - - {/each} -
+ tab = t as typeof tab} tabs={OPT_TABS} /> {/snippet}
@@ -141,7 +136,7 @@ const dummyContainer = $derived({ id: opt.id, label: optLabel, atts: [], secs: [

{glob.t('vcen.editor.entity.id')}

-
- {glob.t('vcen.editor.entity.rules')} - + {#if opt.rules} - editor.removeSec(objId, secId)} + editor.removeSec(objId, secId)} /> {/if} {/snippet} @@ -120,7 +120,7 @@ function cancelNew() {

{glob.t('vcen.editor.entity.id')}

- - {:else if tab === 'atts'} - + {:else if tab === 'visual'}
-

{glob.t('vcen.editor.entity.rules')} - +

{#if sec.rules} @@ -215,7 +215,7 @@ function cancelNew() { {glob.t('vcen.editor.entity.issues')} ({sec.issues?.length ?? 0}) - - editor.updateSecMeta(objId, secId, m)} /> diff --git a/src/vcen-edit/comps/SecAttsPanel.svelte b/src/vcen-edit/comps/PanelSectionAtts.svelte similarity index 100% rename from src/vcen-edit/comps/SecAttsPanel.svelte rename to src/vcen-edit/comps/PanelSectionAtts.svelte diff --git a/src/vcen-edit/comps/ViewPanel.svelte b/src/vcen-edit/comps/PanelView.svelte similarity index 97% rename from src/vcen-edit/comps/ViewPanel.svelte rename to src/vcen-edit/comps/PanelView.svelte index ad2c940..942d5a8 100644 --- a/src/vcen-edit/comps/ViewPanel.svelte +++ b/src/vcen-edit/comps/PanelView.svelte @@ -8,13 +8,13 @@ import type { CatalogEditorStore } from '@/vcen-edit/stores/catalog-editor.svelt import type { EditorGlob } from '@/vcen-edit/lib/editor-glob.svelte.js' import { createConditionBuilderStore } from '@/vcen-edit/stores/condition-builder.svelte.js' import LingInput from '@/ling/svelte/LingInput.svelte' -import EntityIdName from './EntityIdName.svelte' +import InputIdName from './InputIdName.svelte' import Panel from './Panel.svelte' import ConditionBuilder from './ConditionBuilder.svelte' import TemplateBuilder from './TemplateBuilder.svelte' import VisualPreview from './VisualPreview.svelte' import IconPicker from './IconPicker.svelte' -import DeleteButton from './DeleteButton.svelte' +import ButtonDelete from './ButtonDelete.svelte' import TransactionEditor from './TransactionEditor.svelte' import type { LingRecord, LingString } from '@/ling/lib' import { buildScope } from '@/vcen-edit/lib/condition-editor.ts' @@ -264,11 +264,11 @@ function getLabelStr(label: any): string { - { if (ctx) editor.removeView(ctx.objId, ctx.secId, ctx.viewId) }} + { if (ctx) editor.removeView(ctx.objId, ctx.secId, ctx.viewId) }} /> {/if} {/snippet} @@ -277,7 +277,7 @@ function getLabelStr(label: any): string {
-
{glob.t('vcen.editor.view.paramN', { n: pi + 1 })} - removeApiParam(pi)} /> + removeApiParam(pi)} />
@@ -464,7 +464,7 @@ function getLabelStr(label: any): string { class="flex items-center justify-center w-5 h-5 rounded text-xs text-gray-600 hover:text-gray-300 hover:bg-gray-700 transition-colors disabled:opacity-20 disabled:pointer-events-none">↑ - removeLayer(li)} /> + removeLayer(li)} />
diff --git a/src/vcen-edit/comps/VisualPanel.svelte b/src/vcen-edit/comps/PanelVisual.svelte similarity index 98% rename from src/vcen-edit/comps/VisualPanel.svelte rename to src/vcen-edit/comps/PanelVisual.svelte index 5a10cff..b8ed376 100644 --- a/src/vcen-edit/comps/VisualPanel.svelte +++ b/src/vcen-edit/comps/PanelVisual.svelte @@ -8,10 +8,10 @@ import type { CatalogEditorStore } from '@/vcen-edit/stores/catalog-editor.s import type { EditorGlob } from '@/vcen-edit/lib/editor-glob.svelte.js' import { createConditionBuilderStore } from '@/vcen-edit/stores/condition-builder.svelte.js' import LingInput from '@/ling/svelte/LingInput.svelte' -import EntityIdName from './EntityIdName.svelte' +import InputIdName from './InputIdName.svelte' import ConditionBuilder from './ConditionBuilder.svelte' import TemplateBuilder from './TemplateBuilder.svelte' -import DeleteButton from './DeleteButton.svelte' +import ButtonDelete from './ButtonDelete.svelte' import { buildScope } from '@/vcen-edit/lib/condition-editor.ts' import { isValidId } from '@/vcen-edit/lib/validate' @@ -736,18 +736,18 @@ $effect(() => { {:else} - removeView(view.id)} + removeView(view.id)} /> {/if}
- { {glob.t('vcen.editor.view.paramN', { n: pi + 1 })} - removeApiParam(view.id, pi)} + removeApiParam(view.id, pi)} />
@@ -992,10 +992,10 @@ $effect(() => { class="flex items-center justify-center w-5 h-5 rounded text-xs text-gray-600 hover:text-gray-300 hover:bg-gray-700 transition-colors disabled:opacity-20 disabled:pointer-events-none">↓ - removeLayer(view.id, li)} + removeLayer(view.id, li)} />
@@ -1098,17 +1098,17 @@ $effect(() => { {:else} - removeHotspot(view.id, hs.id)} + removeHotspot(view.id, hs.id)} /> {/if}
- ('catalog-editor') const glob = getContext('editor-glob') @@ -161,10 +161,10 @@ const actionSummary = $derived.by(() => { - editor.removeRule(ruleSet, rule.id)} + editor.removeRule(ruleSet, rule.id)} />
diff --git a/src/vcen-edit/comps/IssueSection.svelte b/src/vcen-edit/comps/SectionIssue.svelte similarity index 97% rename from src/vcen-edit/comps/IssueSection.svelte rename to src/vcen-edit/comps/SectionIssue.svelte index fb90299..b5352af 100644 --- a/src/vcen-edit/comps/IssueSection.svelte +++ b/src/vcen-edit/comps/SectionIssue.svelte @@ -10,8 +10,8 @@ import { EDITOR_ICON_MAP } from '@/vcen-edit/lib/editor-icons.ts' import LingInput from '@/ling/svelte/LingInput.svelte' import ConditionBuilder from './ConditionBuilder.svelte' import IconPicker from './IconPicker.svelte' -import DeleteButton from './DeleteButton.svelte' -import DeleteModal from './DeleteModal.svelte' +import ButtonDelete from './ButtonDelete.svelte' +import ModalDelete from './ModalDelete.svelte' const editor = getContext('catalog-editor') const glob = getContext('editor-glob') @@ -203,10 +203,10 @@ function moveDown(idx: number) { onclick={() => isEditing ? cancelEdit() : openEdit(idx)} class="ve-card-btn" >{isEditing ? glob.t('vcen.editor.issue.closeBtn') : glob.t('vcen.editor.issue.editBtn')} - remove(idx)} + remove(idx)} />
diff --git a/src/vcen-edit/comps/SectionPricing.svelte b/src/vcen-edit/comps/SectionPricing.svelte new file mode 100644 index 0000000..1347a0e --- /dev/null +++ b/src/vcen-edit/comps/SectionPricing.svelte @@ -0,0 +1,65 @@ + + +
+
+ {glob.t('vcen.editor.entity.pricing')} + {#if pricing} + + {:else} + + {/if} +
+ {#if pricing} + {@const p = pricing} +
+
+ +
+ {#if p.baseAmount === 'consultation'} + {glob.t('vcen.editor.entity.consultation')} + {:else} + onUpdate({ ...p, baseAmount: parseFloat(e.currentTarget.value) || 0 })} + class="field-input text-xs flex-1" /> + {/if} + +
+
+
+ + +
+
+ {:else} +

{glob.t('vcen.editor.entity.noBasePricing')}

+ {/if} +
diff --git a/src/vcen-edit/comps/SidebarTree.svelte b/src/vcen-edit/comps/SidebarTree.svelte index 06a3063..3f02867 100644 --- a/src/vcen-edit/comps/SidebarTree.svelte +++ b/src/vcen-edit/comps/SidebarTree.svelte @@ -1,6 +1,6 @@ + + +
+ +
{ if (value) open = !open }} + onkeydown={e => { if (e.key === 'Enter' && value) open = !open }} + class="flex items-center gap-2 px-3 py-2 select-none {value ? 'cursor-pointer hover:bg-gray-800/40' : ''} transition-colors" + > + {#if value} + + {/if} + + {glob.t('vcen.editor.transaction.section')} + + {#if value} + {value.name || '—'} + {value.duration}ms + + {:else} + {glob.t('vcen.editor.transaction.noTransaction')} + + {/if} +
+ + + {#if value && open} +
+ +
+ +
+ + + {#if selectedDef?.description} + {selectedDef.description} + {/if} +
+ + +
+ + patch({ duration: Number(e.currentTarget.value) || 0 })} + placeholder="400" + class="field-input text-xs" + /> +
+
+ +
+ +
+ + +
+ + + {#if hasDirection} +
+ + +
+ {/if} +
+ +
+ +
+ + patch({ delayIn: Number(e.currentTarget.value) || undefined })} + placeholder="0" + class="field-input text-xs" + /> +
+ + +
+ + patch({ delayOut: Number(e.currentTarget.value) || undefined })} + placeholder="0" + class="field-input text-xs" + disabled={value.persistent === true} + /> +
+
+ + + + +
+ {/if} + +
diff --git a/src/vcen-edit/comps/VisualPreview.svelte b/src/vcen-edit/comps/VisualPreview.svelte new file mode 100644 index 0000000..d3545cb --- /dev/null +++ b/src/vcen-edit/comps/VisualPreview.svelte @@ -0,0 +1,351 @@ + + +
+ +
+ preview + {STRATEGY_LABELS[strategy] ?? strategy} +
+ +
+ + + +
+ {#if strategy === 'static' && staticUrl} + {#if !imgError} + {getLabelStr(view.label) imgLoaded = true} onerror={() => imgError = true} /> + {:else} +
+ + + + {glob.t('vcen.editor.view.imgLoadError')} + {staticUrl} +
+ {/if} + + {:else if strategy === 'dynamic' && resolvedUrl} + {#if !imgError} + {getLabelStr(view.label) imgLoaded = true} onerror={() => imgError = true} /> + {:else} +
+ + + + {glob.t('vcen.editor.view.imgLoadError')} + {resolvedUrl} +
+ {/if} + {#if resolution?.hasFallback} +
fallback
+ {/if} + + {:else if strategy === 'layers' && resolvedLayers.length > 0} + {#each resolvedLayers as layer, li (li)} + {#if !hiddenLayers.has(li)} + {glob.t('vcen.editor.view.layerN', + {/if} + {/each} + {#if resolution?.hasFallback} +
fallback
+ {/if} + + {:else if strategy === 'layers' && layers.length === 0} +
+ + + + {glob.t('vcen.editor.view.noLayers')} +
+ + {:else if strategy === 'dynamic'} +
+ + + + {#if dynTpl} + {dynTpl} + {:else} + {glob.t('vcen.editor.view.noTemplate')} + {/if} +
+ + {:else if strategy === 'api'} + {#if apiEp && !imgError} + {getLabelStr(view.label) imgLoaded = true} onerror={() => imgError = true} /> + {:else if apiEp && imgError} +
+ + + + {glob.t('vcen.editor.view.imgLoadError')} + {apiEp} +
+ {:else} +
+ + + + {glob.t('vcen.editor.view.noEndpoint')} +
+ {/if} + + {:else if strategy === 'd3'} +
+ + + + {#if d3Model} + {d3Model} + {:else} + {glob.t('vcen.editor.view.noModel')} + {/if} +
+ + {:else} +
+ + + + {pickingPos ? glob.t('vcen.editor.hotspot.clickToPosition') : glob.t('vcen.editor.view.noImage')} +
+ {/if} + + + {#each (view.hotspots ?? []) as marker (marker.id)} + {@const isActive = activeHotspotId === marker.id} + {@const mX = typeof marker.posX === 'number' ? marker.posX : parseFloat(String(marker.posX)) || 0} + {@const mY = typeof marker.posY === 'number' ? marker.posY : parseFloat(String(marker.posY)) || 0} + {@const size = (marker.radius ?? 8) * 2} +
+ {/each} + + + {#if showLayersPanel} + + +
e.stopPropagation()} + > + + + + {#if layersPanelOpen} +
+ {#if resolvedLayers.length > 0} + + {#each sortedLayerIndices as li (li)} + {@const layer = resolvedLayers[li]} + {@const hidden = hiddenLayers.has(li)} + + {/each} + {:else} + + {#each [...layers].sort((a, b) => (b.zIndex ?? 0) - (a.zIndex ?? 0)) as layer, li (li)} +
+ + + + + z{layer.zIndex ?? 0} + {layer.attId || '—'} + {#if layer.condition} + if + {/if} +
+ {/each} + {/if} +
+ {/if} +
+ {/if} + +
+ + +
+
+ {view.width || '?'} × {view.height || '?'} px + {#if pickingPos} + {glob.t('vcen.editor.hotspot.clickToPosition')} + {/if} +
+ {#if resolvedUrl || (strategy === 'static' && staticUrl)} + {resolvedUrl || staticUrl} + {/if} +
+ +
+
diff --git a/src/vcen-edit/demos/InputEntityIDDemo.svelte b/src/vcen-edit/demos/InputEntityIDDemo.svelte index 01496ba..ad8cc45 100644 --- a/src/vcen-edit/demos/InputEntityIDDemo.svelte +++ b/src/vcen-edit/demos/InputEntityIDDemo.svelte @@ -1,6 +1,6 @@