Files
KantSites/src/Controller/ThemeController.php
T
kantarciandClaude Fable 5.1 160c394c3f
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Rework forms, statistics, design and the sidebar foot in 1.15.0
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>
2026-09-15 07:59:30 +02:00

104 lines
3.9 KiB
PHP

<?php
namespace App\Controller;
use App\Content\ButtonDesign;
use App\Content\FontLibrary;
use App\Content\Theme;
use App\Domain\InvalidPage;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class ThemeController extends AbstractController
{
public function __construct(private Theme $theme, private FontLibrary $fonts)
{
}
#[Route('/%kant.admin_path%/theme', name: 'admin_theme', methods: ['GET'])]
public function index(): Response
{
$theme = $this->theme->load();
return $this->render('admin/theme.html.twig', [
'theme' => $theme,
'fallbacks' => Theme::FALLBACKS,
'weights' => Theme::WEIGHTS,
'buttonOptions' => ButtonDesign::OPTIONS,
'buttonPresets' => ButtonDesign::PRESETS,
'fontsLocal' => $this->fonts->hasLocal($theme),
'fontsMissing' => $this->fonts->missing($theme),
// Die Vorschau der Schriften nutzt die Dateien, die schon hier liegen.
'fontsStylesheet' => $this->fonts->hasStylesheet(),
'palettes' => Theme::PALETTES,
'colorNames' => Theme::COLOR_NAMES,
]);
}
/**
* Holt die gewaehlten Google-Schriften auf den eigenen Server.
*
* Auf Zuruf, nicht bei einem Seitenaufruf: das dauert Sekunden und braucht eine Verbindung
* nach aussen, die ein Besucher nie abwarten soll.
*/
#[Route('/%kant.admin_path%/theme/fonts', name: 'admin_theme_fonts', methods: ['POST'])]
public function fonts(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_EDITOR');
if (!$this->isCsrfTokenValid('theme', $request->request->getString('_csrf_token'))) {
$this->addFlash('error', 'Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
return $this->redirectToRoute('admin_theme');
}
try {
$result = $this->fonts->fetch($this->theme->load());
$this->addFlash('success', sprintf(
'%d Schriftdatei(en) geladen, %s insgesamt: %s. Die Website lädt jetzt nichts mehr von Google.',
$result['files'],
$this->bytes($result['bytes']),
implode(', ', $result['families']),
));
} catch (\RuntimeException $error) {
$this->addFlash('error', $error->getMessage());
}
return $this->redirectToRoute('admin_theme');
}
private function bytes(int $bytes): string
{
return $bytes < 1024 * 1024 ? round($bytes / 1024).' KB' : round($bytes / 1024 / 1024, 1).' MB';
}
#[Route('/%kant.admin_path%/theme/save', name: 'admin_theme_save', methods: ['POST'])]
public function save(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_EDITOR');
if (!$this->isCsrfTokenValid('theme', $request->request->getString('_csrf_token'))) {
$this->addFlash('error', 'Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
return $this->redirectToRoute('admin_theme');
}
$fonts = [];
foreach ($request->request->all('fonts') as $row) {
if (!is_array($row)) {
continue;
}
$row['weights'] = array_map('intval', (array) ($row['weights'] ?? []));
$fonts[] = $row;
}
try {
$this->theme->save($request->request->all('colors'), $fonts, $request->request->all('base'), $request->request->has('buttons') ? $request->request->all('buttons') : null);
} catch (InvalidPage $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('admin_theme');
}
$this->addFlash('success', 'Das Design wurde gespeichert. Es gilt sofort auf allen Seiten.');
return $this->redirectToRoute('admin_theme');
}
}