From e1df91459062f8705d9e0206a1ac55eb5a91bbb6 Mon Sep 17 00:00:00 2001 From: SITO Date: Fri, 1 May 2026 02:02:43 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20collapsible=20hamburger=20menu=20for=20?= =?UTF-8?q?mobile=20=E2=80=94=20pure=20CSS,=20no=20JS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../src/client/assets/styles/mobile.css | 93 +++++++++++++++++-- .../src/client/assets/styles/style.css | 6 ++ .../src/client/assets/themes/OasisMobile.css | 22 +++++ .../nodejs-project/src/views/main_views.js | 10 ++ 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/nodejs-project/nodejs-project/src/client/assets/styles/mobile.css b/nodejs-project/nodejs-project/src/client/assets/styles/mobile.css index df86d28c..47bb7123 100644 --- a/nodejs-project/nodejs-project/src/client/assets/styles/mobile.css +++ b/nodejs-project/nodejs-project/src/client/assets/styles/mobile.css @@ -137,7 +137,59 @@ a.logo-icon img.logo-icon { padding: 8px 12px !important; } -/* ---- Layout ---- */ +/* ============================================================ + MENU HAMBURGER — CSS puro, sin JS + Checkbox oculto controla visibilidad del panel + ============================================================ */ + +.mobile-menu-checkbox { + display: none !important; +} + +/* Boton hamburger en el header */ +.mobile-menu-btn { + display: inline-flex !important; + align-items: center !important; + gap: 2px !important; + cursor: pointer !important; + padding: 5px 8px !important; + border-radius: 6px !important; + font-size: 1.2rem !important; + flex-shrink: 0 !important; + line-height: 1 !important; + margin-right: 4px !important; + user-select: none !important; +} + +/* Toggle icono: ☰ cerrado, ✕ abierto */ +.menu-icon-close { display: none !important; } + +#mobile-menu-toggle:checked ~ .header .menu-icon-open { + display: none !important; +} +#mobile-menu-toggle:checked ~ .header .menu-icon-close { + display: inline !important; +} + +/* Boton cerrar dentro del panel */ +.mobile-menu-close { + display: none !important; +} + +/* Backdrop: capa oscura al fondo cuando el menu esta abierto */ +.mobile-menu-backdrop { + display: none !important; +} +#mobile-menu-toggle:checked ~ .mobile-menu-backdrop { + display: block !important; + position: fixed !important; + inset: 0 !important; + background: rgba(0, 0, 0, 0.55) !important; + z-index: 199 !important; + cursor: pointer !important; +} + +/* ---- Layout base: sidebars ocultos, contenido ocupa todo ---- */ .main-content { display: flex !important; flex-direction: column !important; @@ -146,18 +198,47 @@ a.logo-icon img.logo-icon { gap: 10px !important; } -.sidebar-left, .sidebar-right, .main-column { +.sidebar-left, +.sidebar-right { + display: none !important; +} + +.main-column { width: 100% !important; max-width: 100% !important; min-width: 0 !important; padding: 8px !important; - border-left: none !important; + order: 1 !important; +} + +/* ---- Panel lateral: se muestra cuando el menu esta abierto ---- */ +#mobile-menu-toggle:checked ~ .main-content .sidebar-left { + display: block !important; + position: fixed !important; + top: 0 !important; + left: 0 !important; + width: 82vw !important; + max-width: 320px !important; + height: 100vh !important; + overflow-y: auto !important; + z-index: 200 !important; + padding: 0 12px 24px 12px !important; border-right: none !important; } -.sidebar-left { order: 1 !important; } -.main-column { order: 3 !important; } -.sidebar-right { order: 2 !important; } +#mobile-menu-toggle:checked ~ .main-content .sidebar-left .mobile-menu-close { + display: flex !important; + align-items: center !important; + gap: 6px !important; + cursor: pointer !important; + padding: 14px 4px 10px 4px !important; + font-size: 0.9rem !important; + font-weight: bold !important; + width: 100% !important; + border-bottom: 1px solid #444 !important; + margin-bottom: 8px !important; + user-select: none !important; +} .sidebar-left nav ul, .sidebar-right nav ul { display: flex !important; diff --git a/nodejs-project/nodejs-project/src/client/assets/styles/style.css b/nodejs-project/nodejs-project/src/client/assets/styles/style.css index cda9c2b5..b2073d52 100644 --- a/nodejs-project/nodejs-project/src/client/assets/styles/style.css +++ b/nodejs-project/nodejs-project/src/client/assets/styles/style.css @@ -4355,3 +4355,9 @@ button, input[type="submit"], input[type="button"], .filter-btn { max-width: 280px; opacity: 0.7; } + +/* Hamburger: oculto en desktop, visible solo en movil via mobile.css */ +.mobile-menu-btn { display: none; } +.mobile-menu-backdrop { display: none; } +.mobile-menu-close { display: none; } +.mobile-menu-checkbox { display: none; } diff --git a/nodejs-project/nodejs-project/src/client/assets/themes/OasisMobile.css b/nodejs-project/nodejs-project/src/client/assets/themes/OasisMobile.css index 4dc6ad88..8860b3be 100644 --- a/nodejs-project/nodejs-project/src/client/assets/themes/OasisMobile.css +++ b/nodejs-project/nodejs-project/src/client/assets/themes/OasisMobile.css @@ -345,3 +345,25 @@ a.user-link:focus { background-color: #1A1A1A; border: 1px solid #333; } + +/* Hamburger menu */ +.mobile-menu-btn { + background-color: #2a2a00; + color: #FFD700; + border: 1px solid #444; +} + +.mobile-menu-btn:hover { + background-color: #3a3a00; + border-color: #FFD700; +} + +/* Panel lateral abierto */ +#mobile-menu-toggle:checked ~ .main-content .sidebar-left { + background-color: #1A1A1A; + border-right: 1px solid #333; +} + +.mobile-menu-close { + color: #FFD700; +} diff --git a/nodejs-project/nodejs-project/src/views/main_views.js b/nodejs-project/nodejs-project/src/views/main_views.js index f01e39d5..1352fc6d 100644 --- a/nodejs-project/nodejs-project/src/views/main_views.js +++ b/nodejs-project/nodejs-project/src/views/main_views.js @@ -691,6 +691,7 @@ const template = (titlePrefix, ...elements) => { }) ), body( + input({ type: 'checkbox', id: 'mobile-menu-toggle', class: 'mobile-menu-checkbox' }), div( { class: "header" }, div( @@ -703,6 +704,11 @@ const template = (titlePrefix, ...elements) => { alt: "Oasis Logo" }) ), + label( + { for: 'mobile-menu-toggle', class: 'mobile-menu-btn', 'aria-label': 'Menu' }, + span({ class: 'menu-icon-open' }, '☰'), + span({ class: 'menu-icon-close' }, '✕') + ), nav( ul( (() => { @@ -749,6 +755,9 @@ const template = (titlePrefix, ...elements) => { { class: "main-content" }, div( { class: "sidebar-left" }, + label({ for: 'mobile-menu-toggle', class: 'mobile-menu-close' }, + span({ class: 'menu-icon-close' }, '✕'), ' Cerrar' + ), nav( ul( navGroup( @@ -911,6 +920,7 @@ const template = (titlePrefix, ...elements) => { ) ) ), + label({ for: 'mobile-menu-toggle', class: 'mobile-menu-backdrop' }), renderFooter() ) );