Let menu entries appear as buttons with icon, colours and phone placement
The menu editor gets "Als Button darstellen" per entry: shape, appearance and size from the button design, fill and ink with hover and palette, icon colour, icon from the dialog, motion, icon-only and where the button sits on the phone (in the opened menu, beside the burger, or there as an icon only). Colours go into the page stylesheet under a stable per-button id because the CSP forbids inline styles. ADR 110. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
48ae2443cd
commit
13f6759df8
22 files changed
+623
-14
No files matched your search
@@ -405,6 +405,38 @@ final class EditorSecurityTest extends WebTestCase
|
||||
self::assertSame(['/', '/#kontakt', 'https://hausklar.app'], $public->extract(['href']));
|
||||
}
|
||||
|
||||
/**
|
||||
* ADR 110: Ein Menüeintrag wird über das Formular zum Button - mit Gestalt, Farben, Symbol,
|
||||
* Bewegung und Anzeige auf dem Telefon. Die Kennung für die Farbregel entsteht beim ersten
|
||||
* Speichern und bleibt danach gleich; leere Felder heißen Website-Standard und fehlen.
|
||||
*/
|
||||
public function testMenuFormTurnsAnEntryIntoAButtonAndKeepsItsId(): void
|
||||
{
|
||||
$client = $this->login('publisher');
|
||||
$crawler = $client->request('GET', '/admin/menus');
|
||||
$token = $crawler->filter('.menu-form input[name="_csrf_token"]')->first()->attr('value');
|
||||
$row = ['position' => 10, 'level' => 1, 'label' => 'Angebot anfragen', 'type' => 'url', 'url' => '#kontakt',
|
||||
'icon' => 'arrow-right', 'iconPosition' => 'after', 'button' => '1', 'buttonId' => '', 'buttonShape' => 'pill', 'buttonAppearance' => '',
|
||||
'buttonSize' => '', 'buttonFill' => '#b71c22', 'buttonInk' => '', 'buttonHoverFill' => '@ink', 'buttonHoverInk' => '', 'buttonIconColor' => '',
|
||||
'iconMotion' => 'slide', 'buttonMobile' => 'bar'];
|
||||
$client->request('POST', '/admin/menus/header', ['_csrf_token' => $token, 'name' => 'Hauptnavigation', 'expectedVersion' => 0, 'items' => [$row]]);
|
||||
self::assertResponseRedirects('/admin/menus');
|
||||
$button = json_decode($this->db->fetchOne('SELECT items FROM menu WHERE slot = ?', ['header']), true)[0]['button'];
|
||||
self::assertMatchesRegularExpression('/^m[a-f0-9]{10}$/', $button['id']);
|
||||
self::assertSame(['shape' => 'pill', 'fill' => '#b71c22', 'hoverFill' => '@ink', 'mobile' => 'bar', 'iconMotion' => 'slide'], array_diff_key($button, ['id' => true]));
|
||||
|
||||
// Die Verwaltung zeigt die Werte wieder an, und erneutes Speichern behält die Kennung.
|
||||
$crawler = $client->request('GET', '/admin/menus');
|
||||
self::assertSame($button['id'], $crawler->filter('input[data-key="buttonId"]')->attr('value'));
|
||||
self::assertSame('pill', $crawler->filter('select[data-key="buttonShape"] option[selected]')->attr('value'));
|
||||
$client->request('POST', '/admin/menus/header', ['_csrf_token' => $token, 'name' => 'Hauptnavigation', 'expectedVersion' => 1, 'items' => [[...$row, 'buttonId' => $button['id']]]]);
|
||||
self::assertSame($button['id'], json_decode($this->db->fetchOne('SELECT items FROM menu WHERE slot = ?', ['header']), true)[0]['button']['id']);
|
||||
|
||||
// Ohne Häkchen ist es wieder ein Link.
|
||||
$client->request('POST', '/admin/menus/header', ['_csrf_token' => $token, 'name' => 'Hauptnavigation', 'expectedVersion' => 2, 'items' => [array_diff_key($row, ['button' => true])]]);
|
||||
self::assertArrayNotHasKey('button', json_decode($this->db->fetchOne('SELECT items FROM menu WHERE slot = ?', ['header']), true)[0]);
|
||||
}
|
||||
|
||||
public function testMenuWritesNeedAPublisherRoleACsrfTokenAndTheCurrentVersion(): void
|
||||
{
|
||||
$menus = new MenuRepository($this->db, new SiteSettings($this->db, new MediaLibrary($this->db, $this->path.'-media')));
|
||||
|
||||
Reference in new issue
Block a user