Initial import of calendar MVP

This commit is contained in:
MPM Module Upload
2026-10-07 21:14:56 +02:00
commit a5f8db4397
6 changed files with 471 additions and 0 deletions

15
frontend/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!doctype html>
<html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Kalender MVP</title><style>
:root{font:16px system-ui,sans-serif;color:#202423;background:#f3f4f1}*{box-sizing:border-box}body{margin:0;padding:32px 16px}.wrap{max-width:900px;margin:auto}.card{background:white;border:1px solid #dfe2dd;border-radius:14px;padding:22px;margin:16px 0;box-shadow:0 5px 20px #18251c0b}header,.row{display:flex;align-items:center;justify-content:space-between;gap:12px}h1{font-size:26px;margin:0}h2{font-size:18px;margin:0 0 16px}button,input,textarea{font:inherit}button{background:#315f47;color:#fff;border:0;border-radius:8px;padding:9px 14px;cursor:pointer}button.secondary{background:#e9ece8;color:#202423}form{display:grid;grid-template-columns:1fr 1fr;gap:12px}label{display:grid;gap:5px;font-size:14px}input,textarea{width:100%;padding:9px;border:1px solid #cbd1ca;border-radius:7px}textarea{grid-column:1/-1;min-height:70px}.wide{grid-column:1/-1}.event{padding:12px 0;border-top:1px solid #eceeeb}.muted{color:#68716a;font-size:14px}.empty{padding:18px 0;color:#68716a}@media(max-width:600px){form{grid-template-columns:1fr}.wide,textarea{grid-column:auto}body{padding:18px 10px}}
</style></head><body><main class="wrap">
<header><h1>Mein Kalender</h1><div class="row"><button class="secondary" id="prev">‹</button><strong id="month"></strong><button class="secondary" id="next">›</button></div></header>
<section class="card"><h2>Termin anlegen</h2><form id="form"><label>Titel<input name="title" required maxlength="120" placeholder="z. B. Teammeeting"></label><label>Datum<input name="date" type="date" required></label><label class="wide">Notiz<textarea name="notes" maxlength="1000" placeholder="Optional"></textarea></label><button class="wide">Termin speichern</button></form></section>
<section class="card"><h2>Termine im Monat</h2><div id="events" class="muted">Lade Termine …</div></section>
</main><script>
const base=location.pathname.replace(/\/$/,'');let cursor=new Date();const monthEl=document.querySelector('#month'),eventsEl=document.querySelector('#events');
const pad=n=>String(n).padStart(2,'0');const monthKey=d=>String(d.getFullYear())+'-'+pad(d.getMonth()+1);
function api(path,options){return fetch(base+'/api'+path,options||{headers:{'content-type':'application/json'}})}
async function refresh(){monthEl.textContent=new Intl.DateTimeFormat('de-DE',{month:'long',year:'numeric'}).format(cursor);const r=await api('/events?month='+monthKey(cursor));if(!r.ok){eventsEl.textContent='Termine konnten nicht geladen werden.';return}const data=await r.json();eventsEl.replaceChildren();if(!data.events.length){eventsEl.textContent='Noch keine Termine in diesem Monat.';eventsEl.className='empty';return}eventsEl.className='';for(const e of data.events){const item=document.createElement('article');item.className='event';const title=document.createElement('strong');title.textContent=e.title;const date=document.createElement('div');date.className='muted';date.textContent=new Intl.DateTimeFormat('de-DE',{dateStyle:'full'}).format(new Date(e.event_date+'T12:00:00'));item.append(title,date);if(e.notes){const note=document.createElement('p');note.textContent=e.notes;item.append(note)}eventsEl.append(item)}}
document.querySelector('#prev').onclick=()=>{cursor.setMonth(cursor.getMonth()-1);refresh()};document.querySelector('#next').onclick=()=>{cursor.setMonth(cursor.getMonth()+1);refresh()};document.querySelector('#form').onsubmit=async e=>{e.preventDefault();const f=new FormData(e.currentTarget);const saved=await api('/events',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({title:f.get('title'),event_date:f.get('date'),notes:f.get('notes')})});if(!saved.ok){alert('Speichern fehlgeschlagen.');return}e.currentTarget.reset();refresh()};refresh();
</script></body></html>