movil: usabilidad tras la prueba en el Pixel

Lo que salio de recorrer la app como alguien de la acampada:

- borrar (tribus y todo lo que usa renderContentActions) pide un segundo
  toque; la X va la ultima de la fila
- Karvan: Llamar empieza solo con voz (si se negaba la camara no arrancaba
  nada); botones con icono y nombre; textos traducidos; ayuda para invitar
- votaciones: tipo Si/No, semaforo o termometro (el servidor ya aceptaba
  options); resultados en barras; aviso a quien la crea de que no puede votar
- workflow activistas con tribus, parlamento, votaciones y eventos
- seccion apagada: /modules dice cual era y la activa de un toque
- Modulos en el movil: agrupados como el lanzador, interruptores y Guardar fijo
- tribus en filas compactas; secciones de una tribu en tira de fichas + Mas
- lanzador y barra con iconos SVG en vez de letras vai
- Ajustes: idioma y aspecto primero; idiomas de un toque
- aviso de bienvenida solo en la portada y en una linea; Ahora no al final
- pie de una linea con el estado de sincronizacion en claro
- mobile_ux.css para los dos skins: un margen de 14px (eran 74 por lado en
  las fichas), Anton solo en titulos y boton principal, buscador en una linea,
  la barra de abajo se esconde con el teclado
This commit is contained in:
SITO 2026-10-19 12:37:58 +02:00
parent 2e3ff1e79f
commit 4dd573662c
14 changed files with 1279 additions and 54 deletions

View file

@ -10,6 +10,7 @@
const { a, button, div, form, h2, h3, img, input, label, nav, p, section, span } = require("../server/node_modules/hyperaxe");
const { getConfig } = require("../configs/config-manager.js");
const sharedState = require("../configs/shared-state");
const { iconNode, iconKeyOf } = require("./mobile_icons");
// con pocos modulos activos (el workflow activistas) todo cabe en una pantalla:
// sobran el filtro Personal/Social y los accesos de usuario avanzado
@ -96,7 +97,7 @@ module.exports = ({ i18n }) => {
const modOn = (m) => !m || cfg.modules[m] === 'on' || cfg.modules[m] === undefined;
const bbLink = (href, ico, label, badge) => a(
{ class: "bb-item", href },
span({ class: "bb-ico" }, ico),
iconNode("bb-ico", iconKeyOf(href), ico),
(badge && badge > 0) ? span({ class: "bb-badge" }, String(badge)) : "",
span({ class: "bb-lbl" }, label)
);
@ -211,7 +212,7 @@ module.exports = ({ i18n }) => {
// Personal/Social de la topbar (lo pone el middleware desde ?hive=) parte el lanzador en dos
const hiveFilter = compact ? "" : ((typeof global !== "undefined" && global.__OASIS_HIVE_FILTER__) || "");
const app = (m) => a({ class: 'ln-app', href: m.href },
span({ class: 'ln-ico', 'aria-hidden': 'true' }, m.glyph),
iconNode('ln-ico', iconKeyOf(m.href), m.glyph),
span({ class: 'ln-lbl' }, i18n[m.labelKey] || m.href.slice(1)));
const groups = GROUPS
.filter(g => !hiveFilter || g.side === hiveFilter)
@ -243,14 +244,14 @@ module.exports = ({ i18n }) => {
);
const pinnedRow = (m) => actionForm('remove', m.key, 'bb-manage-form',
button({ type: 'submit', class: 'bb-manage-btn', 'aria-label': i18n.bbRemove || 'Remove' },
span({ class: 'bb-manage-ico' }, m.glyph),
iconNode('bb-manage-ico', iconKeyOf(m.href), m.glyph),
span({ class: 'bb-manage-lbl' }, i18n[m.labelKey] || m.key),
span({ class: 'bb-manage-x' }, '✕')
)
);
const addBtn = (m) => actionForm('add', m.key, 'bb-pick-form',
button({ type: 'submit', class: 'bb-pick-btn' },
span({ class: 'bb-pick-ico' }, m.glyph),
iconNode('bb-pick-ico', iconKeyOf(m.href), m.glyph),
span({ class: 'bb-pick-lbl' }, i18n[m.labelKey] || m.key)
)
);
@ -279,5 +280,5 @@ module.exports = ({ i18n }) => {
);
};
return { renderMobileTopbar, renderBottomBar, renderHiveNav, PINNABLE_MODULES, bottomBarPickerView };
return { renderMobileTopbar, renderBottomBar, renderHiveNav, PINNABLE_MODULES, bottomBarPickerView, GROUPS };
};