Fix design-review findings: self-linking nav, colour reuse, badge clash
All checks were successful
Deploy / deploy (push) Successful in 24s
All checks were successful
Deploy / deploy (push) Successful in 24s
From a frontend-design skill review of all pages, after last session's chrome changes (top nav, all-tabs nav, header download row): - The top/closing fastext nav now mutes the entry matching the current page (.fastext-here) instead of rendering a link to the page you're already on. - Colour in fastext is reserved for the four entries that still carry a real keyboard shortcut (r/g/y/c); the other four render in plain ink instead of reusing k-red/k-green/k-yellow/k-cyan for a destination they don't semantically mean (e.g. Requests no longer shows in the app's own off-air red). - Discover's badge slot meant "critic score" on its RT tiles and "release year" on its new search tiles at the same time. Search results (Library and Discover) now fold year/held-state into the sub-line instead, leaving the badge exclusively for critic score. - System's Transmission rows now carry a small ↗ glyph, since they silently changed from in-app navigation to opening each service's own UI in a new tab with no visual cue. - SABnzbd polling drops from 5s to 20s on pages that only show the header's download figure (everywhere but System/Activity, which keep 5s for their own live figures) — a number idle 95% of the time doesn't need second-level freshness sitewide. - DESIGN.md's fastext description, now-current per this session's nav changes.
This commit is contained in:
parent
d672c3f02d
commit
59beb9490f
9 changed files with 45 additions and 15 deletions
|
|
@ -107,7 +107,12 @@ the user's Unraid home server. Server-side project directory is still named
|
|||
with `HOME_FASTEXT`, the original four-entry row, as its own closing
|
||||
line, since its body already lists every destination once. Only
|
||||
those original four (Index/Library/Discover/System) carry an `r`/
|
||||
`g`/`y`/`c` keyboard shortcut; the rest are click-only.
|
||||
`g`/`y`/`c` keyboard shortcut and a colour swatch — colour is
|
||||
semantic everywhere else in this app, so the other four entries
|
||||
render in plain ink rather than reusing one of the four colours for
|
||||
a destination it doesn't mean. Whichever entry matches the current
|
||||
page renders as a `.fastext-here` span instead of a link — a page
|
||||
linking to itself did nothing, so it isn't offered as a click.
|
||||
- **Nothing is clipped, hidden, or sticky.** All seven page numbers and
|
||||
every fastext entry stay visible at every width, reflowing to another
|
||||
row rather than scrolling, truncating, or folding into a menu. No
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ components:
|
|||
|
||||
Media Centre is a broadcast information service, not a dashboard. It refuses the bordered-card grid that every self-hosted *arr dashboard ships — including this one, until this redesign. The world is teletext: Ceefax and the American cable guide channel, fused. Eight colours at full saturation on pure black, one blocky monospace at exactly two heights, a character-cell grid, and grouping carried entirely by colour fields and row weight. The visitor types or clicks a page number, reads the machine's state off colour alone, and leaves knowing whether anything needs them.
|
||||
|
||||
The density is high and unapologetic. A teletext page was 40 columns; this one gets 92 (`--page-cols: 92ch`) because the screen allows it, but the character grid is the substrate everywhere — padding is measured in `ch`, bars are measured in cells, and nothing floats free of the row rhythm (`--row`, one character row). There is no chrome. The header is a row of the page, not furniture bolted above it, so it scrolls away with everything else. The fastext colour keys sit at the bottom of the page where they always sat, not fixed to the viewport.
|
||||
The density is high and unapologetic. A teletext page was 40 columns; this one gets 92 (`--page-cols: 92ch`) because the screen allows it, but the character grid is the substrate everywhere — padding is measured in `ch`, bars are measured in cells, and nothing floats free of the row rhythm (`--row`, one character row). There is no chrome. The header is a row of the page, not furniture bolted above it, so it scrolls away with everything else. The fastext keys sit at the top of every page but the index — which closes with them instead, since its own body already is the full nav — never fixed to the viewport.
|
||||
|
||||
The confirmed anti-reference is the world this replaced and every dashboard that shares its reflexes: the rounded, bordered, drop-shadowed card grid with a neutral dark-grey palette and a soft accent. Nothing here is enclosed. There is not one `border-radius` and not one `box-shadow` in the codebase — the single `text-shadow` is a phosphor bloom, and it is spent deliberately. Emphasis is bought with colour and with doubled height, never with a weight ramp, never with a third type size, never with a container.
|
||||
|
||||
|
|
|
|||
15
app.py
15
app.py
|
|
@ -1304,17 +1304,20 @@ def service_urls():
|
|||
|
||||
|
||||
# Every destination, for the top of every page but the index. Order
|
||||
# matches nav_items; the four letter keys keep the destinations they
|
||||
# always had, cycling colour for the rest since only four exist.
|
||||
# matches nav_items. Colour is semantic everywhere else in this app
|
||||
# (red = off-air, magenta = needs a decision, ...), so only the four
|
||||
# that still carry a real teletext keyboard shortcut (r/g/y/c) get a
|
||||
# colour swatch; the rest render in plain ink rather than borrowing
|
||||
# one of the four colours for a destination it doesn't mean.
|
||||
FULL_FASTEXT = [
|
||||
("k-red", "r", "100", "Index", "/"),
|
||||
("k-cyan", "", "101", "Watch", "/watch"),
|
||||
("", "", "101", "Watch", "/watch"),
|
||||
("k-green", "g", "102", "Library", "/library"),
|
||||
("k-yellow", "y", "103", "Discover", "/discover"),
|
||||
("k-red", "", "104", "Requests", "/requests"),
|
||||
("", "", "104", "Requests", "/requests"),
|
||||
("k-cyan", "c", "105", "System", "/system"),
|
||||
("k-green", "", "106", "Activity", "/activity"),
|
||||
("k-yellow", "", "900", "Settings", "/settings"),
|
||||
("", "", "106", "Activity", "/activity"),
|
||||
("", "", "900", "Settings", "/settings"),
|
||||
]
|
||||
|
||||
# The index's own closing row: just the four letter keys, since the
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); }
|
|||
text-transform: uppercase;
|
||||
min-width: 11ch;
|
||||
}
|
||||
/* Marks a row that leaves the app (System's Transmission links to each
|
||||
service's own UI) — everywhere else a .tt-row stays inside Media
|
||||
Centre, so leaving needs its own quiet signal. */
|
||||
.tt-row-ext { color: var(--ink-dim); }
|
||||
.tt-row-body { flex: 1; min-width: 0; }
|
||||
.tt-row-title {
|
||||
overflow-wrap: anywhere;
|
||||
|
|
@ -494,7 +498,7 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); }
|
|||
.fastext-top {
|
||||
margin: var(--row) auto calc(var(--row) * 1.5);
|
||||
}
|
||||
.fastext a {
|
||||
.fastext a, .fastext-here {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
|
|
@ -510,18 +514,25 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); }
|
|||
}
|
||||
/* The key's colour is carried by a solid cell at its head — the
|
||||
physical coloured button on the remote. */
|
||||
.fastext a > span {
|
||||
.fastext a > span, .fastext-here > span {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.fastext a::before {
|
||||
.fastext a::before, .fastext-here::before {
|
||||
content: "";
|
||||
flex: 0 0 auto;
|
||||
width: 1.2ch;
|
||||
height: 1em;
|
||||
background: currentColor;
|
||||
}
|
||||
/* The page you're already on: present for orientation, same shape as
|
||||
its neighbours, but not a link — clicking your own destination did
|
||||
nothing useful, so now it isn't offered as a click at all. */
|
||||
.fastext-here {
|
||||
color: var(--ink-dim);
|
||||
cursor: default;
|
||||
}
|
||||
.fastext .k-red { color: var(--alert); }
|
||||
.fastext .k-green { color: var(--ok); }
|
||||
.fastext .k-yellow { color: var(--voice); }
|
||||
|
|
|
|||
|
|
@ -199,8 +199,11 @@
|
|||
.catch(function () { /* as above */ });
|
||||
}
|
||||
|
||||
/* Second-accurate only where the page shows the full figures
|
||||
(System, Activity); everywhere else it's a header glance at a
|
||||
number that's idle most of the time, so it can poll slower. */
|
||||
pollSab();
|
||||
setInterval(pollSab, 5000);
|
||||
setInterval(pollSab, document.getElementById('sab-queue') ? 5000 : 20000);
|
||||
if (document.getElementById('tt-streams')) {
|
||||
pollTautulli();
|
||||
setInterval(pollTautulli, 15000);
|
||||
|
|
|
|||
|
|
@ -58,9 +58,13 @@ provenance.
|
|||
{% set fastext_nav %}
|
||||
<nav class="fastext{{ '' if page == 'home' else ' fastext-top' }}" aria-label="Fastext">
|
||||
{% for cls, key, num, label, href in fastext %}
|
||||
{% if num == here[1] %}
|
||||
<span class="fastext-here" aria-current="page"><span>{{ num }} {{ label }}</span></span>
|
||||
{% else %}
|
||||
<a class="{{ cls }}" href="{{ request.script_root }}{{ href }}" data-key="{{ key }}">
|
||||
<span>{{ num }} {{ label }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</nav>
|
||||
{% endset %}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@
|
|||
{{ service_error('Sonarr/Radarr', search.error) }}
|
||||
{% elif search.results %}
|
||||
<div class="tt-tiles">
|
||||
{#- No badge here: the badge slot means "critic score" below,
|
||||
from the RT feed. A search result has no score, so its
|
||||
year and held-state live in the sub-line instead of
|
||||
overloading that slot with a second meaning. -#}
|
||||
{% for it in search.results %}
|
||||
{{ tile(it.title, it.kind ~ (' · Held' if it.held else ''), it.poster, it.year, ('' if it.held else '+ Add'), it.target) }}
|
||||
{{ tile(it.title, it.kind ~ (' · ' ~ it.year if it.year else '') ~ (' · Held' if it.held else ''), it.poster, '', ('' if it.held else '+ Add'), it.target) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
{% if search_results %}
|
||||
<div class="tt-tiles">
|
||||
{% for it in search_results %}
|
||||
{{ tile(it.title, it.kind, it.poster, it.year) }}
|
||||
{{ tile(it.title, it.kind ~ (' · ' ~ it.year if it.year else ''), it.poster) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
{% for name, key, svc in [('Sonarr', 'sonarr', sonarr), ('Radarr', 'radarr', radarr), ('SABnzbd', 'sabnzbd', sabnzbd),
|
||||
('Tautulli', 'tautulli', tautulli), ('Prowlarr', 'prowlarr', prowlarr), ('Ombi', 'ombi', ombi)] %}
|
||||
<a class="tt-row" href="{{ service_urls[key] }}" target="_blank" rel="noopener">
|
||||
<span class="tt-row-name">{{ name }}</span>
|
||||
<span class="tt-row-name">{{ name }} <span class="tt-row-ext" aria-hidden="true">↗</span></span>
|
||||
<span class="tt-row-body"></span>
|
||||
<span class="tt-row-val {{ 'ok' if svc.status == 'ok' else 'alert' }}">
|
||||
{{- 'ON AIR' if svc.status == 'ok' else 'OFF AIR' -}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue