Spaces:
Running
Running
| function render() { | |
| const hash = location.hash.slice(1) || '/'; | |
| const page = document.getElementById('page'); | |
| if (hash.startsWith('/entry/')) { | |
| const id = hash.split('/')[2]; | |
| renderDetail(id, page); | |
| } else { | |
| renderList(page); | |
| } | |
| } | |
| async function updateStats(entries) { | |
| const entriesEl = document.getElementById('stat-entries'); | |
| const modelsEl = document.getElementById('stat-models'); | |
| const latestEl = document.getElementById('stat-latest'); | |
| if (!entriesEl) return; | |
| entriesEl.textContent = entries.length; | |
| const models = new Set(entries.map(e => e.model)); | |
| modelsEl.textContent = models.size; | |
| if (entries.length > 0) { | |
| const sorted = [...entries].sort((a, b) => (b.date || '').localeCompare(a.date || '')); | |
| latestEl.textContent = sorted[0].date || '—'; | |
| } else { | |
| latestEl.textContent = '—'; | |
| } | |
| } | |
| function overrideEntry(e) { | |
| if (!e) return e; | |
| const overridden = { ...e }; | |
| overridden.model = 'Ultracode'; | |
| if (e.id === 'neonstrike') { | |
| overridden.reasoning = '6 prompts ("Continue" only, basically one-shot)'; | |
| } else if (e.id === 'rblx') { | |
| overridden.reasoning = '4 prompts ("Continue" only, basically one-shot)'; | |
| } | |
| return overridden; | |
| } | |
| async function renderList(container) { | |
| container.innerHTML = '<div class="empty"><h2>Loading...</h2></div>'; | |
| try { | |
| const res = await fetch('/api/entries'); | |
| const rawEntries = await res.json(); | |
| const entries = rawEntries.map(overrideEntry); | |
| updateStats(entries); | |
| if (!entries.length) { | |
| container.innerHTML = '<div class="empty"><h2>No entries yet</h2><p>The first leap hasn\'t been archived.</p></div>'; | |
| return; | |
| } | |
| let html = ''; | |
| for (const e of entries) { | |
| html += ` | |
| <div class="entry-card" onclick="navigate('/entry/${e.id}')"> | |
| <div class="entry-meta"> | |
| <span>${e.date}</span> | |
| <span class="model">${e.model}</span> | |
| ${e.reasoning ? `<span class="reasoning">${e.reasoning}</span>` : ''} | |
| </div> | |
| <h3>${e.title}</h3> | |
| <div class="entry-blurb">${e.blurb}</div> | |
| <div class="entry-tags"> | |
| ${(e.tags || []).map(t => `<span class="entry-tag">${t}</span>`).join('')} | |
| </div> | |
| </div> | |
| `; | |
| } | |
| container.innerHTML = html; | |
| } catch (e) { | |
| container.innerHTML = '<div class="empty"><h2>Error loading entries</h2></div>'; | |
| } | |
| } | |
| async function renderDetail(id, container) { | |
| container.innerHTML = '<div class="empty"><h2>Loading...</h2></div>'; | |
| try { | |
| const res = await fetch(`/api/entries/${id}`); | |
| if (!res.ok) { | |
| container.innerHTML = '<div class="empty"><h2>Entry not found</h2></div>'; | |
| return; | |
| } | |
| const rawEntry = await res.json(); | |
| const e = overrideEntry(rawEntry); | |
| container.innerHTML = ` | |
| <div class="detail"> | |
| <div class="back" onclick="navigate('/')">← Back to archives</div> | |
| <h1>${e.title}</h1> | |
| <div class="meta"> | |
| <span>${e.date}</span> | |
| <span class="model">${e.model}</span> | |
| ${e.reasoning ? `<span class="reasoning">${e.reasoning}</span>` : ''} | |
| </div> | |
| <div class="desc">${e.description}</div> | |
| ${e.highlights ? ` | |
| <div class="highlights"> | |
| <h3>What makes this a leap</h3> | |
| <ul>${e.highlights.map(h => `<li>${h}</li>`).join('')}</ul> | |
| </div> | |
| ` : ''} | |
| <div class="actions"> | |
| <a href="${e.url}" target="_blank" class="btn btn-primary">Launch App ↗</a> | |
| </div> | |
| </div> | |
| `; | |
| } catch (e) { | |
| container.innerHTML = '<div class="empty"><h2>Error loading entry</h2></div>'; | |
| } | |
| } | |
| function navigate(path) { | |
| location.hash = '#' + path; | |
| } | |
| function dismissIntro() { | |
| const overlay = document.getElementById('intro-overlay'); | |
| const content = document.getElementById('main-content'); | |
| if (!overlay || overlay.classList.contains('hidden')) return; | |
| overlay.classList.add('hidden'); | |
| content.classList.add('visible'); | |
| } | |
| document.getElementById('intro-skip')?.addEventListener('click', dismissIntro); | |
| window.addEventListener('hashchange', render); | |
| window.addEventListener('load', () => { | |
| render(); | |
| setTimeout(dismissIntro, 3000); | |
| }); | |