Familienangebote im August: Unterschied zwischen den Versionen
Aus Bündnis für Familie Tübingen.
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| Zeile 3: | Zeile 3: | ||
<head> | <head> | ||
<meta charset="UTF-8"> | <meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Familienangebote August 2026</title> | <title>Familienangebote August 2026</title> | ||
<style> | <style> | ||
body{ | body{ | ||
font-family:Arial,sans-serif; | font-family: Arial, sans-serif; | ||
margin:20px; | margin:20px; | ||
background:#f5f5f5; | background:#f5f5f5; | ||
| Zeile 16: | Zeile 15: | ||
h1{ | h1{ | ||
text-align:center; | text-align:center; | ||
} | |||
.toolbar{ | |||
display:flex; | |||
gap:10px; | |||
margin-bottom:20px; | |||
justify-content:center; | |||
} | |||
button{ | |||
cursor:pointer; | |||
} | } | ||
| Zeile 22: | Zeile 32: | ||
grid-template-columns:repeat(7,1fr); | grid-template-columns:repeat(7,1fr); | ||
gap:10px; | gap:10px; | ||
} | |||
.weekday{ | |||
background:#003366; | |||
color:white; | |||
padding:10px; | |||
text-align:center; | |||
font-weight:bold; | |||
} | } | ||
.day{ | .day{ | ||
background:white; | background:white; | ||
min-height: | min-height:150px; | ||
border-radius: | border-radius:8px; | ||
padding: | padding:8px; | ||
box-shadow:0 2px 5px rgba(0,0,0, | box-shadow:0 2px 5px rgba(0,0,0,.15); | ||
cursor:pointer; | cursor:pointer; | ||
} | } | ||
| Zeile 35: | Zeile 53: | ||
.day-number{ | .day-number{ | ||
font-weight:bold; | font-weight:bold; | ||
margin-bottom: | margin-bottom:8px; | ||
} | } | ||
.entry{ | .entry{ | ||
background:# | background:#e8f2ff; | ||
padding:4px; | padding:4px; | ||
margin-bottom:4px; | |||
border-radius:4px; | border-radius:4px; | ||
font-size:12px; | font-size:12px; | ||
} | } | ||
| Zeile 56: | Zeile 68: | ||
position:fixed; | position:fixed; | ||
inset:0; | inset:0; | ||
background:rgba(0,0,0, | background:rgba(0,0,0,.5); | ||
justify-content:center; | |||
align-items:center; | |||
} | } | ||
.modal-content{ | .modal-content{ | ||
background:white; | background:white; | ||
width: | width:90%; | ||
max-width: | max-width:900px; | ||
max-height:90vh; | |||
overflow:auto; | |||
padding:20px; | padding:20px; | ||
border-radius:10px; | border-radius:10px; | ||
} | } | ||
input,textarea{ | label{ | ||
display:block; | |||
margin-top:10px; | |||
font-weight:bold; | |||
} | |||
input, textarea{ | |||
width:100%; | width:100%; | ||
padding:8px; | padding:8px; | ||
box-sizing:border-box; | |||
} | } | ||
.entry-card{ | |||
border:1px solid #ccc; | |||
padding:10px; | padding:10px; | ||
margin- | margin:10px 0; | ||
border-radius:6px; | |||
} | } | ||
. | .actions{ | ||
margin-top: | display:flex; | ||
gap:10px; | |||
margin-top:10px; | |||
} | } | ||
. | .close-btn{ | ||
float:right; | |||
} | } | ||
.empty{ | |||
background:transparent; | |||
} | |||
</style> | </style> | ||
</head> | </head> | ||
<body> | <body> | ||
<h1>Familienangebote August 2026</h1> | <h1>Familienangebote – August 2026</h1> | ||
<div class="toolbar"> | |||
<button onclick="exportData()">Export JSON</button> | |||
<input type="file" id="importFile" onchange="importData(event)"> | |||
</div> | |||
<div class="calendar" id="calendar"></div> | <div class="calendar" id="calendar"></div> | ||
<div class="modal" id="modal"> | <div class="modal" id="modal"> | ||
<div class="modal-content | <div class="modal-content"> | ||
< | <button class="close-btn" onclick="closeModal()">Schließen</button> | ||
< | <h2 id="modalDate"></h2> | ||
< | <button onclick="addEntry()">+ Neuer Eintrag</button> | ||
<div id="entriesContainer"></div> | |||
<div | |||
</div> | </div> | ||
</div> | </div> | ||
<script> | <script> | ||
const | const STORAGE_KEY = "familienangebote_august_2026"; | ||
let selectedDay=null; | let data = JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}"); | ||
let selectedDay = null; | |||
const | const weekdays = ["Mo","Di","Mi","Do","Fr","Sa","So"]; | ||
function saveData(){ | |||
localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); | |||
renderCalendar(); | |||
} | |||
function renderCalendar(){ | |||
const | const cal = document.getElementById("calendar"); | ||
cal.innerHTML = ""; | |||
weekdays.forEach(day=>{ | |||
const div = document.createElement("div"); | |||
div.className = "weekday"; | |||
div.textContent = day; | |||
cal.appendChild(div); | |||
}); | |||
const | const firstDay = new Date(2026,7,1); | ||
let offset = firstDay.getDay(); | |||
offset = offset === 0 ? 6 : offset - 1; | |||
for(let i=0;i<offset;i++){ | |||
const empty = document.createElement("div"); | |||
empty.className = "empty"; | |||
cal.appendChild(empty); | |||
} | |||
for(let day=1; day<=31; day++){ | |||
const div = document.createElement("div"); | |||
div.className = "day"; | |||
div.onclick = () => openDay(day); | |||
const dayNumber = document.createElement("div"); | |||
dayNumber.className = "day-number"; | |||
dayNumber.textContent = day; | |||
div.appendChild(dayNumber); | |||
const entries = data[day] || []; | |||
const | entries.forEach(entry=>{ | ||
const e = document.createElement("div"); | |||
e.className = "entry"; | |||
e.textContent = entry.angebot || "(ohne Titel)"; | |||
div.appendChild(e); | |||
}); | |||
cal.appendChild(div); | |||
} | } | ||
} | } | ||
| Zeile 213: | Zeile 207: | ||
function openDay(day){ | function openDay(day){ | ||
selectedDay=day; | selectedDay = day; | ||
document.getElementById("modal").style.display=" | document.getElementById("modal").style.display="flex"; | ||
document.getElementById("modalDate"). | document.getElementById("modalDate").textContent = | ||
`Samstag, ${day}. August 2026`.replace("Samstag", new Date(2026,7,day) | |||
.toLocaleDateString("de-DE",{weekday:"long"})); | |||
renderEntries(); | |||
} | } | ||
| Zeile 226: | Zeile 221: | ||
} | } | ||
function | function renderEntries(){ | ||
const | const container = document.getElementById("entriesContainer"); | ||
container.innerHTML = ""; | |||
if(!data[selectedDay]){ | |||
data[selectedDay] = []; | |||
} | |||
data[selectedDay].forEach((entry,index)=>{ | |||
const card = document.createElement("div"); | |||
card.className = "entry-card"; | |||
card.innerHTML = ` | |||
<label>Angebot</label> | |||
<input value="${entry.angebot || ''}" onchange="updateField(${index},'angebot',this.value)"> | |||
<label>Uhrzeit</label> | |||
<input value="${entry.uhrzeit || ''}" onchange="updateField(${index},'uhrzeit',this.value)"> | |||
<label>Treffpunkt/Ort</label> | |||
<input value="${entry.ort || ''}" onchange="updateField(${index},'ort',this.value)"> | |||
<label>Zielgruppe</label> | |||
<input value="${entry.zielgruppe || ''}" onchange="updateField(${index},'zielgruppe',this.value)"> | |||
<label>Anmeldung</label> | |||
<input value="${entry.anmeldung || ''}" onchange="updateField(${index},'anmeldung',this.value)"> | |||
<label>Link zum Angebot</label> | |||
<input value="${entry.link || ''}" onchange="updateField(${index},'link',this.value)"> | |||
<label>Beschreibung</label> | |||
<textarea rows="4" onchange="updateField(${index},'beschreibung',this.value)">${entry.beschreibung || ''}</textarea> | |||
<div class="actions"> | |||
<button onclick="copyEntry(${index})">Kopieren</button> | |||
<button onclick="deleteEntry(${index})">Löschen</button> | |||
</div> | |||
`; | |||
container.appendChild(card); | |||
}); | |||
} | |||
function addEntry(){ | |||
data[selectedDay].push({ | |||
angebot:"", | |||
uhrzeit:"", | |||
ort:"", | |||
zielgruppe:"", | |||
anmeldung:"", | |||
link:"", | |||
beschreibung:"" | |||
}); | }); | ||
saveData( | saveData(); | ||
renderEntries(); | |||
} | |||
function updateField(index, field, value){ | |||
data[selectedDay][index][field] = value; | |||
saveData(); | |||
} | } | ||
function | function deleteEntry(index){ | ||
if(confirm("Eintrag löschen?")){ | |||
data[selectedDay].splice(index,1); | |||
saveData(); | |||
renderEntries(); | |||
} | |||
} | |||
function copyEntry(index){ | |||
(data[ | const copy = JSON.parse( | ||
JSON.stringify(data[selectedDay][index]) | |||
); | |||
data[selectedDay].push(copy); | |||
saveData(); | |||
renderEntries(); | |||
} | |||
function exportData(){ | |||
const blob = new Blob( | |||
[JSON.stringify(data,null,2)], | |||
{type:"application/json"} | |||
); | |||
const a = document.createElement("a"); | |||
a.href = URL.createObjectURL(blob); | |||
a.download = "familienangebote_august_2026.json"; | |||
a.click(); | |||
} | } | ||
function | function importData(event){ | ||
const | const file = event.target.files[0]; | ||
if(!file) return; | |||
const reader = new FileReader(); | |||
saveData( | reader.onload = e => { | ||
data = JSON.parse(e.target.result); | |||
saveData(); | |||
alert("Import erfolgreich."); | |||
}; | |||
reader.readAsText(file); | |||
} | } | ||
renderCalendar(); | |||
</script> | </script> | ||
Version vom 9. Juni 2026, 09:43 Uhr
<!DOCTYPE html>