wrolpi/app/src/components
Roland b5884e2d2c ui: tags look like tags, and stay readable in every theme
Four things, three cosmetic and one a real legibility bug.

* Tags were square chips.  They now have a pointed left edge and an
  eyelet, like a tag tied to a garment -- the shape Semantic gave them,
  and the reason a tag reads as a tag rather than as a small button.  The
  point is a square rotated behind the left edge, sized so its diagonal
  equals the body height and its two edges meet the body at the corners.

  Only where something is actually a tag.  `Label` carries the count
  badges in the Tags table too -- file, zim, channel and domain counts --
  and a point on a number reads as an arrow, so the shape is behind a
  `tag` prop and `NameToTagLabel` opts in.

* They were smaller than what they replaced: 11.5px text with 3px of
  padding, against Semantic's 12px and ~7px.  Now 12.5px and 5px, which
  also keeps them a reasonable thing to tap.

* Wrapped rows of tags sat on the row above, so they carry a bottom
  margin, plus a left margin for the point to occupy.

* The text colour was unreadable in night and wrong in amber.

Tags.js calculates black-or-light against the colour the user chose for
each tag, and wrote the answer to `color` inline -- a declaration no
stylesheet rule can outrank.  Night turns a tag into an outline over a
near-black page, so a near-white tag kept the black text calculated for
its fill and was left legible only by its border: 1.1:1, measured.  Amber
replaces every fill with its own bright orange and was painting `#dddddd`
on `#ff9500`, about 1.9:1, and a neutral grey in a theme whose whole
point is that no other hue reaches the eye.

The fix is to stop hard-coding `color` so the theme can decide: the
calculated colour goes into `--label-text`, and night and amber override
it alongside the fill they already override.  There is no second contrast
function to write, which is what this looked like it needed -- once a
theme has discarded the user's colour there is nothing left to calculate
against, and the answer is just the theme's own token.

`.wrolpi-label-white` and `-black` moved to the same variable.  Setting
`color` there outranked the base rule, so amber was painting `--white` on
`--text`: light orange on orange.

`contrastingColor` was also picking the worse of its two options.  It
compared a brightness figure against a threshold, and the figure weighted
the gamma-encoded bytes without linearising them, so Semantic's blue
`#2185d0` got light text at 2.9:1 where dark text gives 5.3:1.  Every
mid-tone blue, teal and purple a user might pick sat in that band.  It
now measures the WCAG contrast ratio of both candidates and returns the
better one, which needs no threshold at all.

Tests
-----
`Tags.test.js` is new, and covers the chip nothing covered: every other
spec takes `NameToTagLabel` from `tagsContextFixture`, which stubs it as
a function returning the name.  That is how a tag could be unreadable
without a single test noticing.  Two of these were verified red against
the inline `color`.

`cy.contrastRatio()` measures text against the surface *actually* behind
it, walking up to the first ancestor that paints something -- a
transparent tag has no background of its own, so a naive check reads
rgba(0,0,0,0) and concludes anything is legible.  Twelve cases, three
tag colours across four themes, at WCAG AA.  Plus a test asserting the
old inline-`color` version still measures below 1.5:1, so the check is
provably able to fail.

The gallery had label swatches in theme colours and no user-coloured tag,
which is why none of this was visible in it.  It has eleven now, spanning
the range where the black-or-light decision flips.
2026-08-01 14:35:35 -06:00
..
admin ui: name the directory fields, announce their help text, let long prefixes shrink 2026-07-30 16:10:56 -06:00
calculators ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
collections build: uninstall Semantic UI 2026-07-30 14:50:47 -06:00
inventory ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
ui ui: tags look like tags, and stay readable in every theme 2026-08-01 14:35:35 -06:00
AddToPlaylist.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
Apps.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
Archive.js ui: bring back the card mimetype accent 2026-07-30 13:51:05 -06:00
ArchivePreview.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
BulkTagModal.js ui: migrate Downloads, Upload, and BulkTagModal off Semantic 2026-07-30 13:10:51 -06:00
BulkTagModal.test.js ui: migrate Downloads, Upload, and BulkTagModal off Semantic 2026-07-30 13:10:51 -06:00
Calculators.js ui: fix the cypress failures, and two real defects behind them 2026-07-30 12:54:24 -06:00
CbzViewer.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
Channels.cy.js Moving form fields. 2025-12-06 15:11:37 -07:00
Channels.js ui: Channels.js and Playlists.js off Semantic 2026-07-30 13:02:57 -06:00
Common.js ui: tags look like tags, and stay readable in every theme 2026-08-01 14:35:35 -06:00
Common.test.js ui: tags look like tags, and stay readable in every theme 2026-08-01 14:35:35 -06:00
DatesSelector.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
DesktopToggle.test.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
Docs.js ui: migrate Docs.js and Zim.js off Semantic UI React 2026-07-30 13:07:48 -06:00
DomainEditPage.test.js app: handle form fetch failures without unhandled rejection 2026-07-16 19:40:28 -06:00
DomainsPage.test.js Reformatting code. 2025-12-06 15:11:37 -07:00
DomainTagging.test.js test: one place for fixtures, real providers instead of mocked context modules 2026-07-30 16:44:40 -06:00
DonatePage.js ui: nine leaf files off Semantic, and the components they needed 2026-07-30 11:55:39 -06:00
Download.cy.js build: uninstall Semantic UI 2026-07-30 14:50:47 -06:00
Download.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
Download.test.js Reformatting code. 2025-12-06 15:11:37 -07:00
ErrorBoundary.js ui: nine leaf files off Semantic, and the components they needed 2026-07-30 11:55:39 -06:00
FileBrowser.js test: one place for fixtures, real providers instead of mocked context modules 2026-07-30 16:44:40 -06:00
FileBrowser.test.js test: the theme drives the colour scheme, and mockModule takes the module 2026-07-30 16:44:40 -06:00
FilePreview.js ui: FileBrowser.js and FilePreview.js off Semantic 2026-07-30 13:11:01 -06:00
FilePreview.test.js File preview: Open in Slicer button for STL/3MF files. 2026-07-05 13:31:40 -06:00
Files.js ui: bring back the card mimetype accent 2026-07-30 13:51:05 -06:00
Flasher.js ui: migrate Flasher.js off Semantic UI React 2026-07-30 13:13:39 -06:00
Flasher.test.js ui: migrate Flasher.js off Semantic UI React 2026-07-30 13:13:39 -06:00
Headline.js ui: nine leaf files off Semantic, and the components they needed 2026-07-30 11:55:39 -06:00
HelpModal.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
KeyboardShortcutsProvider.js ui: fix the cypress failures, and two real defects behind them 2026-07-30 12:54:24 -06:00
Map.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
MapSearchView.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
MapViewer.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
Nav.js ui: Nav off Semantic, and the memory warning starts working 2026-07-30 13:18:12 -06:00
otp.js Move One-Time Pad encryption to the browser (#479) 2026-06-13 13:52:34 -06:00
otp.test.js Move One-Time Pad encryption to the browser (#479) 2026-06-13 13:52:34 -06:00
Placeholder.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
Playlists.js ui: Channels.js and Playlists.js off Semantic 2026-07-30 13:02:57 -06:00
Playlists.test.js Add ordered collections (playlists): polymorphic items + item API (#475) 2026-06-11 19:46:34 -06:00
Search.js ui: fix the cypress failures, and two real defects behind them 2026-07-30 12:54:24 -06:00
SearchFilterModal.test.js ui: thirty-five files off Semantic, leaving fifteen 2026-07-30 12:54:24 -06:00
Share.js ui: nine leaf files off Semantic, and the components they needed 2026-07-30 11:55:39 -06:00
ShortcutHint.js Displaying cmd+k/ctrl+k global search keyboard shortcut suggestion. 2026-02-23 16:07:22 -07:00
SortableTable.js ui: nine leaf files off Semantic, and the components they needed 2026-07-30 11:55:39 -06:00
Tables.js ui: nine leaf files off Semantic, and the components they needed 2026-07-30 11:55:39 -06:00
TaggedDeleteConfirmModal.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
TaggedDeleteConfirmModal.test.js Models like Archive/Video/Doc can be deleted, even if they are tagged. User is shown a warning and must confirm deletion of tagged files. 2026-05-03 19:14:15 -06:00
Theme.tsx ui: the last Semantic UI file, and the stylesheet with it 2026-07-30 13:41:05 -06:00
ThemeProvider.test.js ui: media filtering is a per-theme setting, not a night-mode hardcode 2026-07-30 09:15:04 -06:00
ThemeSamplePage.js ui: tags look like tags, and stay readable in every theme 2026-08-01 14:35:35 -06:00
Upload.js ui: migrate Downloads, Upload, and BulkTagModal off Semantic 2026-07-30 13:10:51 -06:00
Vars.js Restore "Most Views" download order 2026-07-07 16:34:50 -06:00
VideoPlayer.js ui: migrate VideoPlayer.js off Semantic UI React 2026-07-30 13:07:09 -06:00
VideoPlayer.test.js videos: address review — tighten auto-caption detection 2026-07-16 18:29:18 -06:00
Videos.js ui: Statistic and StatisticGroup, and the four defects they had 2026-07-30 19:23:04 -06:00
VncToggle.test.js ui: Common.js and thirteen more files off Semantic 2026-07-30 11:55:39 -06:00
Zim.js ui: migrate Docs.js and Zim.js off Semantic UI React 2026-07-30 13:07:48 -06:00