feat: improved layout, removed htmx-boost for simplicity
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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&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&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 %}
|
||||
@@ -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>
|
||||
|
||||
@@ -4,24 +4,23 @@
|
||||
<h1 class="mb-4">
|
||||
Registrierung MyE&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) }}
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user