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>
This commit is contained in:
@@ -1,32 +1,213 @@
|
||||
# Builder Fields & Attributes
|
||||
# Builder Fields & Acai Attributes
|
||||
|
||||
## Field Types (`data-field-type`)
|
||||
|
||||
The builder uses `data-field-type` attributes to define editable areas in module templates.
|
||||
The builder uses `data-field-type` attributes on HTML elements to define editable areas.
|
||||
|
||||
<!-- TODO: Document available field types (text, image, richtext, link, repeater, etc.) -->
|
||||
| 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>
|
||||
```
|
||||
|
||||
|
||||
## Conditional Attributes
|
||||
## Acai Attributes
|
||||
|
||||
### `c-if`
|
||||
### `c-if` — Conditional Rendering
|
||||
|
||||
<!-- TODO: Document c-if syntax and usage for conditional rendering -->
|
||||
```html
|
||||
<!-- Boolean check -->
|
||||
<div c-if="showBanner">Banner content</div>
|
||||
|
||||
### `c-for`
|
||||
<!-- Equality check (uses = not ==) -->
|
||||
<div c-if="layout = 'grid'">Grid layout</div>
|
||||
|
||||
<!-- TODO: Document c-for syntax for repeating elements -->
|
||||
<!-- Variable exists / is not empty -->
|
||||
<div c-if="subtitle">{{ subtitle }}</div>
|
||||
```
|
||||
|
||||
### `c-class`
|
||||
### `c-else`
|
||||
|
||||
<!-- TODO: Document c-class for conditional CSS classes -->
|
||||
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`)
|
||||
|
||||
<!-- TODO: Document c-form usage for builder-integrated forms -->
|
||||
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 |
|
||||
|
||||
|
||||
## Builder Variables Access
|
||||
## Built-in Components
|
||||
|
||||
<!-- TODO: Document how to access and use builder variables in templates -->
|
||||
### 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 }}" />
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user