@davidbc01/telar 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -9
- package/dist/carrito.html +31 -0
- package/dist/entrar.html +36 -0
- package/dist/generador-js.d.ts +16 -0
- package/dist/generador-js.d.ts.map +1 -0
- package/dist/generador-js.js +306 -0
- package/dist/generador-js.js.map +1 -0
- package/dist/generador.d.ts.map +1 -1
- package/dist/generador.js +6 -0
- package/dist/generador.js.map +1 -1
- package/dist/index.html +42 -0
- package/dist/producto-(id).html +38 -0
- package/dist/telar.css +118 -0
- package/dist/telar.js +251 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ aplicación MiTienda
|
|
|
28
28
|
## Instalación
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
npm install -g telar
|
|
31
|
+
npm install -g @davidbc01/telar
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
O clona el repositorio para desarrollar:
|
|
@@ -106,26 +106,32 @@ Telar compila a HTML + CSS + JavaScript optimizados. El desarrollador nunca toca
|
|
|
106
106
|
| Lexer - tokenización | ✅ Completo |
|
|
107
107
|
| Parser - validador de sintaxis | ✅ Completo |
|
|
108
108
|
| Generación de HTML + CSS | ✅ Completo |
|
|
109
|
+
| Generación de JavaScript | ✅ Completo |
|
|
109
110
|
| CLI — compilar, servir, verificar | ✅ Completo |
|
|
110
|
-
|
|
|
111
|
-
|
|
|
111
|
+
| Publicado en npm | ✅ Completo |
|
|
112
|
+
| Live reload en telar servir | 🟪 Pendiente |
|
|
112
113
|
| Extensión VS Code | 🟪 Pendiente |
|
|
113
114
|
| Lanzamiento público | 🟪 Pendiente |
|
|
114
115
|
|
|
115
116
|
## Hoja de ruta
|
|
116
117
|
|
|
117
|
-
### v0.1 - Prueba de concepto
|
|
118
|
+
### v0.1 - Prueba de concepto ✅
|
|
118
119
|
- [x] Lexer que tokeniza archivos `.telar`
|
|
119
120
|
- [x] Parser que valida la sintaxis
|
|
120
121
|
- [x] Mensajes de error en español
|
|
121
122
|
- [x] Generación de HTML estático + CSS estático
|
|
122
123
|
- [x] CLI con comandos `compilar`, `servir` y `verificar`
|
|
123
124
|
|
|
124
|
-
### v0.2 - Compilador funcional
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
127
|
-
- [
|
|
128
|
-
- [
|
|
125
|
+
### v0.2 - Compilador funcional ✅
|
|
126
|
+
- [x] Generación de JavaScript
|
|
127
|
+
- [x] CLI instalable: `npm install -g @davidbc01/telar`
|
|
128
|
+
- [x] Soporte para condiciones dinámicas y cargadores de datos
|
|
129
|
+
- [x] Servidor HTTP integrado en `telar servir`
|
|
130
|
+
|
|
131
|
+
### v0.3 - Experiencia de desarrollo
|
|
132
|
+
- [ ] Live reload en `telar servir`
|
|
133
|
+
- [ ] Extensión para VS Code
|
|
134
|
+
- [ ] Mensajes de error mejorados con contexto visual
|
|
129
135
|
|
|
130
136
|
### v1.0 - Lanzamiento público
|
|
131
137
|
- [ ] Estabilidad de sintaxis
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Tu carrito</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<link rel="stylesheet" href="telar.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<main role="main">
|
|
14
|
+
<h1>Tu carrito</h1>
|
|
15
|
+
<div data-si="hay-resultados">
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
<p class="campo" data-campo="pedido.productos">{pedido.productos}</p>
|
|
19
|
+
<p class="campo" data-campo="Total: (pedido.total) €">{Total: (pedido.total) €}</p>
|
|
20
|
+
<a href="/pago" class="boton" role="button">Finalizar compra</a>
|
|
21
|
+
<div data-si="hay-resultados">
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
<section class="lista" data-modelo="Tu carrito está vacío">
|
|
25
|
+
<div class="cargando" aria-live="polite">Cargando...</div>
|
|
26
|
+
</section>
|
|
27
|
+
<a href="/inicio" class="boton" role="button">Ver productos</a>
|
|
28
|
+
</main>
|
|
29
|
+
<script src="telar.js" defer></script>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
package/dist/entrar.html
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Entrar</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<link rel="stylesheet" href="telar.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<main role="main">
|
|
14
|
+
<h1>Entrar</h1>
|
|
15
|
+
<div class="campo-grupo">
|
|
16
|
+
<label for="correo-electrnico">Correo electrónico</label>
|
|
17
|
+
<input type="email" id="correo-electrnico" name="correo-electrnico" autocomplete="email">
|
|
18
|
+
</div>
|
|
19
|
+
<div class="campo-grupo">
|
|
20
|
+
<label for="contrasea">Contraseña</label>
|
|
21
|
+
<input type="contraseña" id="contrasea" name="contrasea" >
|
|
22
|
+
</div>
|
|
23
|
+
<button class="boton" data-accion="iniciarSesion" type="button">
|
|
24
|
+
Entrar
|
|
25
|
+
</button>
|
|
26
|
+
<div class="error" role="alert" hidden>
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
<section class="lista" data-modelo="Correo o contraseña incorrectos">
|
|
30
|
+
<div class="cargando" aria-live="polite">Cargando...</div>
|
|
31
|
+
</section>
|
|
32
|
+
<a href="/recuperarContraseña" class="boton" role="button">¿Olvidaste tu contraseña?</a>
|
|
33
|
+
</main>
|
|
34
|
+
<script src="telar.js" defer></script>
|
|
35
|
+
</body>
|
|
36
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NodoAplicacion } from './tipos';
|
|
2
|
+
export declare class GeneradorJS {
|
|
3
|
+
private app;
|
|
4
|
+
constructor(app: NodoAplicacion);
|
|
5
|
+
generar(): string;
|
|
6
|
+
private generarRuntime;
|
|
7
|
+
private generarCondiciones;
|
|
8
|
+
private extraerCondiciones;
|
|
9
|
+
private generarCargadores;
|
|
10
|
+
private generarCargador;
|
|
11
|
+
private generarAcciones;
|
|
12
|
+
private extraerAcciones;
|
|
13
|
+
private generarInit;
|
|
14
|
+
private condicionAAtributo;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=generador-js.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generador-js.d.ts","sourceRoot":"","sources":["../src/generador-js.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,cAAc,EAGjB,MAAM,SAAS,CAAA;AAEhB,qBAAa,WAAW;IACpB,OAAO,CAAC,GAAG,CAAgB;gBAEf,GAAG,EAAE,cAAc;IAI/B,OAAO,IAAI,MAAM;IAejB,OAAO,CAAC,cAAc;IAmHtB,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,eAAe;IA0CvB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,WAAW;IAmCnB,OAAO,CAAC,kBAAkB;CAU7B"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---
|
|
3
|
+
// generador-js.ts
|
|
4
|
+
// Genera el JavaScript de runtime para una aplicación Telar.
|
|
5
|
+
// Se encarga de condiciones dinámicas, carga de datos y acciones.
|
|
6
|
+
// ---
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.GeneradorJS = void 0;
|
|
9
|
+
class GeneradorJS {
|
|
10
|
+
constructor(app) {
|
|
11
|
+
this.app = app;
|
|
12
|
+
}
|
|
13
|
+
generar() {
|
|
14
|
+
const secciones = [];
|
|
15
|
+
secciones.push(this.generarRuntime());
|
|
16
|
+
secciones.push(this.generarCondiciones());
|
|
17
|
+
secciones.push(this.generarCargadores());
|
|
18
|
+
secciones.push(this.generarAcciones());
|
|
19
|
+
secciones.push(this.generarInit());
|
|
20
|
+
return secciones.join('\n\n');
|
|
21
|
+
}
|
|
22
|
+
// --- Runtime base ---
|
|
23
|
+
// Funciones auxiliares que usa todo el código generado
|
|
24
|
+
generarRuntime() {
|
|
25
|
+
return `// Telar runtime — generado automáticamente
|
|
26
|
+
'use strict';
|
|
27
|
+
|
|
28
|
+
const Telar = {
|
|
29
|
+
// Estado de la sesión
|
|
30
|
+
usuario: null,
|
|
31
|
+
|
|
32
|
+
// Inicializar sesión desde localStorage
|
|
33
|
+
iniciarSesion() {
|
|
34
|
+
try {
|
|
35
|
+
const datos = localStorage.getItem('telar_usuario')
|
|
36
|
+
if (datos) this.usuario = JSON.parse(datos)
|
|
37
|
+
} catch (e) {
|
|
38
|
+
this.usuario = null
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Comprobar condiciones
|
|
43
|
+
evaluar(condicion) {
|
|
44
|
+
switch (condicion) {
|
|
45
|
+
case 'usuario-conectado': return this.usuario !== null
|
|
46
|
+
case 'usuario-admin': return this.usuario?.rol === 'admin'
|
|
47
|
+
case 'hay-resultados': return true // se actualiza dinámicamente
|
|
48
|
+
default: return false
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Mostrar u ocultar elementos según condición
|
|
53
|
+
aplicarCondicion(condicion) {
|
|
54
|
+
const elementos = document.querySelectorAll(\`[data-si="\${condicion}"]\`)
|
|
55
|
+
const elementosNo = document.querySelectorAll(\`[data-si-no="\${condicion}"]\`)
|
|
56
|
+
const valor = this.evaluar(condicion)
|
|
57
|
+
|
|
58
|
+
elementos.forEach(el => {
|
|
59
|
+
el.style.display = valor ? '' : 'none'
|
|
60
|
+
})
|
|
61
|
+
elementosNo.forEach(el => {
|
|
62
|
+
el.style.display = valor ? 'none' : ''
|
|
63
|
+
})
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// Cargar datos desde la API
|
|
67
|
+
async cargar(modelo, opciones = {}) {
|
|
68
|
+
const params = new URLSearchParams()
|
|
69
|
+
if (opciones.maximo) params.set('limit', opciones.maximo)
|
|
70
|
+
if (opciones.ordenar) params.set('sort', opciones.ordenar)
|
|
71
|
+
if (opciones.recientes) params.set('recientes', 'true')
|
|
72
|
+
|
|
73
|
+
const url = \`/api/\${modelo.toLowerCase()}?\${params}\`
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(url)
|
|
77
|
+
if (!res.ok) throw new Error(\`Error \${res.status}\`)
|
|
78
|
+
return await res.json()
|
|
79
|
+
} catch (error) {
|
|
80
|
+
throw error
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
// Mostrar error en un contenedor
|
|
85
|
+
mostrarError(contenedor, mensaje) {
|
|
86
|
+
const errorEl = contenedor.querySelector('.error')
|
|
87
|
+
const cargandoEl = contenedor.querySelector('.cargando')
|
|
88
|
+
if (cargandoEl) cargandoEl.style.display = 'none'
|
|
89
|
+
if (errorEl) {
|
|
90
|
+
errorEl.textContent = mensaje
|
|
91
|
+
errorEl.removeAttribute('hidden')
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// Renderizar lista de items
|
|
96
|
+
renderizarLista(contenedor, items, modelo) {
|
|
97
|
+
const cargandoEl = contenedor.querySelector('.cargando')
|
|
98
|
+
const errorEl = contenedor.querySelector('.error')
|
|
99
|
+
if (cargandoEl) cargandoEl.style.display = 'none'
|
|
100
|
+
if (errorEl) errorEl.setAttribute('hidden', '')
|
|
101
|
+
|
|
102
|
+
if (!items || items.length === 0) {
|
|
103
|
+
contenedor.setAttribute('data-vacio', 'true')
|
|
104
|
+
this.aplicarCondicion('hay-resultados')
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Renderizar cada item
|
|
109
|
+
const lista = document.createElement('ul')
|
|
110
|
+
lista.className = 'telar-lista'
|
|
111
|
+
items.forEach(item => {
|
|
112
|
+
const li = document.createElement('li')
|
|
113
|
+
li.className = 'telar-item'
|
|
114
|
+
li.innerHTML = this.renderizarItem(item, modelo)
|
|
115
|
+
lista.appendChild(li)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
contenedor.appendChild(lista)
|
|
119
|
+
this.aplicarCondicion('hay-resultados')
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// Renderizar un item individual
|
|
123
|
+
renderizarItem(item, modelo) {
|
|
124
|
+
return Object.entries(item)
|
|
125
|
+
.map(([clave, valor]) => \`<p><strong>\${clave}:</strong> \${valor}</p>\`)
|
|
126
|
+
.join('')
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Reintentar una operación después de N segundos
|
|
130
|
+
reintentar(fn, segundos) {
|
|
131
|
+
setTimeout(fn, segundos * 1000)
|
|
132
|
+
}
|
|
133
|
+
};`;
|
|
134
|
+
}
|
|
135
|
+
// --- Condiciones ---
|
|
136
|
+
// Aplica todas las condiciones si/sin-no de la página
|
|
137
|
+
generarCondiciones() {
|
|
138
|
+
const condiciones = new Set();
|
|
139
|
+
for (const pagina of this.app.paginas) {
|
|
140
|
+
this.extraerCondiciones(pagina.hijos, condiciones);
|
|
141
|
+
}
|
|
142
|
+
if (condiciones.size === 0)
|
|
143
|
+
return '';
|
|
144
|
+
const lineas = Array.from(condiciones).map(c => ` Telar.aplicarCondicion('${c}');`);
|
|
145
|
+
return `// Aplicar condiciones dinámicas
|
|
146
|
+
function aplicarCondiciones() {
|
|
147
|
+
${lineas.join('\n')}
|
|
148
|
+
}`;
|
|
149
|
+
}
|
|
150
|
+
extraerCondiciones(nodos, set) {
|
|
151
|
+
for (const nodo of nodos) {
|
|
152
|
+
if (nodo.tipo === 'si') {
|
|
153
|
+
const attr = this.condicionAAtributo(nodo.condicion);
|
|
154
|
+
set.add(attr);
|
|
155
|
+
this.extraerCondiciones(nodo.entonces, set);
|
|
156
|
+
if (nodo.siNo)
|
|
157
|
+
this.extraerCondiciones(nodo.siNo, set);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// --- Cargadores de datos ---
|
|
162
|
+
// Una función async por cada "mostrar Modelo"
|
|
163
|
+
generarCargadores() {
|
|
164
|
+
const cargadores = [];
|
|
165
|
+
for (const pagina of this.app.paginas) {
|
|
166
|
+
for (const nodo of pagina.hijos) {
|
|
167
|
+
if (nodo.tipo === 'mostrar' && !nodo.modelo.includes('.')) {
|
|
168
|
+
cargadores.push(this.generarCargador(nodo));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (cargadores.length === 0)
|
|
173
|
+
return '';
|
|
174
|
+
return cargadores.join('\n\n');
|
|
175
|
+
}
|
|
176
|
+
generarCargador(nodo) {
|
|
177
|
+
const modelo = nodo.modelo;
|
|
178
|
+
const atributos = [
|
|
179
|
+
`data-modelo="${modelo}"`,
|
|
180
|
+
...nodo.modificadores.map(m => {
|
|
181
|
+
if (m.tipo === 'maximo')
|
|
182
|
+
return `data-maximo="${m.cantidad}"`;
|
|
183
|
+
if (m.tipo === 'ordenados')
|
|
184
|
+
return `data-ordenar="${m.campo}"`;
|
|
185
|
+
if (m.tipo === 'recientes')
|
|
186
|
+
return `data-recientes="true"`;
|
|
187
|
+
return '';
|
|
188
|
+
}).filter(Boolean)
|
|
189
|
+
];
|
|
190
|
+
const opciones = [];
|
|
191
|
+
nodo.modificadores.forEach(m => {
|
|
192
|
+
if (m.tipo === 'maximo')
|
|
193
|
+
opciones.push(`maximo: '${m.cantidad}'`);
|
|
194
|
+
if (m.tipo === 'ordenados')
|
|
195
|
+
opciones.push(`ordenar: '${m.campo}'`);
|
|
196
|
+
if (m.tipo === 'recientes')
|
|
197
|
+
opciones.push(`recientes: true`);
|
|
198
|
+
});
|
|
199
|
+
const reintentar = nodo.siFalla?.find(n => n.tipo === 'reintentar');
|
|
200
|
+
const reintentarJS = reintentar
|
|
201
|
+
? `Telar.reintentar(() => cargar${modelo}(), ${reintentar.segundos});`
|
|
202
|
+
: '';
|
|
203
|
+
const siFallaMsg = nodo.siFalla?.find(n => n.tipo === 'mostrar');
|
|
204
|
+
const mensajeError = siFallaMsg && 'texto' in siFallaMsg
|
|
205
|
+
? siFallaMsg.texto
|
|
206
|
+
: 'Error al cargar los datos';
|
|
207
|
+
return `// Cargar ${modelo}
|
|
208
|
+
async function cargar${modelo}() {
|
|
209
|
+
const contenedor = document.querySelector('[data-modelo="${modelo}"]')
|
|
210
|
+
if (!contenedor) return
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const datos = await Telar.cargar('${modelo}', { ${opciones.join(', ')} })
|
|
214
|
+
Telar.renderizarLista(contenedor, datos, '${modelo}')
|
|
215
|
+
} catch (error) {
|
|
216
|
+
Telar.mostrarError(contenedor, '${mensajeError}')
|
|
217
|
+
${reintentarJS}
|
|
218
|
+
}
|
|
219
|
+
}`;
|
|
220
|
+
}
|
|
221
|
+
// --- Acciones de botones ---
|
|
222
|
+
// Una función por cada botón con acción "hacer"
|
|
223
|
+
generarAcciones() {
|
|
224
|
+
const acciones = new Set();
|
|
225
|
+
for (const pagina of this.app.paginas) {
|
|
226
|
+
this.extraerAcciones(pagina.hijos, acciones);
|
|
227
|
+
}
|
|
228
|
+
if (acciones.size === 0)
|
|
229
|
+
return '';
|
|
230
|
+
const funciones = Array.from(acciones).map(accion => `
|
|
231
|
+
// Acción: ${accion}
|
|
232
|
+
async function ${accion}() {
|
|
233
|
+
const boton = document.querySelector('[data-accion="${accion}"]')
|
|
234
|
+
const errorEl = boton?.nextElementSibling
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
if (boton) boton.disabled = true
|
|
238
|
+
const res = await fetch('/api/accion/${accion}', { method: 'POST' })
|
|
239
|
+
if (!res.ok) throw new Error()
|
|
240
|
+
// Acción completada — redirigir o actualizar según contexto
|
|
241
|
+
} catch (error) {
|
|
242
|
+
if (errorEl && errorEl.classList.contains('error')) {
|
|
243
|
+
errorEl.removeAttribute('hidden')
|
|
244
|
+
}
|
|
245
|
+
} finally {
|
|
246
|
+
if (boton) boton.disabled = false
|
|
247
|
+
}
|
|
248
|
+
}`);
|
|
249
|
+
const listeners = Array.from(acciones).map(accion => ` document.querySelector('[data-accion="${accion}"]')
|
|
250
|
+
?.addEventListener('click', ${accion});`);
|
|
251
|
+
return `${funciones.join('\n')}
|
|
252
|
+
|
|
253
|
+
// Registrar listeners de acciones
|
|
254
|
+
function registrarAcciones() {
|
|
255
|
+
${listeners.join('\n')}
|
|
256
|
+
}`;
|
|
257
|
+
}
|
|
258
|
+
extraerAcciones(nodos, set) {
|
|
259
|
+
for (const nodo of nodos) {
|
|
260
|
+
if (nodo.tipo === 'boton' && nodo.accion === 'hacer') {
|
|
261
|
+
set.add(nodo.destino);
|
|
262
|
+
}
|
|
263
|
+
if (nodo.tipo === 'si') {
|
|
264
|
+
this.extraerAcciones(nodo.entonces, set);
|
|
265
|
+
if (nodo.siNo)
|
|
266
|
+
this.extraerAcciones(nodo.siNo, set);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// --- Inicialización ---
|
|
271
|
+
generarInit() {
|
|
272
|
+
const tieneCargadores = this.app.paginas.some(p => p.hijos.some(h => h.tipo === 'mostrar' && !('modelo' in h && h.modelo.includes('.'))));
|
|
273
|
+
const tieneCondiciones = this.app.paginas.some(p => p.hijos.some(h => h.tipo === 'si'));
|
|
274
|
+
const tieneAcciones = this.app.paginas.some(p => p.hijos.some(h => h.tipo === 'boton' && h.accion === 'hacer'));
|
|
275
|
+
const llamadas = [' Telar.iniciarSesion();'];
|
|
276
|
+
if (tieneCondiciones)
|
|
277
|
+
llamadas.push(' aplicarCondiciones();');
|
|
278
|
+
if (tieneAcciones)
|
|
279
|
+
llamadas.push(' registrarAcciones();');
|
|
280
|
+
// Llamar a cada cargador
|
|
281
|
+
for (const pagina of this.app.paginas) {
|
|
282
|
+
for (const nodo of pagina.hijos) {
|
|
283
|
+
if (nodo.tipo === 'mostrar' && !('modelo' in nodo && nodo.modelo.includes('.'))) {
|
|
284
|
+
llamadas.push(` cargar${nodo.modelo}();`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return `// Inicializar cuando el DOM esté listo
|
|
289
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
290
|
+
${llamadas.join('\n')}
|
|
291
|
+
});`;
|
|
292
|
+
}
|
|
293
|
+
// --- Helpers ---
|
|
294
|
+
condicionAAtributo(condicion) {
|
|
295
|
+
switch (condicion.tipo) {
|
|
296
|
+
case 'usuario_conectado': return 'usuario-conectado';
|
|
297
|
+
case 'usuario_admin': return 'usuario-admin';
|
|
298
|
+
case 'hay_resultados': return 'hay-resultados';
|
|
299
|
+
case 'campo_mayor': return `${condicion.campo}-mayor-${condicion.valor}`;
|
|
300
|
+
case 'campo_igual': return `${condicion.campo}-igual-${condicion.valor}`;
|
|
301
|
+
default: return 'desconocido';
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
exports.GeneradorJS = GeneradorJS;
|
|
306
|
+
//# sourceMappingURL=generador-js.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generador-js.js","sourceRoot":"","sources":["../src/generador-js.ts"],"names":[],"mappings":"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"}
|
package/dist/generador.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generador.d.ts","sourceRoot":"","sources":["../src/generador.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,cAAc,EAIjB,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"generador.d.ts","sourceRoot":"","sources":["../src/generador.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,cAAc,EAIjB,MAAM,SAAS,CAAA;AAGhB,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,SAAS;IAClB,OAAO,CAAC,GAAG,CAAgB;gBAEf,GAAG,EAAE,cAAc;IAI/B,OAAO,IAAI,eAAe,EAAE;IA2B5B,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,SAAS;IAcjB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,UAAU;IA4HlB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,QAAQ;CAInB"}
|
package/dist/generador.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// ---
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.Generador = void 0;
|
|
8
|
+
const generador_js_1 = require("./generador-js");
|
|
8
9
|
class Generador {
|
|
9
10
|
constructor(app) {
|
|
10
11
|
this.app = app;
|
|
@@ -22,6 +23,11 @@ class Generador {
|
|
|
22
23
|
nombre: 'telar.css',
|
|
23
24
|
contenido: this.generarCSS()
|
|
24
25
|
});
|
|
26
|
+
const generadorJS = new generador_js_1.GeneradorJS(this.app);
|
|
27
|
+
archivos.push({
|
|
28
|
+
nombre: 'telar.js',
|
|
29
|
+
contenido: generadorJS.generar()
|
|
30
|
+
});
|
|
25
31
|
return archivos;
|
|
26
32
|
}
|
|
27
33
|
// --- Página completa ---
|
package/dist/generador.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generador.js","sourceRoot":"","sources":["../src/generador.ts"],"names":[],"mappings":";AAAA,MAAM;AACN,eAAe;AACf,6CAA6C;AAC7C,MAAM;;;
|
|
1
|
+
{"version":3,"file":"generador.js","sourceRoot":"","sources":["../src/generador.ts"],"names":[],"mappings":"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"}
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Bienvenido a MiTienda</title>
|
|
7
|
+
<meta name="description" content="Los mejores productos al mejor precio">
|
|
8
|
+
<meta http-equiv="Cache-Control" content="max-age=600">
|
|
9
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
10
|
+
<link rel="stylesheet" href="telar.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<main role="main">
|
|
14
|
+
<h1>Bienvenido a MiTienda</h1>
|
|
15
|
+
<p class="descripcion">Los mejores productos al mejor precio</p>
|
|
16
|
+
<section class="lista" data-modelo="Producto" data-maximo="8" data-ordenar="fecha" data-recientes="true">
|
|
17
|
+
<div class="cargando" aria-live="polite">Cargando...</div>
|
|
18
|
+
<div class="error" role="alert" hidden>
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
</section>
|
|
22
|
+
<p class="campo" data-campo="No se pudieron cargar los productos.">{No se pudieron cargar los productos.}</p>
|
|
23
|
+
<button class="reintentar" data-reintentar="10" type="button">
|
|
24
|
+
Reintentar
|
|
25
|
+
</button>
|
|
26
|
+
<div data-si="usuario-conectado">
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
<p class="campo" data-campo="Hola, (usuario.nombre)">{Hola, (usuario.nombre)}</p>
|
|
30
|
+
<a href="/cuenta" class="boton" role="button">Mi cuenta</a>
|
|
31
|
+
<a href="/carrito" class="boton" role="button">Mi carrito</a>
|
|
32
|
+
<div data-si="hay-resultados">
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
<a href="/login" class="boton" role="button">Entrar</a>
|
|
36
|
+
<a href="/registro" class="boton" role="button">Registrarse</a>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
</main>
|
|
40
|
+
<script src="telar.js" defer></script>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>(producto.nombre)</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
10
|
+
<link rel="stylesheet" href="telar.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<main role="main">
|
|
14
|
+
<h1>(producto.nombre)</h1>
|
|
15
|
+
<p class="campo" data-campo="producto.imagen">{producto.imagen}</p>
|
|
16
|
+
<p class="campo" data-campo="producto.nombre">{producto.nombre}</p>
|
|
17
|
+
<p class="campo" data-campo="producto.precio">{producto.precio}</p>
|
|
18
|
+
<p class="campo" data-campo="producto.descripción">{producto.descripción}</p>
|
|
19
|
+
<div data-si="producto.stock-mayor-0">
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
<button class="boton" data-accion="añadirAlCarrito" type="button">
|
|
23
|
+
Añadir al carrito
|
|
24
|
+
</button>
|
|
25
|
+
<div data-si="hay-resultados">
|
|
26
|
+
|
|
27
|
+
</div>
|
|
28
|
+
<section class="lista" data-modelo="Sin stock — avísame cuando llegue">
|
|
29
|
+
<div class="cargando" aria-live="polite">Cargando...</div>
|
|
30
|
+
</section>
|
|
31
|
+
<button class="boton" data-accion="suscribirStock" type="button">
|
|
32
|
+
Avisarme
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
</main>
|
|
36
|
+
<script src="telar.js" defer></script>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
package/dist/telar.css
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* Telar — estilos base generados automáticamente */
|
|
2
|
+
|
|
3
|
+
*, *::before, *::after {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
margin: 0;
|
|
6
|
+
padding: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:root {
|
|
10
|
+
--color-fondo: #ffffff;
|
|
11
|
+
--color-texto: #1a1a1a;
|
|
12
|
+
--color-primario: #5B4AB7;
|
|
13
|
+
--color-borde: #e0e0e0;
|
|
14
|
+
--color-error: #dc2626;
|
|
15
|
+
--radio: 8px;
|
|
16
|
+
--espacio: 1rem;
|
|
17
|
+
font-size: 16px;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
22
|
+
background: var(--color-fondo);
|
|
23
|
+
color: var(--color-texto);
|
|
24
|
+
line-height: 1.6;
|
|
25
|
+
padding: var(--espacio);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main {
|
|
29
|
+
max-width: 680px;
|
|
30
|
+
margin: 0 auto;
|
|
31
|
+
padding: var(--espacio);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
h1 {
|
|
35
|
+
font-size: 2rem;
|
|
36
|
+
font-weight: 700;
|
|
37
|
+
margin-bottom: var(--espacio);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.descripcion {
|
|
41
|
+
color: #555;
|
|
42
|
+
margin-bottom: var(--espacio);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.boton {
|
|
46
|
+
display: inline-block;
|
|
47
|
+
padding: 0.6rem 1.2rem;
|
|
48
|
+
background: var(--color-primario);
|
|
49
|
+
color: white;
|
|
50
|
+
border: none;
|
|
51
|
+
border-radius: var(--radio);
|
|
52
|
+
font-size: 1rem;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
text-decoration: none;
|
|
55
|
+
margin: 0.25rem 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.boton:hover {
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.campo-grupo {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
gap: 0.4rem;
|
|
66
|
+
margin-bottom: var(--espacio);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
label {
|
|
70
|
+
font-weight: 500;
|
|
71
|
+
font-size: 0.9rem;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
input, textarea {
|
|
75
|
+
padding: 0.6rem 0.8rem;
|
|
76
|
+
border: 1px solid var(--color-borde);
|
|
77
|
+
border-radius: var(--radio);
|
|
78
|
+
font-size: 1rem;
|
|
79
|
+
width: 100%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
input:focus, textarea:focus {
|
|
83
|
+
outline: 2px solid var(--color-primario);
|
|
84
|
+
border-color: transparent;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.lista {
|
|
88
|
+
margin: var(--espacio) 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.cargando {
|
|
92
|
+
color: #888;
|
|
93
|
+
font-size: 0.9rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.error {
|
|
97
|
+
color: var(--color-error);
|
|
98
|
+
font-size: 0.9rem;
|
|
99
|
+
padding: 0.5rem;
|
|
100
|
+
border: 1px solid var(--color-error);
|
|
101
|
+
border-radius: var(--radio);
|
|
102
|
+
margin: 0.5rem 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.reintentar {
|
|
106
|
+
background: none;
|
|
107
|
+
border: 1px solid var(--color-borde);
|
|
108
|
+
border-radius: var(--radio);
|
|
109
|
+
padding: 0.4rem 0.8rem;
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
font-size: 0.85rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Responsive — optimizar para móvil */
|
|
115
|
+
@media (max-width: 600px) {
|
|
116
|
+
h1 { font-size: 1.5rem; }
|
|
117
|
+
main { padding: 0.5rem; }
|
|
118
|
+
}
|
package/dist/telar.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// Telar runtime — generado automáticamente
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const Telar = {
|
|
5
|
+
// Estado de la sesión
|
|
6
|
+
usuario: null,
|
|
7
|
+
|
|
8
|
+
// Inicializar sesión desde localStorage
|
|
9
|
+
iniciarSesion() {
|
|
10
|
+
try {
|
|
11
|
+
const datos = localStorage.getItem('telar_usuario')
|
|
12
|
+
if (datos) this.usuario = JSON.parse(datos)
|
|
13
|
+
} catch (e) {
|
|
14
|
+
this.usuario = null
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
// Comprobar condiciones
|
|
19
|
+
evaluar(condicion) {
|
|
20
|
+
switch (condicion) {
|
|
21
|
+
case 'usuario-conectado': return this.usuario !== null
|
|
22
|
+
case 'usuario-admin': return this.usuario?.rol === 'admin'
|
|
23
|
+
case 'hay-resultados': return true // se actualiza dinámicamente
|
|
24
|
+
default: return false
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
// Mostrar u ocultar elementos según condición
|
|
29
|
+
aplicarCondicion(condicion) {
|
|
30
|
+
const elementos = document.querySelectorAll(`[data-si="${condicion}"]`)
|
|
31
|
+
const elementosNo = document.querySelectorAll(`[data-si-no="${condicion}"]`)
|
|
32
|
+
const valor = this.evaluar(condicion)
|
|
33
|
+
|
|
34
|
+
elementos.forEach(el => {
|
|
35
|
+
el.style.display = valor ? '' : 'none'
|
|
36
|
+
})
|
|
37
|
+
elementosNo.forEach(el => {
|
|
38
|
+
el.style.display = valor ? 'none' : ''
|
|
39
|
+
})
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Cargar datos desde la API
|
|
43
|
+
async cargar(modelo, opciones = {}) {
|
|
44
|
+
const params = new URLSearchParams()
|
|
45
|
+
if (opciones.maximo) params.set('limit', opciones.maximo)
|
|
46
|
+
if (opciones.ordenar) params.set('sort', opciones.ordenar)
|
|
47
|
+
if (opciones.recientes) params.set('recientes', 'true')
|
|
48
|
+
|
|
49
|
+
const url = `/api/${modelo.toLowerCase()}?${params}`
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch(url)
|
|
53
|
+
if (!res.ok) throw new Error(`Error ${res.status}`)
|
|
54
|
+
return await res.json()
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw error
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// Mostrar error en un contenedor
|
|
61
|
+
mostrarError(contenedor, mensaje) {
|
|
62
|
+
const errorEl = contenedor.querySelector('.error')
|
|
63
|
+
const cargandoEl = contenedor.querySelector('.cargando')
|
|
64
|
+
if (cargandoEl) cargandoEl.style.display = 'none'
|
|
65
|
+
if (errorEl) {
|
|
66
|
+
errorEl.textContent = mensaje
|
|
67
|
+
errorEl.removeAttribute('hidden')
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Renderizar lista de items
|
|
72
|
+
renderizarLista(contenedor, items, modelo) {
|
|
73
|
+
const cargandoEl = contenedor.querySelector('.cargando')
|
|
74
|
+
const errorEl = contenedor.querySelector('.error')
|
|
75
|
+
if (cargandoEl) cargandoEl.style.display = 'none'
|
|
76
|
+
if (errorEl) errorEl.setAttribute('hidden', '')
|
|
77
|
+
|
|
78
|
+
if (!items || items.length === 0) {
|
|
79
|
+
contenedor.setAttribute('data-vacio', 'true')
|
|
80
|
+
this.aplicarCondicion('hay-resultados')
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Renderizar cada item
|
|
85
|
+
const lista = document.createElement('ul')
|
|
86
|
+
lista.className = 'telar-lista'
|
|
87
|
+
items.forEach(item => {
|
|
88
|
+
const li = document.createElement('li')
|
|
89
|
+
li.className = 'telar-item'
|
|
90
|
+
li.innerHTML = this.renderizarItem(item, modelo)
|
|
91
|
+
lista.appendChild(li)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
contenedor.appendChild(lista)
|
|
95
|
+
this.aplicarCondicion('hay-resultados')
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// Renderizar un item individual
|
|
99
|
+
renderizarItem(item, modelo) {
|
|
100
|
+
return Object.entries(item)
|
|
101
|
+
.map(([clave, valor]) => `<p><strong>${clave}:</strong> ${valor}</p>`)
|
|
102
|
+
.join('')
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
// Reintentar una operación después de N segundos
|
|
106
|
+
reintentar(fn, segundos) {
|
|
107
|
+
setTimeout(fn, segundos * 1000)
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Aplicar condiciones dinámicas
|
|
112
|
+
function aplicarCondiciones() {
|
|
113
|
+
Telar.aplicarCondicion('usuario-conectado');
|
|
114
|
+
Telar.aplicarCondicion('hay-resultados');
|
|
115
|
+
Telar.aplicarCondicion('producto.stock-mayor-0');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Cargar Producto
|
|
119
|
+
async function cargarProducto() {
|
|
120
|
+
const contenedor = document.querySelector('[data-modelo="Producto"]')
|
|
121
|
+
if (!contenedor) return
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const datos = await Telar.cargar('Producto', { recientes: true, maximo: '8', ordenar: 'fecha' })
|
|
125
|
+
Telar.renderizarLista(contenedor, datos, 'Producto')
|
|
126
|
+
} catch (error) {
|
|
127
|
+
Telar.mostrarError(contenedor, 'Error al cargar los datos')
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Cargar Sin stock — avísame cuando llegue
|
|
133
|
+
async function cargarSin stock — avísame cuando llegue() {
|
|
134
|
+
const contenedor = document.querySelector('[data-modelo="Sin stock — avísame cuando llegue"]')
|
|
135
|
+
if (!contenedor) return
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const datos = await Telar.cargar('Sin stock — avísame cuando llegue', { })
|
|
139
|
+
Telar.renderizarLista(contenedor, datos, 'Sin stock — avísame cuando llegue')
|
|
140
|
+
} catch (error) {
|
|
141
|
+
Telar.mostrarError(contenedor, 'Error al cargar los datos')
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Cargar Tu carrito está vacío
|
|
147
|
+
async function cargarTu carrito está vacío() {
|
|
148
|
+
const contenedor = document.querySelector('[data-modelo="Tu carrito está vacío"]')
|
|
149
|
+
if (!contenedor) return
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const datos = await Telar.cargar('Tu carrito está vacío', { })
|
|
153
|
+
Telar.renderizarLista(contenedor, datos, 'Tu carrito está vacío')
|
|
154
|
+
} catch (error) {
|
|
155
|
+
Telar.mostrarError(contenedor, 'Error al cargar los datos')
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Cargar Correo o contraseña incorrectos
|
|
161
|
+
async function cargarCorreo o contraseña incorrectos() {
|
|
162
|
+
const contenedor = document.querySelector('[data-modelo="Correo o contraseña incorrectos"]')
|
|
163
|
+
if (!contenedor) return
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const datos = await Telar.cargar('Correo o contraseña incorrectos', { })
|
|
167
|
+
Telar.renderizarLista(contenedor, datos, 'Correo o contraseña incorrectos')
|
|
168
|
+
} catch (error) {
|
|
169
|
+
Telar.mostrarError(contenedor, 'Error al cargar los datos')
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
// Acción: añadirAlCarrito
|
|
176
|
+
async function añadirAlCarrito() {
|
|
177
|
+
const boton = document.querySelector('[data-accion="añadirAlCarrito"]')
|
|
178
|
+
const errorEl = boton?.nextElementSibling
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
if (boton) boton.disabled = true
|
|
182
|
+
const res = await fetch('/api/accion/añadirAlCarrito', { method: 'POST' })
|
|
183
|
+
if (!res.ok) throw new Error()
|
|
184
|
+
// Acción completada — redirigir o actualizar según contexto
|
|
185
|
+
} catch (error) {
|
|
186
|
+
if (errorEl && errorEl.classList.contains('error')) {
|
|
187
|
+
errorEl.removeAttribute('hidden')
|
|
188
|
+
}
|
|
189
|
+
} finally {
|
|
190
|
+
if (boton) boton.disabled = false
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Acción: suscribirStock
|
|
195
|
+
async function suscribirStock() {
|
|
196
|
+
const boton = document.querySelector('[data-accion="suscribirStock"]')
|
|
197
|
+
const errorEl = boton?.nextElementSibling
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
if (boton) boton.disabled = true
|
|
201
|
+
const res = await fetch('/api/accion/suscribirStock', { method: 'POST' })
|
|
202
|
+
if (!res.ok) throw new Error()
|
|
203
|
+
// Acción completada — redirigir o actualizar según contexto
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (errorEl && errorEl.classList.contains('error')) {
|
|
206
|
+
errorEl.removeAttribute('hidden')
|
|
207
|
+
}
|
|
208
|
+
} finally {
|
|
209
|
+
if (boton) boton.disabled = false
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Acción: iniciarSesion
|
|
214
|
+
async function iniciarSesion() {
|
|
215
|
+
const boton = document.querySelector('[data-accion="iniciarSesion"]')
|
|
216
|
+
const errorEl = boton?.nextElementSibling
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
if (boton) boton.disabled = true
|
|
220
|
+
const res = await fetch('/api/accion/iniciarSesion', { method: 'POST' })
|
|
221
|
+
if (!res.ok) throw new Error()
|
|
222
|
+
// Acción completada — redirigir o actualizar según contexto
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (errorEl && errorEl.classList.contains('error')) {
|
|
225
|
+
errorEl.removeAttribute('hidden')
|
|
226
|
+
}
|
|
227
|
+
} finally {
|
|
228
|
+
if (boton) boton.disabled = false
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Registrar listeners de acciones
|
|
233
|
+
function registrarAcciones() {
|
|
234
|
+
document.querySelector('[data-accion="añadirAlCarrito"]')
|
|
235
|
+
?.addEventListener('click', añadirAlCarrito);
|
|
236
|
+
document.querySelector('[data-accion="suscribirStock"]')
|
|
237
|
+
?.addEventListener('click', suscribirStock);
|
|
238
|
+
document.querySelector('[data-accion="iniciarSesion"]')
|
|
239
|
+
?.addEventListener('click', iniciarSesion);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Inicializar cuando el DOM esté listo
|
|
243
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
244
|
+
Telar.iniciarSesion();
|
|
245
|
+
aplicarCondiciones();
|
|
246
|
+
registrarAcciones();
|
|
247
|
+
cargarProducto();
|
|
248
|
+
cargarSin stock — avísame cuando llegue();
|
|
249
|
+
cargarTu carrito está vacío();
|
|
250
|
+
cargarCorreo o contraseña incorrectos();
|
|
251
|
+
});
|