feat: mobile mode-buttons scroll arrows and expand/collapse

Adds left/right arrow navigation to all .mode-buttons on mobile.
Sections with 7+ buttons (Activity, Stats, etc.) also get a
Ver todos / Ver menos toggle to expand the full grid.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SITO 2026-05-02 00:23:13 +02:00
parent 1025f2789d
commit cb32d0b9ad
4 changed files with 160 additions and 1 deletions

View file

@ -735,3 +735,68 @@ pre, code {
max-width: 100% !important;
overflow-x: hidden !important;
}
/* ============================================================
MODE-BUTTONS MOBILE ENHANCEMENT (mobile-ui.js)
Scroll horizontal con flechas + expand/collapse
============================================================ */
/* Wrapper: flechas + contenedor alineados en fila */
.mode-buttons-wrap {
display: flex !important;
align-items: center !important;
gap: 4px !important;
width: 100% !important;
margin-top: 12px !important;
}
/* Contenedor de botones: scroll horizontal, sin wrap */
.mode-buttons-wrap .mode-buttons {
flex: 1 !important;
overflow-x: auto !important;
flex-wrap: nowrap !important;
scrollbar-width: none !important;
scroll-behavior: smooth !important;
margin-top: 0 !important;
padding-bottom: 4px !important;
}
.mode-buttons-wrap .mode-buttons::-webkit-scrollbar {
display: none !important;
}
/* Cuando está expandido: vuelve a wrap para mostrar todo en grid */
.mode-buttons-wrap.mode-buttons-expanded .mode-buttons {
overflow-x: visible !important;
flex-wrap: wrap !important;
}
/* Flechas de scroll */
.mode-btn-arrow {
flex-shrink: 0 !important;
width: 30px !important;
height: 34px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
border-radius: 8px !important;
font-size: 1.6rem !important;
line-height: 1 !important;
cursor: pointer !important;
padding: 0 !important;
transition: opacity 0.15s !important;
user-select: none !important;
}
/* Botón "Ver todos / Ver menos" */
.mode-expand-btn {
display: block !important;
width: 100% !important;
margin-top: 6px !important;
padding: 7px 12px !important;
border-radius: 8px !important;
font-size: 0.82rem !important;
font-weight: 600 !important;
text-align: center !important;
cursor: pointer !important;
letter-spacing: 0.02em !important;
}

View file

@ -395,3 +395,17 @@ a.user-link:focus {
.mobile-menu-close {
color: #FFD700;
}
/* Mode-buttons scroll arrows */
.mode-btn-arrow {
background-color: #2a2a00;
color: #FFD700;
border: 1px solid #444;
}
/* Expand/collapse button */
.mode-expand-btn {
background-color: #1e1e00;
color: #FFD700;
border: 1px solid #555;
}

View file

@ -0,0 +1,79 @@
(function () {
function setup() {
if (window.innerWidth > 768) return;
document.querySelectorAll('.mode-buttons:not([data-ms])').forEach(function (cnt) {
cnt.dataset.ms = '1';
var items = cnt.querySelectorAll('form, button.filter-btn, a.filter-btn');
var n = items.length;
if (n < 3) return;
// Wrap container with arrows
var wrap = document.createElement('div');
wrap.className = 'mode-buttons-wrap';
cnt.parentNode.insertBefore(wrap, cnt);
wrap.appendChild(cnt);
var la = document.createElement('button');
la.type = 'button';
la.className = 'mode-btn-arrow mode-btn-arrow-left';
la.innerHTML = '&#8249;';
la.setAttribute('aria-label', 'Anterior');
var ra = document.createElement('button');
ra.type = 'button';
ra.className = 'mode-btn-arrow mode-btn-arrow-right';
ra.innerHTML = '&#8250;';
ra.setAttribute('aria-label', 'Siguiente');
wrap.insertBefore(la, cnt);
wrap.appendChild(ra);
la.addEventListener('click', function (e) {
e.preventDefault();
cnt.scrollBy({ left: -180, behavior: 'smooth' });
});
ra.addEventListener('click', function (e) {
e.preventDefault();
cnt.scrollBy({ left: 180, behavior: 'smooth' });
});
function syncArrows() {
var atStart = cnt.scrollLeft < 5;
var atEnd = cnt.scrollLeft + cnt.clientWidth >= cnt.scrollWidth - 5;
la.style.opacity = atStart ? '0.2' : '1';
ra.style.opacity = atEnd ? '0.2' : '1';
la.style.pointerEvents = atStart ? 'none' : 'auto';
ra.style.pointerEvents = atEnd ? 'none' : 'auto';
}
cnt.addEventListener('scroll', syncArrows, { passive: true });
setTimeout(syncArrows, 120);
// Expand/collapse toggle for large button groups
if (n > 6) {
var expanded = false;
var xb = document.createElement('button');
xb.type = 'button';
xb.className = 'mode-expand-btn';
xb.textContent = 'Ver todos ▾';
wrap.parentNode.insertBefore(xb, wrap.nextSibling);
xb.addEventListener('click', function (e) {
e.preventDefault();
expanded = !expanded;
cnt.classList.toggle('mode-buttons-expanded', expanded);
wrap.classList.toggle('mode-buttons-expanded', expanded);
xb.textContent = expanded ? 'Ver menos ▴' : 'Ver todos ▾';
setTimeout(syncArrows, 50);
});
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', setup);
} else {
setup();
}
})();

View file

@ -23,7 +23,7 @@ const getUserId = async () => {
return userId;
};
const { a, article, br, body, button, details, div, em, footer, form, h1, h2, h3, head, header, hr, html, img, input, label, li, link, main, meta, nav, option, p, pre, section, select, span, summary, table, td, textarea, title, tr, ul, strong, video: videoHyperaxe, audio: audioHyperaxe } = require("../server/node_modules/hyperaxe");
const { a, article, br, body, button, details, div, em, footer, form, h1, h2, h3, head, header, hr, html, img, input, label, li, link, main, meta, nav, option, p, pre, script, section, select, span, summary, table, td, textarea, title, tr, ul, strong, video: videoHyperaxe, audio: audioHyperaxe } = require("../server/node_modules/hyperaxe");
const lodash = require("../server/node_modules/lodash");
const markdown = require("./markdown");
@ -682,6 +682,7 @@ const template = (titlePrefix, ...elements) => {
link({ rel: "stylesheet", href: "/assets/styles/style.css" }),
themeLink,
link({ rel: "stylesheet", href: "/assets/styles/mobile.css", media: "(max-width: 768px)" }),
script({ src: "/js/mobile-ui.js", defer: true }),
link({ rel: "icon", href: "/assets/images/favicon.svg" }),
meta({ charset: "utf-8" }),
meta({ name: "description", content: i18n.oasisDescription }),