Fix menubar, add lazy loading, improve image quality, limit search results, filter browse artists

This commit is contained in:
2026-01-25 01:16:17 +00:00
committed by GitHub
parent 43a51b165b
commit b5fc05382e
6 changed files with 29 additions and 19 deletions

View File

@@ -124,13 +124,13 @@ export default function AlbumPage() {
// Dynamic cover art URLs based on image size
const getMobileCoverArtUrl = () => {
return album.coverArt && api
? api.getCoverArtUrl(album.coverArt, 280)
? api.getCoverArtUrl(album.coverArt, 600)
: '/default-user.jpg';
};
const getDesktopCoverArtUrl = () => {
return album.coverArt && api
? api.getCoverArtUrl(album.coverArt, 300)
? api.getCoverArtUrl(album.coverArt, 600)
: '/default-user.jpg';
};
@@ -146,8 +146,8 @@ export default function AlbumPage() {
<Image
src={getMobileCoverArtUrl()}
alt={album.name}
width={280}
height={280}
width={600}
height={600}
className="rounded-md shadow-lg"
/>
</div>
@@ -182,8 +182,8 @@ export default function AlbumPage() {
<Image
src={getDesktopCoverArtUrl()}
alt={album.name}
width={300}
height={300}
width={600}
height={600}
className="rounded-md"
/>
<div className="space-y-2">

View File

@@ -19,7 +19,9 @@ import Loading from '@/app/components/loading';
import { useInView } from 'react-intersection-observer';
export default function BrowsePage() {
const { artists, isLoading: contextLoading } = useNavidrome();
const { artists: allArtists, isLoading: contextLoading } = useNavidrome();
// Filter to only show album artists (artists with at least one album)
const artists = allArtists.filter(artist => artist.albumCount && artist.albumCount > 0);
const { shuffleAllAlbums } = useAudioPlayer();
// Use our progressive loading hook
@@ -78,12 +80,13 @@ export default function BrowsePage() {
<div className="relative">
<ScrollArea>
<div className="flex space-x-4 pb-4">
{artists.map((artist) => (
{artists.map((artist, index) => (
<ArtistIcon
key={artist.id}
artist={artist}
className="shrink-0 overflow-hidden"
size={190}
loading={index < 10 ? 'eager' : 'lazy'}
/>
))}
</div>
@@ -110,7 +113,7 @@ export default function BrowsePage() {
<ScrollArea className="h-full">
<div className="h-full overflow-y-auto">
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7 gap-4 p-4 pb-8">
{albums.map((album) => (
{albums.map((album, index) => (
<AlbumArtwork
key={album.id}
album={album}
@@ -118,6 +121,7 @@ export default function BrowsePage() {
aspectRatio="square"
width={200}
height={200}
loading={index < 20 ? 'eager' : 'lazy'}
/>
))}
</div>

View File

@@ -36,6 +36,7 @@ interface AlbumArtworkProps extends Omit<
aspectRatio?: "portrait" | "square"
width?: number
height?: number
loading?: 'eager' | 'lazy'
}
export function AlbumArtwork({
@@ -43,6 +44,7 @@ export function AlbumArtwork({
aspectRatio = "portrait",
width,
height,
loading = 'lazy',
className,
...props
}: AlbumArtworkProps) {
@@ -160,7 +162,7 @@ export function AlbumArtwork({
onLoad={handleImageLoad}
onError={handleImageError}
priority={false}
loading="lazy"
loading={loading}
/>
) : (
<div className="w-full h-full bg-muted rounded flex items-center justify-center">

View File

@@ -27,6 +27,7 @@ interface ArtistIconProps extends React.HTMLAttributes<HTMLDivElement> {
size?: number
imageOnly?: boolean
responsive?: boolean
loading?: 'eager' | 'lazy'
}
export function ArtistIcon({
@@ -34,6 +35,7 @@ export function ArtistIcon({
size = 150,
imageOnly = false,
responsive = false,
loading = 'lazy',
className,
...props
}: ArtistIconProps) {
@@ -77,6 +79,7 @@ export function ArtistIcon({
width={size}
height={size}
className="w-full h-full object-cover transition-all hover:scale-105"
loading={loading}
/>
</div>
);
@@ -116,6 +119,7 @@ export function ArtistIcon({
}
)}
className={isResponsive ? "object-cover" : "object-cover w-full h-full"}
loading={loading}
/>
</div>
</div>

View File

@@ -191,11 +191,8 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu
<MenubarMenu>
<MenubarTrigger className="relative">File</MenubarTrigger>
<MenubarContent>
<MenubarSub>
<MenubarSubTrigger>New</MenubarSubTrigger>
<MenubarSubContent className="w-[230px]">
<MenubarItem>
Playlist <MenubarShortcut>N</MenubarShortcut>
<MenubarItem onClick={() => router.push('/library/playlists')}>
View Playlists
</MenubarItem>
<MenubarItem disabled>
Playlist from Selection <MenubarShortcut>N</MenubarShortcut>
@@ -205,8 +202,6 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu
</MenubarItem>
<MenubarItem>Playlist Folder</MenubarItem>
<MenubarItem disabled>Genius Playlist</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarItem>
Open Stream URL <MenubarShortcut>U</MenubarShortcut>
</MenubarItem>
@@ -386,7 +381,7 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu
) : navidromeUrl ? (
navidromeUrl
) : (
<span className="italic text-gray-400">Not set</span>
<span className="italic text-gray-400">Auto-configured</span>
)}
</span>
</div>

View File

@@ -35,7 +35,12 @@ export default function SearchPage() {
try {
setIsSearching(true);
const results = await search2(query);
setSearchResults(results);
// Limit results to 5 of each type
setSearchResults({
artists: results.artists.slice(0, 5),
albums: results.albums.slice(0, 5),
songs: results.songs.slice(0, 5)
});
} catch (error) {
console.error('Search failed:', error);
setSearchResults({ artists: [], albums: [], songs: [] });