Replace bottom nav with hamburger menu, move friends to Friends panel

This commit is contained in:
Sterling Archer
2026-06-18 14:22:23 -07:00
parent 80c0796113
commit faac0d529a
+173 -65
View File
@@ -191,11 +191,8 @@
.modal-actions .btn { flex: 1; }
/* ── SAFE AREA / MOBILE ── */
.bottom-nav {
padding-bottom: env(safe-area-inset-bottom);
}
.dashboard-content {
padding-bottom: calc(80px + env(safe-area-inset-bottom));
padding-bottom: 40px;
}
/* ── TOUCH TARGETS ── */
@@ -755,51 +752,124 @@
display: inline-block;
}
/* ── BOTTOM NAV ── */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--bg);
border-top: 1px solid var(--border);
display: flex;
z-index: 100;
}
.bn-item {
flex: 1;
/* ── HAMBURGER MENU ── */
.hamburger-btn {
width: 38px;
height: 38px;
display: flex;
flex-direction: column;
align-items: center;
padding: 10px 0 14px;
justify-content: center;
gap: 5px;
cursor: pointer;
border: none;
background: transparent;
color: var(--muted);
font-family: var(--font-body);
font-size: 11px;
gap: 4px;
transition: color 0.15s;
border: none;
padding: 4px;
border-radius: 8px;
transition: background 0.15s;
}
.bn-item.active { color: var(--teal); }
.bn-item .bn-icon { font-size: 20px; line-height: 1; }
.bn-badge {
.hamburger-btn:hover { background: var(--surface2); }
.hamburger-btn span {
display: block;
width: 20px;
height: 2px;
background: var(--white);
border-radius: 2px;
transition: all 0.2s;
}
.hamburger-btn.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger-btn.open span:nth-child(2) { opacity: 0; }
.hamburger-btn.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.menu-overlay {
position: fixed;
inset: 0;
z-index: 150;
pointer-events: none;
}
.menu-overlay.open { pointer-events: all; }
.menu-backdrop {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 0.2s;
}
.menu-overlay.open .menu-backdrop { opacity: 1; }
.menu-drawer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 240px;
background: var(--surface);
border-left: 1px solid var(--border);
display: flex;
flex-direction: column;
transform: translateX(100%);
transition: transform 0.25s cubic-bezier(0.16,1,0.3,1);
padding: 0 0 max(24px, env(safe-area-inset-bottom));
}
.menu-overlay.open .menu-drawer { transform: translateX(0); }
.menu-header {
padding: 20px 20px 16px;
border-bottom: 1px solid var(--border);
margin-bottom: 8px;
}
.menu-header .menu-user-name {
font-family: var(--font-display);
font-weight: 700;
font-size: 16px;
}
.menu-header .menu-user-email {
font-size: 12px;
color: var(--muted);
margin-top: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.menu-item {
display: flex;
align-items: center;
gap: 14px;
padding: 14px 20px;
cursor: pointer;
background: transparent;
border: none;
color: var(--white);
font-family: var(--font-body);
font-size: 15px;
width: 100%;
text-align: left;
transition: background 0.15s;
position: relative;
}
.bn-badge::after {
content: attr(data-count);
position: absolute;
top: -4px;
right: -8px;
.menu-item:hover { background: var(--surface2); }
.menu-item.active { color: var(--teal); }
.menu-item .mi-icon { font-size: 20px; width: 24px; text-align: center; }
.menu-item .mi-badge {
margin-left: auto;
background: var(--danger);
color: white;
font-size: 9px;
font-size: 10px;
font-weight: 700;
border-radius: 10px;
padding: 1px 5px;
padding: 2px 7px;
display: none;
}
.bn-badge[data-count]:not([data-count="0"])::after { display: block; }
.menu-item .mi-badge.show { display: block; }
.menu-divider {
height: 1px;
background: var(--border);
margin: 8px 20px;
}
.menu-spacer { flex: 1; }
/* ── PANEL VIEWS ── */
.panel { display: none; }
@@ -1028,14 +1098,46 @@
<div id="screen-dashboard" class="screen">
<nav>
<div class="nav-logo">Step<span>Mates</span></div>
<div class="nav-user">
<span style="font-size:13px;color:var(--muted)" id="nav-name"></span>
<div class="avatar" id="nav-avatar" onclick="openProfileModal()" title="Edit profile">
<div style="display:flex;align-items:center;gap:10px">
<div class="avatar" id="nav-avatar" onclick="openProfileModal()" title="Edit profile" style="cursor:pointer">
<span id="nav-avatar-initial">?</span>
</div>
<button class="hamburger-btn" id="hamburger-btn" onclick="toggleMenu()" aria-label="Menu">
<span></span><span></span><span></span>
</button>
</div>
</nav>
<!-- SLIDE-OUT MENU -->
<div class="menu-overlay" id="menu-overlay">
<div class="menu-backdrop" onclick="closeMenu()"></div>
<div class="menu-drawer">
<div class="menu-header">
<div class="menu-user-name" id="menu-user-name">—</div>
<div class="menu-user-email" id="menu-user-email">—</div>
</div>
<button class="menu-item active" id="mi-home" onclick="switchPanel('home');closeMenu()">
<span class="mi-icon">👟</span> My Steps
</button>
<button class="menu-item" id="mi-friends" onclick="switchPanel('friends');closeMenu()">
<span class="mi-icon">👥</span> Friends
<span class="mi-badge" id="mi-friends-badge"></span>
</button>
<button class="menu-item" id="mi-settings" onclick="switchPanel('settings');closeMenu()">
<span class="mi-icon">⚙️</span> Setup & Sync
</button>
<div class="menu-divider"></div>
<button class="menu-item" onclick="openProfileModal();closeMenu()">
<span class="mi-icon">✏️</span> Edit Profile
</button>
<div class="menu-spacer"></div>
<div class="menu-divider"></div>
<button class="menu-item" onclick="signOut()" style="color:var(--muted)">
<span class="mi-icon">🚪</span> Sign out
</button>
</div>
</div>
<div class="container dashboard-content">
<!-- TIME TABS -->
@@ -1081,22 +1183,22 @@
</div>
</div>
<!-- PANEL: MY STEPS / FRIENDS -->
<!-- PANEL: MY STEPS -->
<div id="panel-home" class="panel active">
</div>
<!-- Friends' steps -->
<!-- PANEL: FRIENDS -->
<div id="panel-friends" class="panel">
<!-- Friends' steps leaderboard -->
<div class="section-header">
<div class="section-title">Friends</div>
<div class="section-title">Friends' Steps</div>
</div>
<div id="friends-steps-list" class="friends-list">
<div id="friends-steps-list" class="friends-list" style="margin-bottom:28px">
<div class="loader-full" style="padding:40px 0;flex:none">
<div class="spinner" style="width:24px;height:24px;border-width:2px;color:var(--teal)"></div>
</div>
</div>
</div>
<!-- PANEL: FRIENDS MANAGEMENT -->
<div id="panel-friends" class="panel">
<!-- Pending received requests -->
<div id="pending-received-section" style="display:none">
<div class="section-header">
@@ -1195,18 +1297,6 @@
</div><!-- /container -->
<!-- BOTTOM NAV -->
<div class="bottom-nav">
<button class="bn-item active" id="bn-home" onclick="switchPanel('home')">
<span class="bn-icon">👟</span>Steps
</button>
<button class="bn-item" id="bn-friends" onclick="switchPanel('friends')">
<span class="bn-icon bn-badge" id="bn-friends-badge" data-count="0">👥</span>Friends
</button>
<button class="bn-item" id="bn-settings" onclick="switchPanel('settings')">
<span class="bn-icon">⚙️</span>Setup
</button>
</div>
</div>
<!-- PROFILE MODAL -->
@@ -1471,11 +1561,11 @@ function refreshProfileUI() {
const name = currentUserData.displayName || currentUser.email.split('@')[0];
const initial = name[0].toUpperCase();
const avatarUrl = currentUserData.avatarUrl || '';
document.getElementById('nav-name').textContent = name;
setAvatarEl(document.getElementById('nav-avatar'), 'nav-avatar-initial', initial, avatarUrl, 36);
setAvatarEl(document.getElementById('settings-avatar-display'), 'settings-avatar-initial', initial, avatarUrl, 48);
document.getElementById('settings-display-name-show').textContent = name;
document.getElementById('menu-user-name').textContent = name;
document.getElementById('menu-user-email').textContent = currentUser.email;
}
function setAvatarEl(wrapEl, initialId, initial, url, size) {
@@ -1742,8 +1832,13 @@ function renderFriendsPanel() {
}
function updateBadge() {
const badge = document.getElementById('bn-friends-badge');
badge.setAttribute('data-count', pendingReceived.length);
const badge = document.getElementById('mi-friends-badge');
if (pendingReceived.length > 0) {
badge.textContent = pendingReceived.length;
badge.classList.add('show');
} else {
badge.classList.remove('show');
}
}
window.sendFriendRequest = async function() {
@@ -1813,11 +1908,24 @@ window.respondRequest = async function(requestId, status) {
window.switchPanel = function(name) {
document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
document.getElementById('panel-' + name).classList.add('active');
document.querySelectorAll('.bn-item').forEach(b => b.classList.remove('active'));
document.getElementById('bn-' + name).classList.add('active');
document.querySelectorAll('.menu-item').forEach(b => b.classList.remove('active'));
const mi = document.getElementById('mi-' + name);
if (mi) mi.classList.add('active');
if (name === 'friends') loadFriends();
}
window.toggleMenu = function() {
const overlay = document.getElementById('menu-overlay');
const btn = document.getElementById('hamburger-btn');
const isOpen = overlay.classList.contains('open');
if (isOpen) { closeMenu(); } else { overlay.classList.add('open'); btn.classList.add('open'); }
}
window.closeMenu = function() {
document.getElementById('menu-overlay').classList.remove('open');
document.getElementById('hamburger-btn').classList.remove('open');
}
// ─────────────────────────────────────────────
// COPY WEBHOOK
// ─────────────────────────────────────────────
@@ -1948,7 +2056,7 @@ document.getElementById('profile-name-input').addEventListener('input', updatePr
document.getElementById('profile-avatar-input').addEventListener('input', updateProfilePreview);
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeProfileModal();
if (e.key === 'Escape') { closeProfileModal(); closeMenu(); }
});
let ptrStartY = 0;