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.
104 lines
6.2 KiB
Twig
104 lines
6.2 KiB
Twig
{% extends 'game/admin/base.html.twig' %}
|
|
|
|
{% block title %}Users — Admin{% endblock %}
|
|
|
|
{% block admin_body %}
|
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem;">
|
|
<h1 style="margin: 0; font-size: 1.5rem; color: #0f172a;">Users</h1>
|
|
<span style="color: #64748b; font-size: 0.9rem;">{{ users|length }} total · {{ marketingOptInCount }} opted in to marketing</span>
|
|
</div>
|
|
|
|
<div style="background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.07); overflow: hidden;">
|
|
<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>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Username</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Email</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Roles</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Verified</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Marketing</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Last Login</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Status</th>
|
|
<th style="padding: 0.75rem 1rem; text-align: left; color: #475569; font-weight: 600;">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for user in users %}
|
|
<tr style="border-bottom: 1px solid #f1f5f9;">
|
|
<td style="padding: 0.75rem 1rem; color: #94a3b8;">{{ user.id }}</td>
|
|
<td style="padding: 0.75rem 1rem; font-weight: 500; color: #0f172a;">{{ user.username }}</td>
|
|
<td style="padding: 0.75rem 1rem; color: #475569;">{{ user.email }}</td>
|
|
<td style="padding: 0.75rem 1rem;">
|
|
{% for role in user.roles %}
|
|
{% if role != 'ROLE_USER' %}
|
|
<span style="
|
|
display: inline-block;
|
|
padding: 0.15rem 0.5rem;
|
|
border-radius: 4px;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
background: {{ role == 'ROLE_ADMIN' ? '#fef3c7' : '#ede9fe' }};
|
|
color: {{ role == 'ROLE_ADMIN' ? '#92400e' : '#5b21b6' }};
|
|
margin-right: 2px;
|
|
">{{ role }}</span>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</td>
|
|
<td style="padding: 0.75rem 1rem;">
|
|
{% if user.verified %}
|
|
<span style="color: #16a34a; font-weight: 500;">✓ Yes</span>
|
|
{% else %}
|
|
<span style="color: #dc2626;">✗ No</span>
|
|
{% endif %}
|
|
</td>
|
|
<td style="padding: 0.75rem 1rem;">
|
|
{% if user.marketingOptIn %}
|
|
<span style="color: #16a34a; font-weight: 500;">✓ Yes</span>
|
|
{% else %}
|
|
<span style="color: #dc2626;">✗ No</span>
|
|
{% endif %}
|
|
</td>
|
|
<td style="padding: 0.75rem 1rem; color: #475569;">
|
|
{{ user.lastLoginAt ? user.lastLoginAt|date('Y-m-d H:i') : 'Never' }}
|
|
</td>
|
|
<td style="padding: 0.75rem 1rem;">
|
|
{% if user.deleted %}
|
|
<span style="color: #dc2626; font-weight: 500;">Deleted</span>
|
|
{% else %}
|
|
<span style="color: #16a34a; font-weight: 500;">Active</span>
|
|
{% endif %}
|
|
</td>
|
|
<td style="padding: 0.75rem 1rem;">
|
|
<a href="{{ path('game_admin_user_edit', {id: user.id}) }}" style="
|
|
color: #3b82f6;
|
|
text-decoration: none;
|
|
font-size: 0.85rem;
|
|
margin-right: 0.75rem;
|
|
">Edit</a>
|
|
|
|
{% if user != app.user and not user.deleted %}
|
|
<form method="post" action="{{ path('game_admin_user_delete', {id: user.id}) }}" style="display: inline;" onsubmit="return confirm('Delete user {{ user.username }}?')">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('delete_user_' ~ user.id) }}">
|
|
<button type="submit" style="
|
|
background: none;
|
|
border: none;
|
|
color: #ef4444;
|
|
cursor: pointer;
|
|
font-size: 0.85rem;
|
|
padding: 0;
|
|
">Delete</button>
|
|
</form>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="9" style="padding: 2rem; text-align: center; color: #94a3b8;">No users found.</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% endblock %}
|