feat: migrate alpine ui into app shell
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* nav.js — shared navbar logic for non-catalog pages
|
||||
* Handles: auth guard, user dropdown, hamburger, logout
|
||||
*/
|
||||
(function () {
|
||||
|
||||
/* ── Auth guard ── */
|
||||
var STORAGE_KEY = 'crank_user';
|
||||
var user = null;
|
||||
try { user = JSON.parse(localStorage.getItem(STORAGE_KEY)); } catch (e) {}
|
||||
|
||||
if (!user) {
|
||||
var path = window.location.pathname;
|
||||
var isLogin = path.endsWith('login.html') || path.endsWith('/login');
|
||||
if (!isLogin) { window.location.replace((window.APP_BASE||'')+'html/login.html'); return; }
|
||||
}
|
||||
|
||||
/* ── Fill user info once DOM is available ── */
|
||||
function fillUserInfo() {
|
||||
if (!user) return;
|
||||
document.querySelectorAll('.nav-avatar').forEach(function (el) {
|
||||
el.textContent = user.initials || 'AT';
|
||||
});
|
||||
var nameEl = document.querySelector('.user-dropdown-name');
|
||||
var roleEl = document.querySelector('.user-dropdown-role');
|
||||
if (nameEl) nameEl.textContent = user.name || 'Operator';
|
||||
if (roleEl) roleEl.textContent = (user.role || 'Admin') + ' · ' + (user.workspace || 'workspace');
|
||||
}
|
||||
|
||||
/* ── Wire up nav interactions ── */
|
||||
function initNav() {
|
||||
fillUserInfo();
|
||||
|
||||
var dropdown = document.querySelector('.user-dropdown');
|
||||
var avatar = document.querySelector('.nav-avatar');
|
||||
var hamburger = document.querySelector('.nav-hamburger');
|
||||
var mobileNav = document.querySelector('.mobile-nav');
|
||||
|
||||
// Initially hide elements controlled by JS
|
||||
if (dropdown) dropdown.style.display = 'none';
|
||||
if (mobileNav) mobileNav.style.display = 'none';
|
||||
|
||||
// User dropdown toggle
|
||||
if (avatar && dropdown) {
|
||||
avatar.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
var showing = dropdown.style.display !== 'none';
|
||||
dropdown.style.display = showing ? 'none' : 'block';
|
||||
});
|
||||
}
|
||||
|
||||
// Hamburger toggle
|
||||
if (hamburger && mobileNav) {
|
||||
hamburger.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
var showing = mobileNav.style.display !== 'none';
|
||||
mobileNav.style.display = showing ? 'none' : 'block';
|
||||
hamburger.classList.toggle('open', !showing);
|
||||
});
|
||||
}
|
||||
|
||||
// Close dropdown / mobile-nav on outside click
|
||||
document.addEventListener('click', function (e) {
|
||||
if (dropdown && !e.target.closest('.user-menu')) {
|
||||
dropdown.style.display = 'none';
|
||||
}
|
||||
if (mobileNav && !e.target.closest('.navbar') && !e.target.closest('.mobile-nav')) {
|
||||
mobileNav.style.display = 'none';
|
||||
if (hamburger) hamburger.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
// Action buttons inside dropdown
|
||||
document.querySelectorAll('[data-action="logout"]').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
window.location.href = (window.APP_BASE||'')+'html/login.html';
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-action="profile"]').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
if (dropdown) dropdown.style.display = 'none';
|
||||
window.location.href = (window.APP_BASE||'')+'html/settings.html#profile';
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-action="settings-link"]').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
if (dropdown) dropdown.style.display = 'none';
|
||||
window.location.href = (window.APP_BASE||'')+'html/settings.html';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initNav);
|
||||
} else {
|
||||
initNav();
|
||||
}
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user