Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7e708a717 | ||
|
|
fa49f80d65 | ||
|
|
02654c20d3 |
No files matched your search
@@ -1,3 +1,8 @@
|
|||||||
# Shell-Skripte brauchen Unix-Zeilenenden (LF), sonst scheitert der #!-Aufruf
|
# Shell-Skripte brauchen Unix-Zeilenenden (LF), sonst scheitert der #!-Aufruf
|
||||||
# in bash. Unabhaengig von core.autocrlf auf Windows erzwingen.
|
# in bash. Unabhaengig von core.autocrlf auf Windows erzwingen.
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
|
|
||||||
|
# PocketBase-Migration und -Schema laufen im Linux-Container. LF erzwingen, damit
|
||||||
|
# core.autocrlf=true auf Windows sie nicht bei jeder Beruehrung als geaendert
|
||||||
|
# markiert (staendige "LF will be replaced by CRLF"-Warnung).
|
||||||
|
pb/** text eol=lf
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<option name="upForceRecreate" value="true" />
|
<option name="upForceRecreate" value="true" />
|
||||||
</settings>
|
</settings>
|
||||||
</deployment>
|
</deployment>
|
||||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="false" isSslEnabled="false" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
@@ -85,7 +85,9 @@ public sealed class PocketBaseClientTests(PocketBaseFixture pocketBase)
|
|||||||
|
|
||||||
var home = pages.Single(p => p.Slug == "home");
|
var home = pages.Single(p => p.Slug == "home");
|
||||||
home.Embed.ShouldBe(["posts", "events"], ignoreOrder: true);
|
home.Embed.ShouldBe(["posts", "events"], ignoreOrder: true);
|
||||||
home.Location.ShouldBe("header");
|
// Home has no menu slot: the brand is the home link, so a "Start" nav
|
||||||
|
// entry would be redundant. NavBuilder filters it out via this empty value.
|
||||||
|
home.Location.ShouldBe("");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -222,10 +222,12 @@ public sealed class PocketBaseFixture : IAsyncLifetime
|
|||||||
// Pages that the route smoke tests reach through the navigation, the
|
// Pages that the route smoke tests reach through the navigation, the
|
||||||
// footer or the FAQ hub. Header pages carry a location+order; the FAQ
|
// footer or the FAQ hub. Header pages carry a location+order; the FAQ
|
||||||
// sub-pages are plain content pages without a menu slot. All public.
|
// sub-pages are plain content pages without a menu slot. All public.
|
||||||
|
// The home page has no menu slot (location ""): the site brand is the home
|
||||||
|
// link, so a separate "Start" nav entry would be redundant.
|
||||||
await CreateRecordAsync(http, "pages", new
|
await CreateRecordAsync(http, "pages", new
|
||||||
{
|
{
|
||||||
title = "Startseite", body = "# Willkommen", location = "header",
|
title = "Startseite", body = "# Willkommen", location = "",
|
||||||
order = 1, slug = "home", embed = new[] { "posts", "events" }, @public = true,
|
order = 0, slug = "home", embed = new[] { "posts", "events" }, @public = true,
|
||||||
});
|
});
|
||||||
await CreateRecordAsync(http, "pages", new
|
await CreateRecordAsync(http, "pages", new
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,29 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
<div class="page">
|
@* Header, main and footer are plain block children of <body>, which is the page's
|
||||||
<header class="site-header">
|
scroll root. The header is position:sticky and, because it is NOT a flex/grid
|
||||||
|
child (a stretched flex item never sticks -- it fills its cell and unsticks
|
||||||
|
immediately), it pins to the top and stays there while the page scrolls. The
|
||||||
|
footer is kept at the bottom on short pages by a min-height on <main>, not by a
|
||||||
|
flex wrapper -- see MainLayout.razor.css. *@
|
||||||
|
<header class="site-header">
|
||||||
<div class="header-inner">
|
<div class="header-inner">
|
||||||
<a class="brand" href="/">Elternbeirat IGMH</a>
|
<a class="brand" href="/">Elternbeirat IGMH</a>
|
||||||
|
|
||||||
|
@* CSS-only mobile menu: the hidden checkbox holds the open/closed
|
||||||
|
state, the label is the hamburger button, and :checked reveals the
|
||||||
|
nav below (see MainLayout.razor.css). No JavaScript, no @@rendermode
|
||||||
|
-- works under static SSR. *@
|
||||||
|
<input type="checkbox" id="nav-toggle" class="nav-toggle" />
|
||||||
|
<label for="nav-toggle" class="nav-toggle-label" aria-label="Menü öffnen und schließen">
|
||||||
|
<span class="nav-toggle-bar"></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
<nav class="main-nav">
|
<nav class="main-nav">
|
||||||
|
@* A home link that only shows in the collapsed mobile menu. On wide
|
||||||
|
screens the brand is the home link, so this would be a redundant
|
||||||
|
entry -- CSS hides it there (see .nav-home-mobile). *@
|
||||||
|
<NavLink class="nav-home-mobile" href="/" Match="NavLinkMatch.All">Start</NavLink>
|
||||||
@foreach (var link in _header)
|
@foreach (var link in _header)
|
||||||
{
|
{
|
||||||
<NavLink href="@link.Href" Match="@(link.Href == "/" ? NavLinkMatch.All : NavLinkMatch.Prefix)">@link.Title</NavLink>
|
<NavLink href="@link.Href" Match="@(link.Href == "/" ? NavLinkMatch.All : NavLinkMatch.Prefix)">@link.Title</NavLink>
|
||||||
@@ -28,4 +47,3 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
|
||||||
@@ -19,34 +19,37 @@
|
|||||||
top: 0.5rem;
|
top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Page frame: header and footer stay put, the content grows and pushes the
|
/* Header: pinned to the top while the page scrolls, so the brand and (on mobile)
|
||||||
footer to the bottom even on short pages. */
|
the hamburger button are always reachable. It is a plain block child of <body>
|
||||||
.page {
|
(NOT a flex item) -- a stretched flex child fills its cell and never sticks.
|
||||||
display: flex;
|
z-index keeps it above the content; the opaque background stops content showing
|
||||||
flex-direction: column;
|
through as it scrolls underneath. */
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header */
|
|
||||||
.site-header {
|
.site-header {
|
||||||
border-bottom: 1px solid #e0e0e0;
|
/* Brand-blue bar with a warm accent underline -- the strongest, most visible
|
||||||
background: #fff;
|
cue that carries the friendly tone across every page. Uses its own header
|
||||||
|
token so it stays deep blue in dark mode too (see app.css). */
|
||||||
|
background: var(--color-header);
|
||||||
|
border-bottom: 3px solid var(--color-accent);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-inner {
|
.header-inner {
|
||||||
max-width: 60rem;
|
max-width: var(--content-width);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 1rem 1.25rem;
|
padding: var(--space-3) 1.25rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
gap: 0.5rem 1.5rem;
|
gap: var(--space-2) var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand {
|
.brand {
|
||||||
font-size: 1.35rem;
|
font-size: 1.35rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #1f3a5f;
|
color: #fff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -57,61 +60,128 @@
|
|||||||
gap: 0.25rem 1.25rem;
|
gap: 0.25rem 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-nav a {
|
/* The hamburger button, its state checkbox, and the mobile-only home link are
|
||||||
color: #333;
|
hidden on wide screens; the media query below turns them on for narrow ones.
|
||||||
text-decoration: none;
|
(On wide screens the brand is the home link, so a "Start" entry is redundant.) */
|
||||||
padding: 0.2rem 0;
|
.nav-toggle,
|
||||||
border-bottom: 2px solid transparent;
|
.nav-toggle-label,
|
||||||
|
.nav-home-mobile {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-nav a:hover {
|
/* The link colours/states for .main-nav a live in the GLOBAL app.css, not here.
|
||||||
color: #1f3a5f;
|
Reason: NavLink renders plain <a> elements that carry no scoped-CSS attribute
|
||||||
}
|
(b-xxxxx), so a scoped rule ".main-nav a" would not match them. See app.css. */
|
||||||
|
|
||||||
/* NavLink adds .active to the link of the current route. */
|
/* Content: at least tall enough that the footer sits at the bottom of the viewport
|
||||||
.main-nav a.active {
|
on short pages. 100dvh - 4rem leaves room for the header (which sits above in
|
||||||
color: #1f3a5f;
|
normal flow); dvh follows the mobile browser's shrinking toolbar. On long pages
|
||||||
border-bottom-color: #1f3a5f;
|
the content simply grows past this and pushes the footer down naturally. */
|
||||||
}
|
|
||||||
|
|
||||||
/* Content */
|
|
||||||
.content {
|
.content {
|
||||||
flex: 1;
|
min-height: calc(100dvh - 4rem);
|
||||||
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 60rem;
|
max-width: var(--content-width);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 1.5rem 1.25rem 3rem;
|
padding: var(--space-4) 1.25rem var(--space-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
.site-footer {
|
.site-footer {
|
||||||
border-top: 1px solid #e0e0e0;
|
border-top: 1px solid var(--color-border);
|
||||||
background: #fafafa;
|
background: var(--color-surface);
|
||||||
color: #555;
|
color: var(--color-text-soft);
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-inner {
|
.footer-inner {
|
||||||
max-width: 60rem;
|
max-width: var(--content-width);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 1rem 1.25rem;
|
padding: var(--space-3) 1.25rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 0.5rem 1.5rem;
|
gap: var(--space-2) var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-nav {
|
.footer-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1.25rem;
|
gap: var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-nav a {
|
.footer-nav a {
|
||||||
color: #555;
|
color: var(--color-text-soft);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-nav a:hover {
|
.footer-nav a:hover {
|
||||||
color: #1f3a5f;
|
color: var(--color-brand);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile: on narrow screens the nav collapses behind a hamburger button. This is
|
||||||
|
pure CSS -- the #nav-toggle checkbox holds the open/closed state and its
|
||||||
|
:checked state reveals the nav. No JavaScript, so it works under static SSR. */
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
/* The brand stays on the left, the hamburger goes to the right, and the nav
|
||||||
|
occupies its own full-width row below both. */
|
||||||
|
.header-inner {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show the hamburger button. */
|
||||||
|
.nav-toggle-label {
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin: -0.5rem; /* keep the tap target large without shifting layout */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The three-bar icon, drawn with one element plus its ::before/::after. */
|
||||||
|
.nav-toggle-bar,
|
||||||
|
.nav-toggle-bar::before,
|
||||||
|
.nav-toggle-bar::after {
|
||||||
|
display: block;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 2px;
|
||||||
|
background: #fff; /* on the blue header bar */
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle-bar::before {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle-bar::after {
|
||||||
|
transform: translateY(4px); /* 6px minus the bar's own 2px height */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The nav takes its own row and is hidden until the checkbox is checked. */
|
||||||
|
.main-nav {
|
||||||
|
flex-basis: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checked state: reveal the stacked links. The max-height caps the open menu
|
||||||
|
to the space below the sticky header; a longer list scrolls inside it
|
||||||
|
instead of running off the screen. */
|
||||||
|
.nav-toggle:checked ~ .main-nav {
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The mobile-only home link reappears as the first entry in the menu. */
|
||||||
|
.nav-home-mobile {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile per-link spacing/separators for .main-nav a are in the global app.css
|
||||||
|
too, for the same scoped-attribute reason as above. */
|
||||||
|
}
|
||||||
@@ -20,6 +20,6 @@
|
|||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
<p><a href="/events">Alle Termine →</a></p>
|
<p class="embed-more"><a href="/events">Alle Termine <span aria-hidden="true">→</span></a></p>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
@@ -1,33 +1,5 @@
|
|||||||
|
/* Card styles for .event-list are shared with the full events page and live in the
|
||||||
|
global app.css. Only the embed's spacing on the home page is specific here. */
|
||||||
.embed-events {
|
.embed-events {
|
||||||
margin-top: 2rem;
|
margin-top: var(--space-5);
|
||||||
}
|
|
||||||
|
|
||||||
.event-list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list li {
|
|
||||||
padding: 0.75rem 0;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list time {
|
|
||||||
display: block;
|
|
||||||
color: #777;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-title {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-location::before {
|
|
||||||
content: " · ";
|
|
||||||
color: #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-location {
|
|
||||||
color: #555;
|
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
}
|
}
|
||||||
<p><a href="/faqs">Alle Fragen →</a></p>
|
<p class="embed-more"><a href="/faqs">Alle Fragen <span aria-hidden="true">→</span></a></p>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
|
/* Card styles for .faq-item are shared with the full FAQ page and live in the
|
||||||
|
global app.css. Only the embed's spacing on the home page is specific here. */
|
||||||
.embed-faqs {
|
.embed-faqs {
|
||||||
margin-top: 2rem;
|
margin-top: var(--space-5);
|
||||||
}
|
|
||||||
|
|
||||||
.faq-item {
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding: 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.faq-item summary {
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.faq-answer {
|
|
||||||
padding: 0.5rem 0 0.25rem;
|
|
||||||
color: #333;
|
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,6 @@
|
|||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
<p><a href="/posts">Alle Beiträge →</a></p>
|
<p class="embed-more"><a href="/posts">Alle Beiträge <span aria-hidden="true">→</span></a></p>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
@@ -1,24 +1,5 @@
|
|||||||
|
/* Card styles for .post-list are shared with the full posts page and live in the
|
||||||
|
global app.css. Only the embed's spacing on the home page is specific here. */
|
||||||
.embed-posts {
|
.embed-posts {
|
||||||
margin-top: 2rem;
|
margin-top: var(--space-5);
|
||||||
}
|
|
||||||
|
|
||||||
.post-list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-list li {
|
|
||||||
padding: 0.75rem 0;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-list a {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-list time {
|
|
||||||
display: block;
|
|
||||||
color: #777;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
}
|
||||||
@@ -1,42 +1,2 @@
|
|||||||
.event-list {
|
/* The .event-list card styles (including past-event styling) are shared with the
|
||||||
list-style: none;
|
home-page embed and live in the global app.css. Nothing page-specific here. */
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list li {
|
|
||||||
padding: 0.75rem 0;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list time {
|
|
||||||
display: block;
|
|
||||||
color: #777;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-title {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-location::before {
|
|
||||||
content: " · ";
|
|
||||||
color: #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-location {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-note {
|
|
||||||
margin: 0.25rem 0 0;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list-past {
|
|
||||||
color: #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list-past .event-title {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,10 @@
|
|||||||
|
/* The .faq-item card styles are shared with the home-page embed and live in the
|
||||||
|
global app.css. Only the topic grouping is specific to this full page (the
|
||||||
|
embed shows a flat list without topic headings). */
|
||||||
.faq-topic {
|
.faq-topic {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: var(--space-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.faq-topic h2 {
|
.faq-topic h2 {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: var(--space-3);
|
||||||
}
|
|
||||||
|
|
||||||
.faq-item {
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding: 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.faq-item summary {
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.faq-answer {
|
|
||||||
padding: 0.5rem 0 0.25rem;
|
|
||||||
color: #333;
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
.intro {
|
.intro {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
color: #444;
|
/* Softer than body text, via the token -- so it adapts in dark mode instead of
|
||||||
|
staying a fixed dark grey that turns unreadable there. */
|
||||||
|
color: var(--color-text-soft);
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
|
|
||||||
.post-meta time {
|
.post-meta time {
|
||||||
display: block;
|
display: block;
|
||||||
color: #777;
|
color: var(--color-text-soft); /* token, so it adapts in dark mode */
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,2 @@
|
|||||||
.post-list {
|
/* The .post-list card styles are shared with the home-page embed and live in the
|
||||||
list-style: none;
|
global app.css. This page needs no extra styling of its own. */
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-list li {
|
|
||||||
padding: 0.75rem 0;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-list a {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-list time {
|
|
||||||
display: block;
|
|
||||||
color: #777;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
|
||||||
@@ -1,27 +1,360 @@
|
|||||||
|
/* Design tokens: one place for colours, spacing, radius, shadow and type. Every
|
||||||
|
component pulls from these variables (var(--...)), so the whole site shares one
|
||||||
|
look and a change here ripples everywhere. Warm-friendly palette: the brand blue
|
||||||
|
plus a warm accent. No external anything -- just CSS custom properties. */
|
||||||
|
:root {
|
||||||
|
/* Brand blue and two derived shades (darker for hover, lighter for tints). */
|
||||||
|
--color-brand: #1f3a5f;
|
||||||
|
--color-brand-dark: #16293f;
|
||||||
|
--color-brand-tint: #eef2f7;
|
||||||
|
|
||||||
|
/* The header bar's background. Its own token (not --color-brand) so it stays a
|
||||||
|
deep blue in dark mode, where --color-brand is lightened for text/links. */
|
||||||
|
--color-header: #1f3a5f;
|
||||||
|
|
||||||
|
/* Warm accent for highlights (active nav, event dates, call-outs). */
|
||||||
|
--color-accent: #e8a13a;
|
||||||
|
--color-accent-dark: #c9821c;
|
||||||
|
|
||||||
|
/* Headings. Its own token (not --color-brand) so headings and links can differ:
|
||||||
|
in dark mode headings become a soft white while links keep the brand blue. */
|
||||||
|
--color-heading: #1f3a5f;
|
||||||
|
|
||||||
|
/* Text and surfaces. */
|
||||||
|
--color-text: #222;
|
||||||
|
--color-text-soft: #555;
|
||||||
|
--color-bg: #fff; /* cards / content surface */
|
||||||
|
--color-page: #f4f1ea; /* soft warm page background behind the content */
|
||||||
|
--color-surface: #fafafa;
|
||||||
|
--color-border: #e0e0e0;
|
||||||
|
|
||||||
|
/* Spacing scale -- use these instead of ad-hoc rem values so gaps stay even. */
|
||||||
|
--space-1: 0.25rem;
|
||||||
|
--space-2: 0.5rem;
|
||||||
|
--space-3: 1rem;
|
||||||
|
--space-4: 1.5rem;
|
||||||
|
--space-5: 2rem;
|
||||||
|
--space-6: 3rem;
|
||||||
|
|
||||||
|
/* Rounded corners and a soft shadow for cards, matching the friendly tone. */
|
||||||
|
--radius: 12px;
|
||||||
|
--radius-sm: 6px;
|
||||||
|
--shadow: 0 1px 3px rgba(31, 58, 95, 0.08), 0 4px 12px rgba(31, 58, 95, 0.06);
|
||||||
|
--shadow-hover: 0 2px 6px rgba(31, 58, 95, 0.12), 0 8px 20px rgba(31, 58, 95, 0.1);
|
||||||
|
|
||||||
|
/* One transition speed for hovers/focus across the site. */
|
||||||
|
--transition: 0.15s ease;
|
||||||
|
|
||||||
|
/* Reading width, so long text lines never get uncomfortably wide. */
|
||||||
|
--content-width: 60rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode: follows the visitor's OS setting automatically (prefers-color-scheme).
|
||||||
|
No toggle and no JavaScript -- the browser applies this when the operating system
|
||||||
|
is set to dark. Only the colour tokens change; layout, spacing, radius and type
|
||||||
|
stay put, so the whole site adapts from this one block. Choices: a deep blue-grey
|
||||||
|
rather than pure black; cards a touch lighter than the page so they still lift off
|
||||||
|
it; the accent nudged brighter so it doesn't glare; shadows darkened since soft
|
||||||
|
light shadows are invisible on a dark background. The header keeps its deep blue. */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--color-brand: #7fb0e6; /* headings/links need to stay bright enough
|
||||||
|
to read on the dark page background, not
|
||||||
|
just on the lighter card surface */
|
||||||
|
--color-brand-dark: #a3c8f0; /* hover goes lighter, not darker, on dark */
|
||||||
|
--color-brand-tint: #232a35;
|
||||||
|
|
||||||
|
--color-header: #1a2a3f; /* a hair deeper, to sit calmly on dark */
|
||||||
|
|
||||||
|
--color-accent: #f0b45c;
|
||||||
|
--color-accent-dark: #f0b45c; /* no darkening needed on a dark surface */
|
||||||
|
|
||||||
|
--color-heading: #c9ced6; /* soft white, kept a step brighter than the
|
||||||
|
body text so headings still lead the page */
|
||||||
|
|
||||||
|
--color-text: #a2a8b2; /* eased right down to the soft tone -- full
|
||||||
|
near-white reads as glare on the dark page */
|
||||||
|
--color-text-soft: #a2a8b2;
|
||||||
|
--color-bg: #222834; /* cards / content surface */
|
||||||
|
--color-page: #171b22; /* page background, darker than the cards */
|
||||||
|
--color-surface: #1c212a;
|
||||||
|
--color-border: #333b47;
|
||||||
|
|
||||||
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
--shadow-hover: 0 2px 6px rgba(0, 0, 0, 0.5), 0 8px 20px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Base styles. Self-hosted system font stack — no external fonts, for privacy. */
|
/* Base styles. Self-hosted system font stack — no external fonts, for privacy. */
|
||||||
html {
|
html {
|
||||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
line-height: 1.6;
|
line-height: 1.65;
|
||||||
color: #222;
|
color: var(--color-text);
|
||||||
|
/* Tell the browser we support both schemes, so form controls, scrollbars and
|
||||||
|
the native <details> marker follow the OS setting instead of staying light. */
|
||||||
|
color-scheme: light dark;
|
||||||
|
/* Smooth-scroll for in-page anchors, with room so headings clear the sticky
|
||||||
|
header instead of hiding under it. */
|
||||||
|
scroll-padding-top: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
/* A soft tinted page background so white cards/content lift off it. */
|
||||||
|
background: var(--color-page);
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #1f3a5f;
|
color: var(--color-brand);
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
transition: color var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3 {
|
a:hover {
|
||||||
|
color: var(--color-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings: clear hierarchy and a touch more air above them than below, so
|
||||||
|
sections read as groups. */
|
||||||
|
h1, h2, h3, h4 {
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
color: #1f3a5f;
|
color: var(--color-heading);
|
||||||
|
margin: var(--space-5) 0 var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-top: 0; /* the first heading on a page needs no gap above */
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comfortable paragraph rhythm and a capped line length for readability. */
|
||||||
|
p {
|
||||||
|
margin: 0 0 var(--space-3);
|
||||||
|
max-width: 42rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1:focus {
|
h1:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Header navigation links. These live here (global), not in MainLayout.razor.css:
|
||||||
|
NavLink renders plain <a> elements without a scoped-CSS attribute, so a scoped
|
||||||
|
".main-nav a" rule would not match them -- the links would fall back to the
|
||||||
|
global link colour (dark blue) and become unreadable on the blue header bar. */
|
||||||
|
.main-nav a {
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: var(--space-1) 0;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
transition: color var(--transition), border-color var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-nav a:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NavLink adds .active to the current route's link; a warm accent underline marks
|
||||||
|
where the visitor is on the blue bar. */
|
||||||
|
.main-nav a.active {
|
||||||
|
color: #fff;
|
||||||
|
border-bottom-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile: stacked links inside the collapsed menu get row separators. Same global
|
||||||
|
placement, same NavLink reason as above. Scoped to the narrow layout via the
|
||||||
|
media query so it does not affect the desktop row. */
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
.main-nav a {
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-nav a.active {
|
||||||
|
border-bottom-color: rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Shared card styles for content lists --------------------------------------
|
||||||
|
Posts, events and FAQs appear both on their own page (PostList/EventList/
|
||||||
|
FaqList) AND embedded on the home page (the *Embed components), with the same
|
||||||
|
class names. These rules live here (global) so both places share one look
|
||||||
|
instead of duplicating the CSS per component. The card look: a white surface
|
||||||
|
lifted off the tinted page background with a soft shadow and a gentle hover. */
|
||||||
|
|
||||||
|
.post-list,
|
||||||
|
.event-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: grid;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-list li,
|
||||||
|
.event-list li {
|
||||||
|
background: var(--color-bg);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
transition: box-shadow var(--transition), transform var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-list li:hover,
|
||||||
|
.event-list li:hover {
|
||||||
|
box-shadow: var(--shadow-hover);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Posts */
|
||||||
|
.post-list a {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-list time {
|
||||||
|
display: block;
|
||||||
|
margin-top: var(--space-1);
|
||||||
|
color: var(--color-text-soft);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Events: the date leads in the warm accent colour. */
|
||||||
|
.event-list time {
|
||||||
|
display: block;
|
||||||
|
color: var(--color-accent-dark);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
display: block;
|
||||||
|
margin-top: var(--space-1);
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-location::before {
|
||||||
|
content: " · ";
|
||||||
|
color: var(--color-text-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-location {
|
||||||
|
color: var(--color-text-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-note {
|
||||||
|
margin: var(--space-2) 0 0;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Past events (only on the full events page): same cards, quieter and flat. */
|
||||||
|
.event-list-past li {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-list-past li:hover {
|
||||||
|
transform: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-list-past time {
|
||||||
|
color: var(--color-text-soft);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-list-past .event-title {
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--color-text-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FAQ: each question is an expandable card with an accent +/– marker. */
|
||||||
|
.faq-item {
|
||||||
|
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-item:hover {
|
||||||
|
box-shadow: var(--shadow-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-item summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-brand);
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-item summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-item summary::before {
|
||||||
|
content: "+";
|
||||||
|
color: var(--color-accent-dark);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-item[open] summary::before {
|
||||||
|
content: "–";
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq-answer {
|
||||||
|
padding-top: var(--space-2);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "Alle Beiträge/Termine/Fragen →" links below an embedded list on the home page.
|
||||||
|
Set apart from the cards with extra space above, and styled as a distinct call
|
||||||
|
to action in the accent colour rather than looking like body text. The arrow
|
||||||
|
nudges right on hover for a subtle bit of life. */
|
||||||
|
.embed-more {
|
||||||
|
margin-top: var(--space-4);
|
||||||
|
max-width: none; /* override the global paragraph reading cap */
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-more a {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-accent-dark);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-more a:hover {
|
||||||
|
color: var(--color-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-more a span {
|
||||||
|
transition: transform var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-more a:hover span {
|
||||||
|
transform: translateX(3px);
|
||||||
|
}
|
||||||
|
|
||||||
.valid.modified:not([type=checkbox]) {
|
.valid.modified:not([type=checkbox]) {
|
||||||
outline: 1px solid #26b050;
|
outline: 1px solid #26b050;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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":"# Häufige Fragen\n\nHier beantworten wir die Fragen, die uns am häufigsten erreichen. Ausführliche Antworten gibt es auf den Unterseiten:\n\n- [Mensa und Mittagessen](/faq-mensa)\n- [Schließfächer](/faq-schliessfach)\n- [Eltern-Euro](/faq-elterneuro)\n- [Elternarbeit und Mitmachen](/faq-elternarbeit)\n\nIhre Frage ist nicht dabei? Schreiben Sie uns über die [Kontaktseite](/contact).","embed":[],"location":"header","order":6,"public":true,"slug":"faqs","title":"FAQ"},{"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":"# Mensa und Mittagessen\n\n## Wie melde ich mein Kind zum Mittagessen an?\n\nDie Anmeldung läuft über das Bestellsystem der Schule. Die Zugangsdaten erhalten Sie zu Schuljahresbeginn über die Klassenleitung.\n\n## Was kostet ein Essen?\n\nEin Mittagessen kostet aktuell 4,20 €. Für Familien mit Anspruch auf Leistungen nach dem Bildungs- und Teilhabepaket ist das Essen kostenfrei — sprechen Sie das Sekretariat an.\n\n## Gibt es vegetarische Gerichte?\n\nJa, täglich steht mindestens ein vegetarisches Gericht zur Wahl.\n\nWeitere Fragen? [Schreiben Sie uns.](/contact)","embed":[],"location":"","order":0,"public":true,"slug":"faq-mensa","title":"Mensa und Mittagessen"},{"body":"# Schließfächer\n\n## Wie bekommt mein Kind ein Schließfach?\n\nSchließfächer werden über einen externen Anbieter gemietet. Das Anmeldeformular liegt bei den [Downloads](/downloads).\n\n## Was kostet die Miete?\n\nDie Miete beträgt rund 15 € pro Schuljahr zuzüglich einer Kaution, die bei Rückgabe erstattet wird.\n\n## Der Schlüssel ist weg — was nun?\n\nWenden Sie sich an den Anbieter; die Kontaktdaten stehen auf dem Mietvertrag. Bei Fragen hilft auch der [Elternbeirat](/contact).","embed":[],"location":"","order":0,"public":true,"slug":"faq-schliessfach","title":"Schließfächer"},{"body":"# Eltern-Euro\n\n## Was ist der Eltern-Euro?\n\nDer ElterLine truncated
|
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":"# Häufige Fragen\n\nHier beantworten wir die Fragen, die uns am häufigsten erreichen. Ausführliche Antworten gibt es auf den Unterseiten:\n\n- [Mensa und Mittagessen](/faq-mensa)\n- [Schließfächer](/faq-schliessfach)\n- [Eltern-Euro](/faq-elterneuro)\n- [Elternarbeit und Mitmachen](/faq-elternarbeit)\n\nIhre Frage ist nicht dabei? Schreiben Sie uns über die [Kontaktseite](/contact).","embed":[],"location":"header","order":6,"public":true,"slug":"faqs","title":"FAQ"},{"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":"# Mensa und Mittagessen\n\n## Wie melde ich mein Kind zum Mittagessen an?\n\nDie Anmeldung läuft über das Bestellsystem der Schule. Die Zugangsdaten erhalten Sie zu Schuljahresbeginn über die Klassenleitung.\n\n## Was kostet ein Essen?\n\nEin Mittagessen kostet aktuell 4,20 €. Für Familien mit Anspruch auf Leistungen nach dem Bildungs- und Teilhabepaket ist das Essen kostenfrei — sprechen Sie das Sekretariat an.\n\n## Gibt es vegetarische Gerichte?\n\nJa, täglich steht mindestens ein vegetarisches Gericht zur Wahl.\n\nWeitere Fragen? [Schreiben Sie uns.](/contact)","embed":[],"location":"","order":0,"public":true,"slug":"faq-mensa","title":"Mensa und Mittagessen"},{"body":"# Schließfächer\n\n## Wie bekommt mein Kind ein Schließfach?\n\nSchließfächer werden über einen externen Anbieter gemietet. Das Anmeldeformular liegt bei den [Downloads](/downloads).\n\n## Was kostet die Miete?\n\nDie Miete beträgt rund 15 € pro Schuljahr zuzüglich einer Kaution, die bei Rückgabe erstattet wird.\n\n## Der Schlüssel ist weg — was nun?\n\nWenden Sie sich an den Anbieter; die Kontaktdaten stehen auf dem Mietvertrag. Bei Fragen hilft auch der [Elternbeirat](/contact).","embed":[],"location":"","order":0,"public":true,"slug":"faq-schliessfach","title":"Schließfächer"},{"body":"# Eltern-Euro\n\n## Was ist der Eltern-Euro?\n\nDer ElterLine truncated
|
||||||
,
|
,
|
||||||
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