Rework forms, statistics, design and the sidebar foot in 1.15.0
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

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>
This commit is contained in:
kantarciandClaude Fable 5.1 committed 2026-09-15 07:59:30 +02:00
1 parent a4ee04533c
commit 160c394c3f
25 files changed
+1293 -278

No files matched your search

+39 -1
View File
@@ -85,12 +85,20 @@ final class Statistics
/**
* The numbers for a range of days, ending today.
*
* Neben den Reihen ein paar Summen, die eine Zahl einordnen: der gleich lange Zeitraum davor,
* der staerkste Tag, die Wochentage im Schnitt, wie viel ueber Verweise kam und wie oft eine
* Adresse ins Leere lief. Alles aus derselben Tabelle, nichts davon braucht ein Merkmal, das
* eine Person wiedererkennbar macht.
*
* @return array{
* days: list<array{day: string, count: int}>,
* total: int, pages: list<array{path: string, count: int}>,
* total: int, previousTotal: int, busiestDay: ?string,
* pages: list<array{path: string, count: int}>,
* referrers: list<array{host: string, count: int}>,
* missing: list<array{path: string, count: int}>,
* hours: list<array{hour: int, count: int}>,
* weekdays: list<array{weekday: int, count: int, average: float}>,
* missingTotal: int, referred: int, pageCount: int,
* range: int, from: string, compactedBefore: string, busiest: int
* }
*/
@@ -132,10 +140,40 @@ final class Statistics
$hours[(int) $row['hour']] = (int) $row['total'];
}
$sum = fn (string $extra): int => (int) $this->db->fetchOne(
'SELECT COALESCE(SUM(count), 0) FROM stat_hit WHERE '.$where.' '.$extra,
$params,
);
// Der gleich lange Zeitraum davor: erst der Vergleich macht aus einer Zahl eine Aussage.
$previousTotal = (int) $this->db->fetchOne(
'SELECT COALESCE(SUM(count), 0) FROM stat_hit WHERE website_id = ? AND day >= ? AND day < ? AND status = 200',
['default', $now->modify(sprintf('-%d days', 2 * $range - 1))->format('Y-m-d'), $from],
);
$weekdays = array_fill(1, 7, ['count' => 0, 'days' => 0]);
$busiestDay = null;
foreach ($days as $entry) {
$weekday = (int) (new \DateTimeImmutable($entry['day'], new \DateTimeZone('UTC')))->format('N');
$weekdays[$weekday]['count'] += $entry['count'];
++$weekdays[$weekday]['days'];
if ($entry['count'] > 0 && (null === $busiestDay || $entry['count'] > $perDay[$busiestDay])) {
$busiestDay = $entry['day'];
}
}
return [
'days' => $days,
'total' => array_sum(array_column($days, 'count')),
'previousTotal' => $previousTotal,
'busiest' => max(1, max(array_column($days, 'count'))),
'busiestDay' => $busiestDay,
'weekdays' => array_map(static fn (int $weekday): array => [
'weekday' => $weekday,
'count' => $weekdays[$weekday]['count'],
'average' => $weekdays[$weekday]['days'] > 0 ? round($weekdays[$weekday]['count'] / $weekdays[$weekday]['days'], 1) : 0.0,
], range(1, 7)),
'missingTotal' => $sum('AND status = 404'),
'referred' => $sum("AND status = 200 AND referrer_host <> ''"),
'pageCount' => (int) $this->db->fetchOne('SELECT COUNT(DISTINCT path) FROM stat_hit WHERE '.$where.' AND status = 200', $params),
'pages' => $rows('path', 'AND status = 200', 'path'),
'referrers' => $rows('referrer_host', "AND status = 200 AND referrer_host <> ''", 'referrer_host'),
'missing' => $rows('path', 'AND status = 404', 'path'),