Compare commits

...

2 commits

Author SHA1 Message Date
Barely Removable
4b56f1fba9 Bump to v1.3.0 for deploy
All checks were successful
Deploy / deploy (push) Successful in 29s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 23:03:35 -07:00
Barely Removable
bd292fbe32 Rebuild request rows to match indexer rows
The Requests and Indexers cards sit side by side but read as two
unrelated lists: requests led with a type badge, indexers with a status
dot, and the rows drifted out of alignment once the share bar landed.

Give a request row the same anatomy as an indexer row — status dot,
title over a dimmed detail line, badge on the right — folding the type
into the detail line and mapping request status onto the existing
dot colours (a new .warn light covers pending). Both row types now
share a --row-h floor so the two cards line up row for row; the share
bar's top margin is trimmed so an indexer row reaches that height
without overshooting it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 23:02:36 -07:00
4 changed files with 22 additions and 6 deletions

2
app.py
View file

@ -20,7 +20,7 @@ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Docker tab caches stale container IDs, so the footer is the reliable way # Docker tab caches stale container IDs, so the footer is the reliable way
# to confirm a `docker compose up -d --build` actually took effect. # to confirm a `docker compose up -d --build` actually took effect.
# Both are env-overridable if the deploy pipeline ever injects them. # Both are env-overridable if the deploy pipeline ever injects them.
APP_VERSION = os.environ.get("APP_VERSION", "1.2.0") APP_VERSION = os.environ.get("APP_VERSION", "1.3.0")
APP_VERSION_DATE = os.environ.get("APP_VERSION_DATE", "2026-08-26") APP_VERSION_DATE = os.environ.get("APP_VERSION_DATE", "2026-08-26")
# Must point at a path that survives `docker compose up --build` — the # Must point at a path that survives `docker compose up --build` — the

View file

@ -48,6 +48,7 @@
--radius: 10px; --radius: 10px;
--radius-sm: 7px; --radius-sm: 7px;
--tap: 44px; /* minimum touch target */ --tap: 44px; /* minimum touch target */
--row-h: 4.25rem; /* paired Requests / Indexers row height */
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

View file

@ -71,6 +71,7 @@ header {
} }
.status-light.up { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-dim); } .status-light.up { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-dim); }
.status-light.down { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-dim); } .status-light.down { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-dim); }
.status-light.warn { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-dim); }
.header-right { .header-right {
order: 2; order: 2;
@ -442,6 +443,7 @@ dd.is-accent { color: var(--accent); }
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.7rem; gap: 0.7rem;
min-height: var(--row-h);
padding: 0.6rem 0.7rem; padding: 0.6rem 0.7rem;
background: var(--surface-2); background: var(--surface-2);
border: 1px solid var(--border); border: 1px solid var(--border);
@ -458,9 +460,11 @@ dd.is-accent { color: var(--accent); }
.indexer-sub { font-size: var(--fs-xs); color: var(--text-3); } .indexer-sub { font-size: var(--fs-xs); color: var(--text-3); }
.indexer-sub .proto { text-transform: capitalize; } .indexer-sub .proto { text-transform: capitalize; }
.indexer-sub:empty::before { content: "Indexer"; } .indexer-sub:empty::before { content: "Indexer"; }
/* Share of grabs, scaled to the busiest indexer (see dashboard.html) */ /* Share of grabs, scaled to the busiest indexer (see dashboard.html).
The margin is trimmed so a bar-carrying row still fits inside --row-h
and stays flush with the request rows beside it. */
.share-bar { .share-bar {
margin-top: 0.35rem; margin-top: 0.3rem;
height: 4px; height: 4px;
border-radius: 100px; border-radius: 100px;
background: var(--surface); background: var(--surface);
@ -482,17 +486,24 @@ dd.is-accent { color: var(--accent); }
} }
/* ── Requests (Ombi) ────────────────────────────────── */ /* ── Requests (Ombi) ────────────────────────────────── */
/* Request rows are the same object as an indexer row — same geometry and
the same dot/title/sub/badge anatomy — so the two cards read across as
one pair. --row-h keeps them aligned line-for-line; the indexer rows
reach it naturally once their share bar is in. */
.req-list { display: flex; flex-direction: column; gap: 0.5rem; } .req-list { display: flex; flex-direction: column; gap: 0.5rem; }
.req-item.is-hidden { display: none; } .req-item.is-hidden { display: none; }
.req-item { .req-item {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.7rem; gap: 0.7rem;
min-height: var(--row-h);
padding: 0.6rem 0.7rem; padding: 0.6rem 0.7rem;
background: var(--surface-2); background: var(--surface-2);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
} }
.req-item .status-light { width: 9px; height: 9px; flex-shrink: 0; }
.req-type { text-transform: capitalize; }
.badge { .badge {
font-size: var(--fs-xs); font-size: var(--fs-xs);
font-weight: 600; font-weight: 600;

View file

@ -347,13 +347,17 @@
{% if ombi.recent %} {% if ombi.recent %}
<div class="req-list" id="req-list"> <div class="req-list" id="req-list">
{% for req in ombi.recent %} {% for req in ombi.recent %}
{# Same anatomy as an indexer row: status dot, name over a
dimmed detail line, status badge on the right. #}
{% set st = req.status | lower %}
<div class="req-item {{ 'is-hidden' if loop.index > 5 }}"> <div class="req-item {{ 'is-hidden' if loop.index > 5 }}">
<span class="badge {{ 'movie' if req.type == 'Movie' else 'tv' }}">{{ req.type }}</span> <span class="status-light {{ 'up' if st in ('available', 'approved')
else ('down' if st == 'denied' else 'warn') }}"></span>
<div class="req-info"> <div class="req-info">
<div class="req-title">{{ req.title }}</div> <div class="req-title">{{ req.title }}</div>
<div class="req-sub">{{ req.user }} · {{ req.date_display }}</div> <div class="req-sub"><span class="req-type">{{ req.type }}</span> · {{ req.user }} · {{ req.date_display }}</div>
</div> </div>
<span class="badge {{ req.status | lower }}">{{ req.status }}</span> <span class="badge {{ st }}">{{ req.status }}</span>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>