Completes the Watchlist+Wishlist pair (same as music). Watchlist monitors shows/channels for new content; Wishlist is the wanted/missing queue (movies, one-offs, failed grabs to retry). Placeholder for now.
139 lines
5.5 KiB
JavaScript
139 lines
5.5 KiB
JavaScript
/*
|
|
* SoulSync — Video side shell controller.
|
|
*
|
|
* ISOLATION CONTRACT: the music side never imports or references anything here.
|
|
* This file is a self-contained IIFE (no globals) wired entirely via
|
|
* addEventListener (no inline onclick), so it cannot affect the music side and
|
|
* a merge can't touch it. It only drives shared SHELL behaviour:
|
|
* - the Music ↔ Video header toggle (+ remembers the side in localStorage)
|
|
* - showing/hiding the video sidebar nav vs the music nav (CSS does the work
|
|
* off body[data-side]; this just flips the attribute)
|
|
* - a placeholder content host for the video pages (real pages land later)
|
|
*
|
|
* The actual video domain (data model, services, pages, DB) lives elsewhere and
|
|
* is built on top of this shell.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var SIDE_KEY = 'soulsync_side';
|
|
var MUSIC_SUBTITLE = 'Music Sync & Manager';
|
|
var VIDEO_SUBTITLE = 'Movies, TV & YouTube';
|
|
var DEFAULT_VIDEO_PAGE = 'video-dashboard';
|
|
|
|
// The video sidebar pages. Pages flagged shared: true are "same as music"
|
|
// (Import / Issues / Help) — wired to reuse the music pages in a later step;
|
|
// for now every page renders the placeholder.
|
|
var VIDEO_PAGES = [
|
|
{ id: 'video-dashboard', label: 'Dashboard' },
|
|
{ id: 'video-search', label: 'Search' },
|
|
{ id: 'video-discover', label: 'Discover' },
|
|
{ id: 'video-library', label: 'Library' },
|
|
{ id: 'video-watchlist', label: 'Watchlist' },
|
|
{ id: 'video-wishlist', label: 'Wishlist' },
|
|
{ id: 'video-downloads', label: 'Downloads' },
|
|
{ id: 'video-calendar', label: 'Calendar' },
|
|
{ id: 'video-import', label: 'Import', shared: true },
|
|
{ id: 'video-settings', label: 'Settings' },
|
|
{ id: 'video-issues', label: 'Issues', shared: true },
|
|
{ id: 'video-help', label: 'Help & Docs', shared: true },
|
|
];
|
|
|
|
function readSide() {
|
|
try {
|
|
return localStorage.getItem(SIDE_KEY) === 'video' ? 'video' : 'music';
|
|
} catch (e) {
|
|
return 'music';
|
|
}
|
|
}
|
|
|
|
function persistSide(side) {
|
|
try { localStorage.setItem(SIDE_KEY, side); } catch (e) { /* ignore */ }
|
|
}
|
|
|
|
function pageMeta(pageId) {
|
|
for (var i = 0; i < VIDEO_PAGES.length; i++) {
|
|
if (VIDEO_PAGES[i].id === pageId) return VIDEO_PAGES[i];
|
|
}
|
|
return VIDEO_PAGES[0];
|
|
}
|
|
|
|
function showVideoPage(pageId) {
|
|
var meta = pageMeta(pageId);
|
|
var navButtons = document.querySelectorAll('.video-nav .nav-button[data-video-page]');
|
|
for (var i = 0; i < navButtons.length; i++) {
|
|
navButtons[i].classList.toggle(
|
|
'active', navButtons[i].getAttribute('data-video-page') === meta.id);
|
|
}
|
|
var host = document.getElementById('video-page-host');
|
|
if (!host) return;
|
|
// Built from our own static constants only — no user input.
|
|
var shell = document.createElement('div');
|
|
shell.className = 'page-shell video-placeholder';
|
|
var h2 = document.createElement('h2');
|
|
h2.className = 'header-title';
|
|
var span = document.createElement('span');
|
|
span.textContent = 'Video · ' + meta.label;
|
|
h2.appendChild(span);
|
|
var note = document.createElement('p');
|
|
note.className = 'video-placeholder-note';
|
|
note.textContent = 'The ' + meta.label + ' page for the video side is coming soon.';
|
|
host.textContent = '';
|
|
host.appendChild(h2);
|
|
host.appendChild(note);
|
|
}
|
|
|
|
function applySide(side) {
|
|
document.body.setAttribute('data-side', side);
|
|
var subtitle = document.querySelector('.sidebar-header .app-subtitle');
|
|
if (subtitle) subtitle.textContent = side === 'video' ? VIDEO_SUBTITLE : MUSIC_SUBTITLE;
|
|
var toggleButtons = document.querySelectorAll('.side-toggle-btn');
|
|
for (var i = 0; i < toggleButtons.length; i++) {
|
|
toggleButtons[i].classList.toggle(
|
|
'active', toggleButtons[i].getAttribute('data-side-target') === side);
|
|
}
|
|
if (side === 'video') {
|
|
var active = document.querySelector('.video-nav .nav-button.active');
|
|
showVideoPage(active ? active.getAttribute('data-video-page') : DEFAULT_VIDEO_PAGE);
|
|
}
|
|
}
|
|
|
|
function switchSide(side) {
|
|
if (side !== 'music' && side !== 'video') return;
|
|
persistSide(side);
|
|
applySide(side);
|
|
}
|
|
|
|
function init() {
|
|
var toggleButtons = document.querySelectorAll('.side-toggle-btn');
|
|
for (var i = 0; i < toggleButtons.length; i++) {
|
|
(function (btn) {
|
|
btn.addEventListener('click', function () {
|
|
switchSide(btn.getAttribute('data-side-target'));
|
|
});
|
|
})(toggleButtons[i]);
|
|
}
|
|
|
|
var navButtons = document.querySelectorAll('.video-nav .nav-button[data-video-page]');
|
|
for (var j = 0; j < navButtons.length; j++) {
|
|
(function (btn) {
|
|
btn.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
showVideoPage(btn.getAttribute('data-video-page'));
|
|
});
|
|
})(navButtons[j]);
|
|
}
|
|
|
|
var defaultNav = document.querySelector(
|
|
'.video-nav .nav-button[data-video-page="' + DEFAULT_VIDEO_PAGE + '"]');
|
|
if (defaultNav) defaultNav.classList.add('active');
|
|
|
|
applySide(readSide());
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|