fix: Resolve PWA viewport corruption on page navigation

Root cause: Bootstrap offcanvas leaves backdrop/body classes in DOM
when navigating via window.location.href, causing viewport issues.

Changes:
- Remove hamburger menu button from DM navbar (caused overflow)
- Reduce menu button icon size on channels (remove font-size override)
- Add global navigateTo() function in app.js and contacts.js
- Function closes offcanvas, removes backdrops, clears body classes
- Replace all window.location.href calls with navigateTo()
- Updated navigation in: base.html, contacts*.html templates
- Add 100ms delay before navigation to ensure cleanup completes

This fixes the issue where:
1. Opening offcanvas menu on main page
2. Navigating to DM or Contact Management
3. Returning to main page
Results in corrupted viewport with hidden status bar

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2026-01-01 17:31:44 +01:00
parent 00e512104c
commit 11935d419a
8 changed files with 64 additions and 14 deletions

View File

@@ -16,6 +16,35 @@ let unreadCounts = {}; // Track unread message counts per channel
let dmLastSeenTimestamps = {}; // Track last seen DM timestamp per conversation
let dmUnreadCounts = {}; // Track unread DM counts per conversation
/**
* Global navigation function - closes offcanvas and cleans up before navigation
* This prevents Bootstrap backdrop/body classes from persisting after page change
*/
window.navigateTo = function(url) {
// Close offcanvas if open
const offcanvasEl = document.getElementById('mainMenu');
if (offcanvasEl) {
const offcanvas = bootstrap.Offcanvas.getInstance(offcanvasEl);
if (offcanvas) {
offcanvas.hide();
}
}
// Remove any lingering Bootstrap classes/backdrops
document.body.classList.remove('modal-open', 'offcanvas-open');
document.body.style.overflow = '';
document.body.style.paddingRight = '';
// Remove any backdrops
const backdrops = document.querySelectorAll('.offcanvas-backdrop, .modal-backdrop');
backdrops.forEach(backdrop => backdrop.remove());
// Navigate after cleanup
setTimeout(() => {
window.location.href = url;
}, 100);
};
// Initialize on page load
document.addEventListener('DOMContentLoaded', async function() {
console.log('mc-webui initialized');

View File

@@ -10,6 +10,30 @@
* - Mobile-first design
*/
// =============================================================================
// Global Navigation Helper
// =============================================================================
/**
* Global navigation function - cleans up DOM before navigation
* This prevents viewport issues when navigating between pages
*/
window.navigateTo = function(url) {
// Remove any lingering Bootstrap classes/backdrops
document.body.classList.remove('modal-open', 'offcanvas-open');
document.body.style.overflow = '';
document.body.style.paddingRight = '';
// Remove any backdrops
const backdrops = document.querySelectorAll('.offcanvas-backdrop, .modal-backdrop');
backdrops.forEach(backdrop => backdrop.remove());
// Navigate after cleanup
setTimeout(() => {
window.location.href = url;
}, 100);
};
// =============================================================================
// State Management
// =============================================================================

View File

@@ -41,7 +41,7 @@
<!-- Channels loaded dynamically via JavaScript -->
</select>
<button class="btn btn-outline-light btn-sm" data-bs-toggle="offcanvas" data-bs-target="#mainMenu" title="Menu">
<i class="bi bi-list" style="font-size: 1.25rem;"></i>
<i class="bi bi-list"></i>
</button>
</div>
</div>
@@ -63,14 +63,14 @@
<i class="bi bi-broadcast-pin" style="font-size: 1.5rem;"></i>
<span>Manage Channels</span>
</button>
<button class="list-group-item list-group-item-action d-flex align-items-center gap-3" onclick="window.location.href='/dm';">
<button class="list-group-item list-group-item-action d-flex align-items-center gap-3" onclick="navigateTo('/dm');">
<i class="bi bi-envelope" style="font-size: 1.5rem;"></i>
<div class="d-flex flex-grow-1 justify-content-between align-items-center">
<span>Direct Messages</span>
<span id="dmMenuBadge" class="badge bg-success rounded-pill" style="display: none;">0</span>
</div>
</button>
<button class="list-group-item list-group-item-action d-flex align-items-center gap-3" onclick="window.location.href='/contacts/manage';">
<button class="list-group-item list-group-item-action d-flex align-items-center gap-3" onclick="navigateTo('/contacts/manage');">
<i class="bi bi-person-check" style="font-size: 1.5rem;"></i>
<span>Contact Management</span>
</button>

View File

@@ -18,10 +18,10 @@
<div id="existingPageContent">
<!-- Back Buttons -->
<div class="back-buttons">
<button class="btn btn-outline-secondary" onclick="window.location.href='/contacts/manage';">
<button class="btn btn-outline-secondary" onclick="navigateTo('/contacts/manage');">
<i class="bi bi-arrow-left"></i> Contact Management
</button>
<button class="btn btn-outline-secondary" onclick="window.location.href='/';">
<button class="btn btn-outline-secondary" onclick="navigateTo('/');">
<i class="bi bi-house"></i> Home
</button>
</div>

View File

@@ -7,7 +7,7 @@
<i class="bi bi-person-check"></i> Contact Management
</span>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-outline-light btn-sm" onclick="window.location.href='/';" title="Home">
<button class="btn btn-outline-light btn-sm" onclick="navigateTo('/');" title="Home">
<i class="bi bi-house"></i>
</button>
</div>
@@ -44,7 +44,7 @@
</h5>
<!-- Pending Contacts Card -->
<div class="nav-card" onclick="window.location.href='/contacts/pending';">
<div class="nav-card" onclick="navigateTo('/contacts/pending');">
<div>
<h6><i class="bi bi-hourglass-split"></i> Pending Contacts</h6>
<small class="text-muted">Contacts awaiting manual approval</small>
@@ -55,7 +55,7 @@
</div>
<!-- Existing Contacts Card -->
<div class="nav-card" onclick="window.location.href='/contacts/existing';">
<div class="nav-card" onclick="navigateTo('/contacts/existing');">
<div>
<h6><i class="bi bi-person-lines-fill"></i> Existing Contacts</h6>
<small class="text-muted">View and manage your approved contacts</small>

View File

@@ -18,10 +18,10 @@
<div id="pendingPageContent">
<!-- Back Buttons -->
<div class="back-buttons">
<button class="btn btn-outline-secondary" onclick="window.location.href='/contacts/manage';">
<button class="btn btn-outline-secondary" onclick="navigateTo('/contacts/manage');">
<i class="bi bi-arrow-left"></i> Contact Management
</button>
<button class="btn btn-outline-secondary" onclick="window.location.href='/';">
<button class="btn btn-outline-secondary" onclick="navigateTo('/');">
<i class="bi bi-house"></i> Home
</button>
</div>

View File

@@ -366,7 +366,7 @@
<i class="bi bi-person-check"></i> Contact Management
</span>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-outline-light btn-sm" onclick="window.location.href='/';" title="Home">
<button class="btn btn-outline-light btn-sm" onclick="navigateTo('/');" title="Home">
<i class="bi bi-house"></i>
</button>
</div>

View File

@@ -76,9 +76,6 @@
<option value="">Select chat...</option>
<!-- Conversations loaded dynamically via JavaScript -->
</select>
<button class="btn btn-outline-light btn-sm" onclick="window.location.href='/';" title="Back to Main Menu">
<i class="bi bi-list" style="font-size: 1.25rem;"></i>
</button>
</div>
</div>
</nav>