feat: improved layout, removed htmx-boost for simplicity

This commit is contained in:
Björn Fromme
2025-01-25 14:59:09 +01:00
parent 6730c243f6
commit f9e7f28b6b
19 changed files with 95 additions and 209 deletions
+11
View File
@@ -0,0 +1,11 @@
import { Controller} from '@hotwired/stimulus'
export default class extends Controller {
static targets = [ 'indicator' ]
static classes = [ 'hidden' ]
toggle() {
this.indicatorTarget.classList.remove(this.hiddenClass)
}
}
@@ -82,8 +82,6 @@ class EditController extends AbstractController
$form = $this->createForm(BookingType::class, $formData, [
'attr' => ['novalidate' => 'novalidate'],
'hx_post' => $this->generateUrl('app_booking_edit', ['id' => $id]),
'hx_target' => '#myep',
]);
$form->handleRequest($request);
-18
View File
@@ -1,18 +0,0 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class IndexController extends AbstractController
{
#[Route('/', name: 'app_index')]
#[IsGranted('PUBLIC_ACCESS')]
public function index(): Response
{
return $this->render('index/index.html.twig');
}
}
@@ -34,8 +34,6 @@ class PersonalDataController extends AbstractController
$personalDataForm = $this->createForm(PersonalDataType::class, $personalData, [
'attr' => ['novalidate' => 'novalidate'],
'hx_post' => $this->generateUrl('app_personal_data'),
'hx_target' => '#myep',
]);
$personalDataForm->handleRequest($request);
+1 -1
View File
@@ -10,7 +10,7 @@ use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
#[Route('/login', name: 'app_login')]
#[Route('/', name: 'app_login')]
#[IsGranted('PUBLIC_ACCESS')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
-21
View File
@@ -1,21 +0,0 @@
<?php
namespace App\EventListener;
use App\Htmx\HxRedirectResponse;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Event\LogoutEvent;
#[AsEventListener(event: LogoutEvent::class, method: 'onLogout')]
class LogoutListener
{
public function __construct(private readonly UrlGeneratorInterface $urlGenerator)
{
}
public function onLogout(LogoutEvent $event): void
{
$event->setResponse(new HxRedirectResponse($this->urlGenerator->generate('app_index')));
}
}
@@ -1,50 +0,0 @@
<?php
namespace App\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class HtmxSubmitExtension extends AbstractTypeExtension
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'hx_post' => null,
'hx_target' => '#htmx-modal',
'hx_swap' => 'outerHTML',
'hx_indicator' => '#loading-indicator',
'hx_trigger' => null,
'hx_select' => null,
]);
}
public function buildView(FormView $view, FormInterface $form, array $options): void
{
if (null !== $options['hx_post']) {
$attr = [
'hx-post' => $options['hx_post'],
'hx-target' => $options['hx_target'],
'hx-swap' => $options['hx_swap'],
];
if (null !== $options['hx_indicator']) {
$attr['hx-indicator'] = $options['hx_indicator'];
}
if (null !== $options['hx_trigger']) {
$attr['hx-trigger'] = $options['hx_trigger'];
}
if (null !== $options['hx_select']) {
$attr['hx-select'] = $options['hx_select'];
}
$view->vars['attr'] = array_merge($view->vars['attr'], $attr);
}
}
public static function getExtendedTypes(): iterable
{
return [FormType::class];
}
}
-13
View File
@@ -1,13 +0,0 @@
<?php
namespace App\Htmx;
use Symfony\Component\HttpFoundation\Response;
class HxRedirectResponse extends Response
{
public function __construct(string $url)
{
return parent::__construct(null, Response::HTTP_OK, ['HX-Redirect' => $url]);
}
}
-13
View File
@@ -1,13 +0,0 @@
<?php
namespace App\Htmx;
use Symfony\Component\HttpFoundation\Response;
class HxTriggerResponse extends Response
{
public function __construct(string $content, string $trigger)
{
return parent::__construct($content, Response::HTTP_OK, ['HX-Trigger' => $trigger]);
}
}
+3
View File
@@ -24,12 +24,14 @@ class MenuBuilder
'route' => 'app_personal_data',
'linkAttributes' => [
'title' => 'Persönliche Daten',
'data-action' => 'loading#toggle',
],
]);
$menu->addChild('Meine Buchungen', [
'route' => 'app_bookings',
'linkAttributes' => [
'title' => 'Meine Buchungen',
'data-action' => 'loading#toggle',
],
'extras' => [
'routes' => [
@@ -41,6 +43,7 @@ class MenuBuilder
'route' => 'app_logout',
'linkAttributes' => [
'title' => 'Logout',
'data-action' => 'loading#toggle',
],
]);
@@ -0,0 +1,4 @@
<div class="invisible fixed top-0 left-0 inset-0 z-10 bg-white/90 flex items-center justify-center"
{{ stimulus_target('loading', 'indicator') }}>
{% include '_partials/_spinner.html.twig' with { 'class': 'w-8 h-8'} %}
</div>
+2 -2
View File
@@ -232,11 +232,11 @@
</div>
<div class="flex justify-between">
<a href="{{ path('app_bookings') }}"
class="button bg-button">
class="button bg-button" {{ stimulus_action('loading', 'toggle') }}>
zurück
</a>
<button type="submit"
class="button bg-button bg-button--secondary">
class="button bg-button bg-button--secondary" {{ stimulus_action('loading', 'toggle') }}>
Aktualisieren
</button>
</div>
+5 -2
View File
@@ -64,16 +64,19 @@
<div class="flex md:flex-col space-x-2 md:space-x-0 md:space-y-1">
{% if booking.editable %}
<a href="{{ path('app_booking_edit', { 'id': booking.id }) }}"
{{ stimulus_action('loading', 'toggle') }}
class="button bg-button bg-button--secondary button--small">
bearbeiten
</a>
{% endif %}
<a href="{{ path('app_booking_confirmation', { 'id': booking.id }) }}"
class="button bg-button button--small">
class="button bg-button button--small"
target="_blank" {{ stimulus_action('loading', 'toggle') }}>
Bestätigung
</a>
<a href="{{ path('app_booking_documents', { 'id': booking.id }) }}"
class="button bg-button button--small">
class="button bg-button button--small"
target="_blank" {{ stimulus_action('loading', 'toggle') }}>
Reisedokumente
</a>
</div>
-7
View File
@@ -1,7 +0,0 @@
{% extends 'base.html.twig' %}
{% block body %}
<div hx-get="{{ path('app_login') }}"
hx-trigger="load"
hx-swap="outerHTML"></div>
{% endblock %}
+17 -21
View File
@@ -1,23 +1,19 @@
<div class="my-16"
id="myep"
hx-boost="true"
hx-indicator="#loading-indicator">
<div class="fixed inset-x-0 top-0 z-20 flex items-center justify-between pb-4">
{% if is_granted('ROLE_USER') %}
<nav class="w-full bg-zinc-200 flex items-center mb-8 relative">
<div class="flex-1 block text-2xl px-4">My E&amp;P</div>
<div class="bg-zinc-200">
{{ knp_menu_render(knp_menu_get('main')) }}
</div>
</nav>
{% endif %}
</div>
<div id="content">
{% extends 'base.html.twig' %}
{% block body %}
<div class="{{ html_classes('pb-8', { 'pt-16': is_granted('ROLE_USER') }) }}" {{ stimulus_controller('loading', [], { 'hidden': 'invisible' }) }}>
<div class="fixed inset-x-0 top-0 z-20 flex items-center justify-between pb-4">
{% if is_granted('ROLE_USER') %}
<nav class="w-full bg-zinc-200 flex items-center mb-8 relative">
<div class="flex-1 block text-2xl px-4">My E&amp;P</div>
<div class="bg-zinc-200">
{{ knp_menu_render(knp_menu_get('main')) }}
</div>
</nav>
{% endif %}
</div>
{% block content %}{% endblock %}
{% include '_partials/_flashes.html.twig' %}
{% include '_partials/_loading_indicator.html.twig' %}
</div>
<div class="htmx-indicator fixed top-0 left-0 inset-0 z-10 bg-white/90 flex items-center justify-center"
id="loading-indicator">
{% include '_partials/_spinner.html.twig' with { 'class': 'w-8 h-8'} %}
</div>
{% include '_partials/_flashes.html.twig' %}
</div>
{% endblock %}
+9 -10
View File
@@ -6,7 +6,7 @@
<h2 class="text-2xl font-semibold pb-4">
Persönliche Daten
</h2>
{{ form_start(personalDataForm) }}
{{ form_start(personalDataForm, { 'attr': { 'data-action': 'loading#toggle' } }) }}
<div class="grid grid-cols-2 gap-x-8 gap-y-4 pb-4">
{{ form_row(personalDataForm.firstName) }}
{{ form_row(personalDataForm.name) }}
@@ -41,7 +41,7 @@
{{ form_end(personalDataForm) }}
</div>
<div>
<div>
<div id="newsletter">
<h2 class="text-2xl font-semibold pb-4">
Newsletter
</h2>
@@ -50,15 +50,14 @@
angemeldet.
</p>
<button type="button"
class="button bg-button bg-button--secondary"
class="relative button bg-button bg-button--secondary"
hx-post="{{ path('app_personal_data_newsletter') }}"
hx-target="#myep"
hx-swap="outerHTML">
{% if personalData.communication.newsletter %}
jetzt abmelden
{% else %}
jetzt anmelden
{% endif %}
hx-target="#newsletter"
hx-select="#newsletter"
hx-indicator="#button-indicator"
hx-swap="innerHTML">
{% if personalData.communication.newsletter %}jetzt abmelden{% else %}jetzt anmelden{% endif %}
<span class="htmx-indicator absolute top-0 left-0 inset-0 bg-secondary/80 flex items-center justify-center" id="button-indicator">{% include '_partials/_spinner.html.twig' with { 'class': 'w-6 h-6 text-white' } %}</span>
</button>
</div>
</div>
+10 -11
View File
@@ -4,24 +4,23 @@
<h1 class="mb-4">
Registrierung MyE&amp;P
</h1>
{{ form_start(form) }}
{{ form_start(form, { 'attr': { 'data-action': 'loading#toggle' } }) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 mb-4">
{{ form_row(form.firstName) }}
{{ form_row(form.name) }}
{{ form_row(form.email) }}
{{ form_row(form.gender) }}
<div>
{{ form_row(form.firstName) }}
{{ form_row(form.name) }}
{{ form_row(form.email) }}
{{ form_row(form.gender) }}
</div>
</div>
<div class="flex flex-col lg:flex-row space-y-2 lg:space-y-0 lg:space-x-2">
<button type="submit" class="button bg-button">
registrieren
</button>
<button type="button"
hx-get="{{ path('app_login') }}"
hx-target="#myep"
hx-swap="outerHTML"
class="button bg-button bg-button--secondary">
<a href="{{ path('app_login') }}"
class="button bg-button bg-button--secondary">
zum Login
</button>
</a>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
+26 -24
View File
@@ -1,24 +1,26 @@
{{ form_start(form) }}
{{ form_row(form.email) }}
<div class="flex flex-col lg:flex-row space-y-2 lg:space-y-0 lg:space-x-2 mt-4">
<button type="submit" class="button bg-button bg-button--secondary">
Passwort erneuern
</button>
<button type="button"
hx-get="{{ path('app_login') }}"
hx-target="#login-form"
hx-select="#login-form"
hx-swap="outerHTML"
class="button bg-button">
zum Login
</button>
<button type="button"
hx-get="{{ path('app_registration') }}"
hx-target="#myep"
hx-swap="outerHTML"
class="button bg-button">
registrieren
</button>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
{% extends 'layout.html.twig' %}
{% block content %}
<h1 class="mb-4">
Passwort vergessen
</h1>
{{ form_start(form, { 'attr': { 'data-action': 'loading#toggle' } }) }}
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 mb-4">
{{ form_row(form.email) }}
</div>
<div class="flex flex-col lg:flex-row space-y-2 lg:space-y-0 lg:space-x-2 mt-4">
<button type="submit" class="button bg-button">
Passwort erneuern
</button>
<a href="{{ path('app_login') }}"
class="button bg-button bg-button--secondary">
zum Login
</a>
<a href="{{ path('app_registration') }}"
class="button bg-button bg-button--secondary">
registrieren
</a>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
{% endblock %}
+7 -12
View File
@@ -14,7 +14,7 @@
<span class="flex-1 text-sm">{{ error.messageKey|trans(error.messageData, 'security') }}</span>
</div>
{% endif %}
<form action="{{ path('app_login') }}" method="post">
<form action="{{ path('app_login') }}" method="post" {{ stimulus_action('loading', 'toggle') }}>
<div class="mb-4">
<label for="username" class="mb-1 font-semibold">
E-Mail:
@@ -52,19 +52,14 @@
<button type="submit" class="button bg-button">
Login
</button>
<button type="button"
hx-get="{{ path('app_reset_password') }}"
hx-target="#login-form"
class="button bg-button bg-button--secondary">
<a href="{{ path('app_reset_password') }}"
class="button bg-button bg-button--secondary">
Passwort vergessen?
</button>
<button type="button"
hx-get="{{ path('app_registration') }}"
hx-target="#myep"
hx-swap="outerHTML"
class="button bg-button bg-button--secondary">
</a>
<a href="{{ path('app_registration') }}"
class="button bg-button bg-button--secondary">
registrieren
</button>
</a>
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
</form>