diff --git a/src/glob/tests/glob.test.ts b/src/glob/tests/glob.test.ts
index d5d96e5..c6869bf 100644
--- a/src/glob/tests/glob.test.ts
+++ b/src/glob/tests/glob.test.ts
@@ -41,7 +41,9 @@ function makeGlob(locale = 'es') {
numr : { minDecimals: 0, maxDecimals: 2 },
curr : { definitions: currDefinitions, selectedCurrency: 'EUR' },
dati : { selectedTimeFormat: '24h' },
- unit : { selectedSystem: 'metric' },
+ unit : {
+ selectedSystem: 'metric'
+ },
});
}
diff --git a/src/mtas/lib/translations.ts b/src/mtas/lib/translations.ts
new file mode 100644
index 0000000..6a38f7b
--- /dev/null
+++ b/src/mtas/lib/translations.ts
@@ -0,0 +1,132 @@
+import type { LingRecord } from '@/ling/lib';
+import { p } from '@/ling/lib';
+
+/**
+ * Traducciones del editor de metadata.
+ * Namespace: vcen.editor.mtas
+ *
+ * Para registrar en ling:
+ * ling.extend('vcen', { editor: { mtas: mtasTranslations } })
+ *
+ * Los componentes reciben la instancia glob completa:
+ *
+ *
+ * Y acceden a las traducciones via:
+ * glob.t('vcen.editor.mtas.header.title')
+ * glob.t('vcen.editor.mtas.field.nestedCount', { count: 3 })
+ * glob.numr.f(1234.5)
+ * glob.curr.f(99.5)
+ * glob.dati.f(new Date('2024-01-15'))
+ */
+export const translations = {
+
+ // ── Tipos de campo ────────────────────────────────────────────────
+ types: {
+ string: { es: 'Texto', en: 'Text' } satisfies LingRecord,
+ number: { es: 'Número', en: 'Number' } satisfies LingRecord,
+ boolean: { es: 'Bool', en: 'Bool' } satisfies LingRecord,
+ ling: { es: 'i18n', en: 'i18n' } satisfies LingRecord,
+ date: { es: 'Fecha', en: 'Date' } satisfies LingRecord,
+ datetime: { es: 'DateTime', en: 'DateTime' } satisfies LingRecord,
+ url: { es: 'URL', en: 'URL' } satisfies LingRecord,
+ currency: { es: 'Moneda', en: 'Currency' } satisfies LingRecord,
+ image: { es: 'Imagen', en: 'Image' } satisfies LingRecord,
+ video: { es: 'Vídeo', en: 'Video' } satisfies LingRecord,
+ audio: { es: 'Audio', en: 'Audio' } satisfies LingRecord,
+ pdf: { es: 'PDF', en: 'PDF' } satisfies LingRecord,
+ file: { es: 'Fichero', en: 'File' } satisfies LingRecord,
+ html: { es: 'HTML', en: 'HTML' } satisfies LingRecord,
+ group: { es: 'Grupo', en: 'Group' } satisfies LingRecord,
+ },
+
+ // ── Grupos del menú ───────────────────────────────────────────────
+ typeGroups: {
+ text: { es: 'Texto', en: 'Text' } satisfies LingRecord,
+ number: { es: 'Número', en: 'Number' } satisfies LingRecord,
+ date: { es: 'Fecha', en: 'Date' } satisfies LingRecord,
+ logical: { es: 'Lógico', en: 'Boolean' } satisfies LingRecord,
+ media: { es: 'Media', en: 'Media' } satisfies LingRecord,
+ group: { es: 'Grupo', en: 'Group' } satisfies LingRecord,
+ },
+
+ // ── Encabezado ────────────────────────────────────────────────────
+ header: {
+ title: { es: 'Metadata', en: 'Metadata' } satisfies LingRecord,
+ addField: { es: 'Añadir', en: 'Add' } satisfies LingRecord,
+ addFieldTitle: { es: 'Añadir campo', en: 'Add field' } satisfies LingRecord,
+ fieldCount: p({
+ es: { one: '{{count}} campo', other: '{{count}} campos' },
+ en: { one: '{{count}} field', other: '{{count}} fields' },
+ }),
+ },
+
+ // ── Validación ────────────────────────────────────────────────────
+ validation: {
+ valid: { es: 'Válido', en: 'Valid' } satisfies LingRecord,
+ errorsTitle: { es: 'Errores de validación', en: 'Validation errors' } satisfies LingRecord,
+ errorCount: p({
+ es: { one: '{{count}} error', other: '{{count}} errores' },
+ en: { one: '{{count}} error', other: '{{count}} errors' },
+ }),
+ },
+
+ // ── Fila de campo ─────────────────────────────────────────────────
+ field: {
+ moveUp: { es: 'Subir', en: 'Move up' } satisfies LingRecord,
+ moveDown: { es: 'Bajar', en: 'Move down' } satisfies LingRecord,
+ edit: { es: 'Editar', en: 'Edit' } satisfies LingRecord,
+ delete: { es: 'Eliminar', en: 'Delete' } satisfies LingRecord,
+ expand: { es: 'Expandir', en: 'Expand' } satisfies LingRecord,
+ collapse: { es: 'Colapsar', en: 'Collapse' } satisfies LingRecord,
+ hidden: { es: 'oculto', en: 'hidden' } satisfies LingRecord,
+ fieldValid: { es: 'Campo válido', en: 'Valid field' } satisfies LingRecord,
+ fieldInvalid: { es: 'Campo inválido', en: 'Invalid field' } satisfies LingRecord,
+ boolTrue: { es: 'Verdadero', en: 'True' } satisfies LingRecord,
+ boolFalse: { es: 'Falso', en: 'False' } satisfies LingRecord,
+ empty: { es: 'Usa el botón Añadir para crear campos', en: 'Use the Add button to create fields' } satisfies LingRecord,
+ emptyGroup: { es: 'Grupo vacío — añade campos con el botón +', en: 'Empty group — add fields with the + button' } satisfies LingRecord,
+ nestedCount: p({
+ es: { one: '{{count}} campo anidado', other: '{{count}} campos anidados' },
+ en: { one: '{{count}} nested field', other: '{{count}} nested fields' },
+ }),
+ },
+
+ // ── Editor de campo ───────────────────────────────────────────────
+ editor: {
+ keyLabel: { es: 'Clave del campo', en: 'Field key' } satisfies LingRecord,
+ keyPlaceholder: { es: 'nombre_campo', en: 'field_name' } satisfies LingRecord,
+ keyEmpty: { es: 'La clave no puede estar vacía', en: 'Key cannot be empty' } satisfies LingRecord,
+ keyExists: { es: '"{{key}}" ya existe', en: '"{{key}}" already exists' } satisfies LingRecord,
+ hideField: { es: 'Ocultar campo', en: 'Hide field' } satisfies LingRecord,
+ valueLing: { es: 'Valor multiidioma', en: 'Multilingual value' } satisfies LingRecord,
+ valueHtml: { es: 'Contenido HTML', en: 'HTML content' } satisfies LingRecord,
+ amountLabel: { es: 'Importe', en: 'Amount' } satisfies LingRecord,
+ currencyLabel: { es: 'Divisa', en: 'Currency' } satisfies LingRecord,
+ mediaUrlLabel: { es: 'URL del recurso', en: 'Resource URL' } satisfies LingRecord,
+ },
+
+ // ── Drawer ────────────────────────────────────────────────────────
+ drawer: {
+ title: { es: 'Añadir campo', en: 'Add field' } satisfies LingRecord,
+ cancel: { es: 'Cancelar', en: 'Cancel' } satisfies LingRecord,
+ confirm: { es: 'Añadir campo', en: 'Add field' } satisfies LingRecord,
+ },
+
+ // ── Paginación ────────────────────────────────────────────────────
+ pagination: {
+ rowsPerPage: { es: 'Filas por página', en: 'Rows per page' } satisfies LingRecord,
+ all: { es: 'Todos', en: 'All' } satisfies LingRecord,
+ prevPage: { es: 'Página anterior', en: 'Previous page' } satisfies LingRecord,
+ nextPage: { es: 'Página siguiente', en: 'Next page' } satisfies LingRecord,
+ pageN: { es: 'Página {{page}}', en: 'Page {{page}}' } satisfies LingRecord,
+ range: { es: '{{from}}–{{to}} de {{total}}', en: '{{from}}–{{to}} of {{total}}' } satisfies LingRecord,
+ },
+
+ // ── LingInput ─────────────────────────────────────────────────────
+ lingInput: {
+ requiredLocale: { es: 'El campo {{locale}} es obligatorio', en: 'The {{locale}} field is required' } satisfies LingRecord,
+ },
+
+} as const;
+
+export type Translations = typeof translations;
diff --git a/src/mtas/svelte/components/AddFieldDrawer.svelte b/src/mtas/svelte/components/AddFieldDrawer.svelte
index 45124a6..f7f2e4d 100644
--- a/src/mtas/svelte/components/AddFieldDrawer.svelte
+++ b/src/mtas/svelte/components/AddFieldDrawer.svelte
@@ -158,5 +158,5 @@
-
+
diff --git a/src/mtas/svelte/components/AddFieldMenu.svelte b/src/mtas/svelte/components/AddFieldMenu.svelte
new file mode 100644
index 0000000..b0a5e44
--- /dev/null
+++ b/src/mtas/svelte/components/AddFieldMenu.svelte
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+ {#each typeGroups as group}
+
+ {group.label}
+ {#each group.types as type}
+
+ {/each}
+
+ {/each}
+
+
+
\ No newline at end of file
diff --git a/src/mtas/svelte/components/FieldRow.svelte b/src/mtas/svelte/components/FieldRow.svelte
index 77c8a18..ffc0005 100644
--- a/src/mtas/svelte/components/FieldRow.svelte
+++ b/src/mtas/svelte/components/FieldRow.svelte
@@ -5,6 +5,7 @@
import FieldEditor from './FieldEditor.svelte';
import FieldRowRecursive from './FieldRow.svelte';
import AddFieldDrawer from "@/mtas/svelte/components/AddFieldDrawer.svelte";
+ import AddFieldMenu from "@/mtas/svelte/components/AddFieldMenu.svelte";
let {
fieldKey, field, locales, defaultLocale,
@@ -150,7 +151,7 @@
id="field-row-{fieldKey}"
class={[
'card bg-base-100 border transition-all duration-150 flex-row focus-within:border-base-content w-full',
- depth > 0 ? 'ml-5' : '',
+ depth > 0 ? 'w-full' : '',
!validationResult.valid ? 'border-error'
: expanded ? 'border-base-300 shadow-sm'
: 'border-base-200 hover:border-base-300',
@@ -224,7 +225,7 @@