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
80 lines
4 KiB
HTML
80 lines
4 KiB
HTML
{% extends "_shell.html" %}
|
|
{% block title %}P900 Settings{% endblock %}
|
|
|
|
{% block content %}
|
|
<h1 class="tt-dh bloom tt-masthead">SETTINGS</h1>
|
|
<p class="tt-empty">Keys saved here override the values in <code>.env</code>. Both need a container restart to take effect.</p>
|
|
|
|
{#- ── General ────────────────────────────────────────────────── -#}
|
|
<div class="tt-field"><span>General</span></div>
|
|
<div class="tt-form">
|
|
<div class="tt-field-row">
|
|
<label class="tt-label" for="timezone">Timezone</label>
|
|
<select class="tt-input tt-select" id="timezone">
|
|
{% set tzs = [
|
|
'America/New_York','America/Chicago','America/Denver','America/Los_Angeles',
|
|
'America/Toronto','America/Vancouver','America/Phoenix','America/Halifax',
|
|
'Europe/London','Europe/Paris','Europe/Berlin','Europe/Amsterdam',
|
|
'Europe/Stockholm','Europe/Rome','Europe/Madrid','Europe/Zurich',
|
|
'Australia/Sydney','Australia/Melbourne','Australia/Brisbane','Australia/Perth',
|
|
'Pacific/Auckland','Asia/Tokyo','Asia/Singapore','Asia/Dubai','Asia/Kolkata'
|
|
] %}
|
|
{% for tz in tzs %}
|
|
<option value="{{ tz }}" {% if tz == timezone %}selected{% endif %}>{{ tz }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="tt-field-row">
|
|
<label class="tt-label" for="arr_host">Host IP (ARR_HOST)</label>
|
|
<input class="tt-input" type="text" id="arr_host" value="{{ arr_host }}" placeholder="192.168.86.33">
|
|
<p class="tt-hint">LAN address of the machine running Sonarr, Radarr and the rest.</p>
|
|
</div>
|
|
<button class="tt-btn" onclick="saveGeneral()">Save General</button>
|
|
</div>
|
|
|
|
{#- ── Password ───────────────────────────────────────────────── -#}
|
|
<div class="tt-field"><span>Change Password</span></div>
|
|
<div class="tt-form">
|
|
<div class="tt-field-row">
|
|
<label class="tt-label" for="pw_current">Current password</label>
|
|
<input class="tt-input" type="password" id="pw_current" autocomplete="current-password">
|
|
</div>
|
|
<div class="tt-field-row">
|
|
<label class="tt-label" for="pw_new">New password</label>
|
|
<input class="tt-input" type="password" id="pw_new" placeholder="At least 6 characters" autocomplete="new-password">
|
|
</div>
|
|
<div class="tt-field-row">
|
|
<label class="tt-label" for="pw_confirm">Confirm new password</label>
|
|
<input class="tt-input" type="password" id="pw_confirm" autocomplete="new-password">
|
|
<div class="tt-inline-err" id="pw-error" role="alert"></div>
|
|
</div>
|
|
<button class="tt-btn" onclick="changePassword()">Update Password</button>
|
|
</div>
|
|
|
|
{#- ── Keys ───────────────────────────────────────────────────── -#}
|
|
<div class="tt-field"><span>Service Keys</span></div>
|
|
<div class="tt-keys">
|
|
{% for svc, label in [
|
|
('sonarr','Sonarr'), ('radarr','Radarr'), ('sabnzbd','SABnzbd'),
|
|
('tautulli','Tautulli'), ('prowlarr','Prowlarr'), ('ombi','Ombi')
|
|
] %}
|
|
<div class="tt-form">
|
|
<div class="tt-field-row">
|
|
<label class="tt-label" for="{{ svc }}_api_key">{{ label }} API key</label>
|
|
<input class="tt-input" type="password" id="{{ svc }}_api_key"
|
|
value="{{ {'sonarr': sonarr_api_key, 'radarr': radarr_api_key,
|
|
'sabnzbd': sabnzbd_api_key, 'tautulli': tautulli_api_key,
|
|
'prowlarr': prowlarr_api_key, 'ombi': ombi_api_key}[svc] }}"
|
|
autocomplete="off">
|
|
</div>
|
|
<button class="tt-btn tt-btn-quiet" onclick="saveService('{{ svc }}')">Save {{ label }}</button>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div class="tt-toast" id="toast" role="status" aria-live="polite"></div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
|
{% endblock %}
|