create-openclass-uniminuto 1.4.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.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +480 -0
  3. package/bin/create-openclass-uniminuto.mjs +142 -0
  4. package/package.json +39 -0
  5. package/template/.github/workflows/deploy.yml +64 -0
  6. package/template/README.md +326 -0
  7. package/template/config/openclass.config.iot-desde-openclass-iot.json +77 -0
  8. package/template/config/openclass.config.iot-ejemplo.json +81 -0
  9. package/template/demo_semana1.md +11 -0
  10. package/template/demo_semana2.md +11 -0
  11. package/template/demo_semana3.md +11 -0
  12. package/template/demo_semana4.md +11 -0
  13. package/template/demo_semana5.md +11 -0
  14. package/template/demo_semana6.md +11 -0
  15. package/template/demo_semana7.md +11 -0
  16. package/template/demo_semana8.md +11 -0
  17. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana1.md +12 -0
  18. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana2.md +12 -0
  19. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana3.md +12 -0
  20. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana4.md +12 -0
  21. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana5.md +12 -0
  22. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana6.md +12 -0
  23. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana7.md +12 -0
  24. package/template/ejemplos/iot-semanas-1-a-3/raiz/iot_semana8.md +12 -0
  25. package/template/ejemplos/iot-semanas-1-a-3/raiz/slides.md +154 -0
  26. package/template/ejemplos/iot-semanas-1-a-3/semanas/iot_semana1.md +846 -0
  27. package/template/ejemplos/iot-semanas-1-a-3/semanas/iot_semana2.md +1040 -0
  28. package/template/ejemplos/iot-semanas-1-a-3/semanas/iot_semana3.md +1071 -0
  29. package/template/openclass.config.json +79 -0
  30. package/template/package-lock.json +11568 -0
  31. package/template/package.json +61 -0
  32. package/template/plantillas/launcher.md +11 -0
  33. package/template/plantillas/semana.md +177 -0
  34. package/template/public/descargas/.gitkeep +0 -0
  35. package/template/public/favicon.png +0 -0
  36. package/template/public/fondos/slide-01-portada.png +0 -0
  37. package/template/public/fondos/slide-02-titulo.png +0 -0
  38. package/template/public/fondos/slide-03-imagen-izquierda.png +0 -0
  39. package/template/public/fondos/slide-04-imagen-derecha.png +0 -0
  40. package/template/public/fondos/slide-05-template.png +0 -0
  41. package/template/public/fondos/slide-06-cierre.png +0 -0
  42. package/template/public/imagenes/.gitkeep +0 -0
  43. package/template/public/videos/.gitkeep +0 -0
  44. package/template/scripts/build-incremental.mjs +33 -0
  45. package/template/scripts/build-site.mjs +33 -0
  46. package/template/scripts/decks.mjs +29 -0
  47. package/template/scripts/dev-all.mjs +37 -0
  48. package/template/scripts/export-downloads.mjs +53 -0
  49. package/template/scripts/export-incremental.mjs +49 -0
  50. package/template/scripts/generar-desde-config.mjs +279 -0
  51. package/template/scripts/nuevo-curso.mjs +104 -0
  52. package/template/scripts/preparar-github-pages.mjs +52 -0
  53. package/template/scripts/publicar.mjs +36 -0
  54. package/template/scripts/semana.mjs +122 -0
  55. package/template/scripts/zip-template.mjs +70 -0
  56. package/template/semanas/demo_semana1.md +177 -0
  57. package/template/semanas/demo_semana2.md +177 -0
  58. package/template/semanas/demo_semana3.md +177 -0
  59. package/template/semanas/demo_semana4.md +177 -0
  60. package/template/semanas/demo_semana5.md +177 -0
  61. package/template/semanas/demo_semana6.md +177 -0
  62. package/template/semanas/demo_semana7.md +177 -0
  63. package/template/semanas/demo_semana8.md +177 -0
  64. package/template/setup/shiki.ts +10 -0
  65. package/template/slides.md +65 -0
  66. package/template/snippets/external.ts +12 -0
  67. package/template/theme/uniminuto/README-AutoFit.md +28 -0
  68. package/template/theme/uniminuto/components/AutoFitText.vue +159 -0
  69. package/template/theme/uniminuto/components/Counter.vue +37 -0
  70. package/template/theme/uniminuto/components/FontToggle.vue +42 -0
  71. package/template/theme/uniminuto/layouts/slide-01-portada.vue +119 -0
  72. package/template/theme/uniminuto/layouts/slide-02-titulo.vue +63 -0
  73. package/template/theme/uniminuto/layouts/slide-03-imagen-izquierda.vue +110 -0
  74. package/template/theme/uniminuto/layouts/slide-04-imagen-derecha.vue +110 -0
  75. package/template/theme/uniminuto/layouts/slide-05-titulo-superior-texto-derecha.vue +104 -0
  76. package/template/theme/uniminuto/layouts/slide-06-titulo-superior-texto-izquierda.vue +109 -0
  77. package/template/theme/uniminuto/layouts/slide-07-multimedia-con-titulo.vue +87 -0
  78. package/template/theme/uniminuto/layouts/slide-08-titulo-texto.vue +78 -0
  79. package/template/theme/uniminuto/layouts/slide-09-objetivos.vue +77 -0
  80. package/template/theme/uniminuto/layouts/slide-10-titulo-dos-columnas.vue +89 -0
  81. package/template/theme/uniminuto/layouts/slide-11-dos-titulos-dos-columnas.vue +98 -0
  82. package/template/theme/uniminuto/layouts/slide-12-cierre.vue +27 -0
  83. package/template/theme/uniminuto/layouts/slide-codigo.vue +133 -0
  84. package/template/theme/uniminuto/package.json +13 -0
  85. package/template/theme/uniminuto/styles/base.css +109 -0
  86. package/template/theme/uniminuto/styles/index.ts +11 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 William Herrera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,480 @@
1
+ # create-openclass-uniminuto
2
+
3
+ Creador de proyectos **Open Class UNIMINUTO** basados en Slidev, con estructura institucional, generación progresiva de **8 semanas**, exportación de recursos y despliegue automático en **GitHub Pages**.
4
+
5
+ Este repositorio cumple dos funciones:
6
+
7
+ 1. Publicar un paquete npm llamado `create-openclass-uniminuto`.
8
+ 2. Servir como base para mantener una plantilla reutilizable de cursos Open Class.
9
+
10
+ ---
11
+
12
+
13
+ ## Flujo recomendado cuando el repositorio ya existe en GitHub
14
+
15
+ Este es el flujo pensado para la opción C: primero creas el repositorio en GitHub y luego generas el curso dentro de ese repositorio clonado.
16
+
17
+ ```bash
18
+ git clone https://github.com/herrerawilliamh/openclass-iot.git
19
+ cd openclass-iot
20
+ npm create openclass-uniminuto@latest . -- --iot
21
+ npm install
22
+ npm run semana -- 1
23
+ npm run dev
24
+ ```
25
+
26
+ Si el repositorio no está completamente vacío y quieres reemplazar archivos existentes de la plantilla, usa `--force`:
27
+
28
+ ```bash
29
+ npm create openclass-uniminuto@latest . -- --iot --force
30
+ ```
31
+
32
+ Después sincronizas con GitHub mediante Git, no mediante npm:
33
+
34
+ ```bash
35
+ git add -A
36
+ git commit -m "Configura Open Class IoT"
37
+ git push
38
+ ```
39
+
40
+ `npm create` genera o completa el proyecto; `git push` sincroniza el repositorio y activa GitHub Actions/GitHub Pages.
41
+
42
+ ## 1. Nombres recomendados
43
+
44
+ ### Paquete npm
45
+
46
+ ```json
47
+ "name": "create-openclass-uniminuto"
48
+ ```
49
+
50
+ Uso esperado después de publicarlo:
51
+
52
+ ```bash
53
+ npm create openclass-uniminuto@latest openclass-iot
54
+ ```
55
+
56
+ Con configuración inicial de IoT:
57
+
58
+ ```bash
59
+ npm create openclass-uniminuto@latest openclass-iot -- --iot
60
+ ```
61
+
62
+ La relación es esta:
63
+
64
+ ```text
65
+ Paquete publicado: create-openclass-uniminuto
66
+ Comando de uso : npm create openclass-uniminuto@latest nombre-del-curso
67
+ ```
68
+
69
+ ### Repositorio GitHub del generador npm
70
+
71
+ ```text
72
+ herrerawilliamh/create-openclass-uniminuto
73
+ ```
74
+
75
+ ### Repositorio GitHub de la plantilla visual
76
+
77
+ ```text
78
+ herrerawilliamh/openclass-uniminuto-template
79
+ ```
80
+
81
+ Este segundo repositorio puede marcarse como **Template repository** en GitHub para crear cursos desde el botón **Use this template**.
82
+
83
+ ### Repositorios de cursos generados
84
+
85
+ ```text
86
+ herrerawilliamh/openclass-iot
87
+ herrerawilliamh/openclass-bigdata
88
+ herrerawilliamh/openclass-gestion-seguridad
89
+ herrerawilliamh/openclass-percepcion-computacional
90
+ ```
91
+
92
+ URL esperada de GitHub Pages:
93
+
94
+ ```text
95
+ https://herrerawilliamh.github.io/openclass-iot/
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 2. Estructura que genera el paquete
101
+
102
+ ```text
103
+ mi-openclass/
104
+ ├─ .github/
105
+ │ └─ workflows/
106
+ │ └─ deploy.yml
107
+ ├─ config/
108
+ │ ├─ openclass.config.iot-ejemplo.json
109
+ │ └─ openclass.config.iot-desde-openclass-iot.json
110
+ ├─ plantillas/
111
+ │ ├─ launcher.md
112
+ │ └─ semana.md
113
+ ├─ public/
114
+ │ ├─ descargas/
115
+ │ ├─ fondos/
116
+ │ ├─ imagenes/
117
+ │ └─ videos/
118
+ ├─ scripts/
119
+ │ ├─ generar-desde-config.mjs
120
+ │ ├─ nuevo-curso.mjs
121
+ │ ├─ semana.mjs
122
+ │ ├─ preparar-github-pages.mjs
123
+ │ ├─ build-site.mjs
124
+ │ ├─ export-downloads.mjs
125
+ │ └─ decks.mjs
126
+ ├─ semanas/
127
+ ├─ openclass.config.json
128
+ ├─ slides.md
129
+ ├─ package.json
130
+ └─ README.md
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 3. Tres formas de trabajar
136
+
137
+ ### Opción A · Crear curso desde npm
138
+
139
+ Útil cuando quieres trabajar desde consola y generar todo el proyecto localmente.
140
+
141
+ ```bash
142
+ npm create openclass-uniminuto@latest openclass-iot -- --iot
143
+ cd openclass-iot
144
+ npm install
145
+ npm run semana -- 1
146
+ npm run dev
147
+ ```
148
+
149
+ Luego creas el repositorio en GitHub y subes el proyecto.
150
+
151
+ ---
152
+
153
+ ### Opción B · Crear curso desde GitHub Template
154
+
155
+ Útil cuando quieres crear el repositorio primero desde GitHub.
156
+
157
+ 1. Entra al repositorio `openclass-uniminuto-template`.
158
+ 2. Clic en **Use this template**.
159
+ 3. Crea un repositorio nuevo, por ejemplo `openclass-iot`.
160
+ 4. Clónalo en tu equipo.
161
+ 5. Ejecuta los comandos del curso.
162
+
163
+ ```bash
164
+ git clone https://github.com/herrerawilliamh/openclass-iot.git
165
+ cd openclass-iot
166
+ npm install
167
+ npm run nuevo
168
+ npm run semana -- 1
169
+ npm run dev
170
+ ```
171
+
172
+ ---
173
+
174
+ ### Opción C · Crear repo en GitHub y generar curso en local
175
+
176
+ Esta es una opción híbrida y recomendada cuando quieres separar el repositorio remoto de la generación local.
177
+
178
+ Primero creas en GitHub el repositorio `openclass-iot`. Puede ser:
179
+
180
+ - desde el botón **Use this template**;
181
+ - o como repositorio vacío.
182
+
183
+ Luego, en local, tienes dos posibilidades.
184
+
185
+ #### C1. Si el repositorio fue creado desde la plantilla
186
+
187
+ ```bash
188
+ git clone https://github.com/herrerawilliamh/openclass-iot.git
189
+ cd openclass-iot
190
+ npm install
191
+ npm run nuevo
192
+ npm run semana -- 1
193
+ npm run dev
194
+ ```
195
+
196
+ Después subes los cambios:
197
+
198
+ ```bash
199
+ git add -A
200
+ git commit -m "Generar semana 1"
201
+ git push
202
+ ```
203
+
204
+ #### C2. Si el repositorio en GitHub está vacío
205
+
206
+ ```bash
207
+ npm create openclass-uniminuto@latest openclass-iot -- --iot
208
+ cd openclass-iot
209
+ npm install
210
+ npm run semana -- 1
211
+ npm run dev
212
+ ```
213
+
214
+ Luego conectas ese proyecto local con el repositorio remoto:
215
+
216
+ ```bash
217
+ git init
218
+ git branch -M main
219
+ git add -A
220
+ git commit -m "Publicación inicial Open Class IoT"
221
+ git remote add origin https://github.com/herrerawilliamh/openclass-iot.git
222
+ git push -u origin main
223
+ ```
224
+
225
+ Ambas rutas llevan al mismo resultado: un curso Open Class versionado en GitHub y publicable en GitHub Pages.
226
+
227
+ ---
228
+
229
+ ## 4. Publicar este generador en npm
230
+
231
+ Desde la carpeta de este paquete:
232
+
233
+ ```bash
234
+ npm login
235
+ npm whoami
236
+ npm pack --dry-run
237
+ npm publish --access public
238
+ ```
239
+
240
+ Después de publicar, prueba desde otra carpeta:
241
+
242
+ ```bash
243
+ npm create openclass-uniminuto@latest prueba-openclass
244
+ cd prueba-openclass
245
+ npm install
246
+ npm run semana -- 1
247
+ npm run dev
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 5. Subir este generador a GitHub
253
+
254
+ Crea el repositorio:
255
+
256
+ ```text
257
+ herrerawilliamh/create-openclass-uniminuto
258
+ ```
259
+
260
+ Luego ejecuta:
261
+
262
+ ```bash
263
+ git init
264
+ git branch -M main
265
+ git add -A
266
+ git commit -m "Versión inicial del generador Open Class UNIMINUTO"
267
+ git remote add origin https://github.com/herrerawilliamh/create-openclass-uniminuto.git
268
+ git push -u origin main
269
+ ```
270
+
271
+ ---
272
+
273
+ ## 6. Crear el repositorio plantilla de GitHub
274
+
275
+ El repositorio plantilla debe llamarse preferiblemente:
276
+
277
+ ```text
278
+ openclass-uniminuto-template
279
+ ```
280
+
281
+ Para crearlo, puedes copiar el contenido de la carpeta `template/` como raíz de un nuevo repositorio:
282
+
283
+ ```bash
284
+ mkdir openclass-uniminuto-template
285
+ cp -R template/. openclass-uniminuto-template/
286
+ cd openclass-uniminuto-template
287
+
288
+ git init
289
+ git branch -M main
290
+ git add -A
291
+ git commit -m "Plantilla Open Class UNIMINUTO"
292
+ git remote add origin https://github.com/herrerawilliamh/openclass-uniminuto-template.git
293
+ git push -u origin main
294
+ ```
295
+
296
+ En GitHub activa:
297
+
298
+ ```text
299
+ Settings → General → Template repository
300
+ ```
301
+
302
+ Con eso podrás crear cursos desde:
303
+
304
+ ```text
305
+ Use this template → Create a new repository
306
+ ```
307
+
308
+ ---
309
+
310
+ ## 7. Generar semanas una a una
311
+
312
+ Cada curso tiene **8 semanas**. El comando principal es:
313
+
314
+ ```bash
315
+ npm run semana -- 1
316
+ ```
317
+
318
+ Ejemplos:
319
+
320
+ ```bash
321
+ npm run semana -- 2 --title "Arquitectura física de soluciones IoT" --date "Junio 15 de 2026"
322
+ ```
323
+
324
+ ```bash
325
+ npm run semana -- 3 --title "Protocolos de comunicación" --theme "MQTT, HTTP y comunicación entre dispositivos"
326
+ ```
327
+
328
+ ```bash
329
+ npm run semana -- 4 --title "Integración con plataformas en la nube" --activity "Laboratorio guiado" --duration "120 minutos"
330
+ ```
331
+
332
+ Activar solo una semana y desactivar las demás:
333
+
334
+ ```bash
335
+ npm run semana -- 5 --only
336
+ ```
337
+
338
+ Regenerar y sobrescribir el contenido interno de una semana:
339
+
340
+ ```bash
341
+ npm run semana -- 6 --force-content
342
+ ```
343
+
344
+ El comando `semana` actualiza:
345
+
346
+ ```text
347
+ openclass.config.json
348
+ slides.md
349
+ scripts/decks.mjs
350
+ package.json
351
+ curso_semanaN.md
352
+ semanas/curso_semanaN.md
353
+ ```
354
+
355
+ Por defecto conserva el contenido ya editado en `semanas/*.md`.
356
+
357
+ ---
358
+
359
+ ## 8. GitHub Pages
360
+
361
+ Cada curso generado incluye:
362
+
363
+ ```text
364
+ .github/workflows/deploy.yml
365
+ ```
366
+
367
+ El workflow realiza este proceso:
368
+
369
+ 1. Clona el repositorio.
370
+ 2. Configura GitHub Pages.
371
+ 3. Instala Node.js.
372
+ 4. Ejecuta `npm ci`.
373
+ 5. Instala Chromium para exportar PDF/PPTX con Slidev.
374
+ 6. Ejecuta `npm run pages:build`.
375
+ 7. Sube `dist` como artefacto de GitHub Pages.
376
+ 8. Publica el sitio.
377
+
378
+ En cada repositorio de curso debes activar GitHub Pages así:
379
+
380
+ ```text
381
+ Settings → Pages → Build and deployment → Source → GitHub Actions
382
+ ```
383
+
384
+ Después, cada `git push` a `main` publicará el sitio automáticamente.
385
+
386
+ ---
387
+
388
+ ## 9. Flujo semanal sugerido para un curso
389
+
390
+ Semana 1:
391
+
392
+ ```bash
393
+ npm run semana -- 1 --title "Introducción al curso"
394
+ git add -A
395
+ git commit -m "Agregar semana 1"
396
+ git push
397
+ ```
398
+
399
+ Semana 2:
400
+
401
+ ```bash
402
+ npm run semana -- 2 --title "Tema de la semana 2"
403
+ git add -A
404
+ git commit -m "Agregar semana 2"
405
+ git push
406
+ ```
407
+
408
+ Repite el proceso hasta la semana 8.
409
+
410
+ ---
411
+
412
+ ## 10. Actualizar el generador en npm
413
+
414
+ Cambio pequeño:
415
+
416
+ ```bash
417
+ npm version patch
418
+ npm publish
419
+ ```
420
+
421
+ Cambio funcional compatible:
422
+
423
+ ```bash
424
+ npm version minor
425
+ npm publish
426
+ ```
427
+
428
+ Cambio mayor:
429
+
430
+ ```bash
431
+ npm version major
432
+ npm publish
433
+ ```
434
+
435
+ ---
436
+
437
+ ## 11. Convenciones recomendadas
438
+
439
+ | Curso | Repositorio GitHub | Nombre corto sugerido |
440
+ |---|---|---|
441
+ | Internet de las Cosas | `openclass-iot` | `iot` |
442
+ | Big Data | `openclass-bigdata` | `bigdata` |
443
+ | Gestión de Seguridad de la Información | `openclass-gestion-seguridad` | `gsi` |
444
+ | Percepción Computacional | `openclass-percepcion-computacional` | `percepcioncomputacional` |
445
+
446
+ ---
447
+
448
+ ## 12. Resumen operativo
449
+
450
+ Para publicar el generador:
451
+
452
+ ```bash
453
+ npm publish --access public
454
+ ```
455
+
456
+ Para crear un curso desde npm:
457
+
458
+ ```bash
459
+ npm create openclass-uniminuto@latest openclass-iot -- --iot
460
+ ```
461
+
462
+ Para crear un curso desde GitHub:
463
+
464
+ ```text
465
+ Use this template → openclass-iot
466
+ ```
467
+
468
+ Para generar una semana:
469
+
470
+ ```bash
471
+ npm run semana -- 1
472
+ ```
473
+
474
+ Para publicar en GitHub Pages:
475
+
476
+ ```bash
477
+ git add -A
478
+ git commit -m "Actualizar Open Class"
479
+ git push
480
+ ```
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { spawnSync } from "node:child_process";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const packageRoot = path.resolve(__dirname, "..");
10
+ const templateRoot = path.join(packageRoot, "template");
11
+
12
+ const args = process.argv.slice(2);
13
+ const flags = new Set(args.filter((arg) => arg.startsWith("--")));
14
+ const positional = args.filter((arg) => !arg.startsWith("--"));
15
+ const targetArg = positional[0] || "openclass-uniminuto";
16
+ const targetDir = path.resolve(process.cwd(), targetArg);
17
+ const isCurrentDirectoryTarget = targetArg === "." || targetArg === "./";
18
+ const forceOverwrite = flags.has("--force");
19
+
20
+ function log(message = "") {
21
+ console.log(message);
22
+ }
23
+
24
+ function fail(message) {
25
+ console.error(`\n❌ ${message}\n`);
26
+ process.exit(1);
27
+ }
28
+
29
+ function cleanPackageName(value) {
30
+ return String(value || "openclass-uniminuto")
31
+ .normalize("NFD")
32
+ .replace(/[\u0300-\u036f]/g, "")
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9.-]+/g, "-")
35
+ .replace(/^-+|-+$/g, "") || "openclass-uniminuto";
36
+ }
37
+
38
+ function copyTemplate(src, dest) {
39
+ const base = path.basename(src);
40
+ if (["node_modules", "dist", ".slidev", ".git"].includes(base)) return;
41
+ const stat = fs.statSync(src);
42
+ if (stat.isDirectory()) {
43
+ fs.mkdirSync(dest, { recursive: true });
44
+ for (const child of fs.readdirSync(src)) {
45
+ copyTemplate(path.join(src, child), path.join(dest, child));
46
+ }
47
+ return;
48
+ }
49
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
50
+ if (fs.existsSync(dest) && !forceOverwrite) {
51
+ log(`↷ Conservado archivo existente: ${path.relative(targetDir, dest)}`);
52
+ return;
53
+ }
54
+ fs.copyFileSync(src, dest);
55
+ }
56
+
57
+ function isEffectivelyEmptyProject(dir) {
58
+ if (!fs.existsSync(dir)) return true;
59
+ const entries = fs.readdirSync(dir).filter((entry) => ![".git", ".gitkeep"].includes(entry));
60
+ return entries.length === 0;
61
+ }
62
+
63
+ function patchJson(filePath, patcher) {
64
+ if (!fs.existsSync(filePath)) return;
65
+ const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
66
+ patcher(data);
67
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
68
+ }
69
+
70
+ if (!fs.existsSync(templateRoot)) {
71
+ fail("No se encontró la carpeta template dentro del paquete npm.");
72
+ }
73
+
74
+ if (fs.existsSync(targetDir) && !isEffectivelyEmptyProject(targetDir) && !forceOverwrite) {
75
+ fail(`La carpeta destino ya contiene archivos: ${targetDir}
76
+
77
+ Para trabajar dentro de un repositorio ya creado en GitHub, usa una carpeta vacía o ejecuta con --force si deseas sobrescribir archivos existentes.
78
+ Ejemplo:
79
+ npm create openclass-uniminuto@latest . -- --iot --force`);
80
+ }
81
+
82
+ log("\n┌──────────────────────────────────────────────┐");
83
+ log("│ Crear proyecto Open Class UNIMINUTO · Slidev │");
84
+ log("└──────────────────────────────────────────────┘\n");
85
+ log(`Destino: ${targetDir}`);
86
+ if (isCurrentDirectoryTarget) log("Modo: aplicar plantilla en el directorio actual");
87
+ if (forceOverwrite) log("Modo: --force activo; se podrán sobrescribir archivos existentes");
88
+
89
+ copyTemplate(templateRoot, targetDir);
90
+
91
+ const innerName = cleanPackageName(path.basename(targetDir));
92
+ patchJson(path.join(targetDir, "package.json"), (pkg) => {
93
+ pkg.name = innerName;
94
+ });
95
+ patchJson(path.join(targetDir, "package-lock.json"), (lock) => {
96
+ lock.name = innerName;
97
+ if (lock.packages && lock.packages[""]) lock.packages[""].name = innerName;
98
+ });
99
+
100
+ if (flags.has("--iot")) {
101
+ const sourceConfig = path.join(targetDir, "config", "openclass.config.iot-desde-openclass-iot.json");
102
+ const destConfig = path.join(targetDir, "openclass.config.json");
103
+ if (!fs.existsSync(sourceConfig)) {
104
+ fail("No se encontró la configuración IoT incluida en la plantilla.");
105
+ }
106
+ fs.copyFileSync(sourceConfig, destConfig);
107
+ log("✓ Configuración IoT aplicada en openclass.config.json");
108
+
109
+ const result = spawnSync(process.execPath, ["scripts/generar-desde-config.mjs", "--force"], {
110
+ cwd: targetDir,
111
+ stdio: "inherit",
112
+ shell: false,
113
+ });
114
+ if (result.status !== 0) {
115
+ fail("El generador de configuración no pudo completar el proyecto IoT.");
116
+ }
117
+ }
118
+
119
+ if (flags.has("--install")) {
120
+ log("\nInstalando dependencias con npm install...\n");
121
+ const result = spawnSync("npm", ["install"], {
122
+ cwd: targetDir,
123
+ stdio: "inherit",
124
+ shell: process.platform === "win32",
125
+ });
126
+ if (result.status !== 0) {
127
+ fail("npm install terminó con error. Revisa la salida de consola.");
128
+ }
129
+ }
130
+
131
+ log("\n✅ Proyecto creado correctamente.\n");
132
+ log(`Siguientes pasos:`);
133
+ log(` cd ${path.relative(process.cwd(), targetDir) || "."}`);
134
+ if (!flags.has("--install")) log(" npm install");
135
+ if (!flags.has("--iot")) log(" npm run nuevo");
136
+ log(" npm run semana -- 1");
137
+ log(" npm run dev");
138
+ log("\nPara activar una semana adicional:");
139
+ log(" npm run semana -- 2 --title \"Título de la semana 2\"");
140
+ log("\nPara revisar la publicación en GitHub Pages:");
141
+ log(" npm run pages:check");
142
+ log("");
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "create-openclass-uniminuto",
3
+ "version": "1.4.0",
4
+ "description": "Creador de proyectos Open Class UNIMINUTO basados en Slidev, con generación incremental por semanas y GitHub Pages.",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-openclass-uniminuto": "./bin/create-openclass-uniminuto.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "template",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "keywords": [
16
+ "slidev",
17
+ "openclass",
18
+ "uniminuto",
19
+ "edtech",
20
+ "template",
21
+ "cli"
22
+ ],
23
+ "author": "William Herrera",
24
+ "license": "MIT",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/herrerawilliamh/create-openclass-uniminuto.git"
34
+ },
35
+ "homepage": "https://github.com/herrerawilliamh/create-openclass-uniminuto#readme",
36
+ "bugs": {
37
+ "url": "https://github.com/herrerawilliamh/create-openclass-uniminuto/issues"
38
+ }
39
+ }