objetivo.txt (8920B)
1 simpleblog — generador estatico minimalista de blog 2 ==================================================== 3 4 OBJETIVO 5 -------- 6 - Blog simple y minimalista. Minimo espacio, memoria y dependencias. 7 - Estructura limpia, etiquetas semanticas (head, header, main, article, footer). 8 - Versatil y facilmente configurable. 9 - Listado de entradas en la pagina principal con fecha + titulo + descripcion. 10 - Cabecera personalizable, css simple, logo, favicon, titulo, descripcion. 11 - Entradas en markdown (con posibilidad de html plano dentro). 12 - Inspirado en saait (codemadness.org/saait.html) pero comiendo .md. 13 14 15 DECISIONES (2026-05-18) 16 ----------------------- 17 - Lenguaje: shell script POSIX (sh + awk + sed). 18 Razon: minimo absoluto, sin compilar, facil de iterar. Si se queda corto, 19 migramos a C reusando saait. 20 - Conversor markdown: smu (suckless), instalado como paquete aparte 21 (apk add smu). El comando se configura en `config` (variable 22 `markdown_cmd`); rutas que empiezan por `./` se resuelven respecto al 23 directorio del sitio. 24 Nota: smu solo entiende markdown clasico de Gruber, NO triple backtick. 25 Bloques de codigo = 4 espacios de indentacion. 26 - Metadatos: frontmatter dentro del propio .md, formato `key: value`, separado 27 del cuerpo por una linea en blanco. Un fichero por entrada, sin .cfg aparte. 28 - Plantillas: ficheros HTML con `{{var}}` sustituido por sed/awk. Sin parser 29 propio. 30 - Estilo: estructura semantica + css minimal. 31 32 33 ESTRUCTURA (tras refactor 2026-05-18, repo empaquetable, sin make) 34 ------------------------------------------------------------------ 35 repo/ 36 simpleblog script principal (sh) -> /usr/bin/simpleblog 37 dev wrapper sh para devs (./dev build|serve|...) 38 templates/ plantillas DEFAULT -> /usr/share/simpleblog/templates/ 39 header.html, footer.html, post.html, page.html, 40 index.html, index-item.html, tags.html, 41 atom-{header,item,footer}.xml 42 skel/ esqueleto para `simpleblog init` 43 -> /usr/share/simpleblog/skel/ 44 example/ sitio funcional de demo (posts, pages, config...) 45 alpine/APKBUILD receta para empaquetar a .apk (sin make) 46 objetivo.txt este fichero 47 48 sitio del usuario (creado con `simpleblog init`): 49 config config global (key: value) 50 posts/ entradas .md|.html con frontmatter 51 pages/ paginas estaticas 52 images/ imagenes originales 53 static/ se copia tal cual a public/ (css, favicon, etc) 54 templates/ (opcional) overrides de las plantillas default 55 public/ salida generada (gitignored) 56 57 58 USO 59 --- 60 # desarrollo local del repo (sin instalar, sin make) 61 ./dev build construye example/public/ con templates/ del repo 62 ./dev serve sirve example/public/ (darkhttpd / busybox / python) 63 ./dev stats resumen de tamanos 64 ./dev clean borra example/public/ 65 66 # tarball para empaquetar (lo consume el APKBUILD en alpine/) 67 git archive --format=tar.gz --prefix=simpleblog-0.1/ HEAD \ 68 -o simpleblog-0.1.tar.gz 69 70 # como usuario final (despues de `apk add simpleblog`) 71 simpleblog init inicializa un sitio nuevo en el cwd (copia skel) 72 simpleblog build genera public/ 73 simpleblog serve sirve public/ en :8080 74 simpleblog stats resumen de tamanos 75 simpleblog clean borra public/ 76 77 DEPENDENCIAS DEL PAQUETE 78 ------------------------ 79 - smu (obligatoria) — conversor markdown 80 - darkhttpd o busybox-extras (opcional) — solo para `simpleblog serve` 81 - imagemagick (opcional) — solo para procesar imagenes 82 83 Nada de make/build-base/git para el usuario final. `apk add simpleblog` 84 y a usar. 85 86 87 HECHO (2026-05-18) 88 ------------------ 89 [x] Estructura de carpetas 90 [x] Script `simpleblog` (build + clean) 91 [x] Parseo de frontmatter en .md 92 [x] Conversion md -> html via comando externo configurable 93 [x] Plantillas header / footer / post / index / index-item con sustitucion {{var}} 94 [x] Index ordenado por fecha descendente con titulo + fecha + descripcion 95 [x] Copia de static/ tal cual al output 96 [x] CSS minimal de partida 97 [x] Post de ejemplo (posts/2026-05-18-hola-mundo.md) renderiza correctamente 98 [x] Integrar smu vendored (vendor/smu/) y compilar via Makefile 99 [x] Bloques de codigo renderizan como <pre><code> con escapado correcto 100 [x] Makefile con build / clean / serve / install / distclean 101 [x] Feed atom (atom.xml) generado, con plantillas atom-header/item/footer 102 [x] siteurl en config para URLs absolutas del feed 103 [x] <link rel="alternate"> al feed en el <head> de cada pagina 104 [x] XML del feed validado con xmllint 105 [x] Soporte para entradas .html (saltarse smu, usar cuerpo tal cual). El 106 bucle de posts itera sobre *.md y *.html. Frontmatter funciona igual. 107 [x] Borradores: frontmatter `draft: true` salta el post y avisa en stdout 108 [x] Slug en frontmatter: `slug: foo` -> public/foo.html (anula el nombre 109 del fichero, util para que la URL sea estable independiente del nombre) 110 [x] favicon.svg y logo.svg minimos en static/, enlazados desde header.html 111 (favicon como <link rel="icon" type="image/svg+xml">, logo dentro del 112 .site-brand junto al titulo) 113 [x] Paginas estaticas en `pages/` (paralelo a posts/). No aparecen en 114 index ni feed. Frontmatter `menu: true` + `menu_order: N` las anade 115 al menu del sitio (nav en header.html, ordenado numerico). 116 [x] Paginacion del index: config `posts_per_page`. index.html lleva los 117 mas recientes y page/2.html, page/3.html... el resto. Enlaces 118 prev/next pre-renderizados a HTML por el script. 119 [x] Tags en posts: frontmatter `tags: foo, bar`. Cada post muestra sus 120 tags. Se genera una pagina por tag (public/tags/<tag>.html) y un 121 indice global (public/tags.html) con cuenta de posts por tag. 122 [x] Refactor del script: funciones `sub_var` / `sub_file` / `render_layout` 123 eliminan duplicacion entre renders de post / page / index / tag-page. 124 [x] Imagenes: carpeta images/ con originales, config define 125 image_sizes (lista de anchos en px) e image_quality. El build genera 126 public/img/<nombre>-<ancho>.<ext> por cada (imagen, ancho) y copia 127 el original. En markdown usas `` directamente. 128 Sin upscale (-resize "Wx>" de magick). Cache por mtime: la segunda 129 build solo procesa imagenes nuevas/modificadas. Strip de EXIF. 130 Fallback: si magick/convert no estan, copia images/ tal cual. 131 [x] Formatos extra de imagen: config `image_extra_formats: webp` (o avif). 132 Para cada (imagen, ancho) se genera tambien la variante en el formato 133 extra. WebP comprime ~70% menos que JPEG en pruebas reales. 134 [x] Comando `make stats`: resumen de tamanos (originales, salida total, 135 variantes de imagen) y conteos (posts, pages, tags). 136 [x] .gitignore + commit inicial. vendor/ excluido (smu se clona via 137 `make`). public/ excluido (salida generada). 138 [x] Refactor para empaquetar (2026-05-18): script trabaja sobre cwd, 139 plantillas con override (./templates -> /usr/share/simpleblog/templates), 140 nuevo comando `init` que copia skel al cwd. Skel minimo en skel/. 141 Sitio de demo en example/. APKBUILD en alpine/. smu deja de ser 142 vendored y pasa a paquete aparte (apk add smu). 143 [x] Quitar make: no era coherente con la filosofia (en Alpine base no 144 viene). APKBUILD usa `install -Dm` directamente. Para devs, un 145 script `./dev` sh de 8 lineas hace de wrapper sobre example/. 146 147 148 POR HACER (pendiente, priorizado) 149 [ ] Ocultar <nav class="pagination"> cuando esta vacia (en tag pages y 150 cuando hay una sola pagina) — ahora queda un nav vacio en el HTML 151 [ ] Validacion: avisar si un slug colisiona entre posts/pages/borradores 152 [ ] Sanitizar tags (caracteres invalidos en nombre de fichero) 153 154 GOTCHAS / NOTAS 155 --------------- 156 - smu NO entiende triple backtick. Bloques de codigo = 4 espacios de 157 indentacion (markdown clasico). 158 - El feed atom mete el HTML del post dentro de CDATA. Si un post contiene 159 literalmente `]]>` se rompera el XML; cuando aparezca lo solucionamos. 160 - siteurl en `config` no lleva / al final; baseurl si (o empieza por /). 161 Las URLs absolutas del feed se forman como `$siteurl$baseurl<path>`. 162 - Colision de nombres: si tienes `foo.md` y `foo.html` en posts/, el segundo 163 procesado sobreescribe al primero en public/. Lo mismo entre posts/ y 164 pages/ si comparten slug. Usa nombres / slugs distintos. 165 - Tags: los usamos tal cual para nombre de fichero (public/tags/<tag>.html). 166 Si una tag tiene espacios, barras o caracteres raros, fallara. Usa solo 167 [a-z0-9-_] por ahora. 168 - En las paginas de tag y cuando solo hay una pagina de index, el 169 <nav class="pagination"> queda vacio (con espacios). No rompe nada 170 visualmente pero el HTML queda con un nodo vacio. 171 - La cache de imagenes vive en public/img/. `make clean` borra public/ 172 entera, por lo que tras un clean se regeneran TODAS las imagenes. 173 Para iterar rapido, usa `make build` directamente (sin clean) — el 174 check de mtime salta imagenes no modificadas.