Fix/content page heading #36
No files matched your search
@@ -91,52 +91,22 @@ public sealed class PocketBaseClient(HttpClient httpClient)
|
|||||||
=> GetRecordsAsync<Faq>("faqs", "topic.order,order", token, expand: "topic");
|
=> GetRecordsAsync<Faq>("faqs", "topic.order,order", token, expand: "topic");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all public FAQ topics, ordered by <see cref="FaqTopic.Order"/>.
|
/// Gets all public FAQ topics, ordered by <see cref="FaqTopic.Order"/>, each with
|
||||||
|
/// its questions expanded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Backs the FAQ overview, which lists the topics as links to their own pages.
|
/// Backs the FAQ page, which shows every topic as a collapsible group with its
|
||||||
/// The questions are not loaded here; the topic page loads them per topic via
|
/// questions nested inside. The <c>faqs_via_topic</c> back-relation is expanded so
|
||||||
/// <see cref="GetFaqTopicBySlugAsync"/>.
|
/// one request returns the topics and their questions together; drafts among the
|
||||||
|
/// questions are dropped in <see cref="FaqTopic.Faqs"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <inheritdoc cref="GetPagesAsync" path="/param"/>
|
/// <inheritdoc cref="GetPagesAsync" path="/param"/>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// The public FAQ topics, or an empty list if there are none.
|
/// The public FAQ topics with their questions, or an empty list if there are none.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <inheritdoc cref="GetPagesAsync" path="/exception"/>
|
/// <inheritdoc cref="GetPagesAsync" path="/exception"/>
|
||||||
public Task<IReadOnlyList<FaqTopic>> GetFaqTopicsAsync(CancellationToken token = default)
|
public Task<IReadOnlyList<FaqTopic>> GetFaqTopicsAsync(CancellationToken token = default)
|
||||||
=> GetRecordsAsync<FaqTopic>("faq_topics", "order", token);
|
=> GetRecordsAsync<FaqTopic>("faq_topics", "order", token, expand: "faqs_via_topic");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets one public FAQ topic by its slug, with its questions expanded, or
|
|
||||||
/// <see langword="null"/> when no public topic has that slug.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Backs the topic's own page at <c>/faqs/{slug}</c>: it loads the single topic
|
|
||||||
/// and, through the <c>faqs_via_topic</c> back-relation, the questions grouped
|
|
||||||
/// under it, so the page needs one request. The slug is unique, so at most one
|
|
||||||
/// record matches.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="slug">
|
|
||||||
/// The topic slug from the URL, e.g. <c>"cafeteria"</c>.
|
|
||||||
/// </param>
|
|
||||||
/// <inheritdoc cref="GetPagesAsync" path="/param[@name='token']"/>
|
|
||||||
/// <returns>
|
|
||||||
/// The matching public topic with its questions, or <see langword="null"/> if
|
|
||||||
/// none matches.
|
|
||||||
/// </returns>
|
|
||||||
/// <inheritdoc cref="GetPagesAsync" path="/exception"/>
|
|
||||||
public async Task<FaqTopic?> GetFaqTopicBySlugAsync(
|
|
||||||
string slug,
|
|
||||||
CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var topics = await GetRecordsAsync<FaqTopic>(
|
|
||||||
"faq_topics",
|
|
||||||
"order",
|
|
||||||
token,
|
|
||||||
expand: "faqs_via_topic");
|
|
||||||
return topics.FirstOrDefault(
|
|
||||||
topic => string.Equals(topic.Slug, slug, StringComparison.OrdinalIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all public records of a collection in a single request.
|
/// Gets all public records of a collection in a single request.
|
||||||
|
|||||||
@@ -85,19 +85,19 @@ public sealed class RouteSmokeTests : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Faqs_route_renders_the_topic_list()
|
public async Task Faqs_route_renders_the_topic_accordion()
|
||||||
{
|
{
|
||||||
// /faqs is a literal route (FaqList) that must win over the /{Slug}
|
// /faqs is a literal route (FaqList) that must win over the /{Slug}
|
||||||
// catch-all content page. It reads the "faqs" page for heading and intro
|
// catch-all content page. It reads the "faqs" page for heading and intro
|
||||||
// and lists the topics as cards linking to their own pages. The individual
|
// and renders each topic as a collapsible group with its questions nested
|
||||||
// questions live on the topic pages (/faqs/{slug}), not here.
|
// inside, so both the topic headings and the questions are in the markup.
|
||||||
var client = _factory.CreateClient();
|
var client = _factory.CreateClient();
|
||||||
|
|
||||||
var html = await client.GetStringAsync(new Uri("/faqs", UriKind.Relative));
|
var html = await client.GetStringAsync(new Uri("/faqs", UriKind.Relative));
|
||||||
|
|
||||||
html.ShouldContain("FAQs"); // heading from the page title
|
html.ShouldContain("FAQs"); // heading from the page title
|
||||||
html.ShouldContain("Mensa und Mittagessen"); // German topic heading (a card)
|
html.ShouldContain("Mensa und Mittagessen"); // German topic heading (a group)
|
||||||
html.ShouldContain("href=\"/faqs/cafeteria\""); // card links to the topic page
|
html.ShouldContain("Wann gibt es Mittagessen?"); // a question nested in the group
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -25,16 +25,23 @@ else if (_topics.Count == 0)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ul class="faq-topic-list">
|
@foreach (var topic in _topics)
|
||||||
@foreach (var topic in _topics)
|
{
|
||||||
{
|
<details class="faq-topic">
|
||||||
<li>
|
<summary>@topic.Title</summary>
|
||||||
<h2><a href="@($"/faqs/{topic.Slug}")">@topic.Title</a></h2>
|
@if (!string.IsNullOrWhiteSpace(topic.Intro))
|
||||||
@if (!string.IsNullOrWhiteSpace(topic.Intro))
|
{
|
||||||
{
|
<div class="faq-topic-intro">@((MarkupString)Markdown.ToHtml(topic.Intro))</div>
|
||||||
<div class="faq-topic-intro">@((MarkupString)Markdown.ToHtml(topic.Intro))</div>
|
}
|
||||||
}
|
@foreach (var faq in topic.Faqs)
|
||||||
</li>
|
{
|
||||||
}
|
<details class="faq-item">
|
||||||
</ul>
|
<summary>@faq.Question</summary>
|
||||||
|
<div class="faq-answer">
|
||||||
|
@((MarkupString)Markdown.ToHtml(faq.Answer))
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
}
|
||||||
|
</details>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
@page "/faqs/{Slug}"
|
|
||||||
|
|
||||||
@if (_unavailable)
|
|
||||||
{
|
|
||||||
<PageTitle>Vorübergehend nicht erreichbar</PageTitle>
|
|
||||||
<p>Das Thema ist gerade nicht erreichbar. Bitte später erneut versuchen.</p>
|
|
||||||
}
|
|
||||||
else if (_topic is not null)
|
|
||||||
{
|
|
||||||
<PageTitle>@_topic.Title</PageTitle>
|
|
||||||
<nav>
|
|
||||||
<a href="/faqs">← Alle Themen</a>
|
|
||||||
</nav>
|
|
||||||
<h1>@_topic.Title</h1>
|
|
||||||
@if (!string.IsNullOrWhiteSpace(_topic.Intro))
|
|
||||||
{
|
|
||||||
<div class="faq-topic-intro">@((MarkupString)Markdown.ToHtml(_topic.Intro))</div>
|
|
||||||
}
|
|
||||||
@foreach (var faq in _topic.Faqs)
|
|
||||||
{
|
|
||||||
<details class="faq-item">
|
|
||||||
<summary>@faq.Question</summary>
|
|
||||||
<div class="faq-answer">
|
|
||||||
@((MarkupString)Markdown.ToHtml(faq.Answer))
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@* No topic and not unavailable: the slug was unknown; NavigationManager.NotFound()
|
|
||||||
already ran in OnParametersSetAsync and renders the not-found page. *@
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
using Elternbeirat.Contracts;
|
|
||||||
using Elternbeirat.PocketBase;
|
|
||||||
using Elternbeirat.Web.Shared;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
|
|
||||||
namespace Elternbeirat.Web.Features.Faqs;
|
|
||||||
|
|
||||||
public partial class FaqTopicDetail
|
|
||||||
{
|
|
||||||
[LoggerMessage(
|
|
||||||
Level = LogLevel.Error,
|
|
||||||
Message = "Could not load FAQ topic '{Slug}' from PocketBase; content source is unavailable.")]
|
|
||||||
private static partial void LogSourceUnavailable(
|
|
||||||
ILogger logger,
|
|
||||||
string slug,
|
|
||||||
Exception exception);
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string Slug { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
private PocketBaseClient PocketBase { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
private ILogger<FaqTopicDetail> Logger { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
private NavigationManager Navigation { get; set; } = null!;
|
|
||||||
|
|
||||||
[CascadingParameter]
|
|
||||||
private HttpContext? HttpContext { get; set; }
|
|
||||||
|
|
||||||
private FaqTopic? _topic;
|
|
||||||
|
|
||||||
// Set when the content source could not be reached or read. The markup then
|
|
||||||
// shows a "temporarily unavailable" note instead of a not-found page, matching
|
|
||||||
// the 503 this sets on the response.
|
|
||||||
private bool _unavailable;
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_topic = await PocketBase.GetFaqTopicBySlugAsync(
|
|
||||||
Slug,
|
|
||||||
HttpContext?.RequestAborted ?? CancellationToken.None);
|
|
||||||
}
|
|
||||||
catch (PocketBaseUnavailableException exception)
|
|
||||||
{
|
|
||||||
// The site works, its data store is down: 503, not 404.
|
|
||||||
LogSourceUnavailable(Logger, Slug, exception);
|
|
||||||
_unavailable = true;
|
|
||||||
SourceUnavailable.SetStatus(HttpContext);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_topic is null)
|
|
||||||
{
|
|
||||||
// The source answered, but there is no topic with this slug: a genuine 404.
|
|
||||||
Navigation.NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -206,8 +206,7 @@ h1:focus {
|
|||||||
lifted off the tinted page background with a soft shadow and a gentle hover. */
|
lifted off the tinted page background with a soft shadow and a gentle hover. */
|
||||||
|
|
||||||
.post-list,
|
.post-list,
|
||||||
.event-list,
|
.event-list {
|
||||||
.faq-topic-list {
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -216,8 +215,7 @@ h1:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.post-list li,
|
.post-list li,
|
||||||
.event-list li,
|
.event-list li {
|
||||||
.faq-topic-list li {
|
|
||||||
background: var(--color-bg);
|
background: var(--color-bg);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
@@ -226,21 +224,56 @@ h1:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.post-list li:hover,
|
.post-list li:hover,
|
||||||
.event-list li:hover,
|
.event-list li:hover {
|
||||||
.faq-topic-list li:hover {
|
|
||||||
box-shadow: var(--shadow-hover);
|
box-shadow: var(--shadow-hover);
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FAQ topics: each card is a link to the topic's own page, with an optional intro
|
/* FAQ topics: each is a collapsible card. Its summary is the topic heading; open it
|
||||||
below the heading. The heading matches the post/event card titles. */
|
to reveal the optional intro and the questions (themselves collapsible .faq-item
|
||||||
.faq-topic-list h2 {
|
cards). The topic marker is a rotating triangle, distinct from the +/- on the
|
||||||
margin: 0;
|
questions nested inside, so the two accordion levels read apart. */
|
||||||
font-size: 1.15rem;
|
.faq-topic {
|
||||||
|
background: var(--color-bg);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
transition: box-shadow var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.faq-topic-list h2 a {
|
.faq-topic:hover {
|
||||||
text-decoration: none;
|
box-shadow: var(--shadow-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-topic > summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-brand);
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-topic > summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-topic > summary::before {
|
||||||
|
content: "▸";
|
||||||
|
color: var(--color-accent-dark);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-topic[open] > summary::before {
|
||||||
|
content: "▾";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Space the questions off the topic heading once the topic is open. */
|
||||||
|
.faq-topic[open] > .faq-item:first-of-type {
|
||||||
|
margin-top: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.faq-topic-intro {
|
.faq-topic-intro {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ migrate((app) => {
|
|||||||
const schema = JSON.parse(toString($os.readFile("/pb_migrations/collections_schema.json")))
|
const schema = JSON.parse(toString($os.readFile("/pb_migrations/collections_schema.json")))
|
||||||
|
|
||||||
const records = {
|
const records = {
|
||||||
pages: [{"body":"# Vorstandsteam\n\nDer Elternbeirat der IGMH vertritt die Interessen aller Eltern gegenüber der Schulleitung und dem Kollegium. Wir treffen uns regelmäßig, bringen Anliegen aus der Elternschaft ein und begleiten das Schulleben aktiv.\n\n## Vorstand\n\n- **Vorsitz** — Anke Berger\n- **Stellvertretung** — Murat Yılmaz\n- **Kasse** — Sabine Krause\n- **Schriftführung** — Thomas Heinrich\n\n## So erreichen Sie uns\n\nAm schnellsten per Mail über unsere [Kontaktseite](/contact). Zu unseren öffentlichen Sitzungen sind alle Eltern herzlich eingeladen — die Termine finden Sie unter [Termine](/events).","embed":[],"location":"header","order":2,"public":true,"slug":"board","title":"Vorstandsteam"},{"body":"# Förderverein\n\nDer Förderverein der IGMH unterstützt Projekte, für die im regulären Schulhaushalt kein Geld vorgesehen ist: von der Ausstattung der Bibliothek über Pausenspielgeräte bis zu Zuschüssen für Klassenfahrten, damit kein Kind aus finanziellen Gründen zurückbleibt.\n\n## Mitglied werden\n\nDer Jahresbeitrag beträgt 24 € — jeder Euro fließt direkt in die Arbeit an der Schule. Den Aufnahmeantrag finden Sie unter [Downloads](/downloads).\n\n## Spenden\n\nSpenden sind jederzeit willkommen und werden auf Wunsch mit einer Zuwendungsbestätigung quittiert. Sprechen Sie uns über die [Kontaktseite](/contact) an.","embed":[],"location":"header","order":3,"public":true,"slug":"patrons","title":"Förderverein"},{"body":"Hier finden Sie Antworten auf die Fragen, die uns am häufigsten erreichen – nach Themen geordnet. Wählen Sie ein Thema, um die passenden Fragen und Antworten zu sehen.\n\nIhre Frage ist nicht dabei? Schreiben Sie uns über die [Kontaktseite](/contact) – wir helfen gern weiter.","embed":[],"location":"header","order":6,"public":true,"slug":"faqs","title":"FAQs"},{"body":"# Downloads\n\nFormulare und Dokumente zum Herunterladen:\n\n- Aufnahmeantrag Förderverein\n- Einzugsermächtigung\n- Erstattungsformular Klassenkasse\n\nFehlt ein Dokument? Melden Sie sich über die [Kontaktseite](/contact).","embed":[],"location":"header","order":7,"public":true,"slug":"downloads","title":"Downloads"},{"body":"# Kontakt\n\nSie erreichen den Elternbeirat der IGMH per E-Mail:\n\n**elternbeirat@igmh.example**\n\nWir antworten in der Regel innerhalb weniger Tage. Bei dringenden schulischen Angelegenheiten wenden Sie sich bitte direkt an das Sekretariat der Schule.","embed":[],"location":"footer","order":1,"public":true,"slug":"contact","title":"Kontakt"},{"body":"# Impressum\n\nAngaben gemäß § 5 DDG\n\n**Elternbeirat der IGMH**\nVertreten durch den Vorstand\n\nKontakt: siehe [Kontaktseite](/contact)\n\nVerantwortlich für den Inhalt nach § 18 Abs. 2 MStV: der Vorstand des Elternbeirats.","embed":[],"location":"footer","order":2,"public":true,"slug":"imprint","title":"Impressum"},{"body":"# Datenschutz\n\nDer Schutz Ihrer Daten ist uns wichtig. Diese Website kommt ohne externe Dienste aus: keine Analysewerkzeuge, keine eingebundenen Karten oder Videos, keine Schriften von fremden Servern.\n\n## Server-Logs\n\nBeim Aufruf werden technisch notwendige Zugriffsdaten (IP-Adresse, Zeitpunkt, aufgerufene Seite) kurzzeitig verarbeitet, um den Betrieb sicherzustellen. Eine Zusammenführung mit anderen Daten findet nicht statt.\n\n## Ihre Rechte\n\nFragen zum Datenschutz richten Sie bitte an die [Kontaktseite](/contact).","embed":[],"location":"footer","order":3,"public":true,"slug":"privacy","title":"Datenschutz"},{"body":"# Willkommen beim Elternbeirat der IGMH","embed":["posts","events"],"location":"header","order":1,"public":true,"slug":"home","title":"Start"},{"body":"# Beiträge","embed":[],"location":"header","order":4,"public":true,"slug":"posts","title":"Beiträge"},{"body":"# Termine","embed":[],"location":"header","order":5,"public":true,"slug":"events","title":"Termine"}]
|
pages: [{"body":"# Vorstandsteam\n\nDer Elternbeirat der IGMH vertritt die Interessen aller Eltern gegenüber der Schulleitung und dem Kollegium. Wir treffen uns regelmäßig, bringen Anliegen aus der Elternschaft ein und begleiten das Schulleben aktiv.\n\n## Vorstand\n\n- **Vorsitz** — Anke Berger\n- **Stellvertretung** — Murat Yılmaz\n- **Kasse** — Sabine Krause\n- **Schriftführung** — Thomas Heinrich\n\n## So erreichen Sie uns\n\nAm schnellsten per Mail über unsere [Kontaktseite](/contact). Zu unseren öffentlichen Sitzungen sind alle Eltern herzlich eingeladen — die Termine finden Sie unter [Termine](/events).","embed":[],"location":"header","order":2,"public":true,"slug":"board","title":"Vorstandsteam"},{"body":"# Förderverein\n\nDer Förderverein der IGMH unterstützt Projekte, für die im regulären Schulhaushalt kein Geld vorgesehen ist: von der Ausstattung der Bibliothek über Pausenspielgeräte bis zu Zuschüssen für Klassenfahrten, damit kein Kind aus finanziellen Gründen zurückbleibt.\n\n## Mitglied werden\n\nDer Jahresbeitrag beträgt 24 € — jeder Euro fließt direkt in die Arbeit an der Schule. Den Aufnahmeantrag finden Sie unter [Downloads](/downloads).\n\n## Spenden\n\nSpenden sind jederzeit willkommen und werden auf Wunsch mit einer Zuwendungsbestätigung quittiert. Sprechen Sie uns über die [Kontaktseite](/contact) an.","embed":[],"location":"header","order":3,"public":true,"slug":"patrons","title":"Förderverein"},{"body":"Auf dieser Seite haben wir die Fragen zusammengetragen, die uns am häufigsten erreichen.\n\nIhre Frage ist nicht dabei? Schreiben Sie uns über die [Kontaktseite](/contact) – wir helfen gern weiter.","embed":[],"location":"header","order":6,"public":true,"slug":"faqs","title":"FAQs"},{"body":"# Downloads\n\nFormulare und Dokumente zum Herunterladen:\n\n- Aufnahmeantrag Förderverein\n- Einzugsermächtigung\n- Erstattungsformular Klassenkasse\n\nFehlt ein Dokument? Melden Sie sich über die [Kontaktseite](/contact).","embed":[],"location":"header","order":7,"public":true,"slug":"downloads","title":"Downloads"},{"body":"# Kontakt\n\nSie erreichen den Elternbeirat der IGMH per E-Mail:\n\n**kontakt@elternbeirat-igmh.info**\n\nWir antworten in der Regel innerhalb weniger Tage. Bei dringenden schulischen Angelegenheiten wenden Sie sich bitte direkt an das Sekretariat der Schule.","embed":[],"location":"footer","order":1,"public":true,"slug":"contact","title":"Kontakt"},{"body":"# Impressum\n\nAngaben gemäß § 5 DDG\n\n**Elternbeirat der IGMH**\nVertreten durch den Vorstand\n\nKontakt: siehe [Kontaktseite](/contact)\n\nVerantwortlich für den Inhalt nach § 18 Abs. 2 MStV: der Vorstand des Elternbeirats.","embed":[],"location":"footer","order":2,"public":true,"slug":"imprint","title":"Impressum"},{"body":"# Datenschutz\n\nDer Schutz Ihrer Daten ist uns wichtig. Diese Website kommt ohne externe Dienste aus: keine Analysewerkzeuge, keine eingebundenen Karten oder Videos, keine Schriften von fremden Servern.\n\n## Server-Logs\n\nBeim Aufruf werden technisch notwendige Zugriffsdaten (IP-Adresse, Zeitpunkt, aufgerufene Seite) kurzzeitig verarbeitet, um den Betrieb sicherzustellen. Eine Zusammenführung mit anderen Daten findet nicht statt.\n\n## Ihre Rechte\n\nFragen zum Datenschutz richten Sie bitte an die [Kontaktseite](/contact).","embed":[],"location":"footer","order":3,"public":true,"slug":"privacy","title":"Datenschutz"},{"body":"# Willkommen beim Elternbeirat der IGMH","embed":["posts","events"],"location":"header","order":1,"public":true,"slug":"home","title":"Start"},{"body":"# Beiträge","embed":[],"location":"header","order":4,"public":true,"slug":"posts","title":"Beiträge"},{"body":"# Termine","embed":[],"location":"header","order":5,"public":true,"slug":"events","title":"Termine"}]
|
||||||
,
|
,
|
||||||
posts: [{"body":"## Neuer Vorstand gewählt\n\nAuf der Mitgliederversammlung wurde der Vorstand des Elternbeirats für das Schuljahr **2026/27** neu gewählt. Wir danken dem bisherigen Team für sein Engagement und freuen uns auf die gemeinsame Arbeit.\n\nDie neuen Ansprechpartnerinnen und Ansprechpartner finden Sie auf der Seite [Vorstandsteam](/board).","date":"2026-09-24 18:00:00.000Z","public":true,"slug":"new-board-2026","title":"Neuer Vorstand für das Schuljahr 2026/27 gewählt"},{"body":"## Herbstbasar am 22. November\n\nAm **22. November** findet wieder unser beliebter Herbstbasar statt. Es gibt selbst gebackene Kuchen, Bastelstände und ein Bühnenprogramm der Klassen.\n\nWer einen Stand betreuen oder etwas beisteuern möchte, meldet sich bitte bis zum 10. November über das [Kontaktformular](/contact) an. Wir freuen uns über jede helfende Hand!","date":"2026-09-18 09:30:00.000Z","public":true,"slug":"herbstbasar-2026","title":"Herbstbasar am 22. November – jetzt anmelden"},{"body":"## Mehr Auswahl beim Mittagessen\n\nAb den Herbstferien erweitert der Caterer das Angebot in der Mensa: Es gibt künftig **täglich ein zusätzliches vegetarisches Gericht** sowie eine größere Salatauswahl.\n\nRückmeldungen zum Essen nehmen wir gerne über den Elternbeirat auf – sprechen Sie uns an.","date":"2026-09-10 12:15:00.000Z","public":true,"slug":"mensa-mehr-auswahl","title":"Mehr Auswahl beim Mittagessen ab den Herbstferien"},{"body":"## Besuchen Sie unseren Stand\n\nAm kommenden **Elternsprechtag** ist der Elternbeirat mit einem Info-Stand im Foyer vertreten. Kommen Sie vorbei – wir beantworten Fragen rund um die Elternarbeit und freuen uns über neue Mitstreiterinnen und Mitstreiter.\n\nAlle Termine finden Sie unter [Termine](/events).","date":"2026-09-02 08:00:00.000Z","public":true,"slug":"elternsprechtag-stand","title":"Elternbeirat am Elternsprechtag – besuchen Sie unseren Stand"},{"body":"## Neue Spielgeräte für den Pausenhof\n\nDank der Einnahmen aus dem letzten Basar und der Unterstützung des [Fördervereins](/patrons) konnten neue Spielgeräte für den Pausenhof angeschafft werden.\n\nDie Kinder haben die Klettergerüste bereits begeistert in Beschlag genommen.","date":"2026-08-28 16:45:00.000Z","public":true,"slug":"neue-spielgeraete","title":"Neue Spielgeräte für den Pausenhof"}]
|
posts: [{"body":"## Neuer Vorstand gewählt\n\nAuf der Mitgliederversammlung wurde der Vorstand des Elternbeirats für das Schuljahr **2026/27** neu gewählt. Wir danken dem bisherigen Team für sein Engagement und freuen uns auf die gemeinsame Arbeit.\n\nDie neuen Ansprechpartnerinnen und Ansprechpartner finden Sie auf der Seite [Vorstandsteam](/board).","date":"2026-09-24 18:00:00.000Z","public":true,"slug":"new-board-2026","title":"Neuer Vorstand für das Schuljahr 2026/27 gewählt"},{"body":"## Herbstbasar am 22. November\n\nAm **22. November** findet wieder unser beliebter Herbstbasar statt. Es gibt selbst gebackene Kuchen, Bastelstände und ein Bühnenprogramm der Klassen.\n\nWer einen Stand betreuen oder etwas beisteuern möchte, meldet sich bitte bis zum 10. November über das [Kontaktformular](/contact) an. Wir freuen uns über jede helfende Hand!","date":"2026-09-18 09:30:00.000Z","public":true,"slug":"herbstbasar-2026","title":"Herbstbasar am 22. November – jetzt anmelden"},{"body":"## Mehr Auswahl beim Mittagessen\n\nAb den Herbstferien erweitert der Caterer das Angebot in der Mensa: Es gibt künftig **täglich ein zusätzliches vegetarisches Gericht** sowie eine größere Salatauswahl.\n\nRückmeldungen zum Essen nehmen wir gerne über den Elternbeirat auf – sprechen Sie uns an.","date":"2026-09-10 12:15:00.000Z","public":true,"slug":"mensa-mehr-auswahl","title":"Mehr Auswahl beim Mittagessen ab den Herbstferien"},{"body":"## Besuchen Sie unseren Stand\n\nAm kommenden **Elternsprechtag** ist der Elternbeirat mit einem Info-Stand im Foyer vertreten. Kommen Sie vorbei – wir beantworten Fragen rund um die Elternarbeit und freuen uns über neue Mitstreiterinnen und Mitstreiter.\n\nAlle Termine finden Sie unter [Termine](/events).","date":"2026-09-02 08:00:00.000Z","public":true,"slug":"elternsprechtag-stand","title":"Elternbeirat am Elternsprechtag – besuchen Sie unseren Stand"},{"body":"## Neue Spielgeräte für den Pausenhof\n\nDank der Einnahmen aus dem letzten Basar und der Unterstützung des [Fördervereins](/patrons) konnten neue Spielgeräte für den Pausenhof angeschafft werden.\n\nDie Kinder haben die Klettergerüste bereits begeistert in Beschlag genommen.","date":"2026-08-28 16:45:00.000Z","public":true,"slug":"neue-spielgeraete","title":"Neue Spielgeräte für den Pausenhof"}]
|
||||||
,
|
,
|
||||||
|
|||||||
Reference in new issue
Block a user