WikiLog: collapsible per-commit diff on click
This commit is contained in:
@@ -6,29 +6,107 @@ import { SITE_TITLE } from '../../consts';
|
|||||||
<Base title={`WikiLog — ${SITE_TITLE}`} description="Ultime modifiche al wiki">
|
<Base title={`WikiLog — ${SITE_TITLE}`} description="Ultime modifiche al wiki">
|
||||||
<div class="max-w-3xl mx-auto">
|
<div class="max-w-3xl mx-auto">
|
||||||
<h1 class="text-3xl font-bold mb-8" style="color: var(--text-primary)">WikiLog</h1>
|
<h1 class="text-3xl font-bold mb-8" style="color: var(--text-primary)">WikiLog</h1>
|
||||||
<div id="log-list" class="space-y-2">
|
<div id="log-list" class="space-y-1">
|
||||||
<p class="text-sm" style="color: var(--text-4)">Caricamento…</p>
|
<p class="text-sm" style="color: var(--text-4)">Caricamento…</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Base>
|
</Base>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
function esc(s: string) {
|
||||||
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDiff(text: string): string {
|
||||||
|
return text.split('\n').map(line => {
|
||||||
|
if (line.startsWith('diff ') || line.startsWith('index ') || line.startsWith('new file') || line.startsWith('deleted file') || line.startsWith('similarity') || line.startsWith('rename')) {
|
||||||
|
return `<span style="color:var(--text-5)">${esc(line)}</span>`;
|
||||||
|
}
|
||||||
|
if (line.startsWith('--- ') || line.startsWith('+++ ')) {
|
||||||
|
return `<span style="color:var(--text-3)">${esc(line)}</span>`;
|
||||||
|
}
|
||||||
|
if (line.startsWith('@@')) {
|
||||||
|
return `<span style="color:var(--accent);opacity:0.8">${esc(line)}</span>`;
|
||||||
|
}
|
||||||
|
if (line.startsWith('+')) {
|
||||||
|
return `<span style="color:#4ade80;background:rgba(74,222,128,0.07);display:block">${esc(line)}</span>`;
|
||||||
|
}
|
||||||
|
if (line.startsWith('-')) {
|
||||||
|
return `<span style="color:#f87171;background:rgba(248,113,113,0.07);display:block">${esc(line)}</span>`;
|
||||||
|
}
|
||||||
|
return `<span style="color:var(--text-4)">${esc(line)}</span>`;
|
||||||
|
}).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
fetch('/api/log', { credentials: 'include' })
|
fetch('/api/log', { credentials: 'include' })
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(({ log }) => {
|
.then(({ log }) => {
|
||||||
const el = document.getElementById('log-list');
|
const el = document.getElementById('log-list');
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
if (!log?.length) { el.innerHTML = '<p class="text-sm" style="color:var(--text-4)">Nessuna modifica ancora.</p>'; return; }
|
if (!log?.length) {
|
||||||
|
el.innerHTML = '<p class="text-sm" style="color:var(--text-4)">Nessuna modifica ancora.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
el.innerHTML = log.map((e: any) => {
|
el.innerHTML = log.map((e: any) => {
|
||||||
const [author, rest] = e.message.includes(': ') ? e.message.split(': ', 2) : ['', e.message];
|
const [author, rest] = e.message.includes(': ') ? e.message.split(': ', 2) : ['', e.message];
|
||||||
return `
|
return `
|
||||||
<div class="flex items-baseline gap-3 px-3 py-2 rounded-lg text-sm" style="background:var(--bg-card)">
|
<div class="rounded-lg overflow-hidden" style="background:var(--bg-card)">
|
||||||
|
<button class="log-row w-full flex items-center gap-3 px-3 py-2 text-sm text-left transition-colors hover:brightness-110" data-hash="${e.hash}" aria-expanded="false">
|
||||||
<span class="font-mono text-xs shrink-0" style="color:var(--text-5)">${e.hash}</span>
|
<span class="font-mono text-xs shrink-0" style="color:var(--text-5)">${e.hash}</span>
|
||||||
<span class="shrink-0" style="color:var(--accent)">${author || e.author}</span>
|
<span class="shrink-0 font-medium" style="color:var(--accent)">${author || e.author}</span>
|
||||||
<span class="flex-1 truncate" style="color:var(--text-2)">${rest || e.message}</span>
|
<span class="flex-1 min-w-0 truncate" style="color:var(--text-2)">${rest || e.message}</span>
|
||||||
<span class="shrink-0 text-xs" style="color:var(--text-5)">${e.date}</span>
|
<span class="shrink-0 text-xs" style="color:var(--text-5)">${e.date}</span>
|
||||||
|
<span class="log-chevron shrink-0 text-xs transition-transform" style="color:var(--text-5)">▶</span>
|
||||||
|
</button>
|
||||||
|
<div class="log-diff hidden" data-hash="${e.hash}">
|
||||||
|
<pre class="text-xs leading-5 px-3 pb-3 overflow-x-auto" style="font-family:'JetBrains Mono',monospace;border-top:1px solid var(--border);padding-top:0.75rem;margin:0"></pre>
|
||||||
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
|
el.addEventListener('click', async (ev) => {
|
||||||
|
const btn = (ev.target as Element).closest<HTMLButtonElement>('.log-row');
|
||||||
|
if (!btn) return;
|
||||||
|
const hash = btn.dataset.hash!;
|
||||||
|
const diffDiv = el.querySelector<HTMLElement>(`.log-diff[data-hash="${hash}"]`);
|
||||||
|
const pre = diffDiv?.querySelector('pre');
|
||||||
|
const chevron = btn.querySelector<HTMLElement>('.log-chevron');
|
||||||
|
if (!diffDiv || !pre) return;
|
||||||
|
|
||||||
|
const isOpen = btn.getAttribute('aria-expanded') === 'true';
|
||||||
|
if (isOpen) {
|
||||||
|
diffDiv.classList.add('hidden');
|
||||||
|
btn.setAttribute('aria-expanded', 'false');
|
||||||
|
if (chevron) chevron.style.transform = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.setAttribute('aria-expanded', 'true');
|
||||||
|
if (chevron) chevron.style.transform = 'rotate(90deg)';
|
||||||
|
diffDiv.classList.remove('hidden');
|
||||||
|
|
||||||
|
if (pre.dataset.loaded) return;
|
||||||
|
pre.textContent = 'Caricamento diff…';
|
||||||
|
pre.style.color = 'var(--text-5)';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const r = await fetch(`/api/diff/${hash}`, { credentials: 'include' });
|
||||||
|
if (!r.ok) throw new Error(String(r.status));
|
||||||
|
const { diff } = await r.json();
|
||||||
|
pre.dataset.loaded = '1';
|
||||||
|
if (!diff.trim()) {
|
||||||
|
pre.textContent = '(nessuna modifica ai file)';
|
||||||
|
pre.style.color = 'var(--text-5)';
|
||||||
|
} else {
|
||||||
|
pre.innerHTML = renderDiff(diff);
|
||||||
|
pre.style.color = '';
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
pre.textContent = 'Errore nel caricamento della diff.';
|
||||||
|
pre.style.color = '#f87171';
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
const el = document.getElementById('log-list');
|
const el = document.getElementById('log-list');
|
||||||
|
|||||||
Reference in New Issue
Block a user