Redesign Media Centre as a teletext broadcast information service
Replaces the neutral dark card-based theme with "Page 100": teletext's
locked eight colours at full saturation on pure black, numbered pages
reachable by typing the number (or the r/g/y/c fastext keys), and no
borders, boxes, or radius anywhere — grouping is carried by full-bleed
colour fields and row weight instead.
Chosen via the impeccable skill's replacement-world flow: seven visual
candidates derived from the audience's own world, a mandatory roll
assigned Ceefax/US-cable-guide teletext, six catalog challengers weighed
against it, and the user locked the assigned direction on the decision
page (seed aab4510e).
- New templates for all nine pages (home/watch/library/discover/
requests/system/activity/login/settings) behind a shared _shell.html
carrying the direction contract and _macros.html for the row/bar/tile
vocabulary; deletes the old single-page dashboard.html and its
dedicated stylesheets/script.
- static/css/base.css + teletext.css: the locked palette, a two-height
type scale (Chivo Mono / DotGothic16), and the five disciplines the
system is held to (no in-between tone, no enclosure, one shared bar
ruler, trend only where real history exists, pages weighted by state).
- static/js/service.js: header clock, page-number jump, fastext keys,
two-tap arm/confirm add, guarded live polling — replaces dashboard.js.
- app.py: nav_items now carry page numbers; fastext defaults added to
the page-chrome context processor; version bumped to 2.0.0.
- DESIGN.md + .impeccable/design.json regenerated from the built world
by the documenter pass; PRODUCT.md and CLAUDE.md updated to describe
the new system in place of the retired one.
- Fixed a live bug found along the way: settings.html called
url_for('dashboard'), an endpoint removed earlier in the branch, which
would have 500'd the Settings page.
- Fixed a One-Ruler violation the finish review's recapture request
surfaced: --bar-cells disagreed with the bar() macro's hardcoded cell
count below the 760px breakpoint, so a fill could land mid-cell on a
phone. Removed the mobile override; the ruler is now 20 cells at every
width, matching the macro unconditionally.
Passed two inspection rounds (desktop + true-390px mobile, via an
iframe harness since macOS Chrome clamps --window-size) and a finish
review; QA screenshots and interview logs are gitignored as scratch,
not shipped in the repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBw1QodG8ZMYHrGeQfqyDS
This commit is contained in:
parent
9a277b9031
commit
4b19cbdfb2
25 changed files with 3002 additions and 2343 deletions
79
templates/watch.html
Normal file
79
templates/watch.html
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
{% extends "_shell.html" %}
|
||||
{% from "_macros.html" import service_error, bar %}
|
||||
{% block title %}P101 Watch{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="tt-dh bloom tt-masthead">WATCH</h1>
|
||||
|
||||
{% if tautulli.status != 'ok' %}
|
||||
<div class="tt-field crit"><span>Tautulli</span><span class="tt-field-meta">off air</span></div>
|
||||
{{ service_error('Tautulli', tautulli.error) }}
|
||||
{% else %}
|
||||
{%- set sessions = tautulli.sessions or [] -%}
|
||||
|
||||
<div class="tt-field {{ 'warn' if sessions else '' }}">
|
||||
<span>Streaming Now</span>
|
||||
<span class="tt-field-meta">{{ tautulli.active_streams }} active</span>
|
||||
</div>
|
||||
|
||||
{% if sessions %}
|
||||
<div class="tt-rows">
|
||||
{% for s in sessions %}
|
||||
<div class="tt-row">
|
||||
<span class="tt-row-name">{{ (s.media_type or 'play') | upper }}</span>
|
||||
<span class="tt-row-body">
|
||||
<span class="tt-row-title">{{ s.title }}</span>
|
||||
<span class="tt-row-sub">
|
||||
{{ s.user or s.username }}
|
||||
{%- if s.player %} · {{ s.player }}{% endif %}
|
||||
{%- if s.quality %} · {{ s.quality }}{% endif %}
|
||||
{%- if s.decision %} · {{ s.decision | upper }}{% endif %}
|
||||
{%- if s.ends_at %} · ENDS {{ s.ends_at }}{% endif %}
|
||||
</span>
|
||||
</span>
|
||||
{{ bar(s.progress | default(0), 'ok') }}
|
||||
<span class="tt-row-val">{{ s.progress | default(0) | round | int }}%</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="tt-empty">Nothing streaming. The service is quiet.</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="tt-field"><span>Most Played</span><span class="tt-field-meta">last 30 days</span></div>
|
||||
<div class="tt-rows">
|
||||
{% for t in (tautulli.top_tv_list or [])[:5] %}
|
||||
<div class="tt-row">
|
||||
<span class="tt-row-num">{{ loop.index }}</span>
|
||||
<span class="tt-row-name">TV</span>
|
||||
<span class="tt-row-body"><span class="tt-row-title">{{ t.title }}</span></span>
|
||||
<span class="tt-row-val">{{ t.plays }} PLAYS</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for t in (tautulli.top_movie_list or [])[:5] %}
|
||||
<div class="tt-row">
|
||||
<span class="tt-row-num">{{ loop.index }}</span>
|
||||
<span class="tt-row-name">Film</span>
|
||||
<span class="tt-row-body"><span class="tt-row-title">{{ t.title }}</span></span>
|
||||
<span class="tt-row-val">{{ t.plays }} PLAYS</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if not tautulli.top_tv_list and not tautulli.top_movie_list %}
|
||||
<p class="tt-empty">No play history yet.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if tautulli.top_users %}
|
||||
<div class="tt-field"><span>Who Is Watching</span></div>
|
||||
<div class="tt-rows">
|
||||
{% for u in tautulli.top_users[:5] %}
|
||||
<div class="tt-row">
|
||||
<span class="tt-row-num">{{ loop.index }}</span>
|
||||
<span class="tt-row-body"><span class="tt-row-title">{{ u.username or u.user }}</span></span>
|
||||
<span class="tt-row-val">{{ u.plays }} PLAYS</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue