feat: implement mobile navigation enhancements with close button and scroll locking

This commit is contained in:
fynks 2025-10-12 18:21:31 +05:00
parent 110c15792c
commit 093237aecb
2 changed files with 265 additions and 81 deletions

287
dist/css/styles.css vendored
View file

@ -328,7 +328,7 @@ button:focus-visible {
overflow-x: hidden;
position: relative;
background: var(--bg-primary);
transition: background-color var(--transition-normal)
margin: var(--space-3xl) 0;
}
.container {
@ -651,6 +651,14 @@ button:focus-visible {
transition: width var(--transition-fast);
}
.nav-mobile-header {
display: none;
}
.nav-close {
display: none;
}
.nav-link:hover {
color: var(--primary);
background: var(--bg-secondary);
@ -951,6 +959,23 @@ button:focus-visible {
@media (max-width:900px) {
.nav-dropdown {
width: 100%;
display: block;
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-xl);
background: rgba(148, 163, 184, 0.12);
border: 1px solid var(--border-primary);
box-shadow: 0 12px 40px rgba(15, 23, 42, 0.08);
position: relative;
}
.nav-dropdown + .nav-dropdown {
margin-top: var(--space-sm);
}
[data-theme="dark"] .nav-dropdown {
background: rgba(30, 41, 59, 0.6);
border-color: rgba(71, 85, 105, 0.8);
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.35);
}
.nav-dropdown-trigger {
@ -959,17 +984,27 @@ button:focus-visible {
text-align: left;
padding: var(--space-lg) var(--space-xl);
border-radius: var(--radius-lg);
font-size: var(--text-base);
font-weight: var(--font-medium);
color: var(--text-secondary);
min-height: 44px;
font-size: clamp(1rem, 2.5vw, 1.05rem);
font-weight: 600;
color: var(--text-primary);
min-height: 48px;
background: transparent;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
transition: background var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}
.nav-dropdown-trigger:hover {
.nav-dropdown-trigger:hover,
.nav-dropdown-trigger:focus-visible {
color: var(--primary);
background: var(--bg-secondary);
background: rgba(99, 102, 241, 0.1);
box-shadow: inset 0 0 0 1px rgba(99, 102, 241, 0.18);
}
.nav-dropdown-trigger[aria-expanded="true"] {
color: var(--primary);
background: rgba(99, 102, 241, 0.12);
box-shadow: inset 0 0 0 1px rgba(99, 102, 241, 0.25);
}
.nav-dropdown-menu {
@ -986,44 +1021,52 @@ button:focus-visible {
backdrop-filter: none;
display: none;
overflow: hidden;
/* Remove problematic animations */
transition: none;
will-change: auto;
}
[data-theme="dark"] .nav-dropdown-menu {
background: transparent;
}
.nav-dropdown-trigger[aria-expanded="true"] + .nav-dropdown-menu {
display: block;
padding: var(--space-xs) 0 var(--space-md) var(--space-2xl);
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-lg) var(--space-lg);
margin-top: var(--space-xs);
margin-left: var(--space-lg);
border-left: 2px solid var(--border-primary);
background: rgba(99, 102, 241, 0.02);
margin-left: 0;
border-left: none;
background: rgba(99, 102, 241, 0.08);
border-radius: var(--radius-lg);
}
[data-theme="dark"] .nav-dropdown-trigger[aria-expanded="true"] + .nav-dropdown-menu {
background: rgba(99, 102, 241, 0.03);
border-left-color: var(--border-secondary);
background: rgba(99, 102, 241, 0.16);
}
.nav-dropdown-item {
padding: var(--space-md) var(--space-xl);
font-size: var(--text-base);
min-height: 44px;
display: flex;
align-items: center;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
transition: transform 0.2s ease, background 0.2s ease;
padding: var(--space-md) var(--space-lg);
color: var(--text-secondary);
border-radius: var(--radius-md);
font-size: var(--text-base);
font-weight: var(--font-medium);
transform: translateX(0);
transition: transform var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
}
.nav-dropdown-item + .nav-dropdown-item {
margin-top: var(--space-2xs);
}
.nav-dropdown-item:hover,
.nav-dropdown-item:focus-visible,
.nav-dropdown-item:active {
background: rgba(255, 255, 255, 0.65);
color: var(--primary);
transform: translateX(4px);
background: rgba(99, 102, 241, 0.05);
}
[data-theme="dark"] .nav-dropdown-item:hover,
[data-theme="dark"] .nav-dropdown-item:focus-visible {
background: rgba(15, 23, 42, 0.65);
color: var(--primary-light);
}
}
@ -1032,12 +1075,14 @@ button:focus-visible {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 90;
z-index: 120;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
pointer-events: none;
-webkit-tap-highlight-color: transparent;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.nav-open .nav-overlay {
@ -1048,97 +1093,189 @@ button:focus-visible {
/* ===== MOBILE NAVIGATION STYLES ===== */
@media (max-width: 900px) {
/* Show nav toggle button */
.nav-toggle {
display: inline-flex;
width: 48px !important;
height: 48px !important;
}
/* Hide nav by default on mobile */
.header-nav {
display: none;
position: fixed;
top: var(--header-height);
right: 0;
width: min(340px, 85%);
height: calc(100vh - var(--header-height));
background: rgba(255, 255, 255, 0.98);
border-left: 1px solid var(--border-primary);
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.1);
padding: var(--space-2xl) var(--space-xl) var(--space-3xl);
inset: 0;
padding: var(--space-3xl) var(--space-xl) var(--space-3xl);
padding-top: var(--space-3xl);
padding-top: calc(var(--space-3xl) + env(safe-area-inset-top));
background: linear-gradient(180deg, rgba(248, 250, 255, 0.96) 0%, rgba(255, 255, 255, 0.98) 55%, rgba(255, 255, 255, 0.94) 100%);
border: none;
box-shadow: none;
display: flex;
flex-direction: column;
gap: var(--space-sm);
overflow-y: auto;
overflow-x: hidden;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
transform: translateX(100%);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 100;
transform: translateX(105%);
transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 140;
will-change: transform;
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
}
.header-nav::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(120% 120% at 50% 0%, rgba(99, 102, 241, 0.08) 0%, rgba(59, 130, 246, 0.04) 45%, rgba(15, 23, 42, 0) 100%);
z-index: -1;
}
[data-theme="dark"] .header-nav {
background: linear-gradient(180deg, rgba(15, 23, 42, 0.96) 0%, rgba(15, 23, 42, 0.98) 60%, rgba(15, 23, 42, 0.94) 100%);
box-shadow: none;
}
[data-theme="dark"] .header-nav::before {
background: radial-gradient(120% 120% at 50% 0%, rgba(37, 99, 235, 0.2) 0%, rgba(59, 130, 246, 0.12) 45%, rgba(15, 23, 42, 0) 100%);
}
/* Show nav when open */
.nav-open .header-nav {
display: flex;
transform: translateX(0);
}
/* Dark theme mobile nav */
[data-theme="dark"] .header-nav {
background: rgba(15, 23, 42, 0.98);
border-color: rgba(52, 65, 85, 0.6);
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.3);
}
/* Prevent body scroll when nav is open */
body.nav-open {
overflow: hidden;
position: fixed;
width: 100%;
}
/* Mobile nav links */
.nav-open .nav-link {
font-size: var(--text-base);
padding: var(--space-lg) var(--space-xl);
width: 100%;
text-align: left;
border-radius: var(--radius-lg);
min-height: 44px;
.nav-mobile-header {
display: flex;
align-items: center;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
justify-content: space-between;
gap: var(--space-lg);
padding: 0 0 var(--space-xl);
margin-bottom: var(--space-lg);
border-bottom: 1px solid rgba(148, 163, 184, 0.4);
}
.nav-open .nav-link::before {
[data-theme="dark"] .nav-mobile-header {
border-bottom-color: rgba(71, 85, 105, 0.4);
}
.nav-mobile-brand {
display: flex;
flex-direction: column;
gap: var(--space-2xs);
}
.nav-mobile-title {
font-size: clamp(1rem, 2.8vw, 1.15rem);
font-weight: 600;
color: var(--text-primary);
letter-spacing: 0.08em;
text-transform: uppercase;
}
.nav-mobile-subtitle {
font-size: var(--text-sm);
color: var(--text-secondary);
}
.nav-close {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border-radius: var(--radius-full);
border: 1px solid rgba(148, 163, 184, 0.5);
background: rgba(255, 255, 255, 0.92);
color: var(--text-primary);
box-shadow: 0 14px 32px rgba(15, 23, 42, 0.12);
transition: transform var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast);
}
.nav-close:hover,
.nav-close:focus-visible {
transform: scale(1.05);
background: rgba(255, 255, 255, 1);
border-color: rgba(99, 102, 241, 0.55);
}
[data-theme="dark"] .nav-close {
background: rgba(30, 41, 59, 0.9);
border-color: rgba(71, 85, 105, 0.7);
box-shadow: 0 14px 32px rgba(0, 0, 0, 0.4);
color: var(--text-primary);
}
[data-theme="dark"] .nav-close:hover,
[data-theme="dark"] .nav-close:focus-visible {
border-color: rgba(147, 197, 253, 0.6);
}
.nav-close svg {
pointer-events: none;
}
.nav-open a.nav-link {
width: 100%;
justify-content: space-between;
font-size: clamp(1.05rem, 3vw, 1.2rem);
font-weight: 600;
padding: var(--space-lg) var(--space-xl);
border-radius: var(--radius-xl);
min-height: 52px;
background: rgba(99, 102, 241, 0.1);
color: var(--text-primary);
box-shadow: 0 16px 36px rgba(15, 23, 42, 0.12);
margin-bottom: var(--space-sm);
text-align: left;
}
.nav-open a.nav-link:hover,
.nav-open a.nav-link:focus-visible {
background: rgba(99, 102, 241, 0.18);
color: var(--primary);
box-shadow: 0 20px 42px rgba(15, 23, 42, 0.16);
}
[data-theme="dark"] .nav-open a.nav-link {
background: rgba(59, 130, 246, 0.18);
color: var(--text-primary);
box-shadow: 0 20px 48px rgba(0, 0, 0, 0.45);
}
[data-theme="dark"] .nav-open a.nav-link:hover,
[data-theme="dark"] .nav-open a.nav-link:focus-visible {
background: rgba(59, 130, 246, 0.26);
color: var(--primary-light);
}
.nav-open .nav-link::before,
.nav-open .nav-link::after {
display: none;
}
.nav-open .nav-link::after {
border-radius: var(--radius-lg);
}
/* Dark mode toggle positioning on mobile */
.dark-mode-toggle {
display: flex;
flex: 0 0 auto;
width: 40px !important;
height: 40px !important;
order: 3;
align-self: center;
z-index: 110;
align-self: flex-start;
margin-left: auto;
z-index: 150;
}
/* Nav toggle sizing */
.nav-toggle {
width: 40px !important;
height: 40px !important;
}
/* Disable transitions before JS is ready */
body:not(.js-ready) .header-nav,
body:not(.js-ready) .nav-toggle-bar,
body:not(.js-ready) .nav-overlay {
@ -1893,7 +2030,7 @@ table button:focus-visible {
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
border: 1px solid var(--border-primary);
margin: var(--space-3xl) 0;
margin: var(--space-xl) 0;
overflow: hidden;
width: 100%
}
@ -1972,8 +2109,6 @@ th {
align-items: center
}
/* Legacy support - removed duplicate enhanced resource styles and newsletter form */
.social-btn,
.github-link {
width: 36px;

59
dist/index.html vendored
View file

@ -459,6 +459,17 @@
</a>
<nav id="primary-navigation" class="header-nav" aria-label="Main navigation" aria-hidden="true"
role="navigation">
<div class="nav-mobile-header">
<div class="nav-mobile-brand">
<span class="nav-mobile-title">Menu</span>
<span class="nav-mobile-subtitle">Jump to a section</span>
</div>
<button class="nav-close" id="navClose" type="button" aria-label="Close navigation menu">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<use href="#icon-close" />
</svg>
</button>
</div>
<a href="#what-are-debrid-services" class="nav-link">
<span class="nav-link-text">Intro</span>
</a>
@ -555,8 +566,7 @@
Compare Premium <span class="gradient-text">Debrid Services</span>
</h1>
<p class="hero-description">
Compare pricing, features, and 400+ file hosts across 9 premium debrid services in real-time.
Make informed decisions with our comprehensive comparison tool.
Compare pricing, features, policies & 400+ file hosts across 10 premium debrid services in real-time.
</p>
<div class="hero-actions">
<a href="#debrid-pricing-comparison" class="btn btn-primary">
@ -568,7 +578,7 @@
</div>
<div class="hero-stats" aria-label="Key stats">
<div class="stat-item">
<span class="stat-number">9</span>
<span class="stat-number">10</span>
<span class="stat-label">Services</span>
</div>
<div class="stat-item">
@ -1747,9 +1757,39 @@
navToggle: document.getElementById('navToggle'),
nav: document.getElementById('primary-navigation'),
navOverlay: document.getElementById('navOverlay'),
navClose: document.getElementById('navClose'),
darkModeToggle: document.getElementById('darkModeToggle'),
dropdownTriggers: []
};
let scrollPosition = 0;
const lockScroll = () => {
if (!elements.body) return;
scrollPosition = window.scrollY || window.pageYOffset || document.documentElement.scrollTop || 0;
elements.body.dataset.navScrollLock = String(scrollPosition);
elements.body.style.top = `-${scrollPosition}px`;
elements.body.style.position = 'fixed';
elements.body.style.width = '100%';
elements.body.style.overflow = 'hidden';
elements.body.style.touchAction = 'none';
elements.body.style.left = '0';
elements.body.style.right = '0';
};
const unlockScroll = () => {
if (!elements.body) return;
const saved = Number(elements.body.dataset.navScrollLock || scrollPosition || 0);
elements.body.style.removeProperty('top');
elements.body.style.removeProperty('position');
elements.body.style.removeProperty('width');
elements.body.style.removeProperty('overflow');
elements.body.style.removeProperty('touch-action');
elements.body.style.removeProperty('left');
elements.body.style.removeProperty('right');
delete elements.body.dataset.navScrollLock;
requestAnimationFrame(() => window.scrollTo(0, saved));
};
// Check if mobile
const checkMobile = () => window.innerWidth <= 900;
@ -1769,13 +1809,15 @@
// Open mobile navigation
const openNav = () => {
if (!elements.nav || state.isOpen) return;
if (!elements.nav || state.isOpen || !state.isMobile) return;
state.isOpen = true;
lockScroll();
elements.body.classList.add('nav-open');
if (elements.navToggle) {
elements.navToggle.setAttribute('aria-expanded', 'true');
elements.navToggle.setAttribute('aria-label', 'Close navigation menu');
}
if (elements.navOverlay) {
@ -1788,7 +1830,6 @@
}
};
// Close mobile navigation
const closeNav = () => {
if (!elements.nav || !state.isOpen) return;
@ -1797,6 +1838,7 @@
if (elements.navToggle) {
elements.navToggle.setAttribute('aria-expanded', 'false');
elements.navToggle.setAttribute('aria-label', 'Open navigation menu');
}
if (elements.navOverlay) {
@ -1810,6 +1852,7 @@
// Close all dropdowns when closing nav
closeAllDropdowns();
unlockScroll();
};
// Toggle navigation
@ -1883,6 +1926,12 @@
toggleNav();
}, { passive: false });
}
if (elements.navClose) {
elements.navClose.addEventListener('click', () => {
closeNav();
}, { passive: true });
}
// Overlay click handler
if (elements.navOverlay) {