Forms are an editor now: one card per field with add and remove, the technical name derived from the label, options only for a choice, and a new "Aussehen" section with a button label and four colours (field border and background, button and button text) that travel to the page as one rule per form inside the hashed style block. A live preview draws the form with the site's default button and names the text contrast. Statistics open with six figures (views against the same span before, average per day, busiest day, pages, referred views, missing addresses), a chart with grid lines and a title per bar, a weekday chart and ranked lists with share bars. The design screen shows the palette as colour cards with seven ready-made palettes, picks the base colours from the palette, previews every font in itself and the typography as a sample. The sidebar ends in an account card with role and a logout icon. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
102 lines
7.7 KiB
Twig
102 lines
7.7 KiB
Twig
{# The frame around every management screen. One sidebar, always the same, so each area is one
|
|
click away and the current one is visible. Screens fill in heading, lead, actions and content. #}
|
|
{% extends 'admin/base.html.twig' %}
|
|
{% block body_class %}admin-shell{% endblock %}
|
|
{# Solange jemand hier arbeitet, laeuft der Aufgabenplan - auch auf einer Website ohne Besucher.
|
|
Das Skript fragt im Minutentakt an; was faellig ist, entscheidet der Server. #}
|
|
{% block worker %}
|
|
<meta name="kant-tick" content="{{ path('admin_tasks_tick') }}">
|
|
<meta name="kant-tick-token" content="{{ csrf_token('tasks-tick') }}">
|
|
<script src="/assets/task-worker.js?v={{ kant_version() }}" defer></script>
|
|
{% endblock %}
|
|
{% block body %}
|
|
<header class="shell-nav">
|
|
<a class="brand" href="{{ path('admin_pages') }}"><span class="brand-icon" aria-hidden="true">k.</span>kant<span>sites</span></a>
|
|
{# Auf dem Telefon ein Klappmenue, am Schreibtisch die gewohnte Spalte. Ein details-Element
|
|
kann beides, ohne eine Zeile JavaScript: die Zusammenfassung wird auf grossen Bildschirmen
|
|
ausgeblendet und der Inhalt dauerhaft gezeigt. Zwoelf Eintraege in einer Wischleiste zu
|
|
verstecken war die schlechtere Loesung - man sieht nie, was man nicht trifft. #}
|
|
<details class="shell-menu">
|
|
<summary>
|
|
<svg class="shell-menu-icon" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
|
|
<span class="shell-menu-label">{{ {
|
|
'pages': 'Seiten', 'posts': 'Beiträge', 'partials': 'Bereiche', 'menus': 'Menüs', 'media': 'Mediathek',
|
|
'forms': 'Formulare', 'statistics': 'Statistik', 'theme': 'Design',
|
|
'settings': 'Einstellungen', 'system': 'System', 'tasks': 'Aufgaben', 'users': 'Benutzer',
|
|
'account': 'Mein Konto'
|
|
}[nav|default('')]|default('Verwaltung') }}</span>
|
|
</summary>
|
|
<nav aria-label="Verwaltung">
|
|
<p class="nav-label" id="nav-content">INHALT</p>
|
|
<ul class="nav-list" aria-labelledby="nav-content">
|
|
{% set entries = [
|
|
{id: 'pages', route: 'admin_pages', icon: 'pages', label: 'Seiten'},
|
|
{id: 'posts', route: 'admin_posts', icon: 'pages', label: 'Beiträge'},
|
|
{id: 'partials', route: 'admin_partials', icon: 'partials', label: 'Bereiche'},
|
|
{id: 'menus', route: 'admin_menus', icon: 'menus', label: 'Menüs'},
|
|
{id: 'media', route: 'admin_media', icon: 'media', label: 'Mediathek'},
|
|
{id: 'forms', route: 'admin_forms', icon: 'forms', label: 'Formulare'},
|
|
{id: 'statistics', route: 'admin_statistics', icon: 'statistics', label: 'Statistik'}
|
|
] %}
|
|
{% for entry in entries %}
|
|
<li><a class="nav-item" href="{{ path(entry.route) }}"{{ nav|default('') == entry.id ? ' aria-current="page"' : '' }}>{% include 'admin/icon.html.twig' with {name: entry.icon} only %}{{ entry.label }}</a></li>
|
|
{% endfor %}
|
|
</ul>
|
|
<p class="nav-label" id="nav-site">WEBSITE</p>
|
|
<ul class="nav-list" aria-labelledby="nav-site">
|
|
<li><a class="nav-item" href="{{ path('admin_theme') }}"{{ nav|default('') == 'theme' ? ' aria-current="page"' : '' }}>{% include 'admin/icon.html.twig' with {name: 'theme'} only %}Design</a></li>
|
|
<li><a class="nav-item" href="{{ path('admin_settings') }}"{{ nav|default('') == 'settings' ? ' aria-current="page"' : '' }}>{% include 'admin/icon.html.twig' with {name: 'settings'} only %}Einstellungen</a></li>
|
|
{% if is_granted('ROLE_ADMIN') %}<li><a class="nav-item" href="{{ path('admin_system') }}"{{ nav|default('') == 'system' ? ' aria-current="page"' : '' }}>{% include 'admin/icon.html.twig' with {name: 'system'} only %}System</a></li>{% endif %}
|
|
{% if is_granted('ROLE_ADMIN') %}<li><a class="nav-item" href="{{ path('admin_tasks') }}"{{ nav|default('') == 'tasks' ? ' aria-current="page"' : '' }}>{% include 'admin/icon.html.twig' with {name: 'tasks'} only %}Aufgaben</a></li>{% endif %}
|
|
{% if is_granted('ROLE_ADMIN') %}<li><a class="nav-item" href="{{ path('admin_users') }}"{{ nav|default('') == 'users' ? ' aria-current="page"' : '' }}>{% include 'admin/icon.html.twig' with {name: 'users'} only %}Benutzer</a></li>{% endif %}
|
|
<li><a class="nav-item nav-out" href="/">{% include 'admin/icon.html.twig' with {name: 'external'} only %}Website ansehen</a></li>
|
|
</ul>
|
|
</nav>
|
|
</details>
|
|
{# Der Fuss der Leiste: eine Kontokarte mit Namen und Rolle, daneben der Abmeldeknopf als
|
|
Symbol mit Beschriftung fuer Vorlesesoftware, darunter die Fassung. Vorher standen drei
|
|
Zeilen lose untereinander - Fassung, Name, ein grauer Knopf; jetzt ist es eine Einheit. #}
|
|
<div class="shell-foot">
|
|
<div class="shell-account">
|
|
<a class="shell-user" href="{{ path('admin_account') }}" aria-label="Mein Konto: {{ app.user.userIdentifier }}"{{ nav|default('') == 'account' ? ' aria-current="page"' : '' }}>
|
|
<span class="shell-avatar" aria-hidden="true">{{ app.user.userIdentifier|first|upper }}</span>
|
|
<span class="shell-user-text"><strong>{{ app.user.userIdentifier }}</strong><span>{{ is_granted('ROLE_ADMIN') ? 'Administrator' : (is_granted('ROLE_PUBLISHER') ? 'Veröffentlicher' : 'Redakteur') }}</span></span>
|
|
</a>
|
|
<form action="{{ path('admin_logout') }}" method="post">
|
|
<input type="hidden" name="_csrf_token" value="{{ csrf_token('logout') }}">
|
|
<button class="shell-logout" type="submit" title="Abmelden">{% include 'admin/icon.html.twig' with {name: 'logout'} only %}<span class="visually-hidden">Abmelden</span></button>
|
|
</form>
|
|
</div>
|
|
{% set updateVersion = is_granted('ROLE_ADMIN') ? kant_update_version() : null %}
|
|
<p class="shell-version">
|
|
{% if is_granted('ROLE_ADMIN') %}<a href="{{ path('admin_system') }}">KantSites {{ kant_version() }}</a>{% else %}<span>KantSites {{ kant_version() }}</span>{% endif %}
|
|
{% if updateVersion %}<a class="version-update" href="{{ path('admin_system', {pruefen: 1}) }}" aria-label="Update {{ updateVersion }} verfügbar. Aktualisierung öffnen.">Update {{ updateVersion }} verfügbar</a>{% endif %}
|
|
</p>
|
|
</div>
|
|
</header>
|
|
<main id="admin-main" class="shell-main" tabindex="-1">
|
|
<div class="shell-top">
|
|
<div class="shell-heading">
|
|
<h1>{% block heading %}Verwaltung{% endblock %}</h1>
|
|
<p class="muted">{% block lead %}{% endblock %}</p>
|
|
</div>
|
|
<div class="shell-actions">{% block actions %}{% endblock %}</div>
|
|
</div>
|
|
<div class="shell-body stack">
|
|
{# Offene Handlungen, auf jedem Bildschirm gleich: fehlende Schriften, eine neue Fassung.
|
|
Sie stehen hier statt nur auf ihrer eigenen Seite - einen Hinweis findet nur, wer schon
|
|
weiss, wo er steht. Jeder traegt den Knopf, der ihn erledigt. #}
|
|
{% for hinweis in kant_admin_notices() %}{% if not hinweis.admin or is_granted('ROLE_ADMIN') %}
|
|
<p class="shell-notice" role="status">
|
|
<span>{{ hinweis.text }}</span>
|
|
<a class="secondary" href="{{ path(hinweis.route) }}">{{ hinweis.action }} →</a>
|
|
</p>
|
|
{% endif %}{% endfor %}
|
|
{% for type in ['error', 'success'] %}{% for message in app.flashes(type) %}
|
|
<p class="notice {{ type == 'error' ? 'error' : 'ok' }}" role="{{ type == 'error' ? 'alert' : 'status' }}">{{ message }}</p>
|
|
{% endfor %}{% endfor %}
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
</main>
|
|
{% endblock %}
|