A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys, Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun VPN routing, and a web dashboard to manage it all. Free & open forever to self-host; optional paid hosted services fund it. See PROMISE.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
100 lines
2.7 KiB
JavaScript
Executable File
100 lines
2.7 KiB
JavaScript
Executable File
// UI Helper Functions - Shared across all pages
|
|
// Simple functions without import/export syntax for compatibility
|
|
|
|
// App icon and name helpers
|
|
function getAppIcon(appName, appIconUrl) {
|
|
const cleanAppName = appName.replace('install_', '').replace(' ', '');
|
|
// Use icon URL from JSON if available, otherwise fall back to default
|
|
return appIconUrl || `icons/apps/${cleanAppName}.svg`;
|
|
}
|
|
|
|
function getAppStatus(installed) {
|
|
return installed ? 'Installed' : 'Not Installed';
|
|
}
|
|
|
|
function formatAppName(name) {
|
|
return name.split(' - ')[0].split(' -')[0].trim();
|
|
}
|
|
|
|
function getAppShortName(appData) {
|
|
return appData.name.split(' - ')[0].split(' -')[0].trim();
|
|
}
|
|
|
|
// Mobile menu helpers
|
|
function setupMobileMenu() {
|
|
const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
|
|
const sidebar = document.getElementById('sidebar');
|
|
const mobileOverlay = document.getElementById('mobile-overlay');
|
|
|
|
if (!mobileMenuToggle || !sidebar || !mobileOverlay) {
|
|
//console.log('Mobile menu elements not found');
|
|
return;
|
|
}
|
|
|
|
function toggleMobileMenu() {
|
|
sidebar.classList.toggle('mobile-open');
|
|
mobileOverlay.classList.toggle('active');
|
|
|
|
if (sidebar.classList.contains('mobile-open')) {
|
|
document.body.style.overflow = 'hidden';
|
|
} else {
|
|
document.body.style.overflow = '';
|
|
}
|
|
}
|
|
|
|
function closeMobileMenu() {
|
|
sidebar.classList.remove('mobile-open');
|
|
mobileOverlay.classList.remove('active');
|
|
document.body.style.overflow = '';
|
|
}
|
|
|
|
// Mobile menu event listeners
|
|
mobileMenuToggle.addEventListener('click', toggleMobileMenu);
|
|
mobileOverlay.addEventListener('click', closeMobileMenu);
|
|
|
|
// Close mobile menu when window is resized to desktop size
|
|
window.addEventListener('resize', () => {
|
|
if (window.innerWidth > 768) {
|
|
closeMobileMenu();
|
|
}
|
|
});
|
|
|
|
// Expose closeMobileMenu globally for other scripts
|
|
window.closeMobileMenu = closeMobileMenu;
|
|
}
|
|
|
|
// Navigation helpers
|
|
function setupActiveNavigation() {
|
|
const navItems = document.querySelectorAll('.nav-item');
|
|
navItems.forEach(item => {
|
|
if (item.textContent.includes('App Center')) {
|
|
item.classList.add('active');
|
|
}
|
|
});
|
|
}
|
|
|
|
// DOM helpers
|
|
function safeGetElement(id) {
|
|
const element = document.getElementById(id);
|
|
if (!element) {
|
|
//console.log(`${id} element not found`);
|
|
}
|
|
return element;
|
|
}
|
|
|
|
function safeQuerySelector(selector) {
|
|
const element = document.querySelector(selector);
|
|
if (!element) {
|
|
//console.log(`${selector} element not found`);
|
|
}
|
|
return element;
|
|
}
|
|
|
|
function safeQuerySelectorAll(selector) {
|
|
const elements = document.querySelectorAll(selector);
|
|
if (!elements || elements.length === 0) {
|
|
//console.log(`${selector} elements not found`);
|
|
}
|
|
return elements;
|
|
}
|