- Description:
- TUI para gestionar el contenido de nezzontli.xyz sin CMS.
- Last Change:
- Clone URL:
https://git.nezzontli.xyz/clone/nezzontli-ctl.git
Commit Briefs
Autor por defecto de entradas y páginas nuevas: «Ale B. E.»
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
flake.nix: agrega packages.default — paquete Nix real, no solo devShell
Hasta ahora solo había devShells.default (venv + pip, pensado para desarrollar/debuggear). Para poder declararlo en la config de NixOS como un paquete normal (mismo patrón que usa Ale para sus otros proyectos propios, ej. inputs.psysonic.packages.${system}.default en /nixdots) hace falta un output packages.${system}.default de verdad. Se arma con python313Packages.buildPythonApplication usando las deps de nixpkgs directamente (textual, pyfiglet, matplotlib, textual-image y flatlatex ya estaban empaquetadas ahí) — solo cowsay (el paquete de Python) no está, así que se empaqueta a mano (wheel puro de PyPI, sin deps propias, build corto). Ventaja sobre el devShell: numpy/matplotlib de nixpkgs ya vienen enlazados correctamente contra libstdc++, así que este paquete NO necesita el fix de LD_LIBRARY_PATH que sí hace falta en el devShell (venv + pip instala wheels compilados que esperan rutas FHS que no existen en NixOS). Confirmado con 'nix build .#default' + prueba de imports (matplotlib, textual_image, flatlatex, cowsay, nezzontli_ctl) sin exportar nada a mano. El devShell queda intacto para seguir desarrollando/debuggeando igual que hasta ahora.
Agrega wrapper bin/ctl para comando global (evita el bug de pipx en nixpkgs)
pipx no está en el cache binario de nixpkgs para este snapshot — su propio test suite tiene un bug (parametrize mal armado en test_inject.py) que rompe el build desde cero. Y aunque se lo evite, un pipx install plano tampoco alcanzaría: la app necesita libstdc++.so.6 (numpy, para el renderizado de LaTeX del preview) que en NixOS solo está en el LD_LIBRARY_PATH que arma el shellHook del flake. bin/ctl es un wrapper chico que resuelve su propia ubicación (para andar symlinkeado desde ~/.local/bin), se para en el directorio del repo, y delega todo a 'nix develop . --command ctl' — reusa el flake real en vez de duplicar su lógica, así que no se puede desincronizar. Actualiza el README con la instalación (symlink en vez de pipx) y el estado real del proyecto (menú de dos niveles, eliminar, preview LaTeX/imágenes).
Confirmación de eliminar: una sola pregunta, diálogo centrado; centra el mensaje de cowsay
ConfirmDeleteScreen pasa de doble confirmación a una sola (el usuario pidió revertir eso), y en vez de reusar .form-container (pensado para formularios que ocupan toda la pantalla) ahora es un diálogo compacto de ancho fijo (64 cols) centrado con align: center middle sobre la propia screen. #success-container (el cowsay del final) le faltaba width: 100% — sin eso 'align: center middle' no tenía espacio extra para centrar contra, así que quedaba pegado a la izquierda. Se agrega, más content-align: center middle en el Static del arte ASCII para que el bloque de texto multilínea también se centre horizontalmente dentro de su caja.
Menú de dos niveles (Crear/Editar) + eliminar entradas con doble confirmación
El menú principal pasaba de 4 a 9 opciones con post/page/album duplicados entre crear y editar — más difícil de escanear. Ahora es: Crear nuevo…, Editar existente…, Configuración, Salir; cada uno abre un submenú con las 3-4 opciones específicas y un '← Volver'. 'Agregar fotos a un álbum existente' se movió a Editar (opera sobre un álbum ya creado). Se agrega la opción de editar páginas extra de un proyecto (ej. content/blog/cortometraje/rama1.md) — antes solo se podía editar el index.md de cada proyecto, no las páginas extra generadas con 'page'. list_extra_pages() las lista, NewPageScreen ahora acepta existing_file igual que NewPostScreen (oculta proyecto/slug, precarga título/descripción/ tags/páginas relacionadas, preserva la fecha original). Se agrega un botón 'Eliminar' en los tres formularios de edición (post, página, álbum) con confirmación DOBLE (ConfirmDeleteScreen, mismo modal pregunta dos veces antes de devolver True) antes de borrar y pushear: - post: borra content/blog/<slug>/ completo (incluye sus páginas extra) - página: borra solo ese .md, no toca el resto del proyecto - álbum: borra content/photos/<slug>/ Y static/images/<slug>/ (las fotos en sí, para no dejar basura LFS huérfana) Probado de punta a punta contra un fixture git descartable (bare repo como origin) para los tres flujos de borrado: confirma que el path correcto se borra del disco, se commitea y se pushea al origin.
Editor: posiciona el cursor al inicio del documento al abrir, no al final
Tenía sentido para posts nuevos (arrancar escribiendo al final de un frontmatter ya armado), pero al editar un archivo existente el usuario quiere empezar viendo el principio del documento, no el final.
Preview: no parte los bloques de código ``` en varios widgets
split_paragraphs_with_offsets (agregado para el sync por párrafo) cortaba por cualquier línea en blanco, sin distinguir si estaba dentro de un bloque ```código``` — muy común tener líneas en blanco entre funciones/ comentarios en código real. Cada pedazo se montaba como su propio widget Markdown con su propio margen, así que el bloque se veía hecho pedazos con huecos enormes en vez de un solo bloque contiguo. Ahora un bloque ```...``` se detecta primero y se trata como un párrafo atómico — nunca se parte por las líneas en blanco que tenga adentro. El texto antes/después del bloque sigue partiéndose en párrafos finos para el sync, como antes.
Sync del scroll: un anchor por párrafo (no solo por imagen/fórmula) y arregla el salto de imágenes
Dos bugs quedaban con el sync por línea-ancla: 1. Se anclaba CADA widget de un grupo (imagen + su caption, o cada foto de una gallery en la misma línea de origen), y el algoritmo de selección se queda con el ÚLTIMO anchor que empata esa línea — al llegar ahí el scroll saltaba directo a la caption (o a la última foto), dejando la imagen en sí arriba, fuera de vista. Ahora es un solo anchor por línea de origen distinta, apuntando siempre al primer widget ahí. 2. Un tramo largo de texto plano sin imágenes/fórmulas en el medio se montaba como un único widget Markdown gigante con un solo anchor — así que después de la última fórmula/imagen del documento, no había más anchors y el preview se quedaba pegado ahí por el resto del documento por más que se siguiera bajando en el editor. Ahora cada párrafo (separado por línea en blanco) es su propio widget con su propio anchor, repartidos parejo en todo el texto y no solo donde hay medios. _render_segment ahora devuelve (widget, línea_o_None) en vez de solo widgets — None para los que no deben ser su propio punto de anclaje (la caption de una imagen).
Sync del scroll: usa la línea lógica real, no la fila visual (rompía con wrap)
scroll_y de TextArea está en filas VISUALES, no en líneas lógicas del documento — con soft_wrap (el default, y lo normal para escribir párrafos de blog como una sola línea larga) una línea lógica ocupa varias filas visuales. Los anchors del preview se calculan en líneas lógicas (text.count('\n', ...)), así que compararlos directo contra scroll_y (filas visuales) se desalineaba cada vez más division a medida que había párrafos largos arriba en el documento — exactamente el desfase que se seguía viendo. TextArea.wrapped_document.offset_to_location() traduce la fila visual de vuelta a la línea lógica real (confirmado con params: fila=45 → línea 16, no fila=45 → línea 45), que es la misma unidad de los anchors.
Branches
Tree
| .gitignore | commits | blame |
| README.md | commits | blame |
| README.txt | commits | blame |
| bin/ | |
| flake.lock | commits | blame |
| flake.nix | commits | blame |
| nezzontli_ctl/ | |
| pyproject.toml | commits | blame |
README.txt
nezzontli-ctl TUI (Textual) para crear/editar contenido de nezzontli.xyz https://nezzontli.xyz sin depender de un CMS externo ninguno soporta git-lfs, que es como se versionan las fotos de los lbumes. Esta herramienta usa git real (el mismo git lfs install de siempre), as que no tiene ese problema. Es un proyecto separado del repo del sitio: opera sobre ~/projects/website (u otra ruta, ver NEZZONTLI_REPO_PATH abajo), no vive adentro de l. Desarrollo ---------- nix develop # crea/activa .venv y hace pip install -e . automticamente ctl # o: python3 -m nezzontli_ctl NEZZONTLI_REPO_PATH (variable de entorno, opcional) apunta al clone del sitio sobre el que trabaja. Default: ~/projects/website. Tambin se puede fijar de forma persistente en ~/.config/nezzontli-ctl/config.json (repo_path) o cambiarla desde la pantalla de Configuracin. Instalacin (comando ctl global, sin nix develop a mano) ------------------------------------------------------- ln -s ~/projects/nezzontli-ctl/bin/ctl ~/.local/bin/ctl ctl # ya disponible en cualquier terminal bin/ctl es un wrapper (nix develop . --command ctl parado en el directorio del repo) no un pipx install. La app necesita libstdc++.so.6 (lo pide numpy, dependencia de matplotlib para el renderizado de LaTeX del preview), y en NixOS esa lib solo est en el LD_LIBRARY_PATH que arma el shellHook del flake; un pipx install plano no lo lleva y crasheara al primer $...$ en el preview. El wrapper sortea eso reusando siempre el flake real. Estado ------ Men de dos niveles: Crear nuevo (post / pgina en un proyecto / lbum) y Editar existente (post / pgina extra de un proyecto / lbum / agregar fotos a un lbum), ms Configuracin. Cada flujo de edicin tiene botn Eliminar (confirmacin simple, borra del disco y pushea). Validado contra un clone local descartable (bare repo como origin) para los tres borrados: se confirma qu se borra del disco, el commit y el push al origin. El preview del editor, adems de Markdown, renderiza frmulas en bloque ($$...$$) como imagen (subset mathtext de matplotlib, fondo transparente) y aproxima el LaTeX inline ($...$) a texto Unicode en el lugar (no rompe el prrafo). Muestra imgenes referenciadas locales del repo (![](), shortcodes photo()/gallery() de Zola) o remotas por URL (shortcode image()) usando el protocolo de grficos de la terminal (Kitty, Sixel o half-cell segn deteccin; si no hay terminal real, cae a texto). El scroll del editor y el preview estn sincronizados por lnea de origen. Probado contra el repo real de nezzontli.xyz en uso diario. Queda a decisin de Ale cundo retirar website/scripts/ctl.py (el script viejo, todava intacto) y si integrar esta herramienta a su config de NixOS.
