add initial code
This commit is contained in:
123
thread_posts.html
Normal file
123
thread_posts.html
Normal file
@@ -0,0 +1,123 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Thread Posts — Liste</title>
|
||||
<style>
|
||||
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial;line-height:1.4;margin:0;padding:20px;background:#f7f7f8;color:#111}
|
||||
.wrap{max-width:900px;margin:0 auto}
|
||||
header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}
|
||||
h1{font-size:18px;margin:0}
|
||||
.controls{display:flex;gap:8px}
|
||||
.post{background:#fff;border:1px solid #e3e3e6;padding:12px 14px;margin-bottom:12px;border-radius:6px}
|
||||
.meta{font-size:13px;color:#555;margin-bottom:8px;display:flex;gap:12px;flex-wrap:wrap}
|
||||
.text{white-space:pre-wrap;font-size:15px}
|
||||
.small{font-size:13px;color:#666}
|
||||
.file-load{display:none;margin-top:8px}
|
||||
footer{margin-top:20px;color:#666;font-size:13px}
|
||||
button{padding:6px 10px;border-radius:6px;border:1px solid #bbb;background:#fff;cursor:pointer}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<header>
|
||||
<h1>Thread Posts — alle Beiträge untereinander</h1>
|
||||
<div class="controls">
|
||||
<button id="reload">Neu laden</button>
|
||||
<button id="openFileBtn">Lokale JSON laden</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="status" class="small">Versuche, <code>thread_posts.json</code> zu laden…</div>
|
||||
|
||||
<div id="fileLoad" class="file-load">
|
||||
<input id="fileInput" type="file" accept="application/json">
|
||||
</div>
|
||||
|
||||
<main id="list"></main>
|
||||
|
||||
<footer>Hinweis: Wenn Sie die Datei lokal öffnen und `fetch` fehlschlägt, nutzen Sie bitte die Schaltfläche "Lokale JSON laden" oder starten einen kleinen HTTP-Server.</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const status = document.getElementById('status');
|
||||
const list = document.getElementById('list');
|
||||
const fileLoad = document.getElementById('fileLoad');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
const reloadBtn = document.getElementById('reload');
|
||||
const openFileBtn = document.getElementById('openFileBtn');
|
||||
|
||||
function renderPosts(posts){
|
||||
list.innerHTML = '';
|
||||
if(!Array.isArray(posts)){
|
||||
status.textContent = 'JSON hat kein Array von Posts.';
|
||||
return;
|
||||
}
|
||||
|
||||
status.textContent = `Beiträge: ${posts.length}`;
|
||||
|
||||
posts.forEach(p => {
|
||||
const el = document.createElement('article');
|
||||
el.className = 'post';
|
||||
|
||||
const meta = document.createElement('div');
|
||||
meta.className = 'meta';
|
||||
meta.innerHTML = `
|
||||
<strong>${escapeHtml(String(p.author||'—'))}</strong>
|
||||
<span>${escapeHtml(String(p.timestamp||'—'))}</span>
|
||||
<span>Likes: ${escapeHtml(String(p.likes||0))}</span>
|
||||
<span>ID: ${escapeHtml(String(p.post_id||'—'))}</span>
|
||||
<span>Seite: ${escapeHtml(String(p.page||1))}</span>
|
||||
`;
|
||||
|
||||
const body = document.createElement('div');
|
||||
body.className = 'text';
|
||||
body.textContent = p.text || '';
|
||||
|
||||
el.appendChild(meta);
|
||||
el.appendChild(body);
|
||||
list.appendChild(el);
|
||||
});
|
||||
}
|
||||
|
||||
function escapeHtml(s){
|
||||
return s.replace(/[&<>\"]/g, c => ({'&':'&','<':'<','>':'>','"':'"'}[c]));
|
||||
}
|
||||
|
||||
async function tryFetch(){
|
||||
try{
|
||||
const resp = await fetch('thread_posts.json', {cache: 'no-store'});
|
||||
if(!resp.ok) throw new Error('HTTP ' + resp.status);
|
||||
const data = await resp.json();
|
||||
renderPosts(data);
|
||||
}catch(e){
|
||||
console.warn('fetch failed', e);
|
||||
status.textContent = 'Laden per fetch fehlgeschlagen — wähle Datei manuell.';
|
||||
fileLoad.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
fileInput.addEventListener('change', e => {
|
||||
const f = e.target.files && e.target.files[0];
|
||||
if(!f) return;
|
||||
const r = new FileReader();
|
||||
r.onload = ev => {
|
||||
try{
|
||||
const data = JSON.parse(ev.target.result);
|
||||
renderPosts(data);
|
||||
}catch(err){
|
||||
status.textContent = 'Ungültiges JSON.';
|
||||
}
|
||||
};
|
||||
r.readAsText(f, 'utf-8');
|
||||
});
|
||||
|
||||
openFileBtn.addEventListener('click', ()=> fileInput.click());
|
||||
reloadBtn.addEventListener('click', ()=> { status.textContent = 'Neu laden…'; tryFetch(); });
|
||||
|
||||
// initial
|
||||
tryFetch();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user