Commit graph

10 commits

Author SHA1 Message Date
Roland
efe84d17f1 ui: media filtering is a per-theme setting, not a night-mode hardcode
Some checks are pending
Controller Tests / controller-tests (push) Waiting to run
Jest Tests / jest-tests (push) Waiting to run
Filtering media was keyed on `data-theme="night"`, which made it a property of
the theme that no user could turn off.  Some people want their media tinted to
match the interface; some want to see the actual image.

A theme now declares a filter and whether it starts on, and the user decides:

  night   night-red    on by default.  An unfiltered thumbnail undoes dark
                       adaptation, which is the whole point of the mode.
  amber   amber-mono   off by default.  Amber is a look, not a night-vision
                       aid, so media keeps its real colors until asked for.
  light   -            no filter offered, so no toggle is shown.
  dark    -

The choice is stored per theme, so wanting amber's tint says nothing about
wanting night's.  The toggle lives in the theme picker, which puts it on the
Settings page and in the gallery at once.

Mechanically the rules now key on a `data-media-filter` attribute rather than
`data-theme`: a rule keyed on the theme could not be turned off.  index.html
stamps that attribute before first paint alongside data-theme -- without it,
night mode paints a screen of unfiltered thumbnails while the bundle arrives
over a hotspot, costing the user the adaptation the theme exists to protect.
Tests cover both the attribute rule and the fact that the inline script's
duplicated ids and defaults still agree with names.ts.

The amber matrix is the same luminance collapse tinted to #ff9500 (red full,
green 0.584, blue zero) with a gentler gamma than night's: amber carries far
more luminance and clips to a flat wash otherwise.

The gallery gains a Media filtering section showing the WROLPi logo filtered,
beside an unfiltered copy that opts out with `night-unfiltered`.  That copy is
behind a click on purpose -- an unfiltered image is a bright patch, and night
mode should not spring one on someone reading in the dark.

ui-design.md gains the media filtering contract it never got in Phase 0,
including the note that a Phase 3 custom theme names an existing filter id and
cannot ship its own matrix, since that would be code rather than data.
2026-07-30 09:15:04 -06:00
Roland
973a61af28 ui: migrate the extension pages and Configs; five components they needed
Phase 2, part 1.  Three files leave Semantic UI (baseline 75 -> 72), and the
components they needed join the library and the gallery:

  Header       Semantic's shape (as/icon/subheader/dividing).  47 files use
               <Header>, and the level now picks the size, so the type scale
               stays a scale instead of each call site choosing a font size.
  Message      gains an icon and a dismiss button.
  ActionInput  input and button sharing one outline, for <Input action={...}/>.
  Loading      centered loader with a caption, replacing the
               <Loader active inline='centered'> + wrapper div in 19 places.
  Modal        becomes compound - Modal.Header/.Content/.Actions, plus
               Semantic's open, closeIcon, and size names - because 34 files
               are written against that shape.

test-utils mounts MantineProvider with ThemeProvider's exact configuration:
migrated components render Mantine internals and every one of their test files
would otherwise need its own provider.

One Semantic bleed found and fixed: semantic.min.css sets
`h1,h2,h3,h4,h5 { font-family: Lato }` and loads after Mantine's element rule,
so headings ignored the theme's body face.  Only visible in amber, where the
body is mono and the headings were not.  A class-level restatement outranks it;
the rule comes out when Semantic does.

Verified: 925 jest tests, clean production build, and a night-mode audit of
every painted pixel in the gallery (red-only, one known false positive).  The
Configs backup and restore flow was exercised against the real API.
2026-07-30 09:15:04 -06:00
Roland
925b02dccf
ui: theme tokens and a four-theme runtime
Every color now resolves through CSS custom properties on
html[data-theme=...], so a theme is a table of values rather than code.
Four themes ship: light, dark, night (red hues only, to preserve dark
adaptation off-grid) and amber (monochrome amber terminal).

Fonts are exposed as two roles, --font-body and --font-mono, which a theme
assigns a bundled face to; amber uses the mono face. Faces must be
self-hosted, never fetched from a CDN, so the app keeps working offline.

Night mode also filters media that cannot consume tokens - video, images,
PDFs, embedded pages, canvases - through an SVG color matrix that maps
luminance onto the red channel. Tag such an element with `.media`; a filter
on an app-level ancestor would create a containing block and break fixed
positioning.

ThemeProvider persists the choice and index.html stamps data-theme from
localStorage before the bundle loads, so the first paint already matches the
saved theme on a slow connection. The OS preference is followed only while
"system" is selected; night and amber are explicit choices. The nav toggle
becomes a five-item picker.

Semantic components still render themselves, so only the shell is
token-driven for now; the inverted props stay in place until each component
is migrated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 20:08:16 -06:00
Roland
0850b6a7fe
app: handle form fetch failures without unhandled rejection
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Controller Tests / controller-tests (push) Has been cancelled
Jest Tests / jest-tests (push) Has been cancelled
Catch useForm fetcher errors and surface them so DomainEditPage can show a not-found message instead of hanging on the loader (and so the webpack overlay no longer flakes Cypress).
2026-07-16 19:40:28 -06:00
Roland
74cb5171da
FileGroups in Collections can be reorganized in the Collection's directory.
* Batch reorganization is supported for both Domain and Channel Collections.
* Batch reorganization happens when any Collection does not match the respective file format. For example, a Channel Collection file format that does not match the `yt_dlp_options.file_name_format` will show `needs_reorganization`.
* Individual Collections can always be reorganized. The reorganization is a little more aggressive. Useful for when some files may have been missed in the batch reorganization.
2026-01-31 18:08:41 -07:00
Roland
8ea3ea8a67
Updating code to use new version of react-router. 2025-12-07 11:54:20 -07:00
Roland
8a7f0737f0 Reformatting code. 2025-12-06 15:11:37 -07:00
Roland
63a77b87e6 Removing collection metadata. 2025-12-06 15:11:37 -07:00
Roland
269a1f6570 Reworking CollectionTable and CollectionEditForm. 2025-12-06 15:11:37 -07:00
Roland
a1e0fb4e92 Creating a new Collection model for use in organizing FileGroups.
Replacing Channels and Domains with Collection.

Moving downloading relationships from Channel to Collection.

Created domains.yaml config to manage tagged domain collections.

Adding turn-key upgrade solution in the UI.
2025-12-06 15:11:37 -07:00