diora-web/static/js/app/20-tabs.js

71 lines
2.6 KiB
JavaScript
Raw Normal View History

'use strict';
// ---------------------------------------------------------------------------
// Tabs
// ---------------------------------------------------------------------------
const TOP_TABS = ['home', 'radio', 'focus', 'podcasts', 'books', 'feeds', 'ambient', 'audiobooks'];
const RADIO_SUB_TABS = ['search', 'saved', 'history'];
// ---------------------------------------------------------------------------
// URL hash routing — makes tabs deep-linkable/shareable and lets the browser
// back/forward buttons move between them. Deliberately hash-based rather
// than real paths: /podcasts/ and /books/ etc. are already taken by the
// JSON API, so this avoids touching Django's urls.py at all.
// ---------------------------------------------------------------------------
let _routingFromHash = false;
let _currentTopTab = 'radio';
function _syncHash() {
if (_routingFromHash || window.DioraNav) return; // the navigation keeps the hash (static/js/nav.js)
let hash = _currentTopTab;
if (_currentTopTab === 'radio') {
hash += '/' + (localStorage.getItem('diora_active_radio_tab') || 'saved');
}
if (location.hash.slice(1) !== hash) history.pushState(null, '', '#' + hash);
}
function _routeFromHash() {
if (window.DioraNav) return; // nav.js routes (#news, #audiobooks …)
const [tab, sub] = (location.hash || '').replace(/^#/, '').split('/').filter(Boolean);
if (!TOP_TABS.includes(tab)) return;
_routingFromHash = true;
try {
showTab(tab);
if (tab === 'radio' && RADIO_SUB_TABS.includes(sub)) showRadioTab(sub);
} finally {
_routingFromHash = false;
}
}
window.addEventListener('popstate', _routeFromHash);
window.addEventListener('hashchange', _routeFromHash);
function showOfflineBanner(offline) {
document.body.classList.toggle('app-offline', offline);
const uploadArea = $('book-upload-area');
if (uploadArea) uploadArea.style.display = offline ? 'none' : '';
}
function showTab(name) {
TOP_TABS.forEach(p => {
const panel = $(`tab-${p}`);
if (panel) panel.style.display = (p === name) ? '' : 'none';
});
if (!window.DioraNav) { // else nav.js marks its own buttons
document.querySelectorAll('#tabs .tab-btn').forEach((btn, i) => {
btn.classList.toggle('active', TOP_TABS[i] === name);
});
}
localStorage.setItem('diora_active_tab', name);
_currentTopTab = name;
_syncHash();
if (name === 'books') loadBookList();
if (name === 'ambient') _ambientLoad();
if (name === 'home' && window.__dioraHomeShow) window.__dioraHomeShow(); // static/js/home.js
if (name === 'feeds' && window.__dioraFeedsShow) window.__dioraFeedsShow(); // static/js/feeds.js
}