mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
6d7464fddf2453e39ad78a196c4ab477446c01e9
13 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6d7464fddf | refactor(waveform): co-locate seekbar feature into features/waveform | ||
|
|
e1ff4385d6 |
feat(settings): add "Square Corners" appearance toggle (#1215)
* feat(settings): add "Square Corners" appearance toggle A Display toggle in Settings → Appearance → Visual Options that overrides the active theme to render cards and cover art with square (non-rounded) corners, for a sharper, boxy look. Covered surfaces: grid cards (album/playlist/artist/song/because) and their covers, detail-header heros (album/playlist/tracks), the Now Playing / Radio view, the fullscreen player, the cover lightbox, the queue panel cover, and the mini player. Persisted in themeStore and driven by an `html[data-square-corners]` attribute set in App.tsx — applied in both the main and mini-player webviews (the mini player rehydrates the theme store on the shared `storage` event). Strings added for all 12 locales. * docs(changelog): add Square Corners to 1.50.0 CHANGELOG and What's New |
||
|
|
d70060923b |
refactor(settings): interface scale as a segmented picker (#1197)
Replace the Interface Scale zoom slider and its tick row with the shared SettingsSegmented control — one button per preset (80–150%), matching the Lyrics, Queue and Track-transitions sections. Drops the slider/tick alignment issue entirely. Legacy off-preset values snap to the nearest preset so one button is always active. Removes the now-dead slider CSS. |
||
|
|
d49424e95b |
feat(settings): add a Compact buttons appearance toggle (#1189)
* feat(ui): prototype compact hero and toolbar buttons (Large/Small appearance setting) * feat(settings): rename action-button size toggle to "Compact buttons" Promote the hero-button prototype to a real, app-wide setting. - rename heroButtonSize → buttonSize, data-hero-buttons → data-button-size, hero-action-bar/hero-btn-label → compact-action-bar/compact-btn-label - relabel "Hero buttons" → "Compact buttons" and broaden the description (action + toolbar buttons across detail pages and browse views) in all 11 locales - move the feature CSS out of cover-lightbox.css into its own compact-buttons.css - add tests: themeStore buttonSize toggle, SelectionToggleButton * docs(changelog): compact buttons appearance toggle (#1189) * docs(credits): compact buttons appearance toggle (#1189) |
||
|
|
b6ac879b14 |
refactor(settings): SettingsSubCard primitives across all of Settings (#1182)
* feat(settings): add SettingsSubCard primitives for sub-section controls Reusable wrappers (SettingsSubCard / SettingsField / SettingsRow / SettingsValue / SettingsCallout) that encapsulate the settings-norm-* sub-card styles. Per-mode and detail controls inside a settings section should use these instead of hand-rolling the box with inline padding or one-off classes — the lack of a shared primitive is what let recent additions drift off the pattern. * refactor(settings): move the Audio tab onto the SettingsSubCard primitives Normalization, Track transitions and Hi-Res now build their sub-cards from the shared primitives instead of raw settings-norm-* markup. Track Previews, which rendered its sub-options bare with inline styles and dividers, now uses the same sub-card so the whole Audio tab is consistent. Behaviour and styling unchanged; Track Previews' start/duration become labelled slider rows like Normalization. * refactor(settings): move the remaining tabs onto SettingsSubCard Apply the shared sub-card primitives across the rest of Settings so every tab matches the Audio-tab reference look: - Appearance: grid columns, window buttons, UI scale, font, seekbar - Library: random-mix blacklist, rating-filter detail - Input: in-app + global keybind lists - Integrations: Discord templates, external-artwork BYOK - System: language, Linux Wayland text render, clock format, logging - Storage: media dir, hot-cache detail, downloads folder - Backup: mode picker + per-mode export/import Detail/per-mode controls now sit in the bordered sub-card; toggle groups stay on SettingsToggle. Behaviour unchanged. * refactor(settings): box the data-heavy and shared sections in SettingsSubCard Bring the previously-skipped 'borderline' sections onto the sub-card too: - Playback speed: wrap the settings-mode controls in a sub-card; the compact player-popup path is left untouched (shares the component via the compact flag) - Theme scheduler: mode picker + theme/time selects move into the sub-card - Cover-cache + analytics strategy: the per-server tables sit in a sub-card Behaviour unchanged; the table layouts and the playback-rate-* internals stay as they are, only the surrounding sub-card is added for visual consistency. |
||
|
|
7c724a642f |
chore(eslint): add ESLint toolchain and clean src to strict 0/0 (#1165)
* chore(eslint): add eslint toolchain and configs * fix(eslint): resolve gradual-config errors (rules-of-hooks, no-empty, prefer-const, …) * chore(eslint): clear unused vars in config, contexts, app and test * chore(eslint): clear unused vars in api and music-network * chore(eslint): clear unused vars in utils * chore(eslint): clear unused vars in store * chore(eslint): clear unused vars in cover and hooks * chore(eslint): clear unused vars in components * chore(eslint): clear unused vars in pages * chore(eslint): remove explicit any in src * chore(eslint): align react-hooks exhaustive-deps * chore(eslint): zero gradual config on src * chore(eslint): strict hook rules in store and utils * chore(eslint): strict hook rules in hooks and cover * chore(eslint): strict hook rules in components * chore(eslint): strict hook rules in pages and contexts * chore(eslint): document scripts ignore in eslint config * chore(eslint): add lint script and zero strict findings * chore(eslint): address review round 1 (gradual 0/0, per-site disable reasons) * chore(eslint): tighten two set-state disable comments (review round 2 LOW) * chore(nix): sync npmDepsHash with package-lock.json * docs(changelog): add Under the Hood entry for ESLint setup (PR #1165) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
d50c9c444d |
refactor(settings): reusable SettingsGroup/SettingsToggle + boxed sections across tabs (#1126)
* refactor(settings): extract reusable SettingsGroup component
Pull the boxed sub-section pattern (bordered panel + accent uppercase
header) introduced for the Audio tab into a reusable <SettingsGroup
title desc> component, and migrate NormalizationBlock and
PlaybackBehaviorBlock onto it. No visual change.
* feat(settings): box the System behavior section into groups
Split the System -> App Behavior card (which bundled tray toggles, Linux
rendering tweaks and the clock format) into titled SettingsGroup panels
(Tray / Linux rendering / Clock) for a clearer, consistent boxed look.
Adds the group titles across all 9 locales.
* feat(settings): box Appearance visual options; optional SettingsGroup title
Split the Appearance -> Visual options card into a Display group and a
Window group (Linux custom titlebar controls). SettingsGroup now allows an
optional/omitted title for plain boxed panels. Group titles added across
all 9 locales.
* feat(settings): box Discord cover source and templates
Group the Discord cover-source toggles and the activity templates into
separate SettingsGroup panels (templates reuse their existing title/desc),
dropping the manual indent and inline header. No new strings.
* feat(settings): box the Music Network section
Give the scrobble-master toggle, the enrichment-primary picker and the
provider list each a boxed SettingsGroup with an accent header, and switch
the add-a-service provider rows to the boxed panel style for consistent
contrast with the rest of settings.
* feat(settings): titled boxes for Integrations sections + cover source label
Wrap the Discord enable toggle, the Discord cover-source picker (now with a
"Cover art source" title and explainer), Bandsintown and Show-in-Now-Playing
in titled SettingsGroup panels so each single-item section gets the same
accent-headed boxed look. New cover-source strings across all 9 locales.
* feat(settings): box Lyrics tab sections
Wrap the lyrics-sources customizer and the sidebar-style picker in titled
SettingsGroup panels (reusing the existing section titles).
* refactor(settings): consistent content inset in SettingsGroup
Add a body wrapper with a small left inset so every boxed section indents its
controls uniformly (title stays flush at the box edge). Defined once in the
component instead of per section.
* feat(settings): box Storage tab sections incl. cover art cache
Wrap media directory, cover art cache strategy, next-track buffering and
downloads in titled SettingsGroup panels (reusing existing section titles);
align the cover-cache table's first column flush with the new content inset.
* feat(settings): box Library tab, relocate Lucky Mix, add SettingsToggle
- Add a reusable SettingsToggle component for the repeated label/desc/switch row.
- Box the Random Mix blacklist (grouping built-in keywords with the custom
filter), Ratings and the Analytics strategy section.
- Move the "Show Lucky Mix in menu" toggle out of the blacklist and up next to
split-mix navigation and now-playing-at-top in the sidebar customizer.
* feat(settings): box remaining Appearance sections
Wrap library grid, UI scale, font and seekbar style in titled SettingsGroup
panels (reusing the existing section titles).
* feat(settings): box System language, logging and backup sections
Wrap language and logging in titled SettingsGroup panels, and rework the
backup section to drop its redundant inline header (the subsection already
provides it) and box its content. About / Contributors / Licenses stay as
free display content.
* feat(settings): box remaining Audio sections
Wrap Hi-Res, equalizer, playback speed, audio output device and track
previews in titled SettingsGroup panels (reusing the existing section titles).
* feat(settings): box Input tab keybinding sections
Wrap the in-app and global shortcut lists in titled SettingsGroup panels.
* feat(settings): box the Personalisation tab
Convert every customizer (sidebar, home, artist, queue toolbar, playlist,
player bar) to plain inner containers and wrap each in a titled SettingsGroup,
so the boxed look is consistent without nested cards. Box the queue display
mode picker too.
* feat(settings): box the Themes sections above the store
Add a boxed option to the flat Themes sections and apply it to Your Themes,
Auto-Switch Theme and Import (the theme store stays unboxed). Drop the inner
settings-card from InstalledThemes, ThemeImportSection and the scheduler so
the SettingsGroup is the only frame.
* fix(settings): give the Themes boxes a card carrier and accent header
The flat Themes sections had no settings-card behind them, so the bg-app
SettingsGroup had no contrast against the page. Box each above-store section
as settings-card > titled SettingsGroup (accent header) like the rest.
* fix(settings): clean up the server library sync status line
Collapse the offline status to a single icon + phrase ("Server offline —
sync deferred") instead of a redundant "Deferred" badge alongside it, and
drop the now-unused string across all 9 locales.
* fix(queue): keep toolbar toggle buttons coloured active while hovered
The generic .queue-round-btn:hover rule outweighed .active in specificity, so
an active button kept the hover colour until the pointer left — the toggle
only looked on after moving the mouse away. Add an explicit active-hover rule
(mirroring the mini player) so active wins immediately on click.
* fix(settings): fix Lyrics triple title, drop dead Discord cover keys
- Remove LyricsSourcesCustomizer's own section header (the subsection already
titles it) and make its inner cards plain; the Lyrics boxes are now title-less.
- Drop the dead discordCoverSource/discordCoverSourceDesc i18n keys (superseded
by discordCoverTitle/Desc) and un-jam the libraryIndexServer status line in
all 9 locales.
* refactor(settings): drop redundant group titles and double frames
Single-group sections duplicated the subsection title in the group header — make
those groups title-less so the subsection header is the only title. A card whose
sole child is one group now collapses via CSS so single-group sections render a
single frame (matching the card-less Lyrics layout) instead of a card-in-group
double border. Multi-group cards keep their frame as the grouping container.
* fix(settings): keep the flat Themes cards framed when collapsing single-group cards
The single-group card collapse also flattened the Themes section cards, which —
not being inside an accordion — are themselves the contrast surface. Exclude
.themes-section descendants from the collapse.
* refactor(settings): use SettingsToggle for Appearance and System toggle rows
Replace the hand-rolled toggle-row markup in the Appearance visual options and
System tray/Linux/changelog rows with the shared SettingsToggle component, and
extend it with a searchText prop and ReactNode descriptions for the remaining
call sites.
* refactor(settings): roll SettingsToggle out to Integrations, Audio and Storage
Replace hand-rolled toggle rows in the Discord/Bandsintown/Now-Playing,
Hi-Res, hot cache and playback behaviour/rate sections with SettingsToggle.
Make its label optional (desc-only rows whose title is the group header) and
add searchText/id pass-throughs.
* refactor(settings): use SettingsToggle for the remaining standard toggle rows
Track previews master, sidebar lyrics style, YouLyPlus/static-only, queue
display mode and the sidebar split-nav/now-playing/lucky-mix rows now use the
shared component. Genuinely custom rows (drag lists, the skip-star threshold,
the AudioMuse row with its inline link, the fine-step advanced badge) stay
hand-rolled.
* fix(settings): drop duplicate titles on Hi-Res/Bandsintown/Now-Playing, un-jam locale line
These single-toggle sections kept a group title identical to their subsection
header; once the single-group card collapses the title rendered twice stacked.
Make them title-less (the subsection header is the label). Also split the
discordCoverTitle locale entry onto its own line in all 9 locales.
* feat(settings): restore section icons in boxed Themes headers
SettingsGroup gained an optional accent icon slot rendered before the
title; ThemesTab forwards the Palette/Clock/Upload icons the boxed
sections lost when they moved off the bespoke <h2> header.
* style(settings): re-indent SettingsGroup children to nesting level
Pure whitespace: children wrapped in SettingsGroup were left at their
pre-wrap indent. No content change (git diff -w is empty).
* fix(settings): clarify Native Hi-Res Playback description
The old copy led with the disabled-state behaviour ("forces 44.1 kHz"),
which read as if the toggle itself locked output to 44.1 kHz. Describe
what enabling actually does: play each track at its native sample rate
(reconfiguring the output device to match) instead of resampling to
44.1 kHz. Updated across all 9 locales.
* docs: changelog + what's-new for the settings layout refactor (#1126)
|
||
|
|
028eb65f7d |
feat(titlebar): selectable window button styles + minimize toggle (#1083)
* feat(titlebar): selectable window button styles + minimize toggle Custom title bar (Linux) gains a window-button style picker, mirroring the seekbar style picker pattern. Six form-named styles: dots, dotsGlyph, flat, pill, outline, glyph. All buttons now carry minimize/maximize/close glyphs for clear, colour-blind-friendly iconography; dots reveal glyphs on hover, dotsGlyph always shows them. - New authStore state windowButtonStyle (default dots) + showMinimizeButton, with rehydrate validation falling back to dots on unknown values. - WindowButtonPreview reuses the real .titlebar-btn classes for WYSIWYG tiles. - Picker + minimize toggle render under the Custom title bar setting, gated on the toggle being on. - Monochrome styles use --text-primary glyphs and stronger borders for contrast on dark themes. - Dev-build grey marker scoped to the real title bar so previews show true colours. - i18n keys in all 9 locales; setter and rehydrate tests. * docs(changelog): window button styles (#1083) |
||
|
|
f9df918c72 |
feat(themes): community Theme Store + semantic-token refactor (#1009)
* feat(themes): add semantic tokens for the theme-store contract (B0 P1) Additive: define --highlight, --accent-2, --bg-deep, --bg-elevated and --text-on-accent on the :root base as --ctp-* mappings. They resolve per-theme automatically and nothing consumes them yet (zero behaviour change) — groundwork for replacing direct --ctp-* use in components. * refactor(themes): components consume semantic tokens, not --ctp-* (B0 P2) Replace every direct --ctp-* reference in component/layout/track CSS and TSX inline styles with the readable semantic token (--bg-app, --accent, --highlight, --text-on-accent, …). --ctp-* now survives only as the Catppuccin palette layer the base maps from, and as the deliberate categorical rainbow in Composers/Genres/artistsHelpers (left untouched). This is the readable contract surface for the community theme store. Divergences (theme set a semantic var != its --ctp- source) are corrections — the element now uses the theme's real semantic colour. * feat(themes): add player-bar title/artist color tokens New optional --player-title / --player-artist, defaulting to --text-primary / --text-secondary so nothing changes unless a theme overrides them. Lets a theme give the now-playing readout its own colour as a plain token. * refactor(themes): token-only theme library (flatten, whitelist, one file per theme) Turn every built-in theme into a single self-contained [data-theme] var block of semantic whitelist tokens (plus the internal --ctp-* palette layer): - Flatten all themes: drop structural override rules, @keyframes, and global-token overrides (radius / shadow-elevation / transition / spacing / font / focus-ring). Signature player-bar readout colours are preserved via the new --player-title / --player-artist tokens. - Normalize the var blocks to the semantic whitelist: drop the alternate token vocabulary (nav-active / scrollbar / bg-input / success / border-default / ...); rename --success -> --positive and --border-default -> --border where no whitelist equivalent was set. Migrate the few components that read those tokens to the whitelist equivalents. - Split multi-theme files so each theme ships as its own file, making the built-in set 1:1 with the per-theme store packaging. Kept as-is (built-in, not flattened): the two colour-blind-safe accessibility themes, plus the two curated core skins. * chore(themes): remove seven themes retired after the token refactor These themes leaned on heavy structural overrides and were dropped rather than flattened. Full removal each: the CSS file(s), the index.css import, the Theme type union, and the ThemePicker entry. * feat(themes): granular tokens — track lists Wire track rows to per-region tokens: row hover (--row-hover), the now-playing row + indicator (--row-playing-bg / --row-playing-text), track title/artist/ number/duration text, column-header text, row dividers, and the resize-handle active colour. Covers the desktop tracklist, the shared song-row (Tracks hub / search), and the mobile tracklist. Drop a baked border fallback. Visual no-op. * feat(themes): granular tokens — cards Wire album and artist cards to per-region tokens (--card-hover-border, --card-title, --card-subtitle, --card-placeholder-bg). Visual no-op. * fix(themes): drop undefined/baked colour aliases Replace the undefined --bg-surface (resolved to nothing — broken placeholder backgrounds and filter input) with --card-placeholder-bg / --input-bg, and the baked-hex aliases --color-error / --color-warning with --danger / --warning so themes can actually recolour them. * feat(themes): Spectrum demo theme + trim unused cascade tokens Add a loud built-in demo theme that gives each region its own hue (sidebar green, player pink, lists cyan, cards gold, menus red, controls blue) so the per-region granularity is obvious when you switch to it. Drop two unused cascade tokens (--sidebar-text-active, --row-active-bg) and the unused on-media block (those media surfaces stay static by design). * style(themes): make Spectrum demo brutally loud Full-saturation neon per region (toxic green sidebar, magenta player, cyan lists, acid-yellow cards, blood-red menus, electric-blue controls, purple scrollbar) so the per-region separation is unmistakable. The earlier soft tints were too subtle to read. * feat(themes): name the granular demo theme Braindead * feat(themes): granular per-region tokens — cascade layer + sidebar Add an optional per-region token layer (semantic-cascade.css) so a theme can recolour individual regions — sidebar hover, player controls, list rows, menus, inputs, on-media surfaces — independently of the global tokens. Every token defaults to its base token (or a media-safe literal), so this is a visual no-op until a theme overrides one; it only adds control points. Wire the sidebar region as the first consumer and drop the baked grey fallbacks (--bg-tertiary, etc.) that no theme could reach. * feat(themes): granular tokens — controls, menus, scrollbar Wire inputs, buttons, sliders, the custom-select, context menus, submenus and modals to per-region tokens, and tokenise the scrollbar. Complete B0 by dropping the last direct --ctp-* references in the input/button/progress/ scrollbar utility CSS. Fix three undefined-token bugs that fell back to nothing (so no theme could reach them): --surface-2 (context-menu hover had no highlight), --bg-surface (submenu create-input had no background), and the baked grey fallbacks in the custom-select. Every other new token defaults to today's value — a visual no-op that only adds override points. * feat(themes): granular tokens — player bar Wire the desktop player bar's transport controls, time toggle, and overflow menu to per-region tokens (--player-control, --player-time-toggle-*, etc.). Fix the undefined --surface-hover/--surface-active grey fallbacks on the time toggle. Visual no-op; defaults match today's values. * chore(themes): remove empty theme stub files Six theme CSS files were reduced to comment-only stubs by the flatten sweep but their files and @import lines remained. Five are empty structural companions of now-flattened themes (morpheus, p-dvd, aero-glass, luna-teal) and two are orphans of cut themes (order-of-the-phoenix, pandora). Removed the files and their imports. * feat(themes): runtime injection foundation for the theme store Plumbing for installed community themes ahead of the in-app store UI, nothing user-visible yet: - installedThemesStore: persisted (localStorage) record of installed community themes incl. their CSS text, so an active community theme is available synchronously at startup (no flash, fully offline). - themeInjection: reconcile <head> <style data-installed-theme> elements with the store; lightweight defense-in-depth sanitize on top of CI. - themeRegistry: jsDelivr registry client with a 12h localStorage cache and stale-on-error fallback. - App: inject installed themes before applying data-theme, in both webviews. - themeStore: widen the Theme type to accept dynamic installed ids. * feat(themes): dedicated Themes settings tab Move theme selection and the day/night scheduler out of Appearance into a new dedicated Themes tab — the future home of the community Theme Store. Appearance keeps grid columns, visual options, UI scale, font and seekbar. - ThemesTab: theme picker + scheduler (relocated verbatim). - AppearanceTab: drop the two relocated sections + now-unused imports. - Register the tab in settingsTabs (Tab union, resolveTab, search index) and Settings (tab bar, render, label map). - i18n: settings.tabThemes in all 9 locales. * feat(themes): community Theme Store browse + install Add the Theme Store section to the Themes tab: - Fetch the jsDelivr registry (12h cache, stale-on-error fallback). - Search by name/author/description + filter by light/dark + refresh. - Per-row CDN thumbnail, name, author, description and actions: Install / Apply / Update / Uninstall. Installing fetches the CSS, persists it (localStorage) and the runtime injection applies it; uninstalling the active theme falls back to the matching core. - Rating slot left reserved (deferred). - i18n: themeStore* keys in all 9 locales. * feat(themes): slim bundle to fixed cores + flat Themes tab Remove the 86 store palettes (incl. braindead) from the app bundle — the CSS files, their index.css imports, the Theme union and the picker data — leaving only the six fixed cores (Catppuccin Mocha/Latte, Kanagawa Wave, Stark HUD, Vision Dark/Navy). Everything else installs from the store. Themes tab is rebuilt flat (no collapsible accordions): - "Your Themes": one card grid of the fixed cores + installed community themes; click to apply, uninstall on community ones (active theme falls back to the matching core). Catppuccin prefix on Mocha/Latte; a CVD-safe pill on the colour-blind-safe Vision themes. - Scheduler day/night options include installed themes. - Theme Store: alphabetical order, thumbnail lightbox, and a submit hint above the search linking to the themes repository. - Nav order: Servers, Library, Audio, Themes, Appearance, Lyrics, … - ThemePicker accordion removed; fixed-theme data moved to fixedThemes.ts. - i18n for all new strings across 9 locales. * feat(themes): reset removed-from-bundle themes to a bundled fallback After slimming the bundle to the six fixed core themes, a profile upgraded from an older build may have an active or scheduler theme that is now store-only and not installed — it has no [data-theme] block and would render as unstyled :root. Reset any theme/themeDay/themeNight that is neither bundled nor installed to a bundled fallback: Mocha for the main + night slots, Latte for the day slot. Runs synchronously in runPreReactBootstrap, rewriting the persisted selection in localStorage before React mounts (no flash; Zustand rehydrates after first paint). No auto-install and no network — the fallback is always a bundled theme, so it works offline. * feat(themes): floating back-to-top button on the Themes tab The Themes tab can get long (theme grid + scheduler + full store list), so add a floating back-to-top affordance that appears once the page is scrolled and smooth-scrolls to the top. It is portalled into the route host and positioned absolute against it — the main scroll viewport sets contain: paint, which would otherwise make position: fixed resolve against the scrolling box and drift with the content. Reusable component (scroll viewport id + threshold props); i18n common.backToTop added in all nine locales. * feat(themes): accessibility + state polish for the Theme Store - Reuse the shared CoverLightbox for the thumbnail preview instead of a second inline dialog — gains a visible close button and a focus-managed, portalled dialog, and drops duplicated markup. - Theme cards expose aria-pressed so assistive tech announces the selected theme, not just the visual check. - Transient store messages get live-region roles (loading/empty/install failure = status, fetch error = alert). - Thumbnails degrade gracefully when offline/missing (hide the broken-image glyph; the thumbnail button no longer stretches with the row, so its background can't show as letterbox bars). * feat(themes): larger store-row thumbnails (120x75 -> 200x125) The list previews were too small to make a theme out; bump the display size (same 1.6 aspect). Thumbnails are now served at 720x450, so the larger display stays crisp. * fix(themes): bust thumbnail cache on registry change jsDelivr serves theme thumbnails with a 7-day max-age, so when a thumbnail is updated the webview keeps showing its cached old image (the path is unchanged). Append the registry's generatedAt as a cache-busting query to the thumbnail URLs (list + lightbox); it changes on every themes push, so a registry refresh makes the webview re-fetch and reflect the current CDN image instead of a stale one. * docs(themes): changelog + credits for the Theme Store Add the 1.48.0 "Themes — community Theme Store" changelog entry (PR #1009) and the matching line in the Psychotoxical credits. * fix(themes): address PR review (uninstall hygiene, validation, polish) Uninstall/scheduler & validation: - uninstallTheme() repairs every selection slot (active + day + night), not just the manual one, and is shared by both uninstall buttons (dedup). - Validate theme CSS at install time and skip persisting CSS that won't inject (no more "installed/active but renders nothing" with no feedback). - Harden the runtime validator: exactly one rule, scoped exactly to the theme's [data-theme='<id>'] selector (no unscoped/foreign selectors), no at-rules, url() only data:, no expression()/javascript:, size-capped. Tokens & polish: - Fix three dangling undefined tokens (--surface-2 x2, --bg-surface). - Finish the warning/success token sweep (--warning / --positive, themeable). - Apply the active theme synchronously before React mounts (no first-frame flash) and inject installed themes up front. - One-time, dismissible notice when the slim-bundle migration reset a theme. - Update badge uses semver, not string inequality. - Offline/stale indicator in the store; cross-window theme sync; drop the now dead REMOVED_THEME_REMAP and Card.mode field. Tests: themeInjection (validator + sync), themeRegistry (cache/force/stale/ malformed), uninstallTheme (slot repair), migration notice. i18n in all nine locales. Full suite green (1755 tests). * test(bootstrap): cover startup theme apply + cross-window sync The review fixes added applyThemeAtStartup / installCrossWindowThemeSync to bootstrap.ts (a hot-path file) without tests, dropping its coverage to 68.3% and failing the frontend hot-path coverage gate (>=70%). Add unit tests for both (and the no-op / malformed-storage paths); bootstrap.ts is back to ~98%. |
||
|
|
dc4eef1a97 |
feat(fullscreen-player): rebuilt static fullscreen player (#1001)
* feat(player): static media-center fullscreen player (v1) New lean fullscreen player: sharp full-bleed background (artist photo, cover fallback), no blur / no continuous animations. Bottom-left big cover bottom- flush with a full-width semi-transparent text bar (title with queue position, artist, year/genre + rating stars, next-up); control row of transport · center time · actions; full-width seekbar; live clock. Only the seekbar, time readout and clock update at runtime, each owning its state (no per-tick re-render). Reuses FsSeekbar/FsPlayBtn, the cover/artist hooks, idle-fade and queue helpers. Wired in AppShell; old player kept for A/B. * feat(fullscreen-player): true waveform seekbar instead of thin bar Replace FsSeekbar with the real WaveformSeek (cucadmuh's idea). The taller canvas grows the bottom cluster upward, shifting the info/control rows up. Height clamped to 32-52px. * feat(fullscreen-player): up-next popover + control-bar styling - Queue button opens a semi-transparent 'Up next' popover anchored bottom right; clicking a row jumps to that queue item. - Larger bottom-right action buttons. - Control row gets its own darker semi-transparent bar (touches the info bar above) for contrast; play button matches the plain transport buttons (no white circle, same size). * feat(fullscreen-player): high-res (2000px) background cover Fetch the full-screen background cover at the 2000px tier via the existing on-demand fullRes path (same getCoverArt fetch, saved as a high-res WebP outside the backfill pipeline) instead of the low-res 500px pipeline tier. usePlaybackCoverArt now forwards a fullRes option to useCoverArt. * feat(fullscreen-player): scrolling lyrics overlay + control-bar polish - Lyrics button next to Queue toggles a centered, dark semi-transparent scrolling-lyrics overlay (reuses FsLyricsApple). - Control bar darkened to match the lyrics overlay (0.88). - Close button sized down to harmonize with the clock. * feat(fullscreen-player): make rating stars clickable The rating stars next to the year were display-only. Wire them to queueSongRating (same path as the player bar / context menu): click to set, click the current value to clear, with a hover preview. Keeps the lucide outline look to match the rest of the control bar. * fix(fullscreen-player): stable, high-res album cover The foreground cover was keyed per track, so Navidrome's per-track `mf-<id>` coverArt re-triggered the distinct-disc heuristic and reloaded the cover on every song change within the same album. Key it on albumId (via useAlbumCoverRef) so it stays put while the album is unchanged. It also used the low-res tier; reuse the fullRes 2000px cover already fetched for the background so the foreground is crisp and both share a single fetch/decode. * refactor(fullscreen-player): remove the old player and its settings The static rebuild is now the only fullscreen player. Delete the old FullscreenPlayer component, its old-only parts (FsArt, FsPortrait, FsSeekbar, FsLyricsRail, FsLyricsMenu, useFsDynamicAccent) and its test. Remove the now-orphaned settings (showFullscreenLyrics, fsLyricsStyle, showFsArtistPortrait, fsPortraitDim) along with the Appearance 'Fullscreen player' section and its search entry. The new player always shows the artist photo with cover fallback and has its own lyrics toggle. Shared building blocks used by the static player (FsLyricsApple, FsPlayBtn, FsClock, FsTimeReadout, FsQueueModal, useFsArtistPortrait) are kept. * i18n(fullscreen-player): translate the new player's strings Wire the static player's previously English-only strings through i18n across all 9 locales: now-playing label, track position, up-next label, queue/lyrics/shuffle controls, and the queue overlay (title, empty, close). Reuses existing queue.title / common.close keys; adds six new keys to the player namespace. * docs(changelog): note fullscreen player rebuild (#1001) |
||
|
|
0f5ece6d03 |
feat(settings): library card grid max columns in Appearance (4–12, default 6)
Persist libraryGridMaxColumns, wire useCardGridMetrics and card grid layout, add i18n and settings search index; document performance hint in copy. |
||
|
|
dc5c64a109 |
refactor(waveform-seek): H3 — extract renderers + 2 hooks + SeekbarPreview component (#665)
* refactor(waveform-seek): H3.1 — extract helpers + constants + types * refactor(waveform-seek): H3.2 — extract drawSeekbar + style renderers to utils/waveformSeekRenderers.ts * refactor(waveform-seek): H3.3 — split renderers into static + animated * refactor(waveform-seek): H3.4 — extract SeekbarPreview to WaveformSeekPreview.tsx * refactor(waveform-seek): H3.5 — extract useWaveformHeights hook + hoist constants * refactor(waveform-seek): H3.6 — extract useWaveformInterpolation hook |
||
|
|
afd0786e6c |
refactor(settings): G.59 — extract AppearanceTab (#624)
Move the Appearance tab body into AppearanceTab: ThemePicker, theme scheduler (day/night themes + start times, 24h/12h locale-aware), visual options card (cover art bg, playlist cover photo, bitrate badge, floating player bar, artist images, Orbit trigger, preloadMiniPlayer, custom titlebar on Linux non-tiling), UI scale presets, font picker, fullscreen player portrait + dim slider, seekbar style picker. The `isTilingWm` state + `is_tiling_wm_cmd` invoke effect, plus the `useThemeStore` and `useFontStore` hooks, move into AppearanceTab — no other tab needs them. Settings.tsx 1761 → 1404 LOC (−357). Drops 9 imports that only the appearance tab used (ThemePicker, THEME_GROUPS, SeekbarPreview, useThemeStore, useFontStore, FontId, SeekbarStyle, lucide Clock / Maximize2 / Type / ZoomIn). Pure code move — no behaviour change. |