// Theme Management class ThemeManager { constructor() { this.theme = localStorage.getItem('theme') || 'light'; this.init(); } init() { document.documentElement.setAttribute('data-theme', this.theme); this.updateThemeIcon(); } toggle() { this.theme = this.theme === 'light' ? 'dark' : 'light'; document.documentElement.setAttribute('data-theme', this.theme); localStorage.setItem('theme', this.theme); this.updateThemeIcon(); } updateThemeIcon() { const lightIcon = document.querySelector('.light-icon'); const darkIcon = document.querySelector('.dark-icon'); if (this.theme === 'light') { lightIcon.style.display = 'block'; darkIcon.style.display = 'none'; } else { lightIcon.style.display = 'none'; darkIcon.style.display = 'block'; } } } // Date Management class DateManager { constructor() { // Start with today's date, but it will be updated when we get the actual available date this.currentDate = new Date(); this.init(); } init() { this.updateDateDisplay(); this.bindEvents(); } formatDate(date) { const options = { year: 'numeric', month: 'short', day: 'numeric' }; return date.toLocaleDateString('en-US', options); } updateDateDisplay() { const dateDisplay = document.getElementById('dateDisplay'); dateDisplay.textContent = this.formatDate(this.currentDate); } navigateDate(direction) { const newDate = new Date(this.currentDate); newDate.setDate(newDate.getDate() + direction); this.currentDate = newDate; this.updateDateDisplay(); this.loadDaily(); } bindEvents() { document.getElementById('prevDate').addEventListener('click', () => { this.navigateDate(-1); }); document.getElementById('nextDate').addEventListener('click', () => { this.navigateDate(1); }); } getDateString() { const pad = (n) => String(n).padStart(2, '0'); return `${this.currentDate.getFullYear()}-${pad(this.currentDate.getMonth()+1)}-${pad(this.currentDate.getDate())}`; } } // Search Management class SearchManager { constructor() { this.init(); } init() { this.bindEvents(); } bindEvents() { const searchInput = document.querySelector('.search-input'); const aiSearchInput = document.querySelector('.ai-search-input'); searchInput.addEventListener('input', (e) => { this.handleSearch(e.target.value); }); aiSearchInput.addEventListener('input', (e) => { this.handleAISearch(e.target.value); }); } handleSearch(query) { // Implement search functionality console.log('Search query:', query); } handleAISearch(query) { // Implement AI search functionality console.log('AI search query:', query); } } // Paper Card Renderer class PaperCardRenderer { constructor() { this.cardsContainer = document.getElementById('cards'); } generateThumbnail(title) { // Generate a simple thumbnail based on title const canvas = document.createElement('canvas'); canvas.width = 400; canvas.height = 120; const ctx = canvas.getContext('2d'); // Create gradient background const gradient = ctx.createLinearGradient(0, 0, 400, 120); gradient.addColorStop(0, '#3b82f6'); gradient.addColorStop(1, '#06b6d4'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, 400, 120); // Add text ctx.fillStyle = 'rgba(255, 255, 255, 0.9)'; ctx.font = 'bold 16px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; const words = title.split(' '); const lines = []; let currentLine = ''; for (const word of words) { const testLine = currentLine + word + ' '; const metrics = ctx.measureText(testLine); if (metrics.width > 350 && currentLine !== '') { lines.push(currentLine); currentLine = word + ' '; } else { currentLine = testLine; } } lines.push(currentLine); const yStart = 60 - (lines.length * 20) / 2; lines.forEach((line, index) => { ctx.fillText(line.trim(), 200, yStart + index * 20); }); return canvas.toDataURL(); } generateAuthorAvatars(authorCount) { const avatars = []; const count = Math.min(authorCount, 5); for (let i = 0; i < count; i++) { avatars.push(`
  • `); } return avatars.join(''); } renderCard(paper) { const title = paper.title || 'Untitled Paper'; const abstract = paper.abstract || 'No abstract available'; const authors = paper.authors || []; const authorCount = paper.author_count || authors.length || 0; const upvotes = paper.upvotes || 0; const githubStars = paper.github_stars || 0; const comments = paper.comments || 0; const submitter = paper.submitter || 'Anonymous'; // Generate thumbnail URL - try to use HF thumbnail if available const arxivId = paper.arxiv_id; const thumbnailUrl = arxivId ? `https://cdn-thumbnails.huggingface.co/social-thumbnails/papers/${arxivId}.png` : this.generateThumbnail(title); const authorAvatars = this.generateAuthorAvatars(authorCount); const card = document.createElement('article'); card.className = 'hf-paper-card'; card.innerHTML = `
    Submitted by
    ${submitter}

    ${title}

    ${paper.arxiv_id ? `
    Evaluation
    ` : ''} `; return card; } renderCards(papers) { this.cardsContainer.innerHTML = ''; if (!papers || papers.length === 0) { this.cardsContainer.innerHTML = `

    No papers found

    Try selecting a different date or check back later.

    `; return; } papers.forEach(paper => { const card = this.renderCard(paper); this.cardsContainer.appendChild(card); }); } } // Main Application class PaperIndexApp { constructor() { this.themeManager = new ThemeManager(); this.dateManager = new DateManager(); this.searchManager = new SearchManager(); this.cardRenderer = new PaperCardRenderer(); this.init(); } init() { this.bindEvents(); this.loadDaily(); } bindEvents() { // Theme toggle document.getElementById('themeToggle').addEventListener('click', () => { this.themeManager.toggle(); }); // Filter buttons document.querySelectorAll('.filter-btn').forEach(btn => { btn.addEventListener('click', (e) => { document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); e.target.classList.add('active'); }); }); } async loadDaily() { const dateStr = this.dateManager.getDateString(); try { const response = await fetch(`/api/daily?date_str=${encodeURIComponent(dateStr)}`); if (!response.ok) { throw new Error('Failed to load daily papers'); } const data = await response.json(); console.log('API Response:', { requested_date: data.requested_date, actual_date: data.date, fallback_used: data.fallback_used, cards_count: data.cards?.length }); // Update the date display if a fallback was used or if we got a different date than requested if (data.date && data.requested_date && data.date !== data.requested_date) { console.log('Updating date display from', data.requested_date, 'to', data.date); const fallbackDate = new Date(data.date); this.dateManager.currentDate = fallbackDate; this.dateManager.updateDateDisplay(); // Show a notification about the fallback this.showFallbackNotification(data.requested_date, data.date); } // Show cache status if available if (data.cached) { this.showCacheNotification(data.cached_at); } this.cardRenderer.renderCards(data.cards || []); } catch (error) { console.error('Error loading papers:', error); this.cardRenderer.renderCards([]); // Show fallback message this.cardRenderer.cardsContainer.innerHTML = `

    Unable to load papers

    Backend unavailable on static hosting. Try opening the daily page on Hugging Face:

    Open on Hugging Face
    `; } } showFallbackNotification(requestedDate, actualDate) { // Create a temporary notification const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: var(--bg-primary); border: 1px solid var(--border-medium); border-radius: 8px; padding: 16px; box-shadow: var(--shadow-lg); z-index: 1000; max-width: 300px; color: var(--text-primary); `; notification.innerHTML = `
    Date Updated

    Papers for ${requestedDate} not available. Showing latest available: ${actualDate}

    `; document.body.appendChild(notification); // Remove notification after 5 seconds setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 5000); } showCacheNotification(cachedAt) { // Create a temporary notification const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: var(--bg-primary); border: 1px solid var(--border-medium); border-radius: 8px; padding: 16px; box-shadow: var(--shadow-lg); z-index: 1000; max-width: 300px; color: var(--text-primary); `; const cacheTime = new Date(cachedAt).toLocaleString(); notification.innerHTML = `
    Cached Data

    Showing cached data from ${cacheTime}

    `; document.body.appendChild(notification); // Remove notification after 3 seconds setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 3000); } } // Initialize the application when DOM is loaded document.addEventListener('DOMContentLoaded', () => { new PaperIndexApp(); });