Surtidito — optimización mobile (feed ámbar)

Fecha: 2026-09-14 · Repos: ~//nef/surtido · Archivo tocado: asgi.py (solo ahí; el vendored amber-console.css quedó intacto)

Qué estaba roto en móvil (medido con Playwright 390×844)

  1. Tocar una fila no abría la lectura. El reader quedaba hidden (tap solo resaltaba la fila; abrir() solo se disparaba con Enter/tecla, inexistente en móvil).
  2. No había forma de CERRAR el reader en móvil (solo esc).
  3. Overflow horizontal: la tabla del feed se renderizaba a ~829px dentro de un viewport de 390px (un token largo en min-content empujaba el table-layout:auto).
  4. DOM gigante: refrescar() pintaba los 1,581 items del feed-todo.rss.xml → página de ~113,000px de alto, lenta y con glow por fila.
  5. Touch targets chicos (tabs ~23px), overlay de lectura centrado al 86vh (no aprovechaba la pantalla), y sin viewport-fit=cover (safe-area iOS).

Qué se cambió

  • Tap → abrir: tr.onclick llama abrir() cuando movil.matches.
  • Botón ✕ cerrar en el pie del reader (función en JS lx.onclick), visible también en desktop.
  • Overflow: #rows td span{overflow-wrap:anywhere} → la tabla ahora se ajusta al contenedor (306px en móvil, 384px en el split desktop, sin scroll lateral).
  • Cap por mobile: visibles() recorta a 80 items solo si (max-width:719px); desktop sigue con los 1,581. El meta muestra “80 de 1581”.
  • Truncado responsive: títulos 140→42 chars y sub-línea a 60 solo en móvil (VT323 a 16px caben ~21 chars/línea), para que las filas no exploten en alto.
  • Reader full-bleed en móvil: overlay con padding 0, width/height 100dvh, overscroll-behavior:contain, #lect-pie sticky-bottom con safe-area inset y botones ≥46px.
  • Tabs 44px de alto en móvil; filas sin margin del <p>; touch-action:manipulation (mata el doble-tap-zoom); -webkit-text-size-adjust:100%; viewport-fit=cover.

Verificación (comandos)

# lanzar local
.venv/bin/python -m uvicorn asgi:app --port 8123 --log-level warning &
 
# node check del JS embebido
curl -s http://[IP]:8123/ > /tmp/built.html
python - <<'PY'
import re
html=open('/tmp/built.html').read()
open('/tmp/built.js','w').write(re.search(r'<script>(.*?)</script>',html,re.S).group(1))
PY
node --check /tmp/built.js   # -> JS OK
 
# playwright: tap abre reader (390×844), cerrar funciona, 80 filas, tabla 306px

Resultados post-cambio: sin pageerror, tap abre overlay a pantalla completa, siguiente navega (2/80), ✕ cerrar cierra, tabla 306px (sin overflow), scroll ~7,600px, filas ~83px. Desktop intacto: 1,581 filas, split 420px/998px sin overflow.

Notas

  • El table-layout:auto + overflow-wrap:anywhere también arregló el overflow del split desktop (antes la tabla de 829px se recortaba con scroll lateral).
  • Si algún día se quiere quitar el cap de 80 en móvil, es un borrado de una línea en visibles().

TODO pendiente (fuera de alcance): caché service worker / PWA para arrancar offline; mantener 80 en desktop si el feed-todo sigue creciendo.

Addendum (misma fecha): pasada 2 — navegación sencilla en móvil

Sin commit. asgi.py solos. Cambios:

  1. Gesto “atrás” cierra el lector (móvil). abrir() hace history.pushState({r:1}) si movil.matches && !enR; listener popstate cierra (encierra: nuevo function encerrar()) y re-push para que el segundo atrás sí salga de la página. Desktop intacto (guard movil.matches).
  2. Nav superior en una sola fila ≤719px (antes el framework apilaba 3 filas): .ac-nav__mark compacto a la izquierda, links FEED/RSS como pastillas 36px, #meta pegado a la derecha con ellipsis (40vw máx), justify-content:flex-start. 50px de alto medidos.
  3. Pistas de teclado escondidas en touch: #feed-hints, #lect-hints y #status (barra inferior con j/k/esc) → display:none en móvil. Desktop conserva todo (verificado 1280×800: split 838×608, 1,581 filas, Esc cierra).

Verificado (Playwright 390×844): nav 50px × 1 fila, overflow 0, tap abre full-bleed 390×844, go_back() cierra el lector y se queda en la misma URL, ✕ cerrar cierra, 0 pageerrors. Desktop sin regresión.

¿Siguiente si se retoma: panel de fuentes (Inoreader/hnterm) según [CREDENCIAL].md.