feat: wrap game in centered card, style abandon button, abandon anonymous game on login

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thibaud-leclere
2026-03-30 19:55:32 +02:00
parent 96adefbb1e
commit 2f5ba701b6
3 changed files with 71 additions and 15 deletions

View File

@@ -487,19 +487,34 @@ body {
color: #16a34a;
}
/* ── Game card ── */
.game-container {
max-width: fit-content;
margin: 56px auto;
padding: 24px 32px 32px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: 0 4px 32px var(--shadow-warm);
}
.game-container #actors {
margin: 16px auto 0;
}
/* ── Game actions ── */
.game-actions {
display: flex;
justify-content: flex-end;
padding: 12px 40px 0;
justify-content: flex-start;
}
.btn-abandon {
padding: 7px 16px;
background: none;
color: var(--text-muted);
border: 1.5px solid var(--border);
color: #dc2626;
border: 1.5px solid #dc2626;
border-radius: 100px;
font-family: 'Inter', sans-serif;
font-size: 13px;

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\EventListener;
use App\Entity\Game;
use App\Repository\GameRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
#[AsEventListener]
class AbandonAnonymousGameOnLoginListener
{
public function __construct(
private readonly GameRepository $gameRepository,
private readonly EntityManagerInterface $em,
) {}
public function __invoke(LoginSuccessEvent $event): void
{
$session = $event->getRequest()->getSession();
$gameId = $session->get('current_game_id');
if (!$gameId) {
return;
}
$game = $this->gameRepository->find($gameId);
if ($game && $game->getStatus() === Game::STATUS_IN_PROGRESS) {
$game->abandon();
$this->em->flush();
}
$session->remove('current_game_id');
}
}

View File

@@ -2,18 +2,20 @@
{% block body %}
{% if game %}
<div class="game-actions">
<form method="post" action="{{ path('app_game_abandon', {id: game.id}) }}">
<input type="hidden" name="_token" value="{{ csrf_token('game_abandon') }}">
<button type="submit" class="btn btn-abandon">Abandonner</button>
</form>
</div>
<div class="game-container">
<div class="game-actions">
<form method="post" action="{{ path('app_game_abandon', {id: game.id}) }}">
<input type="hidden" name="_token" value="{{ csrf_token('game_abandon') }}">
<button type="submit" class="btn btn-abandon">Abandonner</button>
</form>
</div>
<div {{ react_component('GameGrid', {
grid: grid,
width: width,
middle: middle,
}) }}></div>
<div {{ react_component('GameGrid', {
grid: grid,
width: width,
middle: middle,
}) }}></div>
</div>
{% else %}
<div class="game-start-container">
<form method="post" action="{{ path('app_game_start') }}">