bienvenida: paso Perfil (workflow) de un toque, Activismo primero; Ajustes con la misma lista; fuera Personal/Social de la barra de arriba

This commit is contained in:
hacklab 2026-10-19 16:00:31 +02:00
parent 92a8dc3853
commit d267d2befe
10 changed files with 196 additions and 30 deletions

View file

@ -22,16 +22,13 @@ module.exports = ({ i18n }) => {
const renderMobileTopbar = () => {
// solo en movil: en escritorio manda la cabecera de upstream
if (process.env.OASIS_MOBILE !== '1') return "";
// FORK_IA_UX v3: Personal/Community VUELVEN al topbar (ya funcionan: la hoja cerrada es
// visibility:hidden y no bloquea los taps). Llena el top y da el filtro a un toque.
const hiveFilter = (typeof global !== "undefined" && global.__OASIS_HIVE_FILTER__) || "";
// Personal/Social ya no van aqui: filtraban el lanzador, que ahora esta en la hoja
// del menu, y con muchos modulos (workflow activistas) no cabian a 360px y tapaban
// el logo. Queda el hueco para el boton de No molestar del telefono
return div(
{ class: "oasis-mobile-topbar" },
a({ class: "omt-logo", href: "/" }, img({ src: "/assets/images/snh-oasis.jpg", alt: "Oasis" })),
isCompact() ? div({ class: "omt-menus" }) : div({ class: "omt-menus" },
a({ class: hiveFilter === "personal" ? "oasis-menu-btn active" : "oasis-menu-btn", href: hiveFilter === "personal" ? "/activity" : "/activity?hive=personal" }, span(i18n.menuPersonal || "Personal")),
a({ class: hiveFilter === "community" ? "oasis-menu-btn active" : "oasis-menu-btn", href: hiveFilter === "community" ? "/activity" : "/activity?hive=community" }, span(i18n.menuSocial || "Social"))
),
div({ class: "omt-menus" }),
a({ class: "omt-avatar", href: "/profile" }, img({ src: (typeof global !== "undefined" && global.__OASIS_SELF_AVATAR__) || "/assets/images/default-avatar.png", alt: i18n.profile || "Profile" }))
);
};

View file

@ -157,6 +157,36 @@ const uxPick = (action, cfg, withHint) => {
);
};
// perfil de uso (workflow): igual, un boton por opcion con una linea de para que
// sirve. Activismo y Acampada primero; el resto en el orden del dev
const WORKFLOW_FIRST = ['activists', 'acampada'];
const workflowPick = (action, current, keys, withHint) => {
const i18n = t();
const list = WORKFLOW_FIRST.filter(k => keys.includes(k)).concat(keys.filter(k => !WORKFLOW_FIRST.includes(k)));
const name = (k) => k === 'full' ? (i18n.welcomeWorkflow_full || k) : (i18n[`workflow_${k}`] || k);
return form({ method: 'POST', action, class: 'ux-pick wf-pick' },
withHint ? p({ class: 'ux-pick-hint' }, i18n.uxPickHint || 'Tap one and it is saved. You can change it any time in Settings.') : null,
div({ class: 'ux-pick-grid' },
...list.map(k => button(Object.assign({ type: 'submit', name: 'workflow', value: k, class: k === current ? 'ux-pick-card is-current' : 'ux-pick-card' }, k === current ? { 'aria-current': 'true' } : {}),
span({ class: 'ux-pick-text' },
span({ class: 'ux-pick-label' }, name(k)),
i18n[`wfHint_${k}`] ? span({ class: 'ux-pick-sub' }, i18n[`wfHint_${k}`]) : null),
k === current ? span({ class: 'ux-pick-now' }, i18n.uxPickCurrent || 'In use') : null
))
)
);
};
// pasos de la bienvenida en el movil: el backend del dev quita el de uso en el movil;
// aqui vuelve, el segundo, justo despues de la identidad (/welcome/workflow es suyo)
const welcomeSteps = (usable) => {
if (usable.includes('workflow')) return usable;
const out = usable.slice();
const at = out.indexOf('profile');
out.splice(at === -1 ? 0 : at + 1, 0, 'workflow');
return out;
};
// ---------- acciones de tarjeta ----------
// borrar pide un segundo toque: la X abre "¿Borrar? Si, borrar" y solo ese boton
@ -200,6 +230,6 @@ const welcomeBannerAction = () => t().welcomeBannerActionMobile || t().welcomeBa
module.exports = {
isMobile, VOTE_KINDS, voteKindPicker, voteBars, voteOwnNote, tribeRow, tribeTabs,
settingsOrder, languagePick, uxPick, deleteConfirm, footerLine,
settingsOrder, languagePick, uxPick, workflowPick, welcomeSteps, deleteConfirm, footerLine,
welcomeBannerHere, welcomeBannerText, welcomeBannerAction
};

View file

@ -72,10 +72,7 @@ const settingsView = (params) => {
);
const workflowPicker = () => section({ id: "workflows" },
div({ class: "tags-header" }, h2(i18n.workflowsTitle), p(i18n.workflowsDescriptionMobile)),
form({ action: "/settings/workflow", method: "POST", class: "workflow-pick" },
...WORKFLOWS.map(w => button({ type: "submit", name: "workflow", value: w.key, class: activeWorkflow === w.key ? "workflow-card is-current" : "workflow-card" },
i18n[`workflow_${w.key}`] || w.key))
)
mobileUi.workflowPick("/settings/workflow", activeWorkflow, WORKFLOWS.map(w => w.key))
);
const workflowSection = isMobile ? workflowPicker() : section({ id: "workflows" },

View file

@ -17,6 +17,7 @@ const SECTIONS = {
community: ["welcomeStepCommunity", "welcomeHintCommunity"],
greeting: ["welcomeStepIntro", "welcomeHintIntro"]
}
if (mobileUi.isMobile()) SECTIONS.workflow = ["welcomeStepUseMobile", "welcomeHintUseMobile"]
const submitRow = (text) => div({ class: "welcome-action" }, button({ type: "submit" }, text))
@ -54,6 +55,7 @@ const stepAction = (key, profile, status) => {
}
if (key === "workflow") {
const selected = WIZARD_WORKFLOWS.includes(status.workflow) ? status.workflow : "full"
if (mobileUi.isMobile()) return mobileUi.workflowPick("/welcome/workflow", WIZARD_WORKFLOWS.includes(status.workflow) ? status.workflow : null, WIZARD_WORKFLOWS, true)
return form({ method: "POST", action: "/welcome/workflow", class: "welcome-select-form" },
select({ name: "workflow" },
WIZARD_WORKFLOWS.map(k => option({ value: k, ...(k === selected ? { selected: true } : {}) }, k === "full" ? i18n.welcomeWorkflow_full : (i18n[`workflow_${k}`] || k)))
@ -104,7 +106,7 @@ const stepAction = (key, profile, status) => {
exports.welcomeView = async (status, profile = {}) => {
const steps = status.steps || {}
const usable = status.usable || []
const usable = mobileUi.isMobile() ? mobileUi.welcomeSteps(status.usable || []) : (status.usable || [])
const opened = usable.find(key => !steps[key])
const html = template(
i18n.welcomeTitle,