111 lines
5.3 KiB
Plaintext
111 lines
5.3 KiB
Plaintext
@inherits LayoutComponentBase
|
|
|
|
@* Header, main and footer are plain block children of <body>, which is the page's
|
|
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. *@
|
|
|
|
@* Skip link: the first stop for the Tab key, straight past the menu to the content.
|
|
The href carries the current path because of <base href="/"> in App.razor: a
|
|
bare "#main" would resolve to "/#main" and lead every subpage back home.
|
|
data-enhance-nav="false" leaves the jump to the browser: blazor.web.js would
|
|
otherwise take the click, only scroll to <main> and keep the focus on the link,
|
|
so the next Tab would land in the header menu again. *@
|
|
<a class="skip-link" href="@SkipLinkHref" data-enhance-nav="false">Zum Inhalt springen</a>
|
|
|
|
<header class="site-header">
|
|
<div class="header-inner">
|
|
@* Two-line lettering next to the signet: the body's name large, the
|
|
school small below it. One link, so the whole mark leads home. *@
|
|
<a class="brand" href="/">
|
|
<Signet />
|
|
<span class="brand-text">
|
|
<span class="brand-name">Elternbeirat</span>
|
|
<span class="brand-school">IGMH Mannheim</span>
|
|
</span>
|
|
</a>
|
|
|
|
@* CSS-only mobile menu: the 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. The checkbox is only visually hidden on a phone, not
|
|
removed, so it is what keyboard and screen-reader users operate: Tab
|
|
reaches it, Space toggles it, and its checked state is the menu's
|
|
open/closed state, announced as such ("Hauptmenü anzeigen,
|
|
Kontrollkästchen, aktiviert"). Its name is the label's hidden text;
|
|
aria-controls ties it to the menu it opens. aria-expanded would need
|
|
JavaScript to keep it in sync, the native checked state does not. *@
|
|
<input type="checkbox" id="nav-toggle" class="nav-toggle visually-hidden" aria-controls="main-nav" />
|
|
<label for="nav-toggle" class="nav-toggle-label">
|
|
<span class="nav-toggle-bar"></span>
|
|
<span class="visually-hidden">Hauptmenü anzeigen</span>
|
|
</label>
|
|
|
|
<nav id="main-nav" class="main-nav" aria-label="Hauptmenü">
|
|
@* The home link comes from PocketBase like every other entry (the
|
|
"home" page carries location "header"), so it is rendered by the
|
|
loop below -- no separate hard-coded home link, which would show
|
|
up twice next to the PocketBase one. *@
|
|
@foreach (var link in _header)
|
|
{
|
|
<NavLink href="@link.Href" Match="@(link.Href == "/" ? NavLinkMatch.All : NavLinkMatch.Prefix)">@link.Title</NavLink>
|
|
}
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
@* The skip link's target. tabindex="-1" makes it focusable by the link alone
|
|
(not by Tab), so after the jump the next Tab continues inside the content. *@
|
|
<main id="main" class="content" tabindex="-1">
|
|
@Body
|
|
</main>
|
|
|
|
<footer class="site-footer">
|
|
@* A soft wave as the transition from the page into the dark footer. Pure
|
|
decoration, so hidden from screen readers; it is filled with the footer
|
|
colour and stretched to the full width (preserveAspectRatio="none"). *@
|
|
<svg class="footer-wave" viewBox="0 0 1440 48" preserveAspectRatio="none" aria-hidden="true" focusable="false">
|
|
<path d="M0 24C240 48 480 48 720 28S1200 0 1440 20V48H0z" />
|
|
</svg>
|
|
|
|
<div class="footer-inner">
|
|
<div class="footer-brand">
|
|
<Signet />
|
|
<span>Elternbeirat der IGMH</span>
|
|
</div>
|
|
|
|
@* Both link columns come from PocketBase like the header. An empty list
|
|
(no such pages, or PocketBase down) renders nothing -- no lone
|
|
heading above an empty column. *@
|
|
@if (_header.Count > 0)
|
|
{
|
|
<nav class="footer-nav" aria-label="Schnellzugriff">
|
|
<h2 class="footer-heading">Schnellzugriff</h2>
|
|
<ul>
|
|
@foreach (var link in _header)
|
|
{
|
|
<li><a href="@link.Href">@link.Title</a></li>
|
|
}
|
|
</ul>
|
|
</nav>
|
|
}
|
|
|
|
@if (_footer.Count > 0)
|
|
{
|
|
<nav class="footer-nav" aria-label="Weiteres">
|
|
<h2 class="footer-heading">Weiteres</h2>
|
|
<ul>
|
|
@foreach (var link in _footer)
|
|
{
|
|
<li><a href="@link.Href">@link.Title</a></li>
|
|
}
|
|
</ul>
|
|
</nav>
|
|
}
|
|
</div>
|
|
|
|
<p class="footer-copyright">© @_year Elternbeirat der IGMH</p>
|
|
</footer>
|