librelad 152d9c5d28 fix(webui): make all icon and data asset URLs absolute under path routing
Same class of bug as the topbar partial: icon and data-file references were
relative (icons/apps/x.svg, data/apps/...), so on deep path routes (/app/<name>,
/admin/config/x) the browser resolved them against the route dir and the SPA
catch-all served index.html with HTTP 200 instead of 404 — broken images and
silently-wrong JSON.

Make every reference absolute (anchored on the quote/backtick so already-absolute
/icons paths are untouched):
- JS: all icons/ and data/ literals + templates across components/utils/system
- html/topbar.html: logo <img>
- generators: webui_config.sh and webui_create_app_categories.sh now emit
  /icons/... into apps.json / apps-categories.json (regenerated on install)
- updated the two icon-path comments to match

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-24 23:20:42 +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;
}