navegacion: al abrir, la actividad; los modulos en la pestaña Menu

docs/ESTUDIO_NAVEGACION.md compara cuatro formas de moverse por la app
(lanzador en portada, boton de menu arriba, pestaña Menu abajo, hamburguesa)
y se queda con la pestaña de abajo, el patron Mas de Android y de las apps
grandes: al alcance del pulgar y en todas las pantallas.

- la portada es la actividad; el lanzador ya no se pinta alli
- quinta pestaña fija en la barra de abajo, Menu, que abre desde abajo una
  hoja con todos los modulos por secciones; se cierra con la X, tocando fuera
  o volviendo a tocar Menu. Sin JS: una casilla y CSS
- textos en los 11 idiomas; caben cinco pestañas a 360px
- capturas, portada y esquema de la interfaz al dia
This commit is contained in:
hacklab 2026-10-19 14:23:43 +02:00
parent 6eafe5ee18
commit 382d903bc5
18 changed files with 192 additions and 34 deletions

View file

@ -2,7 +2,7 @@
// Lo que la interfaz de la rama necesita del backend, fuera de backend.js.
//
// Prepara lo que leen la barra de arriba y el lanzador de hive_views.js: el filtro
// Personal/Social, si el lanzador se ensena en esta pagina y el avatar propio. Lo
// Personal/Social, que el lanzador no va en la portada y el avatar propio. Lo
// monta el router propio (fork_routes.js) delante de las rutas del dev. Nada de
// esto corre en escritorio. Ver GUIA_DE_DESARROLLO.md.
//
@ -30,7 +30,9 @@ module.exports = ({ getViewerId, about }) => {
return async (ctx, next) => {
if (!isMobile() || !isPage(ctx.path)) return next();
global.__OASIS_HIVE_FILTER__ = (ctx.path === '/activity' && (ctx.query.hive === 'personal' || ctx.query.hive === 'community')) ? ctx.query.hive : '';
global.__OASIS_SHOW_HIVE__ = (ctx.path === '/activity' || ctx.path === '/');
// el lanzador ya no va en la portada: la portada es la actividad y los modulos
// estan en la hoja de la pestaña Menu (docs/ESTUDIO_NAVEGACION.md)
global.__OASIS_SHOW_HIVE__ = false;
if (!avatarAt) await refreshAvatar();
else if (Date.now() - avatarAt > 60000) refreshAvatar();
return next();

View file

@ -531,3 +531,42 @@ body > .welcome-banner { order: -1; margin-top: 10px !important; }
background: var(--ux-bg) !important; color: var(--ux-fg) !important; box-shadow: none !important;
font-family: var(--ux-text) !important; font-weight: 700 !important; font-size: 15px !important; text-transform: uppercase; text-decoration: none !important;
}
/* ---------- pestaña Menu y su hoja con todos los modulos ---------- */
/* la portada es la actividad; los modulos se abren desde abajo, como el "Mas" de
Android (docs/ESTUDIO_NAVEGACION.md). Una casilla oculta abre y cierra la hoja */
.oasis-bottombar input.menu-toggle { position: absolute; opacity: 0; width: 0 !important; height: 0 !important; min-height: 0 !important; pointer-events: none; }
.oasis-bottombar label.bb-menu { cursor: pointer; }
.oasis-bottombar .menu-toggle:checked ~ label.bb-menu .bb-ico.has-svg { background: var(--ux-accent) !important; color: var(--ux-on-accent) !important; }
.oasis-bottombar .menu-sheet, .oasis-bottombar .menu-sheet-backdrop { display: none; }
.oasis-bottombar .menu-toggle:checked ~ .menu-sheet-backdrop {
display: block; position: fixed; inset: 0; z-index: 1002; background: rgba(0, 0, 0, .45);
}
.oasis-bottombar .menu-toggle:checked ~ .menu-sheet {
display: block; position: fixed; left: 0; right: 0; z-index: 1003;
bottom: 0; max-height: 82dvh; overflow-y: auto; overscroll-behavior: contain;
padding: 8px 14px calc(18px + env(safe-area-inset-bottom, 0px));
background: var(--ux-bg); color: var(--ux-fg);
border-top: 3px solid var(--ux-line); border-radius: 22px 22px 0 0;
box-shadow: 0 -6px 24px rgba(0, 0, 0, .25);
}
.menu-sheet-head {
position: sticky; top: -8px; z-index: 1; display: flex; align-items: center; justify-content: space-between;
margin: 0 -14px 8px; padding: 12px 14px 10px; background: var(--ux-bg); border-bottom: 2px solid var(--ux-line);
}
.menu-sheet-head::before {
content: ""; position: absolute; top: 4px; left: 50%; width: 44px; height: 5px; margin-left: -22px;
border-radius: 3px; background: var(--ux-muted);
}
.menu-sheet-title { font-family: var(--ux-title); font-size: 26px; text-transform: uppercase; line-height: 1; }
.menu-sheet-close {
display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; cursor: pointer;
border: 2px solid var(--ux-line); border-radius: 50%; font-size: 20px; background: var(--ux-bg);
}
.menu-sheet .launcher { margin: 0 !important; padding: 0 !important; }
/* cinco pestañas: que quepan a 360px */
.oasis-bottombar .bb-item { flex: 1 1 0 !important; min-width: 0 !important; }
@media (max-width: 380px) { .oasis-bottombar .bb-lbl { font-size: 11px !important; } }
.oasis-bottombar .menu-toggle:checked ~ div.menu-sheet { background: var(--ux-bg) !important; bottom: calc(66px + env(safe-area-inset-bottom, 0px)); border-radius: 22px 22px 0 0 !important; border: 0 !important; border-top: 3px solid var(--ux-line) !important; }
.oasis-bottombar div.menu-sheet-head { background: var(--ux-bg) !important; border: 0 !important; border-bottom: 2px solid var(--ux-line) !important; }
.oasis-bottombar .menu-toggle:checked ~ .menu-sheet-backdrop { bottom: calc(66px + env(safe-area-inset-bottom, 0px)); }

View file

@ -18,6 +18,8 @@
module.exports = {
en: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menu",
bbMenuClose: "Close",
workflow_acampada: "Camp",
tribeSectionsMore: "More",
tribeSectionsLabel: "Sections",
@ -96,6 +98,8 @@ module.exports = {
},
es: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menú",
bbMenuClose: "Cerrar",
workflow_acampada: "Acampada",
tribeSectionsMore: "Más",
tribeSectionsLabel: "Secciones",
@ -180,6 +184,8 @@ module.exports = {
},
fr: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menu",
bbMenuClose: "Fermer",
workflow_acampada: "Campement",
tribeSectionsMore: "Plus",
tribeSectionsLabel: "Sections",
@ -258,6 +264,8 @@ module.exports = {
},
eu: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menua",
bbMenuClose: "Itxi",
workflow_acampada: "Kanpaldia",
tribeSectionsMore: "Gehiago",
tribeSectionsLabel: "Atalak",
@ -336,6 +344,8 @@ module.exports = {
},
de: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menü",
bbMenuClose: "Schließen",
workflow_acampada: "Camp",
tribeSectionsMore: "Mehr",
tribeSectionsLabel: "Bereiche",
@ -414,6 +424,8 @@ module.exports = {
},
it: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menu",
bbMenuClose: "Chiudi",
workflow_acampada: "Accampata",
tribeSectionsMore: "Altro",
tribeSectionsLabel: "Sezioni",
@ -492,6 +504,8 @@ module.exports = {
},
pt: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Menu",
bbMenuClose: "Fechar",
workflow_acampada: "Acampada",
tribeSectionsMore: "Mais",
tribeSectionsLabel: "Secções",
@ -570,6 +584,8 @@ module.exports = {
},
zh: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "菜单",
bbMenuClose: "关闭",
workflow_acampada: "营地",
tribeSectionsMore: "更多",
tribeSectionsLabel: "板块",
@ -648,6 +664,8 @@ module.exports = {
},
ar: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "القائمة",
bbMenuClose: "إغلاق",
workflow_acampada: "مخيم",
tribeSectionsMore: "المزيد",
tribeSectionsLabel: "الأقسام",
@ -726,6 +744,8 @@ module.exports = {
},
hi: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "मेनू",
bbMenuClose: "बंद करें",
workflow_acampada: "शिविर",
tribeSectionsMore: "और",
tribeSectionsLabel: "खंड",
@ -804,6 +824,8 @@ module.exports = {
},
ru: {
// usabilidad (19/10/2026): votaciones, borrar, modulos, pie
bbMenu: "Меню",
bbMenuClose: "Закрыть",
workflow_acampada: "Лагерь",
tribeSectionsMore: "Ещё",
tribeSectionsLabel: "Разделы",

View file

@ -114,9 +114,26 @@ module.exports = ({ i18n }) => {
const slots = pins.map(m => bbLink(
m.href, m.glyph, i18n[m.labelKey] || m.key, m.key === 'inbox' ? inboxN : 0
));
// quinta pestaña fija: Menu abre desde abajo una hoja con todos los modulos (el
// lanzador). Sin JS: una casilla y CSS. autocomplete=off para que al volver atras
// el navegador no la deje abierta. Ver docs/ESTUDIO_NAVEGACION.md
const menuLabel = i18n.bbMenu || 'Menu';
return nav(
{ class: "oasis-bottombar", attrs: { "aria-label": i18n.bbQuickActions || "Quick actions" } },
...slots
input({ type: 'checkbox', id: 'oasis-menu-toggle', class: 'menu-toggle', autocomplete: 'off', 'aria-label': menuLabel }),
...slots,
label({ class: 'bb-item bb-menu', for: 'oasis-menu-toggle' },
iconNode('bb-ico', 'modules', '▦'),
span({ class: 'bb-lbl' }, menuLabel)
),
label({ class: 'menu-sheet-backdrop', for: 'oasis-menu-toggle', 'aria-hidden': 'true' }),
div({ class: 'menu-sheet', role: 'dialog', 'aria-label': menuLabel },
div({ class: 'menu-sheet-head' },
span({ class: 'menu-sheet-title' }, menuLabel),
label({ class: 'menu-sheet-close', for: 'oasis-menu-toggle', 'aria-label': i18n.bbMenuClose || 'Close' }, '✕')
),
renderHiveNav()
)
);
};