2 Commits
Author SHA1 Message Date
Frank 98cf48b29d Make admin panel usable on mobile
The sidebar was a fixed 220px flex column that left barely any room
for content on a phone, and tables had no min-width so columns just
squeezed into unreadable slivers instead of scrolling.

Moves the sidebar's layout rules out of inline styles (which media
queries can't override) into real CSS classes, and collapses it into
a horizontally-scrollable pill bar below 768px so the content area
gets the full screen width. Tables now get a sensible min-width so
they scroll horizontally on narrow screens instead of squishing, and
the per-player tab bar on the session log view scrolls too.
2026-08-10 14:58:12 +02:00
Frank f6df9f7ba6 Show friendly session status labels on the player dashboard
Players saw the raw enum value (e.g. "created") in the sessions
table, which doesn't mean anything to them. Adds SessionStatus::label()
mapping each status to a player-facing description like "Waiting for
players".
2026-08-10 14:58:01 +02:00
8 changed files with 112 additions and 29 deletions
+11
View File
@@ -9,4 +9,15 @@ enum SessionStatus: string
case PLAYING = 'playing';
case WON = 'won';
case LOST = 'lost';
public function label(): string
{
return match ($this) {
self::CREATED => 'Waiting for players',
self::READY => 'Waiting for players to be ready',
self::PLAYING => 'In progress',
self::WON => 'Completed - Won',
self::LOST => 'Completed - Lost',
};
}
}
+93 -23
View File
@@ -1,23 +1,99 @@
{% extends 'layout/site.html.twig' %}
{% block stylesheets %}
{{ parent() }}
<style>
.admin-shell {
display: flex;
min-height: calc(100vh - 60px);
}
.admin-sidebar {
width: 220px;
flex-shrink: 0;
background: #1e293b;
color: #cbd5e1;
display: flex;
flex-direction: column;
}
.admin-sidebar-title {
padding: 1.25rem 1.5rem;
border-bottom: 1px solid #334155;
font-weight: 700;
font-size: 1rem;
color: #f1f5f9;
}
.admin-nav-list {
list-style: none;
margin: 0;
padding: 0.5rem 0;
flex: 1;
}
.admin-nav-link {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.6rem 1.5rem;
text-decoration: none;
font-size: 0.9rem;
}
.admin-sidebar-footer {
padding: 1rem 1.5rem;
border-top: 1px solid #334155;
}
.admin-main {
flex: 1;
min-width: 0;
background: #f8fafc;
padding: 2rem;
overflow-x: auto;
}
@media (max-width: 767.98px) {
.admin-shell {
flex-direction: column;
min-height: auto;
}
.admin-sidebar {
width: 100%;
flex-direction: row;
flex-wrap: wrap;
}
.admin-sidebar-title {
border-bottom: none;
padding: 0.75rem 1rem 0.25rem;
}
.admin-nav-list {
display: flex;
flex: 0 0 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding: 0.25rem 0.5rem 0.75rem;
gap: 0.25rem;
}
.admin-nav-link {
flex-shrink: 0;
white-space: nowrap;
padding: 0.5rem 0.9rem;
border-radius: 6px;
}
.admin-sidebar-footer {
display: none;
}
.admin-main {
padding: 1rem;
}
}
</style>
{% endblock %}
{% block main %}
<div style="display: flex; min-height: calc(100vh - 60px);">
<div class="admin-shell">
{# ── Sidebar ──────────────────────────────────────────────────────── #}
<nav style="
width: 220px;
flex-shrink: 0;
background: #1e293b;
color: #cbd5e1;
display: flex;
flex-direction: column;
padding: 0;
">
<div style="padding: 1.25rem 1.5rem; border-bottom: 1px solid #334155;">
<span style="font-weight: 700; font-size: 1rem; color: #f1f5f9;">Game Admin</span>
</div>
<nav class="admin-sidebar">
<div class="admin-sidebar-title">Game Admin</div>
<ul style="list-style: none; margin: 0; padding: 0.5rem 0; flex: 1;">
<ul class="admin-nav-list">
{% set current = app.request.attributes.get('_route') %}
{% set navItems = [
@@ -31,15 +107,9 @@
{% for item in navItems %}
{% set isActive = current starts with item.route %}
<li>
<a href="{{ path(item.route) }}" style="
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.6rem 1.5rem;
<a href="{{ path(item.route) }}" class="admin-nav-link" style="
color: {{ isActive ? '#f1f5f9' : '#94a3b8' }};
background: {{ isActive ? '#334155' : 'transparent' }};
text-decoration: none;
font-size: 0.9rem;
border-left: 3px solid {{ isActive ? '#3b82f6' : 'transparent' }};
">
<span>{{ item.icon }}</span>
@@ -49,7 +119,7 @@
{% endfor %}
</ul>
<div style="padding: 1rem 1.5rem; border-top: 1px solid #334155;">
<div class="admin-sidebar-footer">
<a href="{{ path('game_dashboard') }}" style="color: #64748b; font-size: 0.8rem; text-decoration: none;">
← Back to game
</a>
@@ -57,7 +127,7 @@
</nav>
{# ── Content ──────────────────────────────────────────────────────── #}
<main style="flex: 1; background: #f8fafc; padding: 2rem; overflow-x: auto;">
<main class="admin-main">
{% for label, messages in app.flashes %}
{% for message in messages %}
<div style="
@@ -9,7 +9,7 @@
</div>
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); overflow: hidden;">
<table style="width: 100%; border-collapse: collapse; font-size: 0.9rem;">
<table style="width: 100%; min-width: 620px; border-collapse: collapse; font-size: 0.9rem;">
<thead>
<tr style="background: #f1f5f9; border-bottom: 1px solid #e2e8f0;">
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">ID</th>
+1 -1
View File
@@ -9,7 +9,7 @@
</div>
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); overflow: hidden;">
<table style="width: 100%; border-collapse: collapse; font-size: 0.9rem;">
<table style="width: 100%; min-width: 620px; border-collapse: collapse; font-size: 0.9rem;">
<thead>
<tr style="background: #f1f5f9; border-bottom: 1px solid #e2e8f0;">
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">ID</th>
@@ -9,7 +9,7 @@
</div>
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); overflow: hidden;">
<table style="width: 100%; border-collapse: collapse; font-size: 0.9rem;">
<table style="width: 100%; min-width: 700px; border-collapse: collapse; font-size: 0.9rem;">
<thead>
<tr style="background: #f1f5f9; border-bottom: 1px solid #e2e8f0;">
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">ID</th>
+3 -1
View File
@@ -16,12 +16,14 @@
</div>
{% else %}
{# Tab buttons #}
<div style="display: flex; gap: 0; margin-bottom: 0; border-bottom: 1px solid #e2e8f0;">
<div style="display: flex; gap: 0; margin-bottom: 0; border-bottom: 1px solid #e2e8f0; overflow-x: auto; -webkit-overflow-scrolling: touch;">
{% for playerLog in playersLogs %}
<button
onclick="openTab('player-{{ loop.index }}')"
id="tab-{{ loop.index }}"
style="
flex-shrink: 0;
white-space: nowrap;
padding: 0.6rem 1.25rem;
border: 1px solid {{ loop.first ? '#3b82f6' : '#e2e8f0' }};
border-bottom: {{ loop.first ? '1px solid #fff' : '1px solid #e2e8f0' }};
+1 -1
View File
@@ -9,7 +9,7 @@
</div>
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); overflow: hidden;">
<table style="width: 100%; border-collapse: collapse; font-size: 0.9rem;">
<table style="width: 100%; min-width: 760px; border-collapse: collapse; font-size: 0.9rem;">
<thead>
<tr style="background: #f1f5f9; border-bottom: 1px solid #e2e8f0;">
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">ID</th>
+1 -1
View File
@@ -67,7 +67,7 @@
<tr>
<td>{{ session.id }}</td>
<td>{{ session.game.name }}</td>
<td><span class="badge bg-info text-dark">{{ session.status.value }}</span></td>
<td><span class="badge bg-info text-dark">{{ session.status.label }}</span></td>
<td>{{ session.created|date('Y-m-d H:i') }}</td>
<td>
{% set inviteCode = '' %}