Ajustes del scaffold

This commit is contained in:
Jordan
2026-03-23 21:34:03 +00:00
parent 53dde9eb92
commit db90dfaca2
9 changed files with 2400 additions and 319 deletions

View File

@@ -1,63 +1,78 @@
# CSS & JavaScript Conventions
## Estructura del módulo
- Genera HTML + CSS + JS (o Vue 3 si es necesario)
- Define una clase raíz en kebab-case: `product-card`, `hero-section`, etc.
- Todo el CSS y JS scopeado bajo esa clase raíz
---
## CSS
### Tailwind First
Use Tailwind CSS as the primary styling method. Only use custom CSS when Tailwind is insufficient.
Usar TailwindCSS como método principal. Solo CSS custom cuando Tailwind no cubra el estilo o se necesiten estados complejos/transiciones específicas.
```html
<!-- Good: Tailwind classes -->
<div class="flex items-center gap-4 p-6 bg-white rounded-lg shadow-md">
<h2 class="text-2xl font-bold text-gray-900">Title</h2>
</div>
<!-- Custom CSS only when needed (animations, complex selectors, etc.) -->
```
### BEM for Custom CSS
### BEM para CSS Custom
When custom CSS is needed, scope everything under a root class using BEM naming:
Cuando se necesite CSS personalizado, siempre scopeado bajo la clase raíz con BEM:
```css
/* Root class in kebab-case */
.hero-section { }
.hero-section__title { }
.hero-section__image { }
.hero-section--dark { }
```
Never use global classes without a module prefix.
Nunca usar clases globales sin prefijo de módulo.
### CSS Variables
Acai provides theme variables:
### CSS Variables del tema
```css
var(--main-color) /* Primary brand color */
var(--main-color-light) /* Lighter variant */
var(--main-color-dark) /* Darker variant */
var(--main-color) /* Color de marca primario */
var(--main-color-light) /* Variante clara */
var(--main-color-dark) /* Variante oscura */
```
### Utility Classes (Built-in)
### Estilos inline con fallbacks
| Class | Description |
Patrón para colores configurables por el usuario:
```html
<div style="background-color: {{ colordefondo ? colordefondo : 'transparent' }}">
<p style="color: {{ colordeltexto ? colordeltexto : '#111827' }}">
```
### Clases utilitarias de Acai
| Clase | Descripción |
|-------|-------------|
| `transition3s` | 0.3s smooth transition |
| `click-a-child` | Makes parent clickable via child `<a>` tag |
| `line-clamp2` / `line-clamp3` / `line-clamp5` | Text truncation with ellipsis |
| `filter-white` | CSS filter to make images/icons white |
| `lazyload` | Lazy loading (use with `data-src`) |
| `transition3s` | Transición suave 0.3s |
| `click-a-child` | Hace el padre clickeable via primer `<a>` hijo |
| `line-clamp2` / `line-clamp3` / `line-clamp5` | Truncar texto a N líneas |
| `filter-white` | Filtro CSS para hacer imágenes/iconos blancos |
| `lazyload` | Lazy loading (usar con `data-src`) |
| `text-shadow` | Sombra de texto para legibilidad sobre imágenes |
| `wysiwyg` | Wrapper para contenido de texto enriquecido |
| `bg-main-color` / `bg-main-color-light` / `bg-main-color-dark` | Fondos con color primario |
| `text-main-color` / `text-main-color-light` / `text-main-color-dark` | Texto con color primario |
---
## JavaScript
### Module Scripts (`script.js`)
Keep JavaScript scoped to the module. Use `section_id` for targeting:
JavaScript scopeado al módulo usando `section_id`:
```js
// Scope to this module instance
const section = document.getElementById('{{ section_id }}');
if (section) {
const buttons = section.querySelectorAll('.btn');
@@ -68,15 +83,23 @@ if (section) {
### CmsApi (Client-Side)
```js
// Call a hook
CmsApi.hook('/hooks/module_id/', { action: 'getData', id: 123 }, function(response) {
console.log(response);
});
```
### Vue 3 Integration
### Cuándo usar Vue 3
For complex interactivity, use Vue 3 via CDN with Composition API:
Usar Vue 3 CDN cuando la lógica requiera:
- Doble binding / reactividad
- Solicitudes asíncronas complejas
- Componentes reutilizables
- Gestión de estado local
- Ciclos de vida
Para lógica simple, usar JavaScript vanilla.
### Vue 3 Integration
```html
<div id="app-{{ section_id }}">
@@ -87,7 +110,7 @@ For complex interactivity, use Vue 3 via CDN with Composition API:
<script>
const { createApp, ref } = Vue;
createApp({
delimiters: ['${', '}'], // Avoid conflict with Twig {{ }}
delimiters: ['${', '}'], // Evitar conflicto con Twig {{ }}
setup() {
const message = ref('Hello');
const count = ref(0);
@@ -98,4 +121,105 @@ createApp({
</script>
```
**Important:** Use `'${'` and `'}'` as Vue delimiters to avoid conflicts with Twig's `{{ }}` syntax.
Siempre usar `'${'` y `'}'` como delimitadores Vue para evitar conflicto con Twig.
---
## Variables Globales Disponibles
| Variable | Descripción | Ejemplo |
|----------|-------------|---------|
| `section_id` | ID único por instancia del módulo | `<div id="{{section_id}}">` |
| `server.HTTP_HOST` | Dominio actual | `https://{{ server.HTTP_HOST }}/path` |
| `loop.index` | Índice de iteración (1-based) en c-for/for | `{{ loop.index }}` |
| `loop.index is odd` | True en iteraciones impares | Layouts alternados |
| `loop.index is even` | True en iteraciones pares | Patrones zigzag |
| `interno` | True dentro del editor CMS | `c-class="{'editor-mode': interno}"` |
### Patrón section_id
Cada instancia de módulo recibe un `section_id` único. Usar para navigation anchor e IDs:
```html
<div id="{{section_id}}"></div>
<section id="id_{{ section_id }}" class="relative">
<!-- contenido del módulo -->
</section>
```
---
## Componentes Nativos
### Carousel (`c-tns-wrapper`)
```html
<div class="c-tns-wrapper" data-responsive="sm:2, md:3, lg:4" data-speed="1000" data-nav="true">
<ul class="c-tns-container">
<li data-field-type="multiv2" data-field-label="Slides" class="px-2">
<!-- contenido del slide -->
</li>
</ul>
</div>
```
| Atributo | Descripción | Ejemplo |
|----------|-------------|---------|
| `data-responsive` | Items por breakpoint | `"sm:2, md:3, lg:4"` |
| `data-autoplay-timeout` | Intervalo autoplay (ms) | `"5000"` |
| `data-mode` | Modo de transición | `"gallery"` o `"carousel"` |
| `data-speed` | Velocidad de transición (ms) | `"400"` |
| `data-nav` | Puntos de navegación | `"true"` |
Dots de navegación custom:
```html
<div class="c-tns-nav-container absolute bottom-4 left-0 w-full flex justify-center items-end z-20">
<div c-for="item in records"
class="pointer-events-auto cursor-pointer rounded-full border-2 border-white w-4 h-4 mx-1 bg-black bg-opacity-50">
</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 class="bg-gray-200 p-3 rounded" c-prevlinks="null"></breadCrumb>
```
### AOS (Animate On Scroll)
```html
<div data-aos="fade-up" data-aos-duration="800">Contenido</div>
```
Valores comunes: `fade-up`, `fade-down`, `fade-left`, `fade-right`, `zoom-in`, `zoom-in-up`, `fade-up-right`, `fade-up-left`
Después de cambios dinámicos: `AOS.refresh()` en JavaScript.
### Lazy Loading
```html
<!-- Builder var con lazy loading -->
<img data-field-type="upload" data-field-label="Imagen" data-lazy="true" data-field-width="800" alt="">
<!-- Manual en templates -->
<img class="lazyload" data-src="{{ record.imagen[0].urlPath | imagec(800) }}" alt="">
```
---
## Buenas prácticas
- HTML/Twig semántico
- Código limpio y organizado
- Evitar dependencias externas innecesarias
- Evitar estilos inline salvo casos justificados (colores dinámicos del usuario)
- No usar clases globales sin prefijo de módulo