feat: complete UI redesign with DaisyUI + Tailwind CSS v4
Design system overhaul using DaisyUI v5 on Tailwind CSS v4: - Custom 'ohmstream' dark theme with orange primary (#FF9F1C), magenta secondary, gold accent matching existing palette - Tailwind CSS-first config (input.css source, style.css built output) - DaisyUI components: navbar, drawer, cards, badges, alerts, tables, progress bars, tabs, toggles, stats, form controls, tooltips - Mobile-first responsive layout with drawer navigation - Eliminated ~500+ lines of embedded CSS across 15+ template files - Removed all inline style spam from admin_panel and settings_section - Preserved all HTMX triggers, Alpine.js state, and Jinja2 logic - Updated auth-ui.js for DaisyUI tab-active class compatibility Build: npm run build:css (minified) / npm run watch:css (dev)
This commit is contained in:
@@ -1,85 +1,89 @@
|
||||
<div class="settings-container section-container">
|
||||
<div class="section-header">
|
||||
<h2>Administration</h2>
|
||||
<div class="mb-10">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-xl font-bold">Administration</h2>
|
||||
</div>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div id="admin-stats" class="admin-stats-grid" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 15px; margin-bottom: 30px;">
|
||||
<div class="admin-stat-card" style="padding: 20px; background: var(--bg-card); border-radius: var(--card-radius); border: 1px solid #2a2d32;text-align: center;">
|
||||
<div style="font-size: 2rem; font-weight: 800; color: var(--primary);" id="stat-total-users">{{ users|length }}</div>
|
||||
<div style="color: var(--text-dim); font-size: 0.85rem;">Utilisateurs</div>
|
||||
<div class="stats stats-vertical md:stats-horizontal shadow w-full mb-6">
|
||||
<div class="stat bg-base-200 border border-base-300 rounded-box">
|
||||
<div class="stat-title">Utilisateurs</div>
|
||||
<div class="stat-value text-primary">{{ users|length }}</div>
|
||||
</div>
|
||||
<div class="admin-stat-card" style="padding: 20px; background: var(--bg-card); border-radius: var(--card-radius); border: 1px solid #2a2d32;text-align: center;">
|
||||
<div style="font-size: 2rem; font-weight: 800; color: var(--accent);" id="stat-active-users">{{ users|selectattr('is_active')|list|length }}</div>
|
||||
<div style="color: var(--text-dim); font-size: 0.85rem;">Actifs</div>
|
||||
<div class="stat bg-base-200 border border-base-300 rounded-box">
|
||||
<div class="stat-title">Actifs</div>
|
||||
<div class="stat-value text-secondary">{{ users|selectattr('is_active')|list|length }}</div>
|
||||
</div>
|
||||
<div class="admin-stat-card" style="padding: 20px; background: var(--bg-card); border-radius: var(--card-radius); border: 1px solid #2a2d32;text-align: center;">
|
||||
<div style="font-size: 2rem; font-weight: 800; color: #f0a500;" id="stat-admin-users">{{ users|selectattr('is_admin')|list|length }}</div>
|
||||
<div style="color: var(--text-dim); font-size: 0.85rem;">Admins</div>
|
||||
<div class="stat bg-base-200 border border-base-300 rounded-box">
|
||||
<div class="stat-title">Admins</div>
|
||||
<div class="stat-value text-warning">{{ users|selectattr('is_admin')|list|length }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Users Table -->
|
||||
<div style="background: var(--bg-card); border-radius: var(--card-radius); border: 1px solid #2a2d32;overflow: hidden;">
|
||||
<div style="padding: 20px 25px; border-bottom: 1px solid #2a2d32;">
|
||||
<h3 style="margin: 0; color: var(--primary);">Gestion des utilisateurs</h3>
|
||||
<div class="bg-base-200 border border-base-300 rounded-box overflow-hidden">
|
||||
<div class="px-6 py-5 border-b border-base-300">
|
||||
<h3 class="font-bold text-primary m-0">Gestion des utilisateurs</h3>
|
||||
</div>
|
||||
|
||||
{% if users %}
|
||||
<div style="overflow-x: auto;">
|
||||
<table style="width: 100%; border-collapse: collapse;">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr style="border-bottom: 1px solid #2a2d32;">
|
||||
<th style="padding: 12px 20px; text-align: left; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Utilisateur</th>
|
||||
<th style="padding: 12px 15px; text-align: left; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Email</th>
|
||||
<th style="padding: 12px 15px; text-align: center; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Statut</th>
|
||||
<th style="padding: 12px 15px; text-align: center; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Role</th>
|
||||
<th style="padding: 12px 15px; text-align: left; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Derniere connexion</th>
|
||||
<th style="padding: 12px 15px; text-align: left; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Inscription</th>
|
||||
<th style="padding: 12px 20px; text-align: center; color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase;">Actions</th>
|
||||
<tr>
|
||||
<th>Utilisateur</th>
|
||||
<th>Email</th>
|
||||
<th class="text-center">Statut</th>
|
||||
<th class="text-center">Role</th>
|
||||
<th>Derniere connexion</th>
|
||||
<th>Inscription</th>
|
||||
<th class="text-center">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr style="border-bottom: 1px solid #2a2d32; {% if not user.is_active %}opacity: 0.5;{% endif %}">
|
||||
<td style="padding: 12px 20px;">
|
||||
<div style="font-weight: 600;">{{ user.username }}</div>
|
||||
<tr class="{% if not user.is_active %}opacity-50{% endif %}">
|
||||
<td>
|
||||
<div class="font-semibold">{{ user.username }}</div>
|
||||
{% if user.full_name %}
|
||||
<div style="font-size: 0.8rem; color: var(--text-dim);">{{ user.full_name }}</div>
|
||||
<div class="text-xs text-base-content/50">{{ user.full_name }}</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding: 12px 15px; color: var(--text-dim); font-size: 0.9rem;">{{ user.email or '-' }}</td>
|
||||
<td style="padding: 12px 15px; text-align: center;">
|
||||
<span style="display: inline-block; padding: 3px 10px; border-radius: 4px; font-size: 0.75rem; font-weight: 600; background: {% if user.is_active %}rgba(45,147,108,0.1); color: #2d936c{% else %}rgba(230,57,70,0.1); color: #e63946{% endif %};">
|
||||
{% if user.is_active %}Actif{% else %}Inactif{% endif %}
|
||||
</span>
|
||||
<td class="text-base-content/60 text-sm">{{ user.email or '-' }}</td>
|
||||
<td class="text-center">
|
||||
{% if user.is_active %}
|
||||
<span class="badge badge-success badge-sm">Actif</span>
|
||||
{% else %}
|
||||
<span class="badge badge-error badge-sm">Inactif</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding: 12px 15px; text-align: center;">
|
||||
<span style="display: inline-block; padding: 3px 10px; border-radius: 4px; font-size: 0.75rem; font-weight: 600; background: {% if user.is_admin %}rgba(244,162,97,0.15); color: #f4a261{% else %}var(--bg-elevated); color: var(--text-dim){% endif %};">
|
||||
{% if user.is_admin %}Admin{% else %}User{% endif %}
|
||||
</span>
|
||||
<td class="text-center">
|
||||
{% if user.is_admin %}
|
||||
<span class="badge badge-primary badge-sm">Admin</span>
|
||||
{% else %}
|
||||
<span class="badge badge-ghost badge-sm">User</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding: 12px 15px; color: var(--text-dim); font-size: 0.85rem;">
|
||||
<td class="text-base-content/50 text-sm">
|
||||
{{ user.last_login.strftime('%d/%m/%Y %H:%M') if user.last_login else '-' }}
|
||||
</td>
|
||||
<td style="padding: 12px 15px; color: var(--text-dim); font-size: 0.85rem;">
|
||||
<td class="text-base-content/50 text-sm">
|
||||
{{ user.created_at.strftime('%d/%m/%Y') if user.created_at else '-' }}
|
||||
</td>
|
||||
<td style="padding: 12px 20px; text-align: center; white-space: nowrap;">
|
||||
<td class="text-center whitespace-nowrap">
|
||||
{% if user.id != current_user.id %}
|
||||
<button class="btn btn-sm {% if user.is_active %}btn-secondary{% else %}btn-accent{% endif %}"
|
||||
<button class="btn btn-xs {% if user.is_active %}btn-ghost{% else %}btn-success{% endif %}"
|
||||
hx-put="/api/admin/users/{{ user.id }}/toggle-active" hx-swap="none"
|
||||
hx-on::after-request="htmx.ajax('GET', '/api/admin/ui', {target: '#admin-panel-content'})"
|
||||
title="{% if user.is_active %}Desactiver{% else %}Activer{% endif %}">
|
||||
{% if user.is_active %}Desactiver{% else %}Activer{% endif %}
|
||||
</button>
|
||||
<button class="btn btn-sm {% if user.is_admin %}btn-secondary{% else %}btn-accent{% endif %}"
|
||||
<button class="btn btn-xs {% if user.is_admin %}btn-ghost{% else %}btn-success{% endif %}"
|
||||
hx-put="/api/admin/users/{{ user.id }}/toggle-admin" hx-swap="none"
|
||||
hx-on::after-request="htmx.ajax('GET', '/api/admin/ui', {target: '#admin-panel-content'})"
|
||||
title="{% if user.is_admin %}Retrograder{% else %}Promouvoir{% endif %}">
|
||||
{% if user.is_admin %}Retrograder{% else %}Admin{% endif %}
|
||||
</button>
|
||||
<button class="btn btn-sm btn-danger"
|
||||
<button class="btn btn-xs btn-error"
|
||||
hx-delete="/api/admin/users/{{ user.id }}" hx-swap="none"
|
||||
hx-confirm="Supprimer {{ user.username }} ?"
|
||||
hx-on::after-request="htmx.ajax('GET', '/api/admin/ui', {target: '#admin-panel-content'})"
|
||||
@@ -87,7 +91,7 @@
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
{% else %}
|
||||
<span style="color: var(--text-dim); font-size: 0.8rem;">Vous</span>
|
||||
<span class="text-base-content/40 text-xs">Vous</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -96,7 +100,7 @@
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="padding: 40px; text-align: center; color: var(--text-dim);">Aucun utilisateur</div>
|
||||
<div class="p-10 text-center text-base-content/40">Aucun utilisateur</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user