arr-summary/templates/_shell.html
Barely Removable 5dd49c505c
All checks were successful
Deploy / deploy (push) Successful in 23s
Give every fastext destination a distinct mark; add skip-link, fix aria-label
Colours: "if the intent is to have them all different colors than
lets have them all different colors." The locked eight only give five
safe as full text (blue fails contrast, black's invisible on black),
so the other three get their own treatments instead of sharing plain
ink: Watch gets blue as a swatch-only accent (the button cap's colour,
not the label), Activity gets an ordered-dither swatch (the other
legal way to mark something without a ninth colour), and Settings
alone keeps plain ink deliberately, as the one page with no live
status of its own.

Accessibility (items 1 and 3 from the design review, item 2 skipped
per request — the header's download figure stays live and unmuted):
- Added a skip-link, off-screen until focused, jumping past the
  8-item top nav straight to each page's #main-content.
- Renamed the nav's aria-label from "Fastext" (meaningless without
  the visual teletext context) to "Page navigation".
2026-08-30 09:24:52 -07:00

94 lines
4.5 KiB
HTML

{%- set here = (nav_items | selectattr('0', 'equalto', page) | list | first) or ('home', '100', 'Index', '/') -%}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}P{{ here[1] }} Media Centre{% endblock %}</title>
<meta name="theme-color" content="#000000">
<link rel="icon" href="{{ url_for('static', filename='favicon.svg') }}">
{#- Space Mono is self-hosted (see base.css's @font-face) — this app
runs on a LAN-only home server where a Google Fonts request can
simply fail, and a dropped webfont request is a silent identity
change, not a graceful fallback. -#}
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/teletext.css') }}">
{% block css %}{% endblock %}
</head>
<body data-timezone="{{ timezone }}" data-url-base="{{ request.script_root }}"
data-pages='{{ nav_items | tojson }}'>
{#- Skip-link: every page but the index now opens with a full nav
block before any real content — a keyboard or screen-reader visitor
would otherwise tab through all eight destinations on every single
visit. Off-screen until focused, then it's the first thing tabbing
into the page reaches. -#}
<a class="skip-link" href="#main-content">Skip to content</a>
<!--
THESIS: Media Centre is a broadcast information service, not a dashboard. It
refuses the bordered-card grid every self-hosted dashboard ships, this one
included until now.
OWN-WORLD: Teletext's locked eight colours at full saturation on pure black,
phosphor bloom on double-height rows only, one blocky monospace at exactly two
heights, a character-cell grid, and grouping carried by colour fields and row
weight — never a border, never a box, never a radius.
STORY: The visitor types or clicks a page number, reads the machine's state off
colour alone, and leaves knowing whether anything needs them.
FIRST VIEWPORT: P100. Double-height yellow masthead left, live clock right;
seven numbered service rows each carrying a live figure in its status colour, so
the index is the status page; NOW SHOWING fills the lower two-thirds in
double-height cyan with progress as whole mosaic cells; fastext colour keys last.
FORM: Ceefax teletext fused with the US cable guide channel; candidate 3 of 7;
seed aab4510e.
FINISH: unreviewed and undocumented is unfinished; this build ends with the
finish review, the verdict, DESIGN.md, and every shipping raster carrying its
provenance.
-->
<header class="tt-head">
<span class="tt-head-num">P{{ here[1] }}</span>
<span class="tt-head-name">{{ here[2] }}</span>
<span class="tt-entry" id="page-entry" hidden aria-live="polite"></span>
{#- SABnzbd's queue, on every page — the same live /api/sabnzbd poll
Activity and System already use, not a server-rendered fetch, so
an unreachable SABnzbd never adds latency to a page that doesn't
otherwise need it. Starts blank and fills in within a second. -#}
<span class="tt-head-dl" id="head-dl" aria-live="polite"></span>
<span class="tt-head-clock" id="head-clock"></span>
</header>
{#- Fastext: the four coloured keys. Each page names its own four, so the
keys always point somewhere useful from where you are. On the index
it stays the closing row, under Now Showing/Just Added, since the
index's own body already is the full nav. Everywhere else it leads,
right under the header, since it's the only nav those pages carry. -#}
{% set fastext_nav %}
<nav class="fastext{{ '' if page == 'home' else ' fastext-top' }}" aria-label="Page navigation">
{% 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 %}
{% if page != 'home' %}{{ fastext_nav }}{% endif %}
<main class="tt-page" id="main-content">
{% block content %}{% endblock %}
</main>
{% if page == 'home' %}{{ fastext_nav }}{% endif %}
<footer class="tt-foot">
<span>MEDIA CENTRE</span>
<span class="v">v{{ app_version }} &middot; {{ app_version_date }}</span>
</footer>
<script src="{{ url_for('static', filename='js/service.js') }}"></script>
{% block js %}{% endblock %}
</body>
</html>