Ajustes del scaffold
This commit is contained in:
@@ -1,77 +1,196 @@
|
||||
# Builder Fields & Acai Attributes
|
||||
|
||||
## Nombres de variables
|
||||
|
||||
El atributo `data-field-label` se convierte a variable removiendo espacios y caracteres especiales (minúsculas).
|
||||
|
||||
| Label | Variable |
|
||||
|-------|----------|
|
||||
| Categoría Noticia | `categoranoticia` |
|
||||
| Color Principal | `colorprincipal` |
|
||||
| Título Producto | `ttuloproducto` |
|
||||
|
||||
---
|
||||
|
||||
## Field Types (`data-field-type`)
|
||||
|
||||
The builder uses `data-field-type` attributes on HTML elements to define editable areas.
|
||||
| Type | Element | Returns |
|
||||
|------|---------|---------|
|
||||
| `textfield` | `<p>` | String |
|
||||
| `headfield` | `<h1>`-`<h6>` | String + variable `_tag` con la etiqueta elegida |
|
||||
| `textbox` | `<div>` | String multi-línea |
|
||||
| `wysiwyg` | `<div class="wysiwyg">` | HTML string |
|
||||
| `link` | `<a>` | URL string (ya incluye barras) |
|
||||
| `upload` | `<img>` | **Array** de `{urlPath, info1, info2, info3, info4}` |
|
||||
| `uploadMulti` | `<li>` | Itera sobre archivos subidos |
|
||||
| `list` (fijo) | `<div data-list-options="...">` | Valor seleccionado |
|
||||
| `list` (tabla) | `<div data-list-table="...">` | `num` del registro |
|
||||
| `multiv2` | `<li>` wrapper | Array de objetos |
|
||||
|
||||
| Type | Description | Returns |
|
||||
|------|-------------|---------|
|
||||
| `textfield` | Single line text | String |
|
||||
| `headfield` | Heading text (generates `_tag` variable for semantic tag: h1-h6) | String |
|
||||
| `textbox` | Multi-line text | String |
|
||||
| `wysiwyg` | Rich text editor (HTML output) | HTML string |
|
||||
| `link` | URL field (already includes slashes) | String |
|
||||
| `upload` | Single image/file | Array: `[0].urlPath`, `[0].info1` (alt), `[0].info2-4` |
|
||||
| `uploadMulti` | Multiple images | Iterable: `item.urlPath` |
|
||||
| `list` | Dropdown (fixed options or from table) | String or foreign key num |
|
||||
| `multiv2` | Repeatable group of fields | Array of objects |
|
||||
|
||||
### headfield Example
|
||||
### textfield
|
||||
|
||||
```html
|
||||
<{{ title_tag | default('h2') }} data-field-type="headfield" class="text-3xl font-bold">
|
||||
Section Title
|
||||
<p data-field-type="textfield" data-field-label="Título">
|
||||
Elemento editable
|
||||
</p>
|
||||
```
|
||||
|
||||
### headfield
|
||||
|
||||
Genera 2 variables: la estándar y otra con sufijo `_tag` con la etiqueta elegida por el usuario.
|
||||
|
||||
```html
|
||||
<{{ title_tag | default('h2') }} data-field-type="headfield" data-field-label="Título Sección" class="text-3xl font-bold">
|
||||
Título de la sección
|
||||
</{{ title_tag | default('h2') }}>
|
||||
```
|
||||
|
||||
### upload Example
|
||||
### textbox
|
||||
|
||||
```html
|
||||
<!-- Single image -->
|
||||
<img data-field-type="upload"
|
||||
src="{{ image[0].urlPath }}"
|
||||
alt="{{ image[0].info1 }}"
|
||||
class="w-full rounded" />
|
||||
|
||||
<!-- Multiple images -->
|
||||
<div c-for="photo in gallery">
|
||||
<img src="{{ photo.urlPath }}" alt="{{ photo.info1 }}" />
|
||||
<div data-field-type="textbox" data-field-label="Descripción">
|
||||
Texto largo editable
|
||||
</div>
|
||||
```
|
||||
|
||||
### list Example
|
||||
### wysiwyg
|
||||
|
||||
```html
|
||||
<!-- Fixed options -->
|
||||
<select data-field-type="list" data-list-options="option1,option2,option3">
|
||||
<option>option1</option>
|
||||
</select>
|
||||
|
||||
<!-- From table -->
|
||||
<select data-field-type="list" data-list-table="categories" data-list-field="name">
|
||||
<option>Category</option>
|
||||
</select>
|
||||
<div class="wysiwyg" data-field-type="wysiwyg" data-field-label="Contenido Enriquecido">
|
||||
<p>Texto con <strong>estilos</strong> editables</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### link
|
||||
|
||||
```html
|
||||
<a data-field-type="link" data-field-label="Enlace Principal" href="#">
|
||||
Haz clic aquí
|
||||
</a>
|
||||
```
|
||||
|
||||
### upload
|
||||
|
||||
```html
|
||||
<div class="p-1/6 relative">
|
||||
<img
|
||||
class="absolute top-0 left-0 w-full h-full object-cover object-center lazyload"
|
||||
data-field-type="upload"
|
||||
data-field-label="Imagen Principal"
|
||||
data-lazy="true"
|
||||
data-field-info1="titulo"
|
||||
data-field-width="1400"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
```
|
||||
|
||||
Atributos disponibles:
|
||||
- `data-lazy="true"`: Carga perezosa
|
||||
- `data-field-width="1400"`: Ancho máximo sugerido
|
||||
- `data-field-info1="titulo"`: Campo de información adicional (usado como alt)
|
||||
|
||||
Acceso en Twig: `{{ imagen[0].urlPath }}`, `{{ imagen[0].info1 }}`
|
||||
|
||||
### uploadMulti
|
||||
|
||||
Itera sobre todas las imágenes subidas:
|
||||
|
||||
```html
|
||||
<li data-field-type="uploadMulti" data-field-label="Galería" data-field-info1="titulo">
|
||||
<div class="relative min-h-screen">
|
||||
<img class="absolute top-0 left-0 w-full h-full object-cover lazyload"
|
||||
data-src="{{ uploadMulti.urlPath | imagec(2100) }}"
|
||||
alt="{{ uploadMulti.info1 }}">
|
||||
</div>
|
||||
</li>
|
||||
```
|
||||
|
||||
### list (opciones fijas)
|
||||
|
||||
```html
|
||||
<div
|
||||
data-field-type="list"
|
||||
data-field-label="Color Producto"
|
||||
data-list-options="Rojo,Azul,|Verde,3|Amarillo"
|
||||
>
|
||||
</div>
|
||||
```
|
||||
|
||||
Formato de opciones: `opcion1,opcion2,|opcion3,valor3|opcion4`
|
||||
|
||||
### list (tabla)
|
||||
|
||||
```html
|
||||
<div
|
||||
data-field-type="list"
|
||||
data-field-label="Noticia Destacada"
|
||||
data-list-table="noticias"
|
||||
data-list-value="num"
|
||||
data-list-label="titulo"
|
||||
>
|
||||
{{ record.titulo }}
|
||||
</div>
|
||||
```
|
||||
|
||||
- `data-list-table`: Nombre de tabla sin prefijo `cms_`
|
||||
- `data-list-value`: Campo a usar como valor (generalmente `num`)
|
||||
- `data-list-label`: Campo a mostrar como label
|
||||
|
||||
### multiv2 — Campos repetibles
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li data-field-type="multiv2" data-field-label="Productos">
|
||||
<div data-field-type="textfield" data-field-label="Nombre">
|
||||
Nombre del producto
|
||||
</div>
|
||||
<div data-field-type="textbox" data-field-label="Descripción">
|
||||
Descripción del producto
|
||||
</div>
|
||||
<div class="p-1/6 relative">
|
||||
<img
|
||||
class="absolute top-0 left-0 w-full h-full object-cover lazyload"
|
||||
data-field-type="upload"
|
||||
data-field-label="Imagen"
|
||||
data-lazy="true"
|
||||
data-field-width="800"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
Uso en Twig — las variables son propiedades del objeto iterado:
|
||||
|
||||
```twig
|
||||
{% for record in productos %}
|
||||
<div class="producto">
|
||||
<h3>{{ record.nombre }}</h3>
|
||||
<p>{{ record.descripcion }}</p>
|
||||
<img src="{{ record.imagen[0].urlPath }}" alt="">
|
||||
</div>
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acai Attributes
|
||||
|
||||
### `c-if` — Conditional Rendering
|
||||
### `c-if` — Renderizado condicional
|
||||
|
||||
```html
|
||||
<!-- Boolean check -->
|
||||
<div c-if="showBanner">Banner content</div>
|
||||
|
||||
<!-- Equality check (uses = not ==) -->
|
||||
<div c-if="layout = 'grid'">Grid layout</div>
|
||||
|
||||
<!-- Variable exists / is not empty -->
|
||||
<!-- Verificar existencia de variable -->
|
||||
<div c-if="subtitle">{{ subtitle }}</div>
|
||||
|
||||
<!-- Comparación de valores (usa = no ==) -->
|
||||
<div c-if="layout = 'grid'">Grid layout</div>
|
||||
```
|
||||
|
||||
### `c-else`
|
||||
|
||||
Must immediately follow the `c-if` element:
|
||||
Debe ir inmediatamente después del elemento `c-if`:
|
||||
|
||||
```html
|
||||
<div c-if="image">
|
||||
@@ -82,91 +201,173 @@ Must immediately follow the `c-if` element:
|
||||
</div>
|
||||
```
|
||||
|
||||
### `c-for` — Iteration
|
||||
### `c-for` — Iteración sobre array
|
||||
|
||||
```html
|
||||
<!-- Over array/multiv2 -->
|
||||
<div c-for="item in record.features">
|
||||
<h3>{{ item.title }}</h3>
|
||||
</div>
|
||||
|
||||
<!-- Over database table -->
|
||||
<div c-for="product in products" c-where="active = 1" c-order="orden ASC" c-limit="6">
|
||||
<h3>{{ product.nombre }}</h3>
|
||||
</div>
|
||||
```
|
||||
|
||||
Available inside loop: `loop.index` (1-based), `loop.index is odd`, `loop.index is even`
|
||||
|
||||
### `c-class` — Dynamic CSS Classes
|
||||
### `c-for` — Iteración sobre tabla de BD
|
||||
|
||||
```html
|
||||
<div c-class="{ 'bg-blue-500': isActive, 'text-white': isActive, 'hidden': !showElement }">
|
||||
Content
|
||||
</div>
|
||||
<ul>
|
||||
<li c-for="producto in productos" c-where="'visible=1'" c-order="'num desc'" c-limit="10">
|
||||
{{ producto.title }}
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
### `c-hidden` — Hidden Elements
|
||||
Parámetros opcionales: `c-where` (condición SQL), `c-order` (orden), `c-limit` (límite).
|
||||
|
||||
Element is not rendered but can declare builder variables:
|
||||
Equivalente en Twig:
|
||||
```twig
|
||||
{% for producto in 'productos' | get('visible=1','num desc',10) %}
|
||||
<li>{{ producto.title }}</li>
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
Dentro del loop: `loop.index` (1-based), `loop.index is odd`, `loop.index is even`
|
||||
|
||||
### `c-class` — Clases CSS condicionales
|
||||
|
||||
```html
|
||||
<!-- Simple -->
|
||||
<div c-class="{ 'text-center': alineacion == '1', 'text-right': alineacion == '2' }">
|
||||
|
||||
<!-- Múltiples condiciones -->
|
||||
<div c-class="{
|
||||
'flex-row-reverse': orden == '1',
|
||||
'cursor-pointer click-a-child': record.enlace_anchor,
|
||||
'rounded-xl': radioborde == '4'
|
||||
}">
|
||||
|
||||
<!-- Con expresiones Twig (loop) -->
|
||||
<div c-class="{
|
||||
'md:order-1': loop.index is odd,
|
||||
'md:pl-6': loop.index is even
|
||||
}">
|
||||
|
||||
<!-- Combinado con clases estáticas -->
|
||||
<div class="flex items-center" c-class="{ 'justify-center': centrado }">
|
||||
```
|
||||
|
||||
### `c-hidden` — Elementos ocultos
|
||||
|
||||
Elemento que no se renderiza pero puede declarar variables builder:
|
||||
|
||||
```html
|
||||
<div c-hidden="true">
|
||||
<input data-field-type="textfield" value="default config value" />
|
||||
<input data-field-type="textfield" data-field-label="Config" value="default" />
|
||||
</div>
|
||||
```
|
||||
|
||||
### `c-required` — Conditional Required Fields
|
||||
### `c-required` — Campos requeridos condicionales
|
||||
|
||||
```html
|
||||
<input type="text" name="company" c-required="userType = 'business'" />
|
||||
<input type="text" name="telefono" c-required="'2' not in camposquitar" placeholder="Teléfono">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Forms (`c-form`)
|
||||
|
||||
Complete form handling with automatic validation, storage, and email sending.
|
||||
## Definiendo variables con `<set>`
|
||||
|
||||
```html
|
||||
<form c-form
|
||||
tableName="'contacto'"
|
||||
mailRecord="['correos', 'CONTACTO']"
|
||||
sendTo="'admin@domain.com'"
|
||||
sendToClient="'email'"
|
||||
captcha="true"
|
||||
honeypot="true"
|
||||
messageOK="'Mensaje enviado correctamente'"
|
||||
messageKO="'Error al enviar el mensaje'"
|
||||
redirect="'/gracias/'"
|
||||
attachFiles="true"
|
||||
showImages="true"
|
||||
<!-- Obtener configuración de la BD -->
|
||||
<set :tienda="'configuracion_tienda' | get('num != 0')[0]"></set>
|
||||
|
||||
<!-- Construir URLs dinámicas -->
|
||||
<set :logo="tienda.logo.0.urlPath ? 'https://' ~ server.HTTP_HOST ~ tienda.logo.0.urlPath : 'https://' ~ server.HTTP_HOST ~ '/template/estandar/images/logo.png'"></set>
|
||||
|
||||
<!-- Twig set para expresiones complejas -->
|
||||
{% set gracias = 'apartados' | get('num = 20').0 %}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Incluyendo módulos
|
||||
|
||||
Para incluir un módulo dentro de otro módulo o sección general, usa el ID del módulo como etiqueta HTML:
|
||||
|
||||
```html
|
||||
<module_id :param1="value1" :param2="value2"></module_id>
|
||||
```
|
||||
|
||||
Ejemplo:
|
||||
```html
|
||||
<header_menu :showLogo="true" :menuItems="items"></header_menu>
|
||||
<product_card :product="selectedProduct" :showPrice="true"></product_card>
|
||||
```
|
||||
|
||||
El módulo hijo recibe los parámetros como variables en su contexto.
|
||||
|
||||
---
|
||||
|
||||
## Formularios (`c-form`)
|
||||
|
||||
Manejo automático de validación, almacenamiento en BD y envío de emails.
|
||||
|
||||
```html
|
||||
<c-form
|
||||
class="max-w-2xl mx-auto p-6 bg-white rounded-lg shadow"
|
||||
tableName="'solicitudes'"
|
||||
mailRecord="['correos', 'CONTACTO']"
|
||||
sendTo="'contacto@empresa.com'"
|
||||
sendToClient="'email'"
|
||||
captcha="true"
|
||||
honeypot="true"
|
||||
messageOK="'¡Gracias! Te contactaremos pronto'"
|
||||
messageKO="'Por favor, completa todos los campos'"
|
||||
redirect="'/gracias'"
|
||||
attachFiles="true"
|
||||
>
|
||||
<input type="text" name="nombre" required placeholder="Nombre" />
|
||||
<input type="email" name="email" required placeholder="Email" />
|
||||
<textarea name="mensaje" required placeholder="Mensaje"></textarea>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Nombre</label>
|
||||
<input name="nombre" type="text" class="w-full p-2 border rounded" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Email</label>
|
||||
<input name="email" type="text" class="w-full p-2 border rounded" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Mensaje</label>
|
||||
<textarea name="mensaje" class="w-full p-2 border rounded" rows="5" required></textarea>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="flex items-center">
|
||||
<input name="acepto_politica" type="checkbox" class="mr-2" required>
|
||||
<span>Acepto la política de privacidad</span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="bg-teal-500 text-white px-6 py-2 rounded hover:bg-teal-600">Enviar</button>
|
||||
<captcha/>
|
||||
<button type="submit">Enviar</button>
|
||||
</form>
|
||||
</c-form>
|
||||
```
|
||||
|
||||
### c-form Attributes
|
||||
### Atributos de c-form
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `tableName="'table'"` | Store submissions in database table |
|
||||
| `mailRecord="['correos', 'ID']"` | Email template from `correos` table |
|
||||
| `sendTo="'email@domain.com'"` | Recipient email(s), comma-separated |
|
||||
| `sendToClient="'fieldname'"` | Field containing client's email for auto-reply |
|
||||
| `captcha="true"` | Enable Google reCAPTCHA |
|
||||
| `honeypot="true"` | Anti-spam hidden field |
|
||||
| `messageOK="'text'"` | Success message |
|
||||
| `messageKO="'text'"` | Error message |
|
||||
| `redirect="'/path/'"` | Redirect after successful submit |
|
||||
| `attachFiles="true"` | Attach uploaded files to email |
|
||||
| `showImages="true"` | Show image thumbnails in email |
|
||||
| Atributo | Descripción |
|
||||
|----------|-------------|
|
||||
| `tableName="'table'"` | Tabla donde almacenar registros |
|
||||
| `mailRecord="['correos', 'ID']"` | Template de email de la tabla `correos` |
|
||||
| `sendTo="'email@domain.com'"` | Destinatarios (separados por coma) |
|
||||
| `sendToClient="'campo_email'"` | Campo con email del cliente para auto-reply |
|
||||
| `captcha="true"` | Google reCAPTCHA |
|
||||
| `honeypot="true"` | Campo oculto anti-spam |
|
||||
| `messageOK="'texto'"` | Mensaje de éxito |
|
||||
| `messageKO="'texto'"` | Mensaje de error |
|
||||
| `redirect="'/path/'"` | Redirección tras envío exitoso |
|
||||
| `attachFiles="true"` | Adjuntar archivos al email |
|
||||
| `showImages="true"` | Mostrar thumbnails en email |
|
||||
| `emailMode="'twig'"` | Email en formato Twig |
|
||||
| `header="'<div>...</div>'"` | HTML cabecera del email |
|
||||
| `footer="'<div>...</div>'"` | HTML footer del email |
|
||||
| `styles="'body { ... }'"` | CSS para el email |
|
||||
|
||||
---
|
||||
|
||||
## Built-in Components
|
||||
## Componentes Built-in
|
||||
|
||||
### Carousel (`c-tns-wrapper`)
|
||||
|
||||
@@ -208,6 +409,18 @@ Complete form handling with automatic validation, storage, and email sending.
|
||||
|
||||
```html
|
||||
<img class="lazyload" data-src="{{ image[0].urlPath }}" />
|
||||
<!-- or -->
|
||||
<!-- o -->
|
||||
<img data-lazy="true" src="{{ image[0].urlPath }}" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Puntos importantes
|
||||
|
||||
1. **Nombres de variables:** `data-field-label` → sin espacios ni caracteres especiales, minúsculas
|
||||
2. **Variables en multiv2:** Son propiedades del objeto iterado (`record.nombre`)
|
||||
3. **Campos upload:** Retornan arrays, no strings (`imagen[0].urlPath`, no `imagen`)
|
||||
4. **c-if usa `=` no `==`:** `c-if="layout = 'grid'"` (un solo igual)
|
||||
5. **c-for tabla:** El nombre de tabla va sin prefijo `cms_`
|
||||
6. **Enlace:** Ya incluye barras, no añadir extras
|
||||
7. **Checkbox:** Valores `1` o `0`, no `true`/`false`
|
||||
|
||||
Reference in New Issue
Block a user