librelad 875a60f90f LibrePortal v0.1.0 — initial release
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>
2026-05-21 20:37:54 +01:00

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;
}