From edf737092ab50c78ce226e0a16692326adf8ab34 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Tue, 20 May 2025 00:52:23 +0200 Subject: [PATCH] feat: implement responsive hamburger menu and enhance header layout --- src/app.js | 51 +++++++++ src/config/lessons.js | 8 +- src/main.css | 261 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+), 4 deletions(-) diff --git a/src/app.js b/src/app.js index 96851d6..8fe3c6e 100644 --- a/src/app.js +++ b/src/app.js @@ -611,6 +611,57 @@ function init() { e.preventDefault(); } }); + + // Add this to your app.js file + + // Mobile Menu Functionality + document.addEventListener("DOMContentLoaded", function () { + // Create hamburger menu button + const hamburger = document.createElement("button"); + hamburger.className = "hamburger"; + hamburger.setAttribute("aria-label", "Toggle menu"); + hamburger.innerHTML = ` + + + + `; + + // Get the header and nav elements + const header = document.querySelector(".header"); + const logo = document.querySelector(".logo"); + const nav = document.querySelector(".main-nav"); + + // Insert hamburger button after the logo + header.insertBefore(hamburger, logo.nextSibling); + + // Toggle menu on hamburger click + hamburger.addEventListener("click", function () { + nav.classList.toggle("open"); + hamburger.classList.toggle("open"); + + // Set aria-expanded attribute for accessibility + const isExpanded = nav.classList.contains("open"); + hamburger.setAttribute("aria-expanded", isExpanded); + }); + + // Close menu when clicking outside + document.addEventListener("click", function (event) { + if (!nav.contains(event.target) && !hamburger.contains(event.target) && nav.classList.contains("open")) { + nav.classList.remove("open"); + hamburger.classList.remove("open"); + hamburger.setAttribute("aria-expanded", false); + } + }); + + // Close menu when window is resized to desktop size + window.addEventListener("resize", function () { + if (window.innerWidth > 768 && nav.classList.contains("open")) { + nav.classList.remove("open"); + hamburger.classList.remove("open"); + hamburger.setAttribute("aria-expanded", false); + } + }); + }); } // Start the application diff --git a/src/config/lessons.js b/src/config/lessons.js index 3f95818..72a0af5 100644 --- a/src/config/lessons.js +++ b/src/config/lessons.js @@ -17,10 +17,10 @@ import responsiveConfig from "../../lessons/08-responsive.json"; // Module store const moduleStore = [ // basicsConfig, - basicSelectorsConfig - // boxModelConfig, - // selectorsConfig, - // colorsConfig, + basicSelectorsConfig, + boxModelConfig, + selectorsConfig, + colorsConfig // typographyConfig, // unitVariablesConfig, // transitionsAnimationsConfig, diff --git a/src/main.css b/src/main.css index 282712a..1130dce 100644 --- a/src/main.css +++ b/src/main.css @@ -708,3 +708,264 @@ input:checked + .toggle-slider:before { font-size: 14px; color: var(--text-color); } + +/* Hamburger Menu Icon */ +.hamburger { + display: none; + cursor: pointer; + flex-direction: column; + justify-content: space-around; + width: 30px; + height: 21px; + background: transparent; + border: none; + padding: 0; +} + +.hamburger-line { + display: block; + width: 100%; + height: 3px; + background-color: var(--text-color); + border-radius: 10px; + transition: all 0.3s ease; +} + +/* Responsive Header Adjustments */ +@media (max-width: 768px) { + .header { + flex-wrap: wrap; + padding: var(--spacing-md); + } + + .logo { + flex: 1; + } + + .hamburger { + display: flex; + order: 2; + } + + .main-nav { + width: 100%; + order: 3; + height: 0; + overflow: hidden; + transition: height 0.3s ease; + } + + .main-nav.open { + height: auto; + margin-top: var(--spacing-md); + } + + .main-nav ul { + flex-direction: column; + width: 100%; + align-items: flex-start; + gap: var(--spacing-sm); + } + + .main-nav ul li { + width: 100%; + } + + .main-nav ul li .btn { + width: 100%; + text-align: left; + } + + .toggle-container { + margin: var(--spacing-sm) 0; + } + + /* Hamburger animation when open */ + .hamburger.open .hamburger-line:nth-child(1) { + transform: translateY(9px) rotate(45deg); + } + + .hamburger.open .hamburger-line:nth-child(2) { + opacity: 0; + } + + .hamburger.open .hamburger-line:nth-child(3) { + transform: translateY(-9px) rotate(-45deg); + } +} + +/* ================= RESPONSIVE DESIGN ================= */ + +/* Base responsive layout */ +@media (max-width: 1024px) { + .main-content { + flex-direction: column; + } + + .sidebar { + width: 100%; + height: auto; + position: static; + padding: var(--spacing-md); + border-right: none; + border-bottom: 1px solid var(--border-color); + } + + .content-area { + max-width: 100%; + padding: var(--spacing-md); + } + + .module-list { + } + + .module-list-item { + } +} + +/* Header responsiveness */ +@media (max-width: 768px) { + .header { + position: static; + height: auto; + padding: var(--spacing-md) var(--spacing-md); + gap: var(--spacing-md); + } + + .main-nav ul { + flex-wrap: wrap; + justify-content: center; + } + + .main-content { + min-height: calc(100vh - 120px); + } +} + +/* Challenge container */ +@media (max-width: 1024px) { + .challenge-container { + flex-direction: column; + } + + .preview-area, + .editor-container { + width: 100%; + } + + .preview-area { + min-height: 200px; + } +} + +/* Text and other element responsiveness */ +@media (max-width: 768px) { + .lesson-description { + width: 100%; + font-size: 1rem; + } + + .lesson-container { + padding: var(--spacing-md); + } + + #lesson-title { + font-size: 1.5rem; + } + + .code-input { + font-size: 13px; + } + + .controls { + flex-wrap: wrap; + gap: var(--spacing-sm); + } + + .btn { + padding: var(--spacing-xs) var(--spacing-sm); + font-size: 0.85rem; + } +} + +/* Small screens */ +@media (max-width: 480px) { + .logo { + flex-direction: column; + align-items: center; + text-align: center; + } + + .logo h1 { + font-size: 1rem; + } + + .main-nav ul { + gap: var(--spacing-sm); + } + + .toggle-label { + font-size: 12px; + } + + .lesson-description pre { + padding: var(--spacing-md); + font-size: 0.8rem; + } + + .task-instruction { + font-size: 0.9rem; + } + + .modal { + width: 95%; + } +} + +/* Ensure code editor has minimum height */ +.code-editor { + min-height: 200px; +} + +/* Better spacing for lesson progress in mobile */ +@media (max-width: 1024px) { + .lesson-progress { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: var(--spacing-xs); + margin-top: var(--spacing-md); + } +} + +/* Improve validation indicators visibility */ +@media (max-width: 768px) { + .validation-indicators-container { + justify-content: flex-end; + flex: 1; + } + + .editor-header { + flex-wrap: wrap; + } +} + +@media (max-width: 480px) { + .header { + padding: var(--spacing-sm); + gap: var(--spacing-sm); + } + + .logo { + flex-direction: row; + gap: 0.4rem; + } + + .logo img { + width: 40px; + } + + .logo h1 { + font-size: 0.9rem; + } +}