@davidbc01/telar 0.2.0 → 0.3.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 +5 -5
- package/dist/cli.js +102 -31
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/dist/carrito.html +0 -31
- package/dist/entrar.html +0 -36
- package/dist/index.html +0 -42
- package/dist/producto-(id).html +0 -38
- package/dist/telar.css +0 -118
- package/dist/telar.js +0 -251
package/README.md
CHANGED
|
@@ -109,8 +109,8 @@ Telar compila a HTML + CSS + JavaScript optimizados. El desarrollador nunca toca
|
|
|
109
109
|
| Generación de JavaScript | ✅ Completo |
|
|
110
110
|
| CLI — compilar, servir, verificar | ✅ Completo |
|
|
111
111
|
| Publicado en npm | ✅ Completo |
|
|
112
|
-
| Live reload en telar servir |
|
|
113
|
-
| Extensión VS Code |
|
|
112
|
+
| Live reload en telar servir | ✅ Completo |
|
|
113
|
+
| Extensión VS Code | ✅ Completo |
|
|
114
114
|
| Lanzamiento público | 🟪 Pendiente |
|
|
115
115
|
|
|
116
116
|
## Hoja de ruta
|
|
@@ -129,8 +129,8 @@ Telar compila a HTML + CSS + JavaScript optimizados. El desarrollador nunca toca
|
|
|
129
129
|
- [x] Servidor HTTP integrado en `telar servir`
|
|
130
130
|
|
|
131
131
|
### v0.3 - Experiencia de desarrollo
|
|
132
|
-
- [
|
|
133
|
-
- [
|
|
132
|
+
- [x] Live reload en `telar servir`
|
|
133
|
+
- [x] Extensión para VS Code
|
|
134
134
|
- [ ] Mensajes de error mejorados con contexto visual
|
|
135
135
|
|
|
136
136
|
### v1.0 - Lanzamiento público
|
|
@@ -141,7 +141,7 @@ Telar compila a HTML + CSS + JavaScript optimizados. El desarrollador nunca toca
|
|
|
141
141
|
|
|
142
142
|
## ¿Por qué en español?
|
|
143
143
|
|
|
144
|
-
La
|
|
144
|
+
La mayoría de los lenguajes de programación usan palabras clave en inglés. Esto añade una barrera invisible para los más de 500 millones de hispanohablantes que aprenden a programar.
|
|
145
145
|
|
|
146
146
|
Telar no pretende reemplazar el inglés como lengua franca de la programación. Pretende demostrar que la sintaxis de un lenguaje puede ser un dialecto estructurado de cualquier idioma humano, y que eso reduce drásticamente la curva de aprendizaje.
|
|
147
147
|
|
package/dist/cli.js
CHANGED
|
@@ -46,28 +46,28 @@ const lexer_1 = require("./lexer");
|
|
|
46
46
|
const parser_1 = require("./parser");
|
|
47
47
|
const generador_1 = require("./generador");
|
|
48
48
|
const tipos_1 = require("./tipos");
|
|
49
|
-
const VERSION = '0.
|
|
49
|
+
const VERSION = '0.2.0';
|
|
50
50
|
const AYUDA = `
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
51
|
+
Telar v${VERSION} — Lenguaje de programación para la web
|
|
52
|
+
|
|
53
|
+
Uso:
|
|
54
|
+
telar <comando> [opciones]
|
|
55
|
+
|
|
56
|
+
Comandos:
|
|
57
|
+
compilar <archivo.telar> Compila a HTML + CSS
|
|
58
|
+
compilar <archivo.telar> -o <carpeta> Especifica carpeta de salida
|
|
59
|
+
servir <archivo.telar> Compila y sirve en localhost
|
|
60
|
+
verificar <archivo.telar> Verifica la sintaxis sin compilar
|
|
61
|
+
|
|
62
|
+
Ejemplos:
|
|
63
|
+
telar compilar app.telar
|
|
64
|
+
telar compilar app.telar -o dist/
|
|
65
|
+
telar servir app.telar
|
|
66
|
+
telar verificar app.telar
|
|
67
|
+
|
|
68
|
+
Opciones:
|
|
69
|
+
--ayuda, -a Muestra esta ayuda
|
|
70
|
+
--version, -v Muestra la versión
|
|
71
71
|
`;
|
|
72
72
|
// --- Entrada principal ---
|
|
73
73
|
const args = process.argv.slice(2);
|
|
@@ -117,6 +117,7 @@ function comandoCompilar(args) {
|
|
|
117
117
|
function comandoServir(args) {
|
|
118
118
|
const { archivo, salida } = parsearArgs(args, '.telar-tmp');
|
|
119
119
|
const puerto = 3000;
|
|
120
|
+
const puertoWS = 3001;
|
|
120
121
|
// Compilar primero
|
|
121
122
|
console.log(`\nTelar — compilando ${path.basename(archivo)}...\n`);
|
|
122
123
|
const archivos = compilar(archivo);
|
|
@@ -126,18 +127,86 @@ function comandoServir(args) {
|
|
|
126
127
|
if (!fs.existsSync(salida)) {
|
|
127
128
|
fs.mkdirSync(salida, { recursive: true });
|
|
128
129
|
}
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
function recompilarYEscribir() {
|
|
131
|
+
const nuevos = compilar(archivo);
|
|
132
|
+
if (!nuevos)
|
|
133
|
+
return false;
|
|
134
|
+
for (const f of nuevos) {
|
|
135
|
+
// Inyectar script de live reload en cada HTML
|
|
136
|
+
let contenido = f.contenido;
|
|
137
|
+
if (f.nombre.endsWith('.html')) {
|
|
138
|
+
contenido = contenido.replace('</body>', `<script>
|
|
139
|
+
const ws = new WebSocket('ws://localhost:${puertoWS}');
|
|
140
|
+
ws.onmessage = () => location.reload();
|
|
141
|
+
</script>
|
|
142
|
+
</body>`);
|
|
143
|
+
}
|
|
144
|
+
fs.writeFileSync(path.join(salida, f.nombre), contenido, 'utf-8');
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
recompilarYEscribir();
|
|
149
|
+
// Servidor WebSocket para live reload
|
|
150
|
+
const net = require('net');
|
|
151
|
+
const clientes = [];
|
|
152
|
+
const wsServer = net.createServer((socket) => {
|
|
153
|
+
// Handshake WebSocket mínimo
|
|
154
|
+
socket.once('data', (data) => {
|
|
155
|
+
const key = data.toString().match(/Sec-WebSocket-Key: (.+)/)?.[1]?.trim();
|
|
156
|
+
if (!key)
|
|
157
|
+
return;
|
|
158
|
+
const crypto = require('crypto');
|
|
159
|
+
const accept = crypto
|
|
160
|
+
.createHash('sha1')
|
|
161
|
+
.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
|
162
|
+
.digest('base64');
|
|
163
|
+
socket.write('HTTP/1.1 101 Switching Protocols\r\n' +
|
|
164
|
+
'Upgrade: websocket\r\n' +
|
|
165
|
+
'Connection: Upgrade\r\n' +
|
|
166
|
+
`Sec-WebSocket-Accept: ${accept}\r\n\r\n`);
|
|
167
|
+
clientes.push(socket);
|
|
168
|
+
socket.on('close', () => {
|
|
169
|
+
const i = clientes.indexOf(socket);
|
|
170
|
+
if (i !== -1)
|
|
171
|
+
clientes.splice(i, 1);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
wsServer.listen(puertoWS);
|
|
176
|
+
function notificarClientes() {
|
|
177
|
+
// Frame WebSocket mínimo para enviar mensaje de texto
|
|
178
|
+
const msg = Buffer.from('reload');
|
|
179
|
+
const frame = Buffer.alloc(2 + msg.length);
|
|
180
|
+
frame[0] = 0x81; // FIN + opcode texto
|
|
181
|
+
frame[1] = msg.length;
|
|
182
|
+
msg.copy(frame, 2);
|
|
183
|
+
clientes.forEach(s => {
|
|
184
|
+
try {
|
|
185
|
+
s.write(frame);
|
|
186
|
+
}
|
|
187
|
+
catch (e) { }
|
|
188
|
+
});
|
|
131
189
|
}
|
|
132
|
-
//
|
|
190
|
+
// Watcher con debounce — evita doble disparo en Windows
|
|
191
|
+
let timeout = null;
|
|
192
|
+
fs.watch(archivo, () => {
|
|
193
|
+
if (timeout)
|
|
194
|
+
clearTimeout(timeout);
|
|
195
|
+
timeout = setTimeout(() => {
|
|
196
|
+
console.log(`\n↻ Cambio detectado — recompilando...`);
|
|
197
|
+
const ok = recompilarYEscribir();
|
|
198
|
+
if (ok) {
|
|
199
|
+
console.log(`✓ Listo`);
|
|
200
|
+
notificarClientes();
|
|
201
|
+
}
|
|
202
|
+
}, 100);
|
|
203
|
+
});
|
|
204
|
+
// Servidor HTTP
|
|
133
205
|
const servidor = http.createServer((req, res) => {
|
|
134
206
|
let urlPath = req.url === '/' ? '/index.html' : req.url ?? '/index.html';
|
|
135
|
-
// Quitar query strings
|
|
136
207
|
urlPath = urlPath.split('?')[0];
|
|
137
|
-
|
|
138
|
-
if (!path.extname(urlPath)) {
|
|
208
|
+
if (!path.extname(urlPath))
|
|
139
209
|
urlPath = urlPath + '.html';
|
|
140
|
-
}
|
|
141
210
|
const rutaArchivo = path.join(salida, urlPath);
|
|
142
211
|
if (fs.existsSync(rutaArchivo)) {
|
|
143
212
|
const ext = path.extname(rutaArchivo);
|
|
@@ -159,12 +228,14 @@ function comandoServir(args) {
|
|
|
159
228
|
});
|
|
160
229
|
servidor.listen(puerto, () => {
|
|
161
230
|
console.log(`✓ Compilación completada`);
|
|
162
|
-
console.log(`\n🌐 Telar sirviendo en http://localhost:${puerto}
|
|
163
|
-
console.log(
|
|
231
|
+
console.log(`\n🌐 Telar sirviendo en http://localhost:${puerto}`);
|
|
232
|
+
console.log(`⚡ Live reload activo — guarda el archivo para recompilar`);
|
|
233
|
+
console.log(`\n Presiona Ctrl+C para parar\n`);
|
|
164
234
|
});
|
|
165
|
-
// Limpiar
|
|
235
|
+
// Limpiar al salir
|
|
166
236
|
process.on('SIGINT', () => {
|
|
167
237
|
console.log('\n\n Parando servidor...');
|
|
238
|
+
wsServer.close();
|
|
168
239
|
fs.rmSync(salida, { recursive: true, force: true });
|
|
169
240
|
process.exit(0);
|
|
170
241
|
});
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AACA,MAAM;AACN,SAAS;AACT,0CAA0C;AAC1C,wCAAwC;AACxC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEN,uCAAwB;AACxB,2CAA4B;AAC5B,2CAA4B;AAC5B,mCAA+B;AAC/B,qCAAiC;AACjC,2CAAuC;AACvC,mCAAoC;AAEpC,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB,MAAM,KAAK,GAAG;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/carrito.html
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
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>
|
package/dist/index.html
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
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>
|
package/dist/producto-(id).html
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
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
|
-
});
|