${escapeHtml(game.title || game.slug)}
${game.subtitle ? `${escapeHtml(game.subtitle)}
` : ''} ${game.description ? `${escapeHtml(game.description)}
` : ''}/**
* NovelasVM Portal
* Carga el catalogo de juegos y gestiona temas.
*/
(function () {
'use strict';
const THEME_KEY = 'novelasvm-theme';
const THEMES = ['dark', 'light', 'immersive'];
const engineConfig = {
renpy: {
label: 'Ren\'Py',
icon: ''
},
'umineko-ru': {
label: 'ONScripter-RU',
icon: ''
},
unity: {
label: 'Unity',
icon: ''
},
web: {
label: 'Web',
icon: ''
}
};
// --- Theme handling ------------------------------------------------------
function getSavedTheme() {
const saved = localStorage.getItem(THEME_KEY);
if (saved && THEMES.includes(saved)) return saved;
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
return 'light';
}
return 'dark';
}
function setTheme(theme) {
if (!THEMES.includes(theme)) return;
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem(THEME_KEY, theme);
updateThemeButtons(theme);
}
function updateThemeButtons(activeTheme) {
document.querySelectorAll('.theme-btn').forEach(btn => {
const btnTheme = btn.getAttribute('data-theme-value');
btn.classList.toggle('active', btnTheme === activeTheme);
btn.setAttribute('aria-pressed', btnTheme === activeTheme ? 'true' : 'false');
});
}
function initThemeSwitcher() {
setTheme(getSavedTheme());
document.querySelectorAll('.theme-btn').forEach(btn => {
btn.addEventListener('click', () => setTheme(btn.getAttribute('data-theme-value')));
});
}
// --- Catalog rendering ---------------------------------------------------
function formatDate(isoString) {
if (!isoString) return '';
try {
const date = new Date(isoString);
return date.toLocaleDateString('es-ES', {
year: 'numeric', month: 'short', day: 'numeric'
});
} catch (e) {
return '';
}
}
function getEngineBadge(engine) {
const cfg = engineConfig[engine] || engineConfig.web;
return `${cfg.icon}${cfg.label}`;
}
function getCoverImage(game) {
if (game.cover) {
return ``;
}
return `
${escapeHtml(game.subtitle)}
` : ''} ${game.description ? `${escapeHtml(game.description)}
` : ''}