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.0" />
   <meta name="viewport" content="width=device-width, initial-scale=1" />
   <title>Kalender - August 2026</title>
   <title>Kalender August 2026</title>
   <style>
   <style>
     *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
     :root {
 
      --bg: #f6f7fb;
      --card: #ffffff;
      --text: #1f2937;
      --muted: #6b7280;
      --accent: #2563eb;
      --accent-2: #dbeafe;
      --border: #e5e7eb;
      --shadow: 0 10px 30px rgba(0,0,0,.08);
    }
    * { box-sizing: border-box; }
     body {
     body {
       font-family: 'Segoe UI', system-ui, sans-serif;
      margin: 0;
      background: #f0f4f8;
       font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
       color: #1a202c;
       color: var(--text);
      min-height: 100vh;
       background: var(--bg);
       padding: 1.5rem 1rem 3rem;
     }
     }
 
     .wrap {
     header { text-align: center; margin-bottom: 1.75rem; }
       max-width: 1200px;
 
       margin: 0 auto;
    header h1 {
       padding: 24px;
       font-size: clamp(1.5rem, 5vw, 2.25rem);
       font-weight: 700;
      letter-spacing: -0.02em;
       color: #1a202c;
     }
     }
 
     h1 { margin: 0 0 8px; font-size: clamp(1.5rem, 3vw, 2.2rem); }
     header p { color: #64748b; font-size: 0.9rem; margin-top: 0.3rem; }
    .sub { margin: 0 0 20px; color: var(--muted); }
 
     .calendar {
     .calendar {
       max-width: 900px;
       display: grid;
       margin: 0 auto;
      grid-template-columns: repeat(7, minmax(0, 1fr));
       background: #fff;
       gap: 10px;
    }
    .dow, .day {
       background: var(--card);
      border: 1px solid var(--border);
       border-radius: 16px;
       border-radius: 16px;
       overflow: hidden;
       overflow: hidden;
       box-shadow: 0 4px 24px rgba(0,0,0,.08);
       min-height: 120px;
     }
     }
 
     .dow {
     .weekdays {
       padding: 12px;
       display: grid;
       font-weight: 700;
       grid-template-columns: repeat(7, 1fr);
      background: #1e3a5f;
      color: #fff;
    }
 
    .weekdays span {
       text-align: center;
       text-align: center;
       padding: 0.65rem 0;
       color: var(--muted);
      font-size: 0.75rem;
       min-height: auto;
      font-weight: 600;
      letter-spacing: 0.06em;
       text-transform: uppercase;
     }
     }
    .days {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      border-left: 1px solid #e2e8f0;
      border-top: 1px solid #e2e8f0;
    }
     .day {
     .day {
      min-height: 90px;
       padding: 10px;
       padding: 0.45rem;
      border-right: 1px solid #e2e8f0;
      border-bottom: 1px solid #e2e8f0;
      background: #fff;
       display: flex;
       display: flex;
       flex-direction: column;
       flex-direction: column;
       gap: 0.3rem;
       gap: 8px;
      align-items: stretch;
     }
     }
 
     .day.empty { background: transparent; border: 1px dashed transparent; }
     .day.empty { background: #f8fafc; }
     .day-num { font-weight: 700; color: var(--muted); }
 
    .event {
     .day.today .day-number {
       display: block;
      background: #1e3a5f;
       width: 100%;
      color: #fff;
       text-align: left;
      border-radius: 50%;
       border: 1px solid var(--accent-2);
      width: 26px;
       background: var(--accent-2);
       height: 26px;
       color: #0f172a;
       display: flex;
       border-radius: 12px;
       align-items: center;
       padding: 8px 10px;
       justify-content: center;
    }
 
    .day-number {
      font-size: 0.8rem;
      font-weight: 600;
       color: #475569;
      line-height: 1;
      margin-bottom: 0.1rem;
    }
 
    .event-chip {
      background: #dbeafe;
       border-left: 3px solid #2563eb;
       border-radius: 4px;
       padding: 0.2rem 0.35rem;
      font-size: 0.7rem;
      line-height: 1.3;
       cursor: pointer;
       cursor: pointer;
       transition: background 0.15s, transform 0.1s;
       font: inherit;
       word-break: break-word;
       line-height: 1.25;
     }
     }
    .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; }


     .event-chip:hover { background: #bfdbfe; transform: translateY(-1px); }
     dialog {
 
      border: none;
    .event-chip .chip-time {
      border-radius: 18px;
       font-weight: 700;
       width: min(92vw, 560px);
       color: #1d4ed8;
       box-shadow: var(--shadow);
       display: block;
       padding: 0;
     }
     }
 
    dialog::backdrop { background: rgba(15,23,42,.55); }
     .event-chip .chip-title {
     .modal {
       color: #1e3a5f;
       padding: 20px;
       display: block;
       background: white;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
     }
     }
 
     .modal h2 { margin: 0 0 12px; font-size: 1.35rem; }
     .modal-overlay {
    .meta {
      display: none;
       display: grid;
      position: fixed;
       gap: 10px;
      inset: 0;
       margin: 14px 0 18px;
      background: rgba(15, 23, 42, 0.55);
      z-index: 100;
       align-items: center;
       justify-content: center;
       padding: 1rem;
     }
     }
 
    .row { display: grid; grid-template-columns: 140px 1fr; gap: 10px; }
     .modal-overlay.open { display: flex; }
     .label { color: var(--muted); font-weight: 600; }
 
    .actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
     .modal {
     .btn {
      border: 1px solid var(--border);
       background: #fff;
       background: #fff;
      border-radius: 16px;
       padding: 10px 14px;
      max-width: 480px;
       border-radius: 12px;
      width: 100%;
       padding: 2rem;
      position: relative;
      box-shadow: 0 20px 60px rgba(0,0,0,.2);
      animation: pop .18s ease-out;
    }
 
    @keyframes pop {
      from { opacity: 0; transform: scale(.94); }
      to  { opacity: 1; transform: scale(1); }
    }
 
    .modal-close {
      position: absolute;
      top: 1rem;
      right: 1rem;
      background: #f1f5f9;
      border: none;
       border-radius: 50%;
      width: 32px;
      height: 32px;
       cursor: pointer;
       cursor: pointer;
       font-size: 1rem;
       text-decoration: none;
      display: flex;
       color: var(--text);
      align-items: center;
      justify-content: center;
       color: #64748b;
      transition: background .15s;
    }
 
    .modal-close:hover { background: #e2e8f0; }
 
    .modal-date {
      font-size: 0.8rem;
       font-weight: 600;
       font-weight: 600;
      letter-spacing: 0.05em;
      text-transform: uppercase;
      color: #2563eb;
      margin-bottom: 0.4rem;
     }
     }
    .btn.primary { background: var(--accent); border-color: var(--accent); color: white; }


     .modal-title {
     @media (max-width: 900px) {
       font-size: 1.3rem;
       .calendar { gap: 8px; }
      font-weight: 700;
       .dow, .day { border-radius: 14px; }
       color: #1a202c;
      margin-bottom: 0.6rem;
      line-height: 1.3;
     }
     }
 
     @media (max-width: 700px) {
     .modal-time {
       .wrap { padding: 14px; }
       display: inline-flex;
       .calendar {
      align-items: center;
        grid-template-columns: 1fr;
      gap: 0.4rem;
       }
      background: #f0f9ff;
      .dow { display: none; }
       color: #0369a1;
       .day { min-height: auto; }
      border-radius: 6px;
       .day.empty { display: none; }
      padding: 0.3rem 0.7rem;
       .day::before {
      font-size: 0.85rem;
        content: attr(data-date);
      font-weight: 600;
        font-weight: 700;
       margin-bottom: 1rem;
        color: var(--muted);
    }
        margin-bottom: 2px;
 
       }
    .modal-note {
       .row { grid-template-columns: 1fr; }
      font-size: 0.9rem;
       dialog { width: min(95vw, 560px); }
       color: #475569;
      line-height: 1.6;
       margin-bottom: 1.2rem;
    }
 
    .modal-link {
      display: inline-flex;
      align-items: center;
       gap: 0.4rem;
      background: #1e3a5f;
      color: #fff;
      text-decoration: none;
      border-radius: 8px;
      padding: 0.55rem 1.1rem;
      font-size: 0.85rem;
      font-weight: 600;
      transition: background .15s;
    }
 
    .modal-link:hover { background: #2563eb; }
 
    @media (max-width: 600px) {
      .weekdays span { font-size: 0.62rem; }
       .day { min-height: 60px; padding: 0.3rem; }
       .event-chip { font-size: 0.62rem; padding: 0.15rem 0.25rem; }
       .event-chip .chip-title { display: none; }
     }
     }
   </style>
   </style>
</head>
</head>
<body>
<body>
  <div class="wrap">
    <h1>August 2026</h1>
    <p class="sub">Im Grid werden nur Uhrzeit und Titel angezeigt. Details öffnen sich per Klick in einem Popup.</p>


<header>
    <div id="calendar" class="calendar" aria-label="Kalender August 2026"></div>
  <h1>August 2026</h1>
  <p>Klick auf einen Termin fur mehr Details</p>
</header>


<div class="calendar">
    <p class="legend">Beispieleinträge sind direkt im Quelltext als Array gepflegt.</p>
  <div class="weekdays">
    <span>Mo</span><span>Di</span><span>Mi</span><span>Do</span><span>Fr</span><span>Sa</span><span>So</span>
   </div>
   </div>
  <div class="days" id="calGrid"></div>
</div>


<div class="modal-overlay" id="modalOverlay" role="dialog" aria-modal="true">
  <dialog id="eventDialog">
  <div class="modal">
    <div class="modal">
    <button class="modal-close" id="modalClose" aria-label="Schliessen"></button>
      <h2 id="dlgTitle">Event</h2>
    <div class="modal-date" id="mDate"></div>
      <div class="meta">
    <div class="modal-title" id="mTitle"></div>
        <div class="row"><div class="label">Datum</div><div id="dlgDate"></div></div>
    <div class="modal-time">🕐 <span id="mTimeText"></span></div>
        <div class="row"><div class="label">Uhrzeit</div><div id="dlgTime"></div></div>
    <div class="modal-note" id="mNote"></div>
        <div class="row"><div class="label">Zielgruppe</div><div id="dlgAudience"></div></div>
    <a class="modal-link" id="mLink" href="#" target="_blank" rel="noopener">
        <div class="row"><div class="label">Zusatztext</div><div id="dlgNote"></div></div>
      🔗 Mehr Infos
        <div class="row"><div class="label">Mehr Infos</div><div><a id="dlgUrl" href="#" target="_blank" rel="noopener noreferrer">Link öffnen</a></div></div>
    </a>
      </div>
  </div>
      <div class="actions">
</div>
        <button class="btn" id="closeDialog">Schließen</button>
        <a class="btn primary" id="openUrl" href="#" target="_blank" rel="noopener noreferrer">Mehr Infos öffnen</a>
      </div>
    </div>
  </dialog>


<script>
  <script>
  // ==================================================
    const events = [
  // TERMINE - hier pflegen
      {
  // ==================================================
        date: '2026-08-05',
  var events = [
        title: 'Workshop: HTML Basics',
    {
        time: '10:00',
      datum: "2026-08-05",
        zielgruppe: 'Einsteiger',
      titel: "Stadtfest Reutlingen",
        zusatztext: 'Kurzer Praxis-Workshop mit Beispielseiten und Q&A.',
      uhrzeit: "14:00",
        url: 'https://example.com/html-basics'
      zusatztext: "Das jaehrliche Stadtfest in der Innenstadt mit Live-Musik, Essen und Marktstaenden. Parkplaetze sind begrenzt - Anreise mit OPNV empfohlen.",
      },
      url: "https://www.reutlingen.de"
      {
    },
        date: '2026-08-14',
    {
        title: 'Team Meeting',
      datum: "2026-08-12",
        time: '14:30',
      titel: "Team-Meeting Q3",
        zielgruppe: 'Internes Team',
      uhrzeit: "09:30",
        zusatztext: 'Monatliches Update zu laufenden Projekten und nächsten Schritten.',
      zusatztext: "Quartals-Review mit allen Abteilungen. Bitte Berichte bis 08.08. einreichen. Video-Call-Link wird separat verschickt.",
        url: 'https://example.com/team-meeting'
      url: "https://meet.example.com/q3-review"
      },
    },
      {
    {
        date: '2026-08-23',
      datum: "2026-08-22",
        title: 'Netzwerkabend',
      titel: "Open-Air Kino",
        time: '18:00',
      uhrzeit: "21:00",
        zielgruppe: 'Öffentlich',
      zusatztext: "Filmabend im Stadtpark - gezeigt wird Cinema Paradiso (1988). Einlass ab 20:00 Uhr, Decke und Sitzkissen empfohlen. Eintritt frei.",
        zusatztext: 'Lockeres Treffen zum Kennenlernen und Austauschen.',
      url: "https://www.openair-kino-beispiel.de"
        url: 'https://example.com/netzwerkabend'
    }
      }
  ];
    ];
  // ==================================================


  var byDate = {};
    const calendar = document.getElementById('calendar');
  events.forEach(function(e) {
    const dialog = document.getElementById('eventDialog');
     if (!byDate[e.datum]) byDate[e.datum] = [];
     const byDate = events.reduce((acc, e) => ((acc[e.date] ??= []).push(e), acc), {});
     byDate[e.datum].push(e);
     const year = 2026, month = 7;
  });
    const start = new Date(year, month, 1);
    const end = new Date(year, month + 1, 0);
    const daysInMonth = end.getDate();
    const startDow = (start.getDay() + 6) % 7;
    const weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];


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


  for (var i = 0; i < offset; i++) {
    for (let i = 0; i < startDow; i++) {
    var empty = document.createElement('div');
      const empty = document.createElement('div');
    empty.className = 'day empty';
      empty.className = 'day empty';
    grid.appendChild(empty);
      calendar.appendChild(empty);
  }
    }


  for (var d = 1; d <= daysInMonth; d++) {
    function openEvent(event) {
    var cell = document.createElement('div');
      document.getElementById('dlgTitle').textContent = event.title;
    cell.className = 'day';
      document.getElementById('dlgDate').textContent = new Date(event.date).toLocaleDateString('de-DE', { year: 'numeric', month: 'long', day: 'numeric' });
      document.getElementById('dlgTime').textContent = event.time;
      document.getElementById('dlgAudience').textContent = event.zielgruppe;
      document.getElementById('dlgNote').textContent = event.zusatztext;
      document.getElementById('dlgUrl').href = event.url;
      document.getElementById('openUrl').href = event.url;
      dialog.showModal();
    }


     var isToday = today.getFullYear() === year
     for (let day = 1; day <= daysInMonth; day++) {
       && today.getMonth() === month
       const dateStr = `2026-08-${String(day).padStart(2, '0')}`;
       && today.getDate() === d;
       const cell = document.createElement('div');
    if (isToday) cell.classList.add('today');
      cell.className = 'day';
      cell.dataset.date = `${String(day).padStart(2, '0')}.08.2026`;
      cell.innerHTML = `<div class="day-num">${day}</div>`;


    var num = document.createElement('div');
      (byDate[dateStr] || []).forEach(event => {
    num.className = 'day-number';
         const btn = document.createElement('button');
    num.textContent = d;
         btn.className = 'event';
    cell.appendChild(num);
         btn.type = 'button';
 
         btn.innerHTML = `<span class="time">${event.time}</span><span class="title">${event.title}</span>`;
    var mm = String(month + 1).padStart(2, '0');
         btn.addEventListener('click', () => openEvent(event));
    var dd = String(d).padStart(2, '0');
         cell.appendChild(btn);
    var dateKey = year + '-' + mm + '-' + dd;
 
    if (byDate[dateKey]) {
      byDate[dateKey].forEach(function(ev) {
         var chip = document.createElement('div');
         chip.className = 'event-chip';
 
        var timeSpan = document.createElement('span');
         timeSpan.className = 'chip-time';
         timeSpan.textContent = ev.uhrzeit;
 
        var titleSpan = document.createElement('span');
        titleSpan.className = 'chip-title';
        titleSpan.textContent = ev.titel;
 
        chip.appendChild(timeSpan);
        chip.appendChild(titleSpan);
 
         chip.addEventListener('click', (function(evData) {
          return function() { openModal(evData); };
        })(ev));
 
         cell.appendChild(chip);
       });
       });
    }


    grid.appendChild(cell);
      calendar.appendChild(cell);
  }
 
  var overlay  = document.getElementById('modalOverlay');
  var btnClose = document.getElementById('modalClose');
 
  function openModal(ev) {
    var d = new Date(ev.datum + 'T00:00:00');
    document.getElementById('mDate').textContent =
      d.toLocaleDateString('de-DE', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
    document.getElementById('mTitle').textContent  = ev.titel;
    document.getElementById('mTimeText').textContent = ev.uhrzeit + ' Uhr';
    document.getElementById('mNote').textContent    = ev.zusatztext;
    var link = document.getElementById('mLink');
    if (ev.url) {
      link.href = ev.url;
      link.style.display = 'inline-flex';
    } else {
      link.style.display = 'none';
     }
     }
    overlay.classList.add('open');
  }
  function closeModal() { overlay.classList.remove('open'); }


  btnClose.addEventListener('click', closeModal);
    document.getElementById('closeDialog').addEventListener('click', () => dialog.close());
  overlay.addEventListener('click', function(e) { if (e.target === overlay) closeModal(); });
    dialog.addEventListener('click', (e) => {
  document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeModal(); });
      const rect = dialog.getBoundingClientRect();
</script>
      const clickedOutside = e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom;
      if (clickedOutside) dialog.close();
    });
  </script>
</body>
</body>
</html>
</html>

Version vom 10. Juni 2026, 10:02 Uhr

<!doctype html> Kalender August 2026

August 2026

Im Grid werden nur Uhrzeit und Titel angezeigt. Details öffnen sich per Klick in einem Popup.

Beispieleinträge sind direkt im Quelltext als Array gepflegt.