Design system refactor: shared CSS tokens, cleaner customer/admin pages, kiosk name privacy, v0.9.1
This commit is contained in:
parent
2f5050b29f
commit
cc27c5db48
10 changed files with 1490 additions and 1224 deletions
|
|
@ -7,127 +7,35 @@
|
|||
{% if refresh_seconds and refresh_seconds > 0 %}
|
||||
<meta http-equiv="refresh" content="{{ refresh_seconds }}">
|
||||
{% endif %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@500;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/booth.css') }}">
|
||||
<style>
|
||||
/*
|
||||
Operator dashboard queue.
|
||||
Shows all requests in a table with status filters, per-row Open/Delete
|
||||
actions, a Settings link, auto-refresh hint, and logout.
|
||||
*/
|
||||
body{
|
||||
font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
|
||||
background:#111827;
|
||||
color:#f3f4f6;
|
||||
margin:0;
|
||||
padding:1rem;
|
||||
line-height:1.5;
|
||||
}
|
||||
.container{max-width:1100px;margin:0 auto;}
|
||||
h1{color:#60a5fa;margin-top:0;}
|
||||
.filters{margin-bottom:1rem;display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;}
|
||||
.filters a{
|
||||
color:#93c5fd;
|
||||
text-decoration:none;
|
||||
padding:.35rem .7rem;
|
||||
border-radius:.4rem;
|
||||
border:1px solid transparent;
|
||||
}
|
||||
.filters a:hover{background:#1f2937;}
|
||||
.filters a.active{
|
||||
font-weight:bold;
|
||||
color:#fff;
|
||||
background:#2563eb;
|
||||
border-color:#2563eb;
|
||||
}
|
||||
table{
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
background:#1f2937;
|
||||
border-radius:.5rem;
|
||||
overflow:hidden;
|
||||
}
|
||||
th,td{padding:.7rem;text-align:left;border-bottom:1px solid #374151;}
|
||||
th{background:#111827;color:#9ca3af;}
|
||||
tr:hover{background:#2d3748;}
|
||||
.status-badge{
|
||||
display:inline-block;
|
||||
padding:.25rem .6rem;
|
||||
border-radius:9999px;
|
||||
font-size:.8rem;
|
||||
font-weight:600;
|
||||
background:#374151;
|
||||
}
|
||||
.awaiting_payment{background:#f59e0b;color:#000;}
|
||||
.paid,.delivered{background:#10b981;color:#000;}
|
||||
.pending,.prompt_ready{background:#60a5fa;color:#000;}
|
||||
.songs_uploaded{background:#a78bfa;color:#000;}
|
||||
.revisions_requested{background:#f87171;color:#000;}
|
||||
.actions a{
|
||||
color:#93c5fd;
|
||||
text-decoration:none;
|
||||
margin-right:.8rem;
|
||||
}
|
||||
.actions button.delete{
|
||||
background:transparent;
|
||||
color:#f87171;
|
||||
border:none;
|
||||
padding:0;
|
||||
cursor:pointer;
|
||||
font:inherit;
|
||||
text-decoration:none;
|
||||
margin-right:.8rem;
|
||||
}
|
||||
.logout{float:right;color:#f87171;text-decoration:none;}
|
||||
.flash{
|
||||
padding:.8rem;
|
||||
background:#064e3b;
|
||||
border-radius:.5rem;
|
||||
margin-bottom:1rem;
|
||||
}
|
||||
.flash.error{background:#450a0a;}
|
||||
|
||||
/* Topbar with Settings and Log out link */
|
||||
.topbar{
|
||||
float:right;
|
||||
display:flex;
|
||||
gap:.75rem;
|
||||
align-items:center;
|
||||
}
|
||||
.topbar form{display:inline;}
|
||||
.topbar a{
|
||||
color:#93c5fd;
|
||||
text-decoration:none;
|
||||
}
|
||||
.topbar a.settings{
|
||||
color:#10b981;
|
||||
}
|
||||
|
||||
.refresh-hint{
|
||||
color:#6b7280;
|
||||
font-size:.85rem;
|
||||
margin-left:auto;
|
||||
}
|
||||
.dashboard-table td { white-space: nowrap; }
|
||||
.dashboard-table td.wrap { white-space: normal; max-width: 220px; }
|
||||
.dashboard-table .id-cell { font-family: var(--font-mono); font-weight: 700; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Topbar: Kiosk, Pricing, Sales, Settings, Log out -->
|
||||
<body class="booth-page">
|
||||
<div class="container container-wide">
|
||||
<div class="topbar">
|
||||
<a href="{{ url_for('kiosk') }}" target="_blank" rel="noopener noreferrer">Kiosk</a>
|
||||
<a href="{{ url_for('admin_pricing') }}">Pricing</a>
|
||||
<a href="{{ url_for('admin_sales') }}">Sales</a>
|
||||
<a href="{{ url_for('admin_settings') }}" class="settings">Settings</a>
|
||||
<a href="{{ url_for('admin_logout') }}" class="logout">Log out</a>
|
||||
<h1>Theme Song Booth — Admin Dashboard</h1>
|
||||
<div class="nav">
|
||||
<a href="{{ url_for('kiosk') }}" target="_blank" rel="noopener noreferrer">Kiosk</a>
|
||||
<a href="{{ url_for('admin_pricing') }}">Pricing</a>
|
||||
<a href="{{ url_for('admin_sales') }}">Sales</a>
|
||||
<a href="{{ url_for('admin_settings') }}" class="text-success" style="font-weight:700">Settings</a>
|
||||
<a href="{{ url_for('admin_logout') }}" class="text-danger">Log out</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Theme Song Booth — Admin Dashboard</h1>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% for category, message in messages %}
|
||||
<div class="flash {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- Status filter links -->
|
||||
<div class="filters">
|
||||
<a href="{{ url_for('admin_dashboard') }}" class="{% if current_status in (None, '') %}active{% endif %}">All</a>
|
||||
<a href="{{ url_for('admin_dashboard', status='pending') }}" class="{% if current_status == 'pending' %}active{% endif %}">Pending</a>
|
||||
|
|
@ -135,7 +43,7 @@
|
|||
<a href="{{ url_for('admin_dashboard', status='awaiting_payment') }}" class="{% if current_status == 'awaiting_payment' %}active{% endif %}">Awaiting Payment</a>
|
||||
<a href="{{ url_for('admin_dashboard', status='delivered') }}" class="{% if current_status == 'delivered' %}active{% endif %}">Delivered</a>
|
||||
<form method="POST" action="{{ url_for('admin_musicgpt_refresh') }}" style="display:inline;margin-left:auto">
|
||||
<button type="submit" class="secondary" style="margin:0;padding:.35rem .7rem;font-weight:600;background:#4b5563">Refresh MusicGPT Status</button>
|
||||
<button type="submit" class="button-secondary" style="padding:var(--space-1) var(--space-3);font-size:0.85rem">Refresh MusicGPT Status</button>
|
||||
</form>
|
||||
<span class="refresh-hint">
|
||||
{% if refresh_seconds and refresh_seconds > 0 %}
|
||||
|
|
@ -146,41 +54,60 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Requests table -->
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Genre</th>
|
||||
<th>Status</th>
|
||||
<th>Approved</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in requests %}
|
||||
<tr>
|
||||
<td>#{{ r.id }}</td>
|
||||
<td>{{ r.name }}</td>
|
||||
<td>{{ r.email }}</td>
|
||||
<td>{{ r.style_genre or '-' }}</td>
|
||||
<td><span class="status-badge {{ r.status }}">{{ statuses[r.status] }}</span></td>
|
||||
<td>{% if r.customer_approved and r.customer_approved != 'none' %}{{ (r.customer_approved or 'none').upper() }}{% else %}-{% endif %}</td>
|
||||
<td class="actions">
|
||||
<a href="{{ url_for('admin_request', rid=r.id) }}">Open</a>
|
||||
<form method="POST" action="{{ url_for('admin_delete_request', rid=r.id) }}" style="display:inline" onsubmit="return confirm('ARE YOU SURE you want to delete request #{{ r.id }} for {{ r.name }}? This cannot be undone.')">
|
||||
<button type="submit" class="delete">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if not requests %}
|
||||
<tr><td colspan="7">No requests found.</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="table-wrap">
|
||||
<table class="dashboard-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Genre</th>
|
||||
<th>Status</th>
|
||||
<th>Approved</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in requests %}
|
||||
<tr>
|
||||
<td class="id-cell">#{{ r.id }}</td>
|
||||
<td class="wrap">{{ r.name }}</td>
|
||||
<td class="wrap">{{ r.email }}</td>
|
||||
<td class="wrap">{{ r.style_genre or '-' }}</td>
|
||||
<td><span class="status-badge {{ r.status }}">{{ statuses[r.status] }}</span></td>
|
||||
<td>{% if r.customer_approved and r.customer_approved != 'none' %}{{ (r.customer_approved or 'none').upper() }}{% else %}-<{% endif %}</td>
|
||||
<td class="table-actions">
|
||||
<a href="{{ url_for('admin_request', rid=r.id) }}" class="button">Open</a>
|
||||
{% if r.status in ('pending', 'revisions_requested') %}
|
||||
<a href="{{ url_for('admin_request', rid=r.id) }}#prompt" class="button-secondary">Prompt</a>
|
||||
{% endif %}
|
||||
{% if r.status == 'prompt_ready' and not r.musicgpt_status %}
|
||||
<form method="POST" action="{{ url_for('admin_request', rid=r.id) }}" style="display:inline">
|
||||
<input type="hidden" name="action" value="generate_musicgpt">
|
||||
<button type="submit" class="button-secondary" style="font-size:0.8rem">Generate</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if r.status == 'songs_uploaded' and r.customer_approved == 'none' %}
|
||||
<form method="POST" action="{{ url_for('admin_request', rid=r.id) }}" style="display:inline">
|
||||
<input type="hidden" name="action" value="notify_customer">
|
||||
<button type="submit" class="button-secondary" style="font-size:0.8rem">Send Preview</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if r.status == 'awaiting_payment' %}
|
||||
<a href="{{ url_for('admin_request', rid=r.id) }}#delivery" class="button-secondary">Deliver</a>
|
||||
{% endif %}
|
||||
<form method="POST" action="{{ url_for('admin_delete_request', rid=r.id) }}" style="display:inline" onsubmit="return confirm('ARE YOU SURE you want to delete request #{{ r.id }} for {{ r.name }}? This cannot be undone.')">
|
||||
<button type="submit" class="button-danger" style="font-size:0.8rem">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if not requests %}
|
||||
<tr><td colspan="7" style="text-align:center;color:var(--text-muted);padding:var(--space-8)">No requests found.</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue