Familienangebote im August: Unterschied zwischen den Versionen

Aus Bündnis für Familie Tübingen.
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 1: Zeile 1:
<!doctype html>
<html lang="de">
<html lang="de">
<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" />
   <title>Kalender August 2026</title>
   <title>Familienangebote im August 2026</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
   <style>
   <style>
     :root {
     :root {
       --bg: #f6f7fb;
       --bg: #f7f6f2;
       --card: #ffffff;
       --surface: #ffffff;
       --text: #1f2937;
      --surface-2: #f3f0ec;
       --muted: #6b7280;
       --text: #28251d;
       --accent: #2563eb;
       --muted: #6f6a63;
       --accent-2: #dbeafe;
       --border: rgba(40, 37, 29, 0.12);
       --border: #e5e7eb;
       --primary: #01696f;
       --shadow: 0 10px 30px rgba(0,0,0,.08);
       --primary-soft: #dcebea;
       --shadow: 0 10px 28px rgba(36, 31, 24, 0.08);
      --radius: 18px;
      --radius-sm: 12px;
     }
     }
     * { box-sizing: border-box; }
     * { box-sizing: border-box; }
    html { scroll-behavior: smooth; }
     body {
     body {
       margin: 0;
       margin: 0;
       font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
       font-family: 'Inter', system-ui, sans-serif;
      background: var(--bg);
       color: var(--text);
       color: var(--text);
       background: var(--bg);
       line-height: 1.5;
     }
     }
     .wrap {
 
       max-width: 1200px;
     .calendar-app {
       max-width: 1180px;
       margin: 0 auto;
       margin: 0 auto;
       padding: 24px;
       padding: 24px 16px 40px;
    }
 
    .calendar-head {
      display: flex;
      justify-content: space-between;
      align-items: end;
      gap: 16px;
      margin-bottom: 18px;
      flex-wrap: wrap;
    }
 
    .calendar-title-wrap h1 {
      margin: 0;
      font-size: clamp(1.7rem, 2.8vw, 2.5rem);
      line-height: 1.1;
    }
 
    .calendar-title-wrap p {
      margin: 8px 0 0;
      color: var(--muted);
      max-width: 70ch;
      font-size: 0.98rem;
     }
     }
     h1 { margin: 0 0 8px; font-size: clamp(1.5rem, 3vw, 2.2rem); }
 
    .sub { margin: 0 0 20px; color: var(--muted); }
     .badge {
     .calendar {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: var(--primary-soft);
      color: var(--primary);
      border-radius: 999px;
      padding: 10px 14px;
      font-size: 0.92rem;
      font-weight: 600;
      white-space: nowrap;
    }
 
    .weekday-row,
     .calendar-grid {
       display: grid;
       display: grid;
       grid-template-columns: repeat(7, minmax(0, 1fr));
       grid-template-columns: repeat(7, minmax(0, 1fr));
       gap: 10px;
       gap: 10px;
     }
     }
     .dow, .day {
 
       background: var(--card);
     .weekday {
      text-align: center;
      padding: 12px 8px;
      color: var(--muted);
      font-weight: 700;
      font-size: 0.92rem;
    }
 
    .day-card {
      min-height: 146px;
       background: var(--surface);
       border: 1px solid var(--border);
       border: 1px solid var(--border);
       border-radius: 16px;
       border-radius: var(--radius);
       overflow: hidden;
      padding: 12px;
       min-height: 120px;
      box-shadow: var(--shadow);
      display: flex;
      flex-direction: column;
      gap: 10px;
    }
 
    .day-card.empty {
       background: transparent;
      border-style: dashed;
      box-shadow: none;
       min-height: 146px;
    }
 
    .day-top {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 8px;
     }
     }
     .dow {
 
      padding: 12px;
     .day-number {
       font-weight: 700;
       font-weight: 700;
       text-align: center;
       font-size: 0.98rem;
       color: var(--muted);
       color: var(--muted);
      min-height: auto;
     }
     }
     .day {
 
       padding: 10px;
     .event-count {
      font-size: 0.78rem;
      color: var(--primary);
      background: var(--primary-soft);
       padding: 4px 8px;
      border-radius: 999px;
      font-weight: 600;
    }
 
    .events-list {
       display: flex;
       display: flex;
       flex-direction: column;
       flex-direction: column;
       gap: 8px;
       gap: 8px;
      align-items: stretch;
     }
     }
    .day.empty { background: transparent; border: 1px dashed transparent; }
 
     .day-num { font-weight: 700; color: var(--muted); }
     .event-chip {
    .event {
      display: block;
       width: 100%;
       width: 100%;
       text-align: left;
       text-align: left;
       border: 1px solid var(--accent-2);
       border: 1px solid transparent;
       background: var(--accent-2);
       background: var(--surface-2);
      color: #0f172a;
       border-radius: var(--radius-sm);
       border-radius: 12px;
       padding: 10px 11px;
       padding: 8px 10px;
       cursor: pointer;
       cursor: pointer;
       font: inherit;
      transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease, background .18s ease;
       line-height: 1.25;
    }
 
    .event-chip:hover,
    .event-chip:focus-visible {
      transform: translateY(-1px);
      border-color: rgba(1, 105, 111, 0.3);
      box-shadow: 0 8px 18px rgba(1, 105, 111, 0.10);
      background: #eef6f5;
      outline: none;
    }
 
    .event-time {
      display: block;
      color: var(--primary);
       font-weight: 700;
      font-size: 0.82rem;
       margin-bottom: 3px;
    }
 
    .event-title {
      display: block;
      font-size: 0.92rem;
      font-weight: 600;
      color: var(--text);
     }
     }
    .event:hover { border-color: var(--accent); box-shadow: 0 2px 8px rgba(37,99,235,.12); }
    .event .time { display: block; font-size: .82rem; color: var(--accent); font-weight: 700; margin-bottom: 2px; }
    .event .title { display: block; font-weight: 600; }
    .legend { margin-top: 18px; color: var(--muted); font-size: .95rem; }


     dialog {
     dialog {
      width: min(94vw, 620px);
       border: none;
       border: none;
      border-radius: 18px;
      width: min(92vw, 560px);
      box-shadow: var(--shadow);
       padding: 0;
       padding: 0;
      border-radius: 22px;
      overflow: hidden;
      box-shadow: 0 24px 60px rgba(0,0,0,.25);
    }
    dialog::backdrop {
      background: rgba(20, 24, 34, 0.55);
      backdrop-filter: blur(3px);
    }
    .modal-content {
      background: var(--surface);
      padding: 22px;
    }
    .modal-header {
      display: flex;
      justify-content: space-between;
      gap: 12px;
      align-items: start;
      margin-bottom: 18px;
     }
     }
    dialog::backdrop { background: rgba(15,23,42,.55); }
 
     .modal {
     .modal-header h2 {
       padding: 20px;
       margin: 0;
       background: white;
       font-size: 1.4rem;
      line-height: 1.2;
     }
     }
     .modal h2 { margin: 0 0 12px; font-size: 1.35rem; }
 
     .meta {
     .modal-close {
      width: 42px;
      height: 42px;
      border-radius: 999px;
      border: 1px solid var(--border);
      background: var(--surface-2);
      font-size: 1.2rem;
      cursor: pointer;
      flex: 0 0 auto;
    }
 
     .detail-grid {
       display: grid;
       display: grid;
      grid-template-columns: 140px 1fr;
      gap: 12px 14px;
      margin-bottom: 22px;
    }
    .detail-label {
      font-weight: 700;
      color: var(--muted);
    }
    .detail-value {
      min-width: 0;
    }
    .modal-actions {
      display: flex;
      justify-content: flex-end;
       gap: 10px;
       gap: 10px;
       margin: 14px 0 18px;
       flex-wrap: wrap;
     }
     }
    .row { display: grid; grid-template-columns: 140px 1fr; gap: 10px; }
 
    .label { color: var(--muted); font-weight: 600; }
    .actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
     .btn {
     .btn {
       border: 1px solid var(--border);
       display: inline-flex;
       background: #fff;
      align-items: center;
       padding: 10px 14px;
      justify-content: center;
       min-height: 44px;
       padding: 10px 16px;
       border-radius: 12px;
       border-radius: 12px;
      cursor: pointer;
       text-decoration: none;
       text-decoration: none;
      font-weight: 600;
      border: 1px solid var(--border);
       color: var(--text);
       color: var(--text);
       font-weight: 600;
       background: var(--surface);
    }
 
    .btn-primary {
      background: var(--primary);
      color: #fff;
      border-color: var(--primary);
     }
     }
    .btn.primary { background: var(--accent); border-color: var(--accent); color: white; }


     @media (max-width: 900px) {
     .muted-empty {
       .calendar { gap: 8px; }
       color: var(--muted);
       .dow, .day { border-radius: 14px; }
       font-style: italic;
     }
     }
     @media (max-width: 700px) {
 
       .wrap { padding: 14px; }
     @media (max-width: 780px) {
       .calendar {
       .weekday-row { display: none; }
      .calendar-grid { grid-template-columns: 1fr; }
      .day-card.empty { display: none; }
      .day-card {
        min-height: auto;
        padding: 14px;
      }
       .day-top {
        align-items: start;
      }
      .day-number {
        font-size: 1rem;
      }
      .detail-grid {
         grid-template-columns: 1fr;
         grid-template-columns: 1fr;
        gap: 6px 0;
       }
       }
      .dow { display: none; }
      .day { min-height: auto; }
      .day.empty { display: none; }
      .day::before {
        content: attr(data-date);
        font-weight: 700;
        color: var(--muted);
        margin-bottom: 2px;
      }
      .row { grid-template-columns: 1fr; }
      dialog { width: min(95vw, 560px); }
     }
     }
   </style>
   </style>
</head>
</head>
<body>
<body>
   <div class="wrap">
   <section class="calendar-app" aria-labelledby="calendar-heading">
    <h1>August 2026</h1>
    <div class="calendar-head">
    <p class="sub">Im Grid werden nur Uhrzeit und Titel angezeigt. Details öffnen sich per Klick in einem Popup.</p>
      <div class="calendar-title-wrap">
        <h1 id="calendar-heading">Familienangebote im August 2026</h1>
        <p>In der Übersicht erscheinen nur Uhrzeit und Titel. Beim Klick öffnet sich ein Popup mit allen Details, Hinweisen zur Anmeldung und dem Link zu weiteren Informationen.</p>
      </div>
      <div class="badge">August 2026 · mobile optimiert</div>
    </div>


     <div id="calendar" class="calendar" aria-label="Kalender August 2026"></div>
     <div class="weekday-row" aria-hidden="true">
      <div class="weekday">Mo</div>
      <div class="weekday">Di</div>
      <div class="weekday">Mi</div>
      <div class="weekday">Do</div>
      <div class="weekday">Fr</div>
      <div class="weekday">Sa</div>
      <div class="weekday">So</div>
    </div>


     <p class="legend">Beispieleinträge sind direkt im Quelltext als Array gepflegt.</p>
     <div class="calendar-grid" id="calendarGrid"></div>
   </div>
   </section>


   <dialog id="eventDialog">
   <dialog id="eventDialog" aria-labelledby="dialogTitle">
     <div class="modal">
     <div class="modal-content">
      <h2 id="dlgTitle">Event</h2>
       <div class="modal-header">
       <div class="meta">
         <h2 id="dialogTitle"></h2>
         <div class="row"><div class="label">Datum</div><div id="dlgDate"></div></div>
         <button class="modal-close" type="button" id="closeDialog" aria-label="Popup schließen"></button>
         <div class="row"><div class="label">Uhrzeit</div><div id="dlgTime"></div></div>
        <div class="row"><div class="label">Zielgruppe</div><div id="dlgAudience"></div></div>
        <div class="row"><div class="label">Zusatztext</div><div id="dlgNote"></div></div>
        <div class="row"><div class="label">Mehr Infos</div><div><a id="dlgUrl" href="#" target="_blank" rel="noopener noreferrer">Link öffnen</a></div></div>
       </div>
       </div>
       <div class="actions">
 
         <button class="btn" id="closeDialog">Schließen</button>
       <div class="detail-grid">
         <a class="btn primary" id="openUrl" href="#" target="_blank" rel="noopener noreferrer">Mehr Infos öffnen</a>
        <div class="detail-label">Datum</div>
        <div class="detail-value" id="dialogDate"></div>
 
        <div class="detail-label">Uhrzeit</div>
        <div class="detail-value" id="dialogTime"></div>
 
        <div class="detail-label">Ort</div>
        <div class="detail-value" id="dialogLocation"></div>
 
        <div class="detail-label">Zielgruppe</div>
        <div class="detail-value" id="dialogAudience"></div>
 
        <div class="detail-label">Anmeldung</div>
        <div class="detail-value" id="dialogRegistration"></div>
 
        <div class="detail-label">Zusatztext</div>
        <div class="detail-value" id="dialogDescription"></div>
      </div>
 
      <div class="modal-actions">
         <button class="btn" type="button" id="dialogCloseBottom">Schließen</button>
         <a class="btn btn-primary" id="dialogLink" href="#" target="_blank" rel="noopener noreferrer">Mehr Infos</a>
       </div>
       </div>
     </div>
     </div>
Zeile 162: Zeile 343:
     const events = [
     const events = [
       {
       {
         date: '2026-08-05',
         date: "2026-08-01",
         title: 'Workshop: HTML Basics',
         title: "Bächlewanderung mit Kind und Kescher",
         time: '10:00',
         time: "10:00 - 13:00",
         zielgruppe: 'Einsteiger',
        location: "Start und Treffpunkt ist am Parkplatz Bebenhausen.",
         zusatztext: 'Kurzer Praxis-Workshop mit Beispielseiten und Q&A.',
        audience: "Geeignet für Familien mit Kindern ab 5 Jahren",
         url: 'https://example.com/html-basics'
        registration: "wird benötigt",
        url: "https://www.fbs-tuebingen.de/eltern-und-kinder/kw/bereich/kursdetails/kurs/261-2516B/kursname/Baechlewanderung%20mit%20Kind%20und%20Kescher/kategorie-id/11/",
         description: "Wir wandern am Goldersbach entlang über die Tellerbrücke zur Teufelsbrücke."
      },
      {
         date: "2026-08-02",
        title: "Eiscafé frieDa",
        time: "14:00 - 17:00",
        location: "Café frieDa, Friedrich-Dannenmann-Straße 69, 72070 Tübingen",
        audience: "Familien, Nachbarn, Menschen mit und ohne Behinderung",
        registration: "Keine Angabe",
         url: "https://www.lebenshilfe-tuebingen.de/service/termine/",
        description: "Das Eiscafé frieDa ist ein Begegnungs-Ort."
       },
       },
       {
       {
         date: '2026-08-14',
         date: "2026-08-02",
         title: 'Team Meeting',
         title: "Geschwisterchen auf dem Weg",
         time: '14:30',
         time: "10:00 - 12:00",
         zielgruppe: 'Internes Team',
        location: "FBS, Raum 003 Villa Metz, Hechingerstraße 13",
         zusatztext: 'Monatliches Update zu laufenden Projekten und nächsten Schritten.',
         audience: "Für Kinder ab 4 Jahren mit einem Elternteil",
         url: 'https://example.com/team-meeting'
         registration: "wird benötigt",
         url: "https://www.fbs-tuebingen.de/programm/kw/bereich/kursdetails/kurs/261-2509/kursname/Geschwisterchen%20auf%20dem%20Weg/",
        description: "Vorbereitung auf ein Geschwisterchen."
       },
       },
       {
       {
         date: '2026-08-23',
         date: "2026-08-04",
         title: 'Netzwerkabend',
        title: "BabyBrunch",
         time: '18:00',
        time: "09:30 - 11:30",
         zielgruppe: 'Öffentlich',
        location: "elkiko Familienzentrum",
         zusatztext: 'Lockeres Treffen zum Kennenlernen und Austauschen.',
        audience: "Eltern mit Säuglingen und Kleinkindern",
         url: 'https://example.com/netzwerkabend'
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-05",
        title: "Spielplatztreff",
        time: "14:30 - 15:30",
        location: "Piratenspielplatz, Anlagenpark",
        audience: "Familien mit jüngeren Kindern",
        registration: "Keine Anmeldung erforderlich",
        url: "",
        description: "Treffpunkt zum Austausch mit der Familienbeauftragten."
      },
      {
        date: "2026-08-06",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-06",
        title: "Sommerferien mit dem LESE-HAUS",
        time: "11:00",
        location: "Alter Botanischer Garten, Wiese neben dem Kinderspielplatz; bei schlechtem Wetter: Thekla-Waitz-Studio, im EG der Stadtbücherei, Nonnengasse 19, 72070 Tübingen",
        audience: "Kinder von 4 bis 8 Jahre mit Begleitpersonen",
        registration: "Keine Angabe",
        url: "https://tuebingen.ferienprogramm-online.de/",
        description: "Vorlesestunde zum Thema „Unsere Welt ist bunt“ mit Geschichten von Lesepatinnen und Lesepaten des LESE-HAUSes sowie Mitarbeitenden der Stadtbücherei. Bei schönem Wetter findet die Veranstaltung im Alten Botanischen Garten statt, bei schlechtem Wetter im Thekla-Waitz-Studio."
      },
      {
        date: "2026-08-09",
        title: "Eiscafé frieDa",
        time: "14:00 - 17:00",
        location: "Café frieDa, Friedrich-Dannenmann-Straße 69, 72070 Tübingen",
        audience: "Familien, Nachbarn, Menschen mit und ohne Behinderung",
        registration: "Keine Angabe",
        url: "https://www.lebenshilfe-tuebingen.de/service/termine/",
        description: "Das Eiscafé frieDa ist ein Begegnungs-Ort."
      },
      {
        date: "2026-08-11",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-12",
        title: "Spielplatztreff",
        time: "14:30 - 15:30",
        location: "Ort bitte ergänzen",
        audience: "Zielgruppe bitte ergänzen",
        registration: "Keine Angabe",
        url: "",
        description: ""
      },
      {
        date: "2026-08-13",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-13",
        title: "Sommerferien mit dem LESE-HAUS",
        time: "11:00",
        location: "Alter Botanischer Garten, Wiese neben dem Kinderspielplatz; bei schlechtem Wetter: Thekla-Waitz-Studio, im EG der Stadtbücherei, Nonnengasse 19, 72070 Tübingen",
        audience: "Kinder von 4 bis 8 Jahre mit Begleitpersonen",
        registration: "Keine Angabe",
        url: "https://tuebingen.ferienprogramm-online.de/",
        description: "Vorlesestunde zum Thema „Unsere Welt ist bunt“ mit Geschichten von Lesepatinnen und Lesepaten des LESE-HAUSes sowie Mitarbeitenden der Stadtbücherei. Bei schönem Wetter findet die Veranstaltung im Alten Botanischen Garten statt, bei schlechtem Wetter im Thekla-Waitz-Studio."
      },
      {
        date: "2026-08-16",
        title: "Eiscafé frieDa",
        time: "14:00 - 17:00",
        location: "Café frieDa, Friedrich-Dannenmann-Straße 69, 72070 Tübingen",
        audience: "Familien, Nachbarn, Menschen mit und ohne Behinderung",
        registration: "Keine Angabe",
        url: "https://www.lebenshilfe-tuebingen.de/service/termine/",
        description: "Das Eiscafé frieDa ist ein Begegnungs-Ort."
      },
      {
        date: "2026-08-16",
        title: "Bunt backen mit Kindern: Regenbogen-Muffins & Cake-Pops",
        time: "16:00 - 18:30",
        location: "Ort bitte ergänzen",
        audience: "Zielgruppe bitte ergänzen",
        registration: "Keine Angabe",
        url: "",
        description: ""
      },
      {
        date: "2026-08-18",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-19",
        title: "Spielplatztreff",
        time: "14:30 - 15:30",
        location: "Ort bitte ergänzen",
        audience: "Zielgruppe bitte ergänzen",
        registration: "Keine Angabe",
        url: "",
        description: ""
      },
      {
        date: "2026-08-20",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-20",
        title: "Sommerferien mit dem LESE-HAUS",
        time: "11:00",
        location: "Alter Botanischer Garten, Wiese neben dem Kinderspielplatz; bei schlechtem Wetter: Thekla-Waitz-Studio, im EG der Stadtbücherei, Nonnengasse 19, 72070 Tübingen",
        audience: "Kinder von 4 bis 8 Jahre mit Begleitpersonen",
        registration: "Keine Angabe",
        url: "https://tuebingen.ferienprogramm-online.de/",
        description: "Vorlesestunde zum Thema „Unsere Welt ist bunt“ mit Geschichten von Lesepatinnen und Lesepaten des LESE-HAUSes sowie Mitarbeitenden der Stadtbücherei. Bei schönem Wetter findet die Veranstaltung im Alten Botanischen Garten statt, bei schlechtem Wetter im Thekla-Waitz-Studio."
      },
      {
        date: "2026-08-23",
         title: "Eiscafé frieDa",
         time: "14:00 - 17:00",
        location: "Café frieDa, Friedrich-Dannenmann-Straße 69, 72070 Tübingen",
        audience: "Familien, Nachbarn, Menschen mit und ohne Behinderung",
        registration: "Keine Angabe",
        url: "https://www.lebenshilfe-tuebingen.de/service/termine/",
        description: "Das Eiscafé frieDa ist ein Begegnungs-Ort."
      },
      {
        date: "2026-08-25",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-26",
        title: "Spielplatztreff",
        time: "14:30 - 15:30",
        location: "Ort bitte ergänzen",
        audience: "Zielgruppe bitte ergänzen",
        registration: "Keine Angabe",
        url: "",
        description: ""
      },
      {
        date: "2026-08-27",
        title: "BabyBrunch",
        time: "09:30 - 11:30",
        location: "elkiko Familienzentrum",
        audience: "Eltern mit Säuglingen und Kleinkindern",
        registration: "babybrunch@elkiko.de",
        url: "https://www.elkiko.de/content2/index.php/de/programm/babybrunch-brunch1plus.html",
        description: ""
      },
      {
        date: "2026-08-27",
        title: "Sommerferien mit dem LESE-HAUS",
        time: "11:00",
        location: "Alter Botanischer Garten, Wiese neben dem Kinderspielplatz; bei schlechtem Wetter: Thekla-Waitz-Studio, im EG der Stadtbücherei, Nonnengasse 19, 72070 Tübingen",
         audience: "Kinder von 4 bis 8 Jahre mit Begleitpersonen",
         registration: "Keine Angabe",
        url: "https://tuebingen.ferienprogramm-online.de/",
        description: "Vorlesestunde zum Thema „Unsere Welt ist bunt“ mit Geschichten von Lesepatinnen und Lesepaten des LESE-HAUSes sowie Mitarbeitenden der Stadtbücherei. Bei schönem Wetter findet die Veranstaltung im Alten Botanischen Garten statt, bei schlechtem Wetter im Thekla-Waitz-Studio."
      },
      {
        date: "2026-08-30",
        title: "Eiscafé frieDa",
        time: "14:00 - 17:00",
        location: "Café frieDa, Friedrich-Dannenmann-Straße 69, 72070 Tübingen",
        audience: "Familien, Nachbarn, Menschen mit und ohne Behinderung",
        registration: "Keine Angabe",
         url: "https://www.lebenshilfe-tuebingen.de/service/termine/",
        description: "Das Eiscafé frieDa ist ein Begegnungs-Ort."
       }
       }
     ];
     ];


     const calendar = document.getElementById('calendar');
     const weekdayLabels = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
     const dialog = document.getElementById('eventDialog');
    const monthName = "August";
     const byDate = events.reduce((acc, e) => ((acc[e.date] ??= []).push(e), acc), {});
    const year = 2026;
    const year = 2026, month = 7;
    const monthIndex = 7;
    const start = new Date(year, month, 1);
    const calendarGrid = document.getElementById("calendarGrid");
    const end = new Date(year, month + 1, 0);
     const dialog = document.getElementById("eventDialog");
    const daysInMonth = end.getDate();
 
    const startDow = (start.getDay() + 6) % 7;
     const grouped = events.reduce((acc, item) => {
     const weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
      const day = Number(item.date.split("-")[2]);
      if (!acc[day]) acc[day] = [];
      acc[day].push(item);
      return acc;
     }, {});


     weekdays.forEach(d => {
     const firstDay = new Date(year, monthIndex, 1);
      const el = document.createElement('div');
    const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
      el.className = 'dow';
    const offset = (firstDay.getDay() + 6) % 7;
      el.textContent = d;
      calendar.appendChild(el);
    });


     for (let i = 0; i < startDow; i++) {
     for (let i = 0; i < offset; i++) {
       const empty = document.createElement('div');
       const empty = document.createElement("div");
       empty.className = 'day empty';
       empty.className = "day-card empty";
       calendar.appendChild(empty);
       empty.setAttribute("aria-hidden", "true");
      calendarGrid.appendChild(empty);
     }
     }


     function openEvent(event) {
     for (let day = 1; day <= daysInMonth; day++) {
       document.getElementById('dlgTitle').textContent = event.title;
       const card = document.createElement("article");
       document.getElementById('dlgDate').textContent = new Date(event.date).toLocaleDateString('de-DE', { year: 'numeric', month: 'long', day: 'numeric' });
      card.className = "day-card";
       document.getElementById('dlgTime').textContent = event.time;
 
       document.getElementById('dlgAudience').textContent = event.zielgruppe;
      const items = grouped[day] || [];
       document.getElementById('dlgNote').textContent = event.zusatztext;
      const weekday = weekdayLabels[(offset + day - 1) % 7];
      document.getElementById('dlgUrl').href = event.url;
       const top = document.createElement("div");
      document.getElementById('openUrl').href = event.url;
      top.className = "day-top";
       dialog.showModal();
      top.innerHTML = `
        <div class="day-number">${weekday}, ${day}. ${monthName}</div>
        ${items.length ? `<div class="event-count">${items.length} Termin${items.length > 1 ? 'e' : ''}</div>` : ''}
      `;
      card.appendChild(top);
 
       const list = document.createElement("div");
      list.className = "events-list";
 
       if (!items.length) {
        const emptyText = document.createElement("div");
        emptyText.className = "muted-empty";
        emptyText.textContent = "Keine Einträge";
        list.appendChild(emptyText);
       } else {
        items.forEach(item => {
          const btn = document.createElement("button");
          btn.className = "event-chip";
          btn.type = "button";
          btn.innerHTML = `<span class="event-time">${item.time || 'Uhrzeit offen'}</span><span class="event-title">${item.title}</span>`;
          btn.addEventListener("click", () => openDialog(item));
          list.appendChild(btn);
        });
      }
 
      card.appendChild(list);
       calendarGrid.appendChild(card);
     }
     }


     for (let day = 1; day <= daysInMonth; day++) {
     const fields = {
       const dateStr = `2026-08-${String(day).padStart(2, '0')}`;
       title: document.getElementById("dialogTitle"),
       const cell = document.createElement('div');
      date: document.getElementById("dialogDate"),
       cell.className = 'day';
      time: document.getElementById("dialogTime"),
       cell.dataset.date = `${String(day).padStart(2, '0')}.08.2026`;
       location: document.getElementById("dialogLocation"),
       cell.innerHTML = `<div class="day-num">${day}</div>`;
       audience: document.getElementById("dialogAudience"),
       registration: document.getElementById("dialogRegistration"),
      description: document.getElementById("dialogDescription"),
       link: document.getElementById("dialogLink")
    };


      (byDate[dateStr] || []).forEach(event => {
    function formatDate(dateString) {
        const btn = document.createElement('button');
      return new Date(dateString + "T00:00:00").toLocaleDateString("de-DE", {
        btn.className = 'event';
         weekday: "long",
         btn.type = 'button';
         day: "numeric",
         btn.innerHTML = `<span class="time">${event.time}</span><span class="title">${event.title}</span>`;
        month: "long",
        btn.addEventListener('click', () => openEvent(event));
         year: "numeric"
         cell.appendChild(btn);
       });
       });
    }
    function fillValue(el, value, fallback = "Keine Angabe") {
      el.textContent = value && String(value).trim() ? value : fallback;
      el.classList.toggle("muted-empty", !(value && String(value).trim()));
    }
    function openDialog(item) {
      fields.title.textContent = item.title;
      fillValue(fields.date, formatDate(item.date));
      fillValue(fields.time, item.time, "Uhrzeit offen");
      fillValue(fields.location, item.location);
      fillValue(fields.audience, item.audience);
      fillValue(fields.registration, item.registration);
      fillValue(fields.description, item.description);
      if (item.url && item.url.trim()) {
        fields.link.href = item.url;
        fields.link.style.display = "inline-flex";
      } else {
        fields.link.removeAttribute("href");
        fields.link.style.display = "none";
      }


       calendar.appendChild(cell);
       dialog.showModal();
     }
     }


     document.getElementById('closeDialog').addEventListener('click', () => dialog.close());
    function closeDialog() {
     dialog.addEventListener('click', (e) => {
      dialog.close();
    }
 
     document.getElementById("closeDialog").addEventListener("click", closeDialog);
    document.getElementById("dialogCloseBottom").addEventListener("click", closeDialog);
 
     dialog.addEventListener("click", (event) => {
       const rect = dialog.getBoundingClientRect();
       const rect = dialog.getBoundingClientRect();
       const clickedOutside = e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom;
       const clickedOutside = event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom;
       if (clickedOutside) dialog.close();
       if (clickedOutside) dialog.close();
     });
     });

Version vom 10. Juni 2026, 10:12 Uhr

Familienangebote im August 2026

Familienangebote im August 2026

In der Übersicht erscheinen nur Uhrzeit und Titel. Beim Klick öffnet sich ein Popup mit allen Details, Hinweisen zur Anmeldung und dem Link zu weiteren Informationen.

August 2026 · mobile optimiert