Initial commit
This commit is contained in:
225
docs/css-js-conventions.md
Normal file
225
docs/css-js-conventions.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# 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
|
||||
|
||||
Usar TailwindCSS como método principal. Solo CSS custom cuando Tailwind no cubra el estilo o se necesiten estados complejos/transiciones específicas.
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
### BEM para CSS Custom
|
||||
|
||||
Cuando se necesite CSS personalizado, siempre scopeado bajo la clase raíz con BEM:
|
||||
|
||||
```css
|
||||
.hero-section { }
|
||||
.hero-section__title { }
|
||||
.hero-section__image { }
|
||||
.hero-section--dark { }
|
||||
```
|
||||
|
||||
Nunca usar clases globales sin prefijo de módulo.
|
||||
|
||||
### CSS Variables del tema
|
||||
|
||||
```css
|
||||
var(--main-color) /* Color de marca primario */
|
||||
var(--main-color-light) /* Variante clara */
|
||||
var(--main-color-dark) /* Variante oscura */
|
||||
```
|
||||
|
||||
### Estilos inline con fallbacks
|
||||
|
||||
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` | 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`)
|
||||
|
||||
JavaScript scopeado al módulo usando `section_id`:
|
||||
|
||||
```js
|
||||
const section = document.getElementById('{{ section_id }}');
|
||||
if (section) {
|
||||
const buttons = section.querySelectorAll('.btn');
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### CmsApi (Client-Side)
|
||||
|
||||
```js
|
||||
CmsApi.hook('/hooks/module_id/', { action: 'getData', id: 123 }, function(response) {
|
||||
console.log(response);
|
||||
});
|
||||
```
|
||||
|
||||
### Cuándo usar Vue 3
|
||||
|
||||
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 }}">
|
||||
<p>${ message }</p>
|
||||
<button @click="increment">${ count }</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const { createApp, ref } = Vue;
|
||||
createApp({
|
||||
delimiters: ['${', '}'], // Evitar conflicto con Twig {{ }}
|
||||
setup() {
|
||||
const message = ref('Hello');
|
||||
const count = ref(0);
|
||||
const increment = () => count.value++;
|
||||
return { message, count, increment };
|
||||
}
|
||||
}).mount('#app-{{ section_id }}');
|
||||
</script>
|
||||
```
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user