users index page
parent
5c3f8dbd6a
commit
834ca1b272
@ -0,0 +1,178 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>👥 Users</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background:#111; color:#eee; }
|
||||
a { color:#4af; text-decoration:none; }
|
||||
.header { display:flex; gap:12px; align-items:center; justify-content:center; margin:18px 0; flex-wrap:wrap; }
|
||||
input[type="text"] { padding:8px; width:280px; }
|
||||
select, button { padding:8px 12px; background:#222; color:#eee; border:1px solid #444; }
|
||||
|
||||
.grid { width:92%; margin:0 auto; display:grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap:14px; }
|
||||
|
||||
/* Make thumb take full card height */
|
||||
.card {
|
||||
background:#1a1a1a; border:1px solid #333; border-radius:8px; padding:10px;
|
||||
display:grid; grid-template-columns: 180px 1fr; gap:12px; align-items:stretch;
|
||||
min-height: 120px;
|
||||
}
|
||||
.thumb {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 120px;
|
||||
background:#222; border:1px solid #333; border-radius:6px; overflow:hidden;
|
||||
}
|
||||
.thumb img, .thumb .fallback {
|
||||
position:absolute; inset:0;
|
||||
width:100%; height:100%;
|
||||
object-fit:cover; display:block;
|
||||
}
|
||||
.thumb .fallback { display:none; align-items:center; justify-content:center; font-size:28px; }
|
||||
|
||||
.meta { display:flex; flex-direction:column; gap:6px; }
|
||||
.meta h3 { margin:0; font-size:16px; display:flex; align-items:center; gap:6px; }
|
||||
.muted { color:#bbb; }
|
||||
.row { font-size:14px; }
|
||||
|
||||
.status-dot { display:inline-block; width:10px; height:10px; border-radius:50%; vertical-align:middle; }
|
||||
.dot-online { background:#22c55e; }
|
||||
.dot-record { background:#ef4444; }
|
||||
.dot-offline { background:#666; }
|
||||
|
||||
.pagination { margin:16px 0; text-align:center; }
|
||||
.pagination a, .pagination span { display:inline-block; background:#222; color:#eee; border:1px solid #444; margin:0 5px; padding:6px 12px; text-decoration:none; }
|
||||
.pagination .active { background:#555; }
|
||||
.toolbar { display:flex; gap:10px; align-items:center; justify-content:center; flex-wrap:wrap; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// If an <img> fails, hide it and show the next candidate; if none left, show the fallback emoji.
|
||||
function tryNext(el) {
|
||||
el.style.display = 'none';
|
||||
let sib = el.nextElementSibling;
|
||||
while (sib && sib.tagName !== 'IMG' && !(sib.classList && sib.classList.contains('fallback'))) {
|
||||
sib = sib.nextElementSibling;
|
||||
}
|
||||
if (!sib) return;
|
||||
if (sib.tagName === 'IMG') {
|
||||
sib.style.display = 'block';
|
||||
} else {
|
||||
sib.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>👥 Users</h1>
|
||||
|
||||
<div class="header">
|
||||
<!-- Search -->
|
||||
<form method="get" action="{{ url_for('web.users') }}" class="toolbar">
|
||||
<input type="text" name="q" placeholder="Search users..." value="{{ query or '' }}">
|
||||
<input type="hidden" name="sort" value="{{ sort }}">
|
||||
<input type="hidden" name="dir" value="{{ dir }}">
|
||||
<input type="hidden" name="timeframe" value="{{ timeframe }}">
|
||||
<input type="hidden" name="start" value="{{ start_date or '' }}">
|
||||
<input type="hidden" name="end" value="{{ end_date or '' }}">
|
||||
<button type="submit">Search</button>
|
||||
</form>
|
||||
|
||||
<!-- Sort -->
|
||||
{% set next_user_dir = 'asc' if sort != 'user' or dir == 'desc' else 'desc' %}
|
||||
{% set next_site_dir = 'asc' if sort != 'site' or dir == 'desc' else 'desc' %}
|
||||
{% set next_total_dir = 'asc' if sort != 'total_size_display' or dir == 'desc' else 'desc' %}
|
||||
{% set next_count_dir = 'asc' if sort != 'video_count' or dir == 'desc' else 'desc' %}
|
||||
|
||||
<div class="toolbar">
|
||||
<a href="{{ url_for('web.users', q=query, page=1, sort='user', dir=next_user_dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: User{% if sort=='user' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
||||
<a href="{{ url_for('web.users', q=query, page=1, sort='site', dir=next_site_dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: Site{% if sort=='site' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
||||
<a href="{{ url_for('web.users', q=query, page=1, sort='total_size_display', dir=next_total_dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: Total Size{% if sort=='total_size_display' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
||||
<a href="{{ url_for('web.users', q=query, page=1, sort='video_count', dir=next_count_dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: Videos{% if sort=='video_count' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
||||
|
||||
<!-- Online-first toggle -->
|
||||
<a href="{{ url_for('web.users', q=query, page=1, sort=sort, dir=dir, online=('0' if online=='1' else '1'), timeframe=timeframe, start=start_date, end=end_date) }}">
|
||||
{{ '📶 Show online (ON)' if online=='1' else '📶 Show online (OFF)' }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Timeframe -->
|
||||
<form method="get" action="{{ url_for('web.users') }}" class="toolbar">
|
||||
<label>Timeframe:</label>
|
||||
<select name="timeframe" onchange="this.form.submit()">
|
||||
<option value="all" {{ 'selected' if timeframe=='all' else '' }}>All time</option>
|
||||
<option value="week" {{ 'selected' if timeframe=='week' else '' }}>This week</option>
|
||||
<option value="month" {{ 'selected' if timeframe=='month' else '' }}>Last 30 days</option>
|
||||
<option value="year" {{ 'selected' if timeframe=='year' else '' }}>Last 365 days</option>
|
||||
<option value="custom"{{ 'selected' if timeframe=='custom' else '' }}>Custom…</option>
|
||||
</select>
|
||||
<input type="date" name="start" value="{{ start_date or '' }}" placeholder="Start" />
|
||||
<input type="date" name="end" value="{{ end_date or '' }}" placeholder="End" />
|
||||
<input type="hidden" name="q" value="{{ query or '' }}">
|
||||
<input type="hidden" name="sort" value="{{ sort }}">
|
||||
<input type="hidden" name="dir" value="{{ dir }}">
|
||||
<input type="hidden" name="online" value="{{ online }}">
|
||||
<button type="submit">Apply</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
{% for c in cards %}
|
||||
<div class="card">
|
||||
<div class="thumb">
|
||||
{% if c.thumb_urls and c.thumb_urls|length %}
|
||||
{# render all candidates; show first, hide the rest; each tries the next on error #}
|
||||
{% for url in c.thumb_urls %}
|
||||
<img src="{{ url }}" loading="lazy" decoding="async" alt="{{ c.user }}" {% if not loop.first %}style="display:none"{% endif %} onerror="tryNext(this)">
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<span class="fallback">🎞️</span>
|
||||
</div>
|
||||
|
||||
<div class="meta">
|
||||
<h3>
|
||||
<a href="{{ url_for('web.user_page', username=c.user) }}">{{ c.user }}</a>
|
||||
{% if c.is_online %}
|
||||
<span class="status-dot dot-online" title="Online"></span>
|
||||
{% elif c.is_recording_offline %}
|
||||
<span class="status-dot dot-record" title="Recording (offline)"></span>
|
||||
{% else %}
|
||||
<span class="status-dot dot-offline" title="Offline"></span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<div class="row">
|
||||
<span class="muted">Site:</span>
|
||||
<a href="https://{{ c.site }}.com/{{ c.user }}" target="_blank" rel="noopener">{{ c.site }}</a>
|
||||
</div>
|
||||
<div class="row"><span class="muted">Total size:</span> {{ c.total_size_display }} GB</div>
|
||||
<div class="row"><span class="muted">Videos:</span> {{ c.video_count }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if total_pages > 1 %}
|
||||
<div class="pagination">
|
||||
{% if page > 1 %}
|
||||
<a href="{{ url_for('web.users', page=page-1, q=query, sort=sort, dir=dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">« Prev</a>
|
||||
{% else %}<span>« Prev</span>{% endif %}
|
||||
|
||||
{% for p in range(1, total_pages + 1) %}
|
||||
{% if p == page %}
|
||||
<span class="active">{{ p }}</span>
|
||||
{% else %}
|
||||
<a href="{{ url_for('web.users', page=p, q=query, sort=sort, dir=dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">{{ p }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page < total_pages %}
|
||||
<a href="{{ url_for('web.users', page=page+1, q=query, sort=sort, dir=dir, online=online, timeframe=timeframe, start=start_date, end=end_date) }}">Next »</a>
|
||||
{% else %}<span>Next »</span>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue