// ─── Theme Management ───
let currentTheme = 'dark';
function toggleTheme() {
currentTheme = currentTheme === 'dark' ? 'light' : 'dark';
const html = document.documentElement;
// Set theme attribute — CSS variables handle the rest
html.setAttribute('data-theme', currentTheme);
if (currentTheme === 'light') {
document.body.classList.remove('dark');
} else {
document.body.classList.add('dark');
}
// Override Gradio internal CSS variables
const root = document.documentElement;
const isLight = currentTheme === 'light';
const vars = isLight ? {
'--body-background-fill': '#f8fafc',
'--block-background-fill': '#ffffff',
'--block-border-color': '#e2e8f0',
'--block-label-text-color': '#475569',
'--block-title-text-color': '#0f172a',
'--input-background-fill': '#f1f5f9',
'--input-border-color': '#cbd5e1',
'--body-text-color': '#0f172a',
'--neutral-100': '#f1f5f9',
'--neutral-200': '#e2e8f0',
'--neutral-300': '#cbd5e1',
'--neutral-400': '#94a3b8',
'--neutral-500': '#64748b',
'--neutral-600': '#475569',
'--neutral-700': '#334155',
'--neutral-800': '#1e293b',
'--neutral-900': '#0f172a',
} : {
'--body-background-fill': '#0a0a0c',
'--block-background-fill': '#111827',
'--block-border-color': '#374151',
'--block-label-text-color': '#9ca3af',
'--block-title-text-color': '#ffffff',
'--input-background-fill': '#1f2937',
'--input-border-color': '#374151',
'--body-text-color': '#ffffff',
'--neutral-100': '#1f2937',
'--neutral-200': '#374151',
'--neutral-300': '#4b5563',
'--neutral-400': '#6b7280',
'--neutral-500': '#9ca3af',
'--neutral-600': '#d1d5db',
'--neutral-700': '#e5e7eb',
'--neutral-800': '#f3f4f6',
'--neutral-900': '#ffffff',
};
// Apply Gradio vars to all containers
document.querySelectorAll('.gradio-container').forEach(el => {
Object.entries(vars).forEach(([k, v]) => el.style.setProperty(k, v));
el.style.background = isLight ? '#f8fafc' : '#0a0a0c';
el.style.color = isLight ? '#0f172a' : '#ffffff';
});
// Force Gradio block/form/panel backgrounds
const bgColor = isLight ? '#ffffff' : '#111827';
const borderColor = isLight ? '#e2e8f0' : '#374151';
const textColor = isLight ? '#0f172a' : '#ffffff';
const subTextColor = isLight ? '#475569' : '#9ca3af';
const inputBg = isLight ? '#f1f5f9' : '#1f2937';
document.querySelectorAll('.block, .form, .panel').forEach(el => {
el.style.backgroundColor = bgColor;
el.style.borderColor = borderColor;
});
document.querySelectorAll('input, textarea, select').forEach(el => {
if (!el.closest('.glass-input-wrapper')) {
el.style.backgroundColor = inputBg;
el.style.borderColor = borderColor;
}
el.style.color = textColor;
});
document.querySelectorAll('label, .label-wrap, .block-label').forEach(el => {
if (!el.closest('.header-banner') && !el.closest('.glass-input-wrapper')) {
el.style.color = subTextColor;
}
});
// Update toggle button icon
const btn = document.getElementById('theme-toggle');
if (btn) {
btn.innerHTML = currentTheme === 'dark' ? '☀️' : '🌙';
btn.title = currentTheme === 'dark' ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro';
}
// Save preference
try { localStorage.setItem('letxipu-theme', currentTheme); } catch(e) {}
}
// Initialize theme on load (respect saved preference)
document.addEventListener('DOMContentLoaded', function() {
try {
var saved = localStorage.getItem('letxipu-theme');
if (saved === 'light') {
currentTheme = 'dark'; // will be toggled to light
toggleTheme();
return;
}
} catch(e) {}
document.body.classList.add('dark');
document.documentElement.setAttribute('data-theme', 'dark');
});
window._copyCitation = function(btn, citeText) {
navigator.clipboard.writeText(citeText).then(function() {
var originalHtml = btn.innerHTML;
btn.innerHTML = '✅ Copiado';
btn.style.color = '#10b981';
btn.style.borderColor = 'rgba(16,185,129,0.3)';
setTimeout(function() {
btn.innerHTML = originalHtml;
btn.style.color = 'var(--foreground, #fff)';
btn.style.borderColor = 'var(--border, rgba(255,255,255,0.1))';
}, 2000);
});
};
// ─── Citation Floating Card (Global) ───
window.showCiteCard = function(el) {
var b64 = el.getAttribute('data-cite-b64');
var raw = el.getAttribute('data-cite');
if (!b64 && !raw) return;
var data;
try {
if (b64) {
var decoded = decodeURIComponent(escape(atob(b64)));
data = JSON.parse(decoded);
} else {
data = JSON.parse(raw.replace(/"/g,'"').replace(/'/g,"'"));
}
} catch(e) { console.error('CiteCard parse error', e); return; }
var card = document.getElementById('cite-card-global');
var overlay = document.getElementById('cite-card-overlay-global');
if (!card) {
overlay = document.createElement('div');
overlay.id = 'cite-card-overlay-global';
overlay.style.cssText = 'display:none;position:fixed;top:0;left:0;width:100%;height:100%;z-index:999998;background:transparent;';
overlay.addEventListener('click', function(){ window.closeCiteCard(); });
document.body.appendChild(overlay);
card = document.createElement('div');
card.id = 'cite-card-global';
card.style.cssText = 'display:none;position:fixed;z-index:999999;width:340px;max-width:90vw;background:var(--popup-bg, rgba(17,24,39,0.95));backdrop-filter:blur(10px);border:1px solid var(--popup-border, rgba(139,92,246,0.3));border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,0.5),0 0 30px rgba(139,92,246,0.1);font-family:Inter,sans-serif;transition:opacity 0.2s ease,transform 0.2s ease;opacity:0;transform:translateY(8px);color:var(--foreground, #fff);display:flex;flex-direction:column;';
card.innerHTML = '
';
document.body.appendChild(card);
// Setup dragging
var isDragging = false;
var dragOffset = {x: 0, y: 0};
document.addEventListener('mousemove', function(e) {
if (isDragging && card) {
card.style.left = (e.clientX - dragOffset.x) + 'px';
card.style.top = (e.clientY - dragOffset.y) + 'px';
card.style.transform = 'none'; // Clear animation transform
}
});
document.addEventListener('mouseup', function(e) {
isDragging = false;
});
window._startCardDrag = function(e) {
isDragging = true;
var rect = card.getBoundingClientRect();
dragOffset.x = e.clientX - rect.left;
dragOffset.y = e.clientY - rect.top;
e.preventDefault();
};
}
overlay = document.getElementById('cite-card-overlay-global');
var content = document.getElementById('cite-card-content-global');
var doi = data.DOI || data.doi || '';
var pdfUrl = data.pdf_url || data.PDF || '';
var title = data['Título'] || data.title || 'Sin título';
var authors = data['Autores'] || data.authors || 'Autor desconocido';
var year = data['Año'] || data.year || '?';
var source = data['Fuente'] || data.source || 'Desconocido';
var abstract = data['Abstract'] || data.abstract || '';
// Icon SVGs
var iconMove = '';
var iconX = '';
var iconMsg = '';
var iconDl = '';
var iconQuote = '';
var iconLang = '';
var iconBranch = '';
var iconExt = '';
var iconSearch = '';
// Header
var headerHtml =
'' +
'
' +
iconMove +
'CITAR' +
'
' +
'
' +
'
';
var authorStr = Array.isArray(authors) ? authors.join(', ') : authors;
var firstAuthor = Array.isArray(authors) ? authors[0] : authors.split(",")[0];
// Compute source URL and button styling
var sourceUrl = data.url || data.URL || '';
if (!sourceUrl && doi) sourceUrl = 'https://doi.org/' + doi;
if (!sourceUrl) sourceUrl = '#';
var sourceBtnText = 'Ver fuente';
var sourceBtnColor = '#a78bfa';
var sourceBtnBg = 'rgba(139,92,246,0.1)';
var sourceBtnBorder = 'rgba(139,92,246,0.3)';
var sourceBtnIcon = iconExt;
if (source.toLowerCase().includes('pubmed')) {
sourceBtnText = 'PubMed'; sourceBtnColor = '#22c55e'; sourceBtnBg = 'rgba(34,197,94,0.1)'; sourceBtnBorder = 'rgba(34,197,94,0.3)'; sourceBtnIcon = iconSearch;
} else if (source.toLowerCase().includes('semantic')) {
sourceBtnText = 'Semantic Scholar'; sourceBtnColor = '#3b82f6'; sourceBtnBg = 'rgba(59,130,246,0.1)'; sourceBtnBorder = 'rgba(59,130,246,0.3)'; sourceBtnIcon = iconSearch;
} else if (source.toLowerCase().includes('crossref')) {
sourceBtnText = 'Crossref'; sourceBtnColor = '#f59e0b'; sourceBtnBg = 'rgba(245,158,11,0.1)'; sourceBtnBorder = 'rgba(245,158,11,0.3)'; sourceBtnIcon = iconSearch;
} else if (source.toLowerCase().includes('openalex')) {
sourceBtnText = 'OpenAlex'; sourceBtnColor = '#ec4899'; sourceBtnBg = 'rgba(236,72,153,0.1)'; sourceBtnBorder = 'rgba(236,72,153,0.3)'; sourceBtnIcon = iconSearch;
} else if (doi) {
sourceBtnText = 'DOI'; sourceBtnColor = '#06b6d4'; sourceBtnBg = 'rgba(6,182,212,0.1)'; sourceBtnBorder = 'rgba(6,182,212,0.3)'; sourceBtnIcon = iconExt;
}
var citeString = firstAuthor + " et al. (" + year + "). " + title + ". " + sourceUrl;
var escapedCiteString = citeString.replace(/'/g, "\\'").replace(/"/g, """).replace(/\n/g, " ").replace(/\r/g, "");
// Buttons
var actionBtnsHtml =
'' +
'
' +
(pdfUrl ?
'
' +
iconDl + ' Descargar' +
'' : '') +
'
' +
'
' +
'
' +
'
';
// Abstract box
var abstractHtml = '';
if (abstract) {
abstractHtml =
'' +
abstract +
'
';
}
var bodyHtml =
'' +
'
' + title + '
' +
actionBtnsHtml +
'
' +
authorStr + ' | ' + year +
'
' +
abstractHtml +
'
' +
'
';
content.innerHTML = headerHtml + bodyHtml;
// Centering Logic
var rect = el.getBoundingClientRect();
var cardW = 340;
var left = rect.left + rect.width/2 - cardW/2;
if (left < 10) left = 10;
if (left + cardW > window.innerWidth - 10) left = window.innerWidth - cardW - 10;
// Position slightly offset from cursor or element
var top = rect.bottom + 10;
if (top + 400 > window.innerHeight) {
top = window.innerHeight - 410;
if (top < 10) top = 10;
}
card.style.left = left + 'px';
card.style.top = top + 'px';
overlay.style.display = 'block';
card.style.display = 'flex';
setTimeout(function(){ card.style.opacity='1'; card.style.transform='translateY(0)'; }, 10);
};
window.closeCiteCard = function() {
var card = document.getElementById('cite-card-global');
var overlay = document.getElementById('cite-card-overlay-global');
if (card) {
card.style.opacity = '0';
card.style.transform = 'translateY(8px)';
setTimeout(function(){ card.style.display='none'; if(overlay) overlay.style.display='none'; }, 200);
}
};
// Event Delegation for Cite Links (Fix for Gradio 6 removing inline onclick handlers)
document.addEventListener('click', function(e) {
const citeLink = e.target.closest('.cite-link');
if (citeLink) {
e.preventDefault();
window.showCiteCard(citeLink);
return;
}
// Check for close button
if (e.target.closest('.close-cite-btn')) {
e.preventDefault();
window.closeCiteCard();
}
});
// References Pagination Logic
window.initRefsPagination = function() {
var container = document.getElementById('refs-container');
if (!container) return;
var items = Array.from(container.querySelectorAll('.ref-item'));
var filterCb = document.getElementById('refs-filter-cited');
var citedFilter = filterCb ? filterCb.checked : false;
var visibleItems = items.filter(function(item) {
if (citedFilter && item.getAttribute('data-cited') !== 'true') return false;
return true;
});
var perPage = 10;
var totalPages = Math.ceil(visibleItems.length / perPage);
var currentPage = parseInt(container.getAttribute('data-page')) || 1;
if (currentPage > totalPages && totalPages > 0) currentPage = totalPages;
if (currentPage < 1) currentPage = 1;
items.forEach(function(item) { item.style.display = 'none'; });
var start = (currentPage - 1) * perPage;
var end = start + perPage;
for (var i = start; i < end && i < visibleItems.length; i++) {
visibleItems[i].style.display = 'flex';
}
var pagContainer = document.getElementById('refs-pagination');
if (pagContainer) {
pagContainer.innerHTML = '';
if (totalPages > 1) {
var createBtn = function(text, page, disabled, active) {
var b = document.createElement('button');
b.innerHTML = text;
b.style.cssText = 'padding: 6px 14px; margin: 0 2px; border: 1px solid var(--border, #374151); background: ' + (active ? 'var(--accent, #8b5cf6)' : 'transparent') + '; color: ' + (active ? '#fff' : 'var(--foreground, #d1d5db)') + '; border-radius: 6px; cursor: ' + (disabled ? 'default' : 'pointer') + '; opacity: ' + (disabled ? '0.5' : '1') + '; font-size: 13px; font-weight: 600; transition: all 0.2s;';
if (!disabled && !active) {
b.onmouseover = function() { b.style.background = 'rgba(139,92,246,0.15)'; };
b.onmouseout = function() { b.style.background = 'transparent'; };
b.onclick = function() {
container.setAttribute('data-page', page);
window.initRefsPagination();
// Scroll to top of container smoothly
var y = container.getBoundingClientRect().top + window.scrollY - 100;
window.scrollTo({top: y, behavior: 'smooth'});
};
}
return b;
};
pagContainer.appendChild(createBtn('Anterior', currentPage - 1, currentPage === 1, false));
var startP = Math.max(1, currentPage - 2);
var endP = Math.min(totalPages, startP + 4);
if (endP - startP < 4) startP = Math.max(1, endP - 4);
for (var p = startP; p <= endP; p++) {
pagContainer.appendChild(createBtn(p, p, false, p === currentPage));
}
pagContainer.appendChild(createBtn('Siguiente', currentPage + 1, currentPage === totalPages, false));
}
}
var stats = document.getElementById('refs-stats');
if (stats) stats.innerHTML = 'Mostrando ' + (visibleItems.length > 0 ? start + 1 : 0) + ' - ' + Math.min(end, visibleItems.length) + ' de ' + visibleItems.length + ' referencias';
};
// Make Headers Collapsible
window.makeHeadersCollapsible = function() {
var container = document.getElementById('report-content');
if (!container) return;
// Prevent double processing
if (container.getAttribute('data-collapsible-processed') === 'true') return;
container.setAttribute('data-collapsible-processed', 'true');
var headers = Array.from(container.querySelectorAll('h1, h2, h3, h4, h5, h6'));
if (headers.length === 0) return;
headers.forEach(function(h) {
if (h.parentElement && h.parentElement.tagName.toLowerCase() === 'summary') return;
var details = document.createElement('details');
details.open = true; // Open by default as requested
var summary = document.createElement('summary');
summary.innerHTML = h.innerHTML;
summary.className = h.className;
h.parentNode.insertBefore(details, h);
details.appendChild(summary);
var headerLevel = parseInt(h.tagName[1]);
var next = h.nextSibling;
while (next) {
var current = next;
next = next.nextSibling;
if (current.nodeType === 1 && current.tagName.match(/^H[1-6]$/i)) {
var currentLevel = parseInt(current.tagName[1]);
if (currentLevel <= headerLevel) {
break;
}
}
details.appendChild(current);
}
h.remove();
});
};
// MathJax Loading
window.MathJax = {
tex: { inlineMath: [['$','$'], ['\\\\(','\\\\)']], displayMath: [['$$','$$'], ['\\\\[','\\\\]']] },
options: { skipHtmlTags: ['script','noscript','style','textarea','pre','code'] }
};
const script = document.createElement('script');
script.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js";
script.async = true;
document.head.appendChild(script);