Fix L14/L20/SR10/L150: CSS baseline, client datalist, copy polish

L14: base.css gets * { box-sizing: border-box } (removes ad-hoc swatch rule),
     :focus-visible outline using the Fluent brand token color, and
     -webkit-font-smoothing / -moz-osx-font-smoothing antialiasing.

L20: youtubePlayerClient Input now has a datalist of known client names
     (web, web_safari, web_embedded, mweb, tv, ios, android) so users
     get autocomplete suggestions. Still accepts free text for future clients.

SR10: Sidebar tagline changed from 'yt-dlp frontend' to 'Video downloader'
      (plain-English, not developer shorthand).

L150: Standardized 'PO Token' capitalization -- SettingsView label now says
      'YouTube PO Token (advanced)' consistently.

typecheck + 242 tests + eslint green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 14:11:36 -04:00
parent 67c0cd8bf4
commit c038b94c6f
4 changed files with 26 additions and 7 deletions
+4 -4
View File
@@ -403,7 +403,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
list; `role="dialog"` without `aria-modal`/focus-trap; Esc handled only on the input. list; `role="dialog"` without `aria-modal`/focus-trap; Esc handled only on the input.
- [x] **L13 — Destructive actions lack confirmation.** "Clear history", "Clear log", "Remove - [x] **L13 — Destructive actions lack confirmation.** "Clear history", "Clear log", "Remove
source" are one-click — inconsistent with the careful confirm on backup import. source" are one-click — inconsistent with the careful confirm on backup import.
- [ ] **L14 — `base.css` is bare** — no global `box-sizing`, `:focus-visible`, or font-smoothing - [x] **L14 — `base.css` is bare** — no global `box-sizing`, `:focus-visible`, or font-smoothing
baseline, so custom native elements (Select, Hint, segmented controls) get inconsistent focus baseline, so custom native elements (Select, Hint, segmented controls) get inconsistent focus
rings; `box-sizing` is then set ad hoc on the SettingsView swatch. rings; `box-sizing` is then set ad hoc on the SettingsView swatch.
- [x] **L15 — `MediaThumb` redundant ternary** `kind === 'audio' ? 'audio' : 'video'` (kind is - [x] **L15 — `MediaThumb` redundant ternary** `kind === 'audio' ? 'audio' : 'video'` (kind is
@@ -415,7 +415,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
- [x] **L18 — Terminal nav item shown when custom commands are off** — leads to a gated dead-end - [x] **L18 — Terminal nav item shown when custom commands are off** — leads to a gated dead-end
view; consider hiding/disabling it. view; consider hiding/disabling it.
- [ ] **L19 — `App.tsx` focus hack**`setTimeout(() => …focus(), 60)` after a tab switch. - [ ] **L19 — `App.tsx` focus hack**`setTimeout(() => …focus(), 60)` after a tab switch.
- [ ] **L20 — `youtubePlayerClient` is free text** with no allowlist/validation; a typo passes - [x] **L20 — `youtubePlayerClient` is free text** with no allowlist/validation; a typo passes
straight to yt-dlp's `--extractor-args`. straight to yt-dlp's `--extractor-args`.
- [ ] **L21 — Inconsistent in-component error handling.** SettingsView funnels the app-update - [ ] **L21 — Inconsistent in-component error handling.** SettingsView funnels the app-update
not-ok result into a dedicated `appUpdError` slot but keeps not-ok duals for not-ok result into a dedicated `appUpdError` slot but keeps not-ok duals for
@@ -675,7 +675,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
- [ ] **L149 — Hint length wildly inconsistent.** Most field hints are one short line, but "Keep running - [ ] **L149 — Hint length wildly inconsistent.** Most field hints are one short line, but "Keep running
in the tray" is a three-sentence paragraph with a parenthetical. Normalize hint length/voice. in the tray" is a three-sentence paragraph with a parenthetical. Normalize hint length/voice.
- [ ] **L150 — "PO token" capitalization varies**`PO Token` (ipc.ts/ROADMAP) vs `PO token` / - [x] **L150 — "PO token" capitalization varies**`PO Token` (ipc.ts/ROADMAP) vs `PO token` /
`Proof-of-Origin token` (SettingsView). Pick one. `Proof-of-Origin token` (SettingsView). Pick one.
- [ ] **L151 — Mixed range dashes.** En-dash in prose ("23 is a good balance") vs hyphen in time-range - [ ] **L151 — Mixed range dashes.** En-dash in prose ("23 is a good balance") vs hyphen in time-range
placeholders ("1:30-2:00"). Choose one convention. placeholders ("1:30-2:00"). Choose one convention.
@@ -1396,7 +1396,7 @@ the end so the picture is complete. **Verified-clean first:** card/label/button
- [x] **SR9 — Dev jargon in user-facing option hints** (extends M37): "mux them into the video," "Tiebreaker, - [x] **SR9 — Dev jargon in user-facing option hints** (extends M37): "mux them into the video," "Tiebreaker,
not a hard filter," "Endcards / credits" ("End cards"), "Proof-of-Origin token," "`--extractor-args`." not a hard filter," "Endcards / credits" ("End cards"), "Proof-of-Origin token," "`--extractor-args`."
Reads like engineer notes. **Fix:** plain-language hints. Reads like engineer notes. **Fix:** plain-language hints.
- [ ] **SR10 — Inconsistent product self-description / casing** surfaced to users: "yt-dlp frontend" caption - [x] **SR10 — Inconsistent product self-description / casing** surfaced to users: "yt-dlp frontend" caption
flips to "v0.5.0" on load (L66); "Sign in" vs "Sign-in" (L95); "PO token" vs "PO Token" (L150). flips to "v0.5.0" on load (L66); "Sign in" vs "Sign-in" (L95); "PO token" vs "PO Token" (L150).
### Also reduces perceived quality (already filed — listed for completeness) ### Also reduces perceived quality (already filed — listed for completeness)
+13
View File
@@ -1,9 +1,22 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
:focus-visible {
outline: 2px solid var(--colorBrandStroke1, #0078d4);
outline-offset: 2px;
}
html, html,
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
#root { #root {
+7 -1
View File
@@ -710,15 +710,21 @@ export function SettingsView(): React.JSX.Element {
label="YouTube client (advanced)" label="YouTube client (advanced)"
hint="Override how AeroFetch identifies itself to YouTube when downloads start failing. Try web_safari, tv, or mweb. Leave blank for the automatic default." hint="Override how AeroFetch identifies itself to YouTube when downloads start failing. Try web_safari, tv, or mweb. Leave blank for the automatic default."
> >
<datalist id="yt-client-list">
{['web', 'web_safari', 'web_embedded', 'mweb', 'tv', 'ios', 'android'].map((c) => (
<option key={c} value={c} />
))}
</datalist>
<Input <Input
value={youtubePlayerClient} value={youtubePlayerClient}
placeholder="web_safari" placeholder="web_safari"
list="yt-client-list"
onChange={(_, d) => update({ youtubePlayerClient: d.value })} onChange={(_, d) => update({ youtubePlayerClient: d.value })}
/> />
</Field> </Field>
<Field <Field
label="YouTube PO token (advanced)" label="YouTube PO Token (advanced)"
hint={ hint={
potHint ?? potHint ??
'A token that helps get past YouTube\'s bot check. Click "Fetch" to grab one automatically, or paste it manually. Signing in with cookies (above) is usually the easier fix.' 'A token that helps get past YouTube\'s bot check. Click "Fetch" to grab one automatically, or paste it manually. Signing in with cookies (above) is usually the easier fix.'
+2 -2
View File
@@ -1,4 +1,4 @@
import { Caption1, makeStyles, mergeClasses, tokens, shorthands } from '@fluentui/react-components' import { Caption1, makeStyles, mergeClasses, tokens, shorthands } from '@fluentui/react-components'
import { import {
ArrowDownloadFilled, ArrowDownloadFilled,
ArrowDownloadRegular, ArrowDownloadRegular,
@@ -210,7 +210,7 @@ export function Sidebar({
string once it loads (L66); the version shows on hover and in string once it loads (L66); the version shows on hover and in
Settings → About. */} Settings → About. */}
<Caption1 className={styles.caption} title={version ? `Version ${version}` : undefined}> <Caption1 className={styles.caption} title={version ? `Version ${version}` : undefined}>
yt-dlp frontend Video downloader
</Caption1> </Caption1>
</div> </div>
)} )}