68 lines
2.4 KiB
JavaScript
68 lines
2.4 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Tabs
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
const TOP_TABS = ['home', 'radio', 'focus', 'podcasts', 'books', 'feeds', 'ambient'];
|
||
|
|
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) return;
|
||
|
|
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() {
|
||
|
|
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';
|
||
|
|
});
|
||
|
|
|
||
|
|
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
|
||
|
|
}
|