* fix(ui): prevent Safari album grid resize when top menus open
* fix(ui): disable scroll lock for all popovers
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
The theme rounded the cover image directly and set a border radius on
albumContainer, which has no background or clipping, so it rounded
nothing. The hover overlay is a sibling of the image inside the same
link, so it kept square corners that poked out over the rounded cover.
Move the radius to that link and clip it, so both the image and the
overlay follow the same rounded box. This also covers the mobile bar,
which is always visible.
Fixes#6110
* added catppuccin mocha theme
* added catppuccin mocha theme to index.js
* fix syntax
* add catppuccin frappé theme
* made frappe and mocha themes more consistant with official color palette and added comments for easy verification
* same for macchiato, seperate commit in case original is preferred
* added comments to .js files
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* fix(ui): anchor detail pages to the top when opened from a list
React Router keeps the previous page's scroll offset, so opening an album from
a scrolled list started the detail page mid-song-list. Artist pages had the
same bug; it just shows less because the artist list is rarely long enough to
scroll far.
Keyed on the record id rather than mount, so detail-to-detail navigation (an
album's artist link) resets too, and so the scroll waits for the record instead
of firing against an empty page.
* feat(ui): remember each route's scroll offset
A hook that saves window.scrollY per history entry and, on navigation, tops a
pushed route or returns a popped one to where it was. Keyed on location.key so
back and forward each restore their own offset, and bounded because history
entries are not.
Callers pass their own readiness: restoring before the rows render leaves the
document too short, so the browser clamps to the top and the offset is lost with
no error to show for it.
* refactor(ui): fold scroll-to-top into route scroll restoration
useScrollToTop only ever forced the top, so it fixed opening a detail page from a
scrolled list and did nothing for the return trip: coming back to the list landed
wherever it happened to be. The new hook covers both, and its readiness argument
carries over the reason the old one keyed on the record id - waiting for the
record rather than firing against an empty page.
* feat(ui): restore the album list's position when returning to it
The list is the page worth remembering: scrolling a long way to find an album and
landing back at the top is the annoyance the detail-page scroll fix could not
reach.
Mounted as a pass-through around the List's child rather than beside it, because
React Admin calls Children.only on List children and clones that one child with
the list props - which is also how this reads loaded/total to wait for rows.
* fix(ui): key scroll restoration on the route, not location.key
Hash history never assigns location.key - history.js calls createLocation with an
undefined key and warns that it cannot carry state - so every route collapsed
into one slot. The detail page's own scroll listener then overwrote the list's
saved offset with 0, and going back restored that 0. Only the scroll-to-top half
worked, which is what made it look fine.
Keyed on pathname+search instead. The spec that would have caught this asserts
two routes keep separate offsets; the previous ones mocked the router and so
only ever confirmed the assumption.
* refactor(ui): tidy up scroll restoration after review
Four cleanups, none changing behaviour:
ScrollRestorer read loaded/total off whatever props React Admin happened to clone
in. useListContext is the contract for those values and is already used three
times elsewhere, including further down this same file; the clone payload is an
implementation detail that would fail silently if it ever changed.
The restore runs in a layout effect now. A passive effect is flushed after paint,
so an image-heavy grid was painted at the old offset and then jumped.
MAX_ENTRIES matches the naming every other module-level cap in common/ uses.
The per-instance guard against re-restoring was deletable with a green suite, so
it now has a spec: readiness flickering on one route must not scroll twice.
* fix(ui): resolve media queries on the first render
MUI defaults useMediaQuery and withWidth to SSR-safe two-pass rendering: the first
render reports the wrong breakpoint and a layout effect corrects it. Navidrome is
client-only, so every mount paints a layout it immediately reflows. Album tiles
render without their artist line and grow 14px when it arrives, and react-admin's
own buttons paint labelled before collapsing to icons, which together grew the
album list 79px right after a scroll restore and dragged the position with it.
Setting noSsr on the theme reaches react-admin's internals too. withWidth needs its
own option because it gates on a mount flag rather than on the media query.
* fix(ui): keep restoring the scroll offset until it sticks
A single scrollTo assumes the page is already at its final height. It often is not:
the artist page reports ready as soon as its cached header record renders, while the
albums below are still loading, so the browser clamps the offset to the top of a
viewport-tall document and it is lost with no error.
The restore now retries until the offset lands, yielding as soon as the position moves
somewhere we did not put it. Keying that on input events instead breaks the trackpad
back-swipe, whose wheel momentum keeps firing through the restore window.
Offsets are also committed when leaving the page rather than on every scroll. Tearing
the page down collapses the document and snaps to the top, and a live listener recorded
that clamp over the offset being left behind.
* refactor(ui): tidy up scroll restoration after review
Folds the offset commit into the scroll tracker's own cleanup now that the tracker
ignores the collapse snap, so one effect does what two did. Skips scheduling the retry
loop when the first scrollTo already landed, and only pays for the scrollHeight read on
scroll events that reach the top, since that is the only case the guard can fire.
The theme hook's own prefers-color-scheme query runs above the ThemeProvider carrying
the new prop, so it needs noSsr passed directly or the auto theme still renders dark
first and flips.
Also lifts the repeated fake-timer fixture in the specs into one helper and restores
real timers from afterEach, so a failing assertion no longer leaves them installed for
every later spec.
* fix(ui): bank the scroll offset before the next page tops itself
Committing the offset from the scroll listener's passive cleanup ran too late. The
incoming page scrolls to the top in its own layout effect, and the outgoing page's
listener is still attached at that moment, so it recorded that 0 over the offset being
left behind. Whether it did depended on when the browser dispatched the scroll event
relative to React's passive flush, which made returning to a detail page lose its
position intermittently.
Moving the commit back into a layout cleanup makes it deterministic: React runs those
in the mutation phase, before the incoming page's layout effects. The scrollHeight
guard in the listener went with it, since it only covered the case where the incoming
page was shorter than the viewport and the ordering covers all of them.
Add Catppuccin Latte (the light version) theme based on the existing Catppuccin Macchiato theme.
The palette and player styling are adapted for light mode while staying as close as practical
to the existing Macchiato theme behavior. I've opted to use gray for the
color for controls.
The dark version appears to mix a few control/accent colors,
so for Latte I standardized those choices. This might be worth looking
into in a separate PR. It uses gray and blue.
Signed-off-by: Love Billenius <lovebillenius@disroot.org>
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
* Add Moonbase theme
A warm dark theme with gold (#d4a039) accents on deep charcoal
backgrounds (#0a0a09/#141413). Features muted cream text (#e5ddd3),
copper error states (#c45c3c), and subtle earthy secondary tones.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix review comments on Moonbase theme
- Fix CSS selector: use :not(.player-delete) instead of :not([class=".player-delete"])
- Fix MuiFormHelperText override structure: target error key directly
- Remove empty icon: {} and avatar: {} from NDLogin overrides
- Use comma-separated rgba syntax and hex for linear-gradient
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add Moonbase Alpha (light) and rename dark to Moonbase Bravo
Split the Moonbase theme into a complementary pair:
- Moonbase Alpha: warm cream/stone light theme with deep gold accents
- Moonbase Bravo: the original deep charcoal dark theme
Both share the same gold (#d4a039) brand accent, copper error states,
and earthy neutral palette. Alpha uses darkened gold (#9a7420) for
better contrast on light backgrounds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* Add Gruvbox Dark theme
Add Gruvbox Dark color theme including:
- gruvboxDark.js with full palette and component overrides
- gruvboxDark.css.js with custom player styles
* Fix: move error state to MuiFormHelperText
The secondary color (#3c3836) matches the panel/table cell background,
making checked MuiSwitch thumbs invisible. Add MuiSwitch override using
Gruvbox cyan (#458588), consistent with existing interactive elements.
* fix(ui): improve the lyric button of the AMusic theme
* fix(amusic): update styles for music player panel SVG and disabled button states
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
Set document.body.style.backgroundColor to match the current theme's background
color whenever the theme changes. This fixes the white background that appeared
during pull-to-refresh gestures on mobile or overscroll on desktop, where the
browser reveals the area behind the app content.
The background color is determined by the theme's palette.background.default
value if defined, otherwise falls back to Material-UI defaults (#303030 for
dark themes, #fafafa for light themes).
Signed-off-by: Deluan <deluan@navidrome.org>
* fix low contrast in "delete missing files" button
* make login screen a bit nicer
* style modal similar to rest of ui
* Add custom styles for Ra Pagination
* Refactor styles in amusic.js
Removed albumSubtitle color and updated styles for albumPlayButton and albumArtistName
* Add NDDeleteLibraryButton and NDDeleteUserButton styles
low contrast
* low contrast text on delete buttons
* playbutton color back to pink without background
* feat: Add SquiddiesGlass Theme
* feat: fix commnets by gemini-code-assist in PR
* feat: fix Prettier format
* feat: fix play button, and text mobile
* feat: fix play button, and text mobile, prettier
* feat: fix chip, title artist
* fix: loading albbun, play button color
* prettier
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Xavier Araque <francisco.araque@toolfactory.net>
Co-authored-by: Deluan <deluan@navidrome.org>
* first show at AMuisc Theme
* prettier
* fix Duplicate key 'MuiButton'
* fix file name
* Update amusic.js
* Add styles for NDAlbumGridView in amusic.js
* Fix MuiToolbar background property in amusic.js
* Fix syntax error in amusic.js background property
* run prettier
* fix banded table styling and more
* more styling to player
- fix some appearances of green in queue
- match queue styling to rest of theme
- round albumart in player and prevent rotation
* fix queue panel background and border
to make it stand out more against the background
* fix stray comma
and lint+prettier
* queue hover still green
and player preview image not rounded properly
* Update amusic.css.js
* more mobile color fixes
* artist page
* prettier
* rounded art in albumgridview
* small tweaks to colors and radiuses
* artist and album heading
* external links colors
* unify font colors + albumgrid corner radius
* get rid of queue hover green
* unify colors in player
same red shades as primary
* mobile player floating panel background shade of green
* unify border colors
and attempt to get album cover corner radius working
* final touches
* Update amusic.css.js
* fix invisible button color fir muibutton
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* fix css syntax on player queue color overrides
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* remove unused MuiTableHead
* sort theme list in index.js alphabetically
* remove unused properties
* Revert "fix css syntax on player queue color overrides"
This reverts commit 503bba321d958aed5251667c58214822ceb70f59.
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Fixed the multi-library selector dropdown background in the Ligera theme by changing the palette.background.paper value from 'inherit' to bLight['500'] ('#ffffff'). This ensures the dropdown has a solid white background that properly overlays content, making the library selection options clearly readable.
Closes#4502
Closes#1737
* wrapping playlist comment in a <Collapse> element
* Extract common collapsible logic into a component
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* spotify-improvement
* fixing the issue of applying styles to filter fields too
* Remove scrollbar styling.
Maybe we should simulate macOS's scrollbar behaviour, with something like this: https://gist.github.com/spemer/a0e218bbb45433bd611e68446523a00b
Co-authored-by: Rishabh Malhotra <rishabhmalhotraa01@gmail.com>
* Re-add tpbnick's Nord theme
* Run Prettier formatter on Nord theme
* Update themes index
* Fix button margins
* Modernise the look of switches
* Adjust margins and padding
* Fix sidebar's background colour not applying to all of sidebar when scrolling down
* Adjust App Bar box shadow
* Adjust roundedness
* Adjust shadows
* Adjust outlined inputs
* Add transitions to items in sidebar when hovered / losing hover
* Adjust border radiuses
* Adjust pagination buttons
* Add big play button from Spotify theme
* Remove playlist background gradient
* Adjust colour of MuiChip elelments
* Adjust table borders
* Remove duplicate MuiTableRow key
* Attempt to make switches in both the playlist section and settings section visable against background & the toggle. Not ideal.
* Style the player
* Format CSS to Prettier standards
* Fix mobile player style
* Make play button in album grid view blue
* Make main view background lighter