05/24 Fix UI/UX

This commit is contained in:
2026-05-24 17:59:24 -04:00
parent 07e0ae02c2
commit 6605484927
8 changed files with 154 additions and 24 deletions
+2 -2
View File
@@ -40,7 +40,7 @@
<tbody>
{% for row in activity_rows %}
<tr>
<td class="text-muted nowrap">{{ row.created_at.strftime('%Y-%m-%d %H:%M:%S') if row.created_at else '—' }}</td>
<td class="text-muted nowrap"><span data-ts="{{ row.created_at.isoformat() if row.created_at else '' }}" title="{{ row.created_at.strftime('%Y-%m-%d %H:%M:%S') if row.created_at else '' }}">{{ row.created_at.strftime('%Y-%m-%d %H:%M:%S') if row.created_at else '—' }}</span></td>
<td>{{ row.username or '—' }}</td>
<td><code class="action-badge">{{ row.action }}</code></td>
<td class="text-muted">{{ row.entity or '' }} {% if row.entity_id %}#{{ row.entity_id }}{% endif %}</td>
@@ -68,7 +68,7 @@
<tbody>
{% for row in app_rows %}
<tr class="log-{{ row.level | lower }}">
<td class="text-muted nowrap">{{ row.logged_at.strftime('%Y-%m-%d %H:%M:%S') if row.logged_at else '—' }}</td>
<td class="text-muted nowrap"><span data-ts="{{ row.logged_at.isoformat() if row.logged_at else '' }}" title="{{ row.logged_at.strftime('%Y-%m-%d %H:%M:%S') if row.logged_at else '' }}">{{ row.logged_at.strftime('%Y-%m-%d %H:%M:%S') if row.logged_at else '—' }}</span></td>
<td><span class="badge badge-log-{{ row.level | lower }}">{{ row.level }}</span></td>
<td class="text-muted">{{ row.logger_name }}</td>
<td class="log-message">{{ row.message }}</td>
+5 -1
View File
@@ -139,7 +139,11 @@
</td>
</tr>
{% else %}
<tr><td colspan="4" class="text-center text-muted" style="padding:1rem">No history yet.</td></tr>
<tr><td colspan="{{ 5 if is_admin else 4 }}" style="padding:2.5rem 1rem;text-align:center">
<div style="font-size:2rem;margin-bottom:.5rem">🤖</div>
<p class="text-muted" style="margin:0 0 .75rem">No analyses yet. Upload a document above to get started.</p>
<button class="btn btn-primary btn-sm" onclick="document.getElementById('ai-files').scrollIntoView({behavior:'smooth'});document.getElementById('ai-files').focus()">Start Analyzing</button>
</td></tr>
{% endfor %}
</tbody>
</table>
+4
View File
@@ -9,6 +9,10 @@
</head>
<body class="layout">
<!-- Mobile sidebar toggle (hidden on desktop via CSS) -->
<button class="sidebar-toggle" id="sidebar-toggle" aria-label="Open navigation"></button>
<div class="sidebar-backdrop" id="sidebar-backdrop"></div>
<!-- Sidebar -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-brand">
+40 -4
View File
@@ -164,6 +164,9 @@
var _activeBidId = null;
var _activeStatus = '';
var _allBids = []; // cached from last load
var _bidOffset = 0;
var _hasMore = false;
var _PAGE_SIZE = 50;
var _currentUserId = {{ session['user']['id'] }};
var _isAdmin = {{ 'true' if session['user']['role'] == 'admin' else 'false' }};
@@ -189,12 +192,21 @@ var STATUS_BADGE = {
Load / render bid list
══════════════════════════════════════════════════════════ */
function loadBids() {
fetch('/bids/list/json?status=' + encodeURIComponent(_activeStatus))
_bidOffset = 0;
_allBids = [];
_hasMore = false;
_fetchBids(false);
}
function _fetchBids(append) {
fetch('/bids/list/json?status=' + encodeURIComponent(_activeStatus) + '&offset=' + _bidOffset)
.then(function(r) { return r.json(); })
.then(function(bids) {
_allBids = bids;
renderBidList(bids);
// Restore selection
if (!Array.isArray(bids)) return;
_allBids = append ? _allBids.concat(bids) : bids;
_bidOffset += bids.length;
_hasMore = bids.length >= _PAGE_SIZE;
renderBidList(_allBids);
if (_activeBidId) {
var row = document.querySelector('.bt-row[data-id="' + _activeBidId + '"]');
if (row) row.classList.add('active');
@@ -220,21 +232,42 @@ function renderBidList(bids) {
return;
}
var today = new Date(); today.setHours(0, 0, 0, 0);
list.innerHTML = filtered.map(function(b) {
var due = b.due_date ? b.due_date.slice(0, 10) : '—';
var badge = STATUS_BADGE[b.status] || 'badge-muted';
var label = STATUS_LABELS[b.status] || b.status;
var active = b.id === _activeBidId ? ' active' : '';
var upds = b.update_count || 0;
var urgencyBadge = '';
if (b.due_date) {
var dueD = new Date(b.due_date.slice(0, 10)); dueD.setHours(0, 0, 0, 0);
var diff = Math.round((dueD - today) / 86400000);
if (diff < 0) {
urgencyBadge = '<span class="badge badge-danger badge-sm">Overdue</span>';
} else if (diff <= 7) {
urgencyBadge = '<span class="badge badge-warning badge-sm">Due Soon</span>';
}
}
return '<div class="bt-row' + active + '" data-id="' + b.id + '" onclick="selectBid(' + b.id + ')">'
+ '<div class="bt-row-title">' + esc(b.title) + '</div>'
+ '<div class="bt-row-meta">'
+ '<span class="badge ' + badge + ' badge-sm">' + label + '</span>'
+ '<span class="text-muted text-xs">Due: ' + due + '</span>'
+ urgencyBadge
+ (upds ? '<span class="text-muted text-xs">💬 ' + upds + '</span>' : '')
+ '</div>'
+ '</div>';
}).join('');
if (_hasMore && !q) {
list.innerHTML += '<div class="bt-load-more">'
+ '<button class="btn btn-secondary btn-sm" onclick="_fetchBids(true)">Load more…</button>'
+ '</div>';
}
}
/* ══════════════════════════════════════════════════════════
@@ -533,6 +566,9 @@ loadBids();
.bt-upd-body{font-size:.875rem;color:var(--text-secondary);line-height:1.6;
white-space:pre-wrap}
/* ── Load more ─────────────────────────────────────────────── */
.bt-load-more{padding:.75rem 1rem;text-align:center;border-top:1px solid var(--border)}
@media(max-width:900px){
.bt-layout{grid-template-columns:1fr;grid-template-rows:auto auto}
.bt-right{min-height:300px}