Files
acai-scaffold/docs/builder-fields.md
Jordan 963174b4c4 Add complete Acai development documentation
- CLAUDE.md: expanded with critical rules, hook syntax, DB conventions, web-base endpoint
- docs/modular-system.md: modules, general sections, global vars, multiv2
- docs/builder-fields.md: all field types, c-if/c-for/c-class, c-form, built-in components
- docs/twig-filters.md: get, hook, module, queryDB, imagec, translate, raw, etc.
- docs/hooks-and-api.md: PHP hooks, CmsApi CRUD, table schemas, field formats
- docs/css-js-conventions.md: Tailwind, BEM, CSS vars, Vue 3 integration, CmsApi JS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:53:10 +00:00

214 lines
5.1 KiB
Markdown

# Builder Fields & Acai Attributes
## Field Types (`data-field-type`)
The builder uses `data-field-type` attributes on HTML elements to define editable areas.
| 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
```html
<{{ title_tag | default('h2') }} data-field-type="headfield" class="text-3xl font-bold">
Section Title
</{{ title_tag | default('h2') }}>
```
### upload Example
```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>
```
### list Example
```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>
```
## Acai Attributes
### `c-if` — Conditional Rendering
```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 -->
<div c-if="subtitle">{{ subtitle }}</div>
```
### `c-else`
Must immediately follow the `c-if` element:
```html
<div c-if="image">
<img src="{{ image[0].urlPath }}" />
</div>
<div c-else>
<p>No image available</p>
</div>
```
### `c-for` — Iteration
```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
```html
<div c-class="{ 'bg-blue-500': isActive, 'text-white': isActive, 'hidden': !showElement }">
Content
</div>
```
### `c-hidden` — Hidden Elements
Element is not rendered but can declare builder variables:
```html
<div c-hidden="true">
<input data-field-type="textfield" value="default config value" />
</div>
```
### `c-required` — Conditional Required Fields
```html
<input type="text" name="company" c-required="userType = 'business'" />
```
## Forms (`c-form`)
Complete form handling with automatic validation, storage, and email sending.
```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"
>
<input type="text" name="nombre" required placeholder="Nombre" />
<input type="email" name="email" required placeholder="Email" />
<textarea name="mensaje" required placeholder="Mensaje"></textarea>
<captcha/>
<button type="submit">Enviar</button>
</form>
```
### c-form Attributes
| 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 |
## Built-in Components
### Carousel (`c-tns-wrapper`)
```html
<div class="c-tns-wrapper"
data-responsive='{"0":1,"768":2,"1024":3}'
data-speed="400"
data-nav="true"
data-autoplay-timeout="3000">
<div c-for="slide in record.slides">
<img src="{{ slide.image[0].urlPath }}" />
</div>
</div>
```
### Lightbox
```html
<a href="{{ image[0].urlPath }}" class="glightbox" data-gallery="gallery1">
<img src="{{ image[0].urlPath | imagec(400) }}" />
</a>
```
### Breadcrumb
```html
<breadCrumb/>
```
### Animate On Scroll (AOS)
```html
<div data-aos="fade-up" data-aos-delay="200">
Animated content
</div>
```
### Lazy Loading
```html
<img class="lazyload" data-src="{{ image[0].urlPath }}" />
<!-- or -->
<img data-lazy="true" src="{{ image[0].urlPath }}" />
```