Files
KiraTV-APP-NodeCast-Modific…/public/js/app.js
T
Yuri 51c2fb915c feat: implement fully responsive mobile design with channel drawer
- Add comprehensive responsive breakpoints (1024px, 768px, 640px, 480px)
- Implement slide-out channel drawer for mobile Live TV page
- Add floating 'Channels' button with overlay for mobile
- Convert navigation to hamburger menu on small screens
- Optimize all pages (Movies, Series, EPG, Settings) for mobile
- Add touch-friendly interactions and safe area insets
- Improve source action buttons layout on mobile
- Add smooth scrolling and overscroll behavior controls
- Implement proper visibility handling for mobile menus
2026-01-01 10:50:56 -05:00

141 lines
4.8 KiB
JavaScript

/**
* NodeCast TV Application Entry Point
*/
class App {
constructor() {
this.currentPage = 'home';
this.pages = {};
// Initialize components
this.player = new VideoPlayer();
this.channelList = new ChannelList();
this.sourceManager = new SourceManager();
this.epgGuide = new EpgGuide();
// Initialize page controllers
this.pages.home = new HomePage(this);
this.pages.guide = new GuidePage(this);
this.pages.movies = new MoviesPage(this);
this.pages.series = new SeriesPage(this);
this.pages.settings = new SettingsPage(this);
this.init();
}
async init() {
// Mobile menu toggle
const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
const navbarMenu = document.getElementById('navbar-menu');
if (mobileMenuToggle && navbarMenu) {
mobileMenuToggle.addEventListener('click', () => {
mobileMenuToggle.classList.toggle('active');
navbarMenu.classList.toggle('active');
});
// Close menu when a nav link is clicked
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', () => {
mobileMenuToggle.classList.remove('active');
navbarMenu.classList.remove('active');
});
});
// Close menu when clicking outside
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar')) {
mobileMenuToggle.classList.remove('active');
navbarMenu.classList.remove('active');
}
});
}
// Channel drawer toggle (mobile)
const channelToggleBtn = document.getElementById('channel-toggle-btn');
const channelSidebar = document.getElementById('channel-sidebar');
const channelOverlay = document.getElementById('channel-sidebar-overlay');
if (channelToggleBtn && channelSidebar && channelOverlay) {
const toggleChannelDrawer = () => {
channelSidebar.classList.toggle('active');
channelOverlay.classList.toggle('active');
};
channelToggleBtn.addEventListener('click', toggleChannelDrawer);
channelOverlay.addEventListener('click', toggleChannelDrawer);
// Close drawer when a channel is selected
channelSidebar.addEventListener('click', (e) => {
if (e.target.closest('.channel-item')) {
// Small delay to let the channel selection happen
setTimeout(() => {
channelSidebar.classList.remove('active');
channelOverlay.classList.remove('active');
}, 300);
}
});
}
// Navigation handling
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
this.navigateTo(link.dataset.page);
});
});
// Toggle groups button
document.getElementById('toggle-groups').addEventListener('click', () => {
this.channelList.toggleAllGroups();
});
// Search clear buttons (global handler for all)
document.querySelectorAll('.search-clear').forEach(btn => {
btn.addEventListener('click', () => {
const wrapper = btn.closest('.search-wrapper');
const input = wrapper?.querySelector('.search-input');
if (input) {
input.value = '';
input.dispatchEvent(new Event('input', { bubbles: true }));
input.focus();
}
});
});
// Initialize home page
await this.pages.home.init();
this.navigateTo('home');
console.log('NodeCast TV initialized');
}
navigateTo(pageName) {
// Update nav
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.toggle('active', link.dataset.page === pageName);
});
// Update pages
document.querySelectorAll('.page').forEach(page => {
page.classList.toggle('active', page.id === `page-${pageName}`);
});
// Notify page controllers
if (this.pages[this.currentPage]?.hide) {
this.pages[this.currentPage].hide();
}
this.currentPage = pageName;
if (this.pages[pageName]?.show) {
this.pages[pageName].show();
}
}
}
// Start app when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
window.app = new App();
});