From 108ba53be2b741756dba6aca70ac17dfdfd20373 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 29 Nov 2025 17:38:19 -0800 Subject: [PATCH] lint all files --- eslint.config.mjs | 4 +- postcss.config.cjs | 10 +- .../item-detail-list.module.css | 18 -- .../item-detail-list/item-detail-list.tsx | 288 ------------------ .../components/album-list-infinite-grid.tsx | 23 +- .../components/subsonic-album-filters.tsx | 10 +- .../albums/hooks/use-album-list-filters.ts | 9 +- .../routes/dummy-album-detail-route.tsx | 9 +- .../components/album-artist-detail-header.tsx | 172 ++++++----- .../album-artist-list-header-filters.tsx | 5 +- .../album-artist-list-infinite-grid.tsx | 23 +- .../components/artist-list-header-filters.tsx | 4 +- .../components/artist-list-infinite-grid.tsx | 23 +- ...bum-artist-detail-top-songs-list-route.tsx | 4 +- .../actions/add-to-playlist-action.tsx | 24 +- .../context-menu/menus/queue-context-menu.tsx | 7 +- .../components/genre-list-infinite-grid.tsx | 23 +- .../features/lyrics/lyrics-actions.tsx | 2 +- .../mobile-fullscreen-player.module.css | 6 +- .../components/playerbar-seek-slider.tsx | 3 +- .../playlist-list-infinite-grid.tsx | 23 +- .../hooks/use-playlist-list-filters.ts | 13 +- .../search/components/command-palette.tsx | 1 - .../components/library-command-item.tsx | 4 +- .../settings/components/settings-header.tsx | 4 +- .../hooks/use-music-folder-id-filter.ts | 2 +- .../components/jellyfin-song-filters.tsx | 4 +- .../components/navidrome-song-filters.tsx | 4 +- .../components/song-list-infinite-grid.tsx | 23 +- .../context-menu/context-menu.module.css | 2 - 30 files changed, 202 insertions(+), 545 deletions(-) delete mode 100644 src/renderer/components/item-list/item-detail-list/item-detail-list.module.css delete mode 100644 src/renderer/components/item-list/item-detail-list/item-detail-list.tsx diff --git a/eslint.config.mjs b/eslint.config.mjs index 7d77d38a3..6cb0fda89 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -27,8 +27,6 @@ export default tseslint.config( rules: { ...eslintPluginReactHooks.configs.recommended.rules, ...eslintPluginReactRefresh.configs.vite.rules, - 'react-hooks/set-state-in-effect': 'off', - 'react-hooks/refs': 'off', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/no-duplicate-enum-values': 'off', '@typescript-eslint/no-explicit-any': 'off', @@ -45,6 +43,8 @@ export default tseslint.config( 'no-unused-vars': 'off', 'no-use-before-define': 'off', quotes: ['error', 'single'], + 'react-hooks/refs': 'off', + 'react-hooks/set-state-in-effect': 'off', 'react-refresh/only-export-components': 'off', 'react/display-name': 'off', semi: ['error', 'always'], diff --git a/postcss.config.cjs b/postcss.config.cjs index 0a1980dc6..913bb9b43 100644 --- a/postcss.config.cjs +++ b/postcss.config.cjs @@ -3,13 +3,13 @@ module.exports = { 'postcss-preset-mantine': {}, 'postcss-simple-vars': { variables: { - 'mantine-breakpoint-xs': '36em', - 'mantine-breakpoint-sm': '48em', - 'mantine-breakpoint-md': '62em', - 'mantine-breakpoint-lg': '75em', - 'mantine-breakpoint-xl': '88em', 'mantine-breakpoint-2xl': '120em', 'mantine-breakpoint-3xl': '160em', + 'mantine-breakpoint-lg': '75em', + 'mantine-breakpoint-md': '62em', + 'mantine-breakpoint-sm': '48em', + 'mantine-breakpoint-xl': '88em', + 'mantine-breakpoint-xs': '36em', }, }, }, diff --git a/src/renderer/components/item-list/item-detail-list/item-detail-list.module.css b/src/renderer/components/item-list/item-detail-list/item-detail-list.module.css deleted file mode 100644 index 62a1178da..000000000 --- a/src/renderer/components/item-list/item-detail-list/item-detail-list.module.css +++ /dev/null @@ -1,18 +0,0 @@ -.item-detail-container { - display: flex; - flex-direction: column !important; - width: 100%; - height: 100%; - padding: 0 var(--theme-spacing-md); -} - -.list-expanded-container { - width: 100%; - height: 100%; -} - -.item-list { - width: 100%; - height: 100%; - padding-bottom: var(--theme-spacing-sm); -} diff --git a/src/renderer/components/item-list/item-detail-list/item-detail-list.tsx b/src/renderer/components/item-list/item-detail-list/item-detail-list.tsx deleted file mode 100644 index 2b5f23381..000000000 --- a/src/renderer/components/item-list/item-detail-list/item-detail-list.tsx +++ /dev/null @@ -1,288 +0,0 @@ -import throttle from 'lodash/throttle'; -import { AnimatePresence, motion, Variants } from 'motion/react'; -import { useOverlayScrollbars } from 'overlayscrollbars-react'; -import { - MouseEvent, - Ref, - UIEvent, - useCallback, - useEffect, - useLayoutEffect, - useMemo, - useRef, - useState, -} from 'react'; -import { List, ListImperativeAPI, RowComponentProps, useListRef } from 'react-window-v2'; - -import styles from './item-detail-list.module.css'; - -import { ItemDetail } from '/@/renderer/components/item-detail/item-detail'; -import { ExpandedListItem } from '/@/renderer/components/item-list/expanded-list-item'; -import { - useItemListState, - useItemListStateSubscription, -} from '/@/renderer/components/item-list/helpers/item-list-state'; -import { useElementSize } from '/@/shared/hooks/use-element-size'; -import { useMergedRef } from '/@/shared/hooks/use-merged-ref'; -import { LibraryItem } from '/@/shared/types/domain-types'; - -export interface ItemDetailListProps { - data: unknown[]; - enableExpansion?: boolean; - enableSelection?: boolean; - initialTopMostItemIndex?: - | number - | { - align: 'center' | 'end' | 'start'; - behavior: 'auto' | 'smooth'; - index: number; - offset?: number; - }; - itemType: LibraryItem; - onEndReached?: (index: number) => void; - onItemClick?: (item: unknown, index: number) => void; - onItemContextMenu?: (item: unknown, index: number) => void; - onItemDoubleClick?: (item: unknown, index: number) => void; - onRangeChanged?: (range: { endIndex: number; startIndex: number }) => void; - onScroll?: (e: UIEvent) => void; - onScrollEnd?: () => void; - onStartReached?: (index: number) => void; - ref: Ref; - totalItemCount?: number; -} - -const expandedAnimationVariants: Variants = { - hidden: { - height: 0, - minHeight: 0, - }, - show: { - minHeight: '300px', - transition: { - duration: 0.3, - ease: 'easeInOut', - }, - }, -}; - -export const ItemDetailList = ({ - data, - enableExpansion = false, - enableSelection = false, - initialTopMostItemIndex = 0, - itemType, - onEndReached, - onItemClick, - onItemContextMenu, - onItemDoubleClick, - onRangeChanged, - onScroll, - onScrollEnd, - onStartReached, - totalItemCount = 0, -}: ItemDetailListProps) => { - const itemDetailRef = useListRef(null); - const scrollContainerRef = useRef(null); - const { ref: containerRef, width: containerWidth } = useElementSize(); - const mergedContainerRef = useMergedRef(containerRef, scrollContainerRef); - - const internalState = useItemListState(); - - const [initialize] = useOverlayScrollbars({ - defer: true, - events: { - initialized(osInstance) { - const { viewport } = osInstance.elements(); - viewport.style.overflowX = `var(--os-viewport-overflow-x)`; - viewport.style.overflowY = `var(--os-viewport-overflow-y)`; - }, - }, - options: { - overflow: { x: 'hidden', y: 'scroll' }, - paddingAbsolute: true, - scrollbars: { - autoHide: 'leave', - autoHideDelay: 500, - pointers: ['mouse', 'pen', 'touch'], - theme: 'feishin-os-scrollbar', - visibility: 'visible', - }, - }, - }); - - useEffect(() => { - const { current: root } = scrollContainerRef; - - if (root) { - initialize({ - elements: { viewport: root.firstElementChild as HTMLElement }, - target: root, - }); - } - }, [itemDetailRef, initialize]); - - const hasExpanded = useItemListStateSubscription(internalState, (state) => - state ? state.expanded.size > 0 : false, - ); - - const handleExpand = useCallback( - (_e: MouseEvent, item: unknown, itemType: LibraryItem) => { - if (item && typeof item === 'object' && 'id' in item && 'serverId' in item) { - internalState.toggleExpanded({ - _itemType: itemType, - _serverId: item.serverId as string, - id: item.id as string, - }); - } - }, - [internalState], - ); - - const handleScroll = useCallback( - (e: UIEvent) => { - onScroll?.(e); - }, - [onScroll], - ); - - const [tableMeta, setTableMeta] = useState(null); - - // Throttled function to update table meta - const throttledSetTableMeta = useMemo(() => { - return throttle((width: number) => { - const isSm = width >= 600; - const isMd = width >= 768; - const isLg = width >= 1200; - const isXl = width >= 1500; - const is2xl = width >= 1920; - const is3xl = width >= 2560; - - let itemHeight = 160; - - if (is3xl) { - itemHeight = 160; - } else if (is2xl) { - itemHeight = 160; - } else if (isXl) { - itemHeight = 160; - } else if (isLg) { - itemHeight = 160; - } else if (isMd) { - itemHeight = 160; - } else if (isSm) { - itemHeight = 160; - } else { - itemHeight = 160; - } - - if (itemHeight === 0) { - return; - } - - setTableMeta({ - itemHeight, - }); - }, 200); - }, []); - - useLayoutEffect(() => { - throttledSetTableMeta(containerWidth); - }, [containerWidth, data.length, itemType, throttledSetTableMeta]); - - const handleOnRowsRendered = useCallback( - (visibleRows: { startIndex: number; stopIndex: number }) => { - onRangeChanged?.({ - endIndex: visibleRows.stopIndex * (tableMeta?.columnCount || 0), - startIndex: visibleRows.startIndex * (tableMeta?.columnCount || 0), - }); - - if (onStartReached || onEndReached) { - const totalRows = Math.ceil(totalItemCount / (tableMeta?.columnCount || 0)); - const startRow = visibleRows.startIndex; - const endRow = visibleRows.stopIndex; - - if (startRow === 0) { - onStartReached?.(startRow); - } - if (endRow >= totalRows) { - onEndReached?.(endRow); - } - } - }, - [onEndReached, onRangeChanged, onStartReached, totalItemCount, tableMeta?.columnCount], - ); - - return ( - - - - {hasExpanded && ( - - - - )} - - - ); -}; - -function RowComponent({ - data, - handleExpand, - index, - itemHeight, - itemType, - style, -}: RowComponentProps<{ - data: any[]; - handleExpand: (e: MouseEvent, item: unknown, itemType: LibraryItem) => void; - itemHeight: number; - itemType: LibraryItem; -}>) { - return ( -
- handleExpand(e, item, itemType)} - withControls - /> -
- ); -} diff --git a/src/renderer/features/albums/components/album-list-infinite-grid.tsx b/src/renderer/features/albums/components/album-list-infinite-grid.tsx index f18f21438..a8e5542e3 100644 --- a/src/renderer/features/albums/components/album-list-infinite-grid.tsx +++ b/src/renderer/features/albums/components/album-list-infinite-grid.tsx @@ -18,20 +18,17 @@ import { ItemListKey } from '/@/shared/types/types'; interface AlbumListInfiniteGridProps extends ItemListGridComponentProps {} export const AlbumListInfiniteGrid = forwardRef( - ( - { - gap = 'md', - itemsPerPage = 100, - itemsPerRow, - query = { - sortBy: AlbumListSort.NAME, - sortOrder: SortOrder.ASC, - }, - saveScrollOffset = true, - serverId, + ({ + gap = 'md', + itemsPerPage = 100, + itemsPerRow, + query = { + sortBy: AlbumListSort.NAME, + sortOrder: SortOrder.ASC, }, - ref, - ) => { + saveScrollOffset = true, + serverId, + }) => { const listCountQuery = albumQueries.listCount({ query: { ...query }, serverId: serverId, diff --git a/src/renderer/features/albums/components/subsonic-album-filters.tsx b/src/renderer/features/albums/components/subsonic-album-filters.tsx index 01daee0d3..ac8363045 100644 --- a/src/renderer/features/albums/components/subsonic-album-filters.tsx +++ b/src/renderer/features/albums/components/subsonic-album-filters.tsx @@ -62,14 +62,16 @@ export const SubsonicAlbumFilters = ({ }), ); - const selectableAlbumArtists = useMemo(() => { - if (!albumArtistListQuery?.data?.items) return []; + const items = albumArtistListQuery?.data?.items; - return albumArtistListQuery?.data?.items?.map((artist) => ({ + const selectableAlbumArtists = useMemo(() => { + if (!items) return []; + + return items.map((artist) => ({ label: artist.name, value: artist.id, })); - }, [albumArtistListQuery?.data?.items]); + }, [items]); const handleAlbumArtistFilter = (e: null | string[]) => { setArtistIds(e ?? null); diff --git a/src/renderer/features/albums/hooks/use-album-list-filters.ts b/src/renderer/features/albums/hooks/use-album-list-filters.ts index f70b2e18e..24bcd244b 100644 --- a/src/renderer/features/albums/hooks/use-album-list-filters.ts +++ b/src/renderer/features/albums/hooks/use-album-list-filters.ts @@ -1,4 +1,3 @@ -import { useCallback } from 'react'; import { parseAsArrayOf, parseAsBoolean, @@ -7,6 +6,7 @@ import { parseAsString, useQueryState, } from 'nuqs'; +import { useCallback } from 'react'; import { useSearchTermFilter } from '/@/renderer/features/shared/hooks/use-search-term-filter'; import { useSortByFilter } from '/@/renderer/features/shared/hooks/use-sort-by-filter'; @@ -16,9 +16,12 @@ import { AlbumListSort, SortOrder } from '/@/shared/types/domain-types'; import { ItemListKey } from '/@/shared/types/types'; export const useAlbumListFilters = () => { - const { sortBy, setSortBy } = useSortByFilter(AlbumListSort.NAME, ItemListKey.ALBUM); + const { setSortBy, sortBy } = useSortByFilter( + AlbumListSort.NAME, + ItemListKey.ALBUM, + ); - const { sortOrder, setSortOrder } = useSortOrderFilter(SortOrder.ASC, ItemListKey.ALBUM); + const { setSortOrder, sortOrder } = useSortOrderFilter(SortOrder.ASC, ItemListKey.ALBUM); const { searchTerm, setSearchTerm } = useSearchTermFilter(''); diff --git a/src/renderer/features/albums/routes/dummy-album-detail-route.tsx b/src/renderer/features/albums/routes/dummy-album-detail-route.tsx index c9e8b3a22..9401daedb 100644 --- a/src/renderer/features/albums/routes/dummy-album-detail-route.tsx +++ b/src/renderer/features/albums/routes/dummy-album-detail-route.tsx @@ -15,7 +15,7 @@ import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-e import { DefaultPlayButton } from '/@/renderer/features/shared/components/play-button'; import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation'; import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation'; -import { useContainerQuery, useFastAverageColor } from '/@/renderer/hooks'; +import { useFastAverageColor } from '/@/renderer/hooks'; import { queryClient } from '/@/renderer/lib/react-query'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer } from '/@/renderer/store'; @@ -33,7 +33,6 @@ import { Text } from '/@/shared/components/text/text'; import { LibraryItem, SongDetailResponse } from '/@/shared/types/domain-types'; const DummyAlbumDetailRoute = () => { - const { ref, ...cq } = useContainerQuery(); const { t } = useTranslation(); const { albumId } = useParams() as { albumId: string }; @@ -117,7 +116,7 @@ const DummyAlbumDetailRoute = () => { return ( - + { /> { + onClick={() => { if (!detailQuery?.data) return; }} variant="subtle" @@ -199,7 +198,7 @@ const DummyAlbumDetailRoute = () => { key={`genre-${genre.id}`} radius={0} size="compact-md" - to={generatePath(AppRoute.LIBRARY_GENRES_SONGS, { + to={generatePath(AppRoute.LIBRARY_GENRES_DETAIL, { genreId: genre.id, })} variant="outline" diff --git a/src/renderer/features/artists/components/album-artist-detail-header.tsx b/src/renderer/features/artists/components/album-artist-detail-header.tsx index d58e14ef8..f91e4f864 100644 --- a/src/renderer/features/artists/components/album-artist-detail-header.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-header.tsx @@ -15,102 +15,100 @@ import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; import { LibraryItem, ServerType } from '/@/shared/types/domain-types'; -export const AlbumArtistDetailHeader = forwardRef( - (_props, ref: Ref) => { - const { albumArtistId, artistId } = useParams() as { - albumArtistId?: string; - artistId?: string; - }; - const routeId = (artistId || albumArtistId) as string; - const server = useCurrentServer(); - const { t } = useTranslation(); - const detailQuery = useQuery( - artistsQueries.albumArtistDetail({ - query: { id: routeId }, - serverId: server?.id, - }), - ); +export const AlbumArtistDetailHeader = forwardRef((_props, ref: Ref) => { + const { albumArtistId, artistId } = useParams() as { + albumArtistId?: string; + artistId?: string; + }; + const routeId = (artistId || albumArtistId) as string; + const server = useCurrentServer(); + const { t } = useTranslation(); + const detailQuery = useQuery( + artistsQueries.albumArtistDetail({ + query: { id: routeId }, + serverId: server?.id, + }), + ); - const albumCount = detailQuery?.data?.albumCount; - const songCount = detailQuery?.data?.songCount; - const duration = detailQuery?.data?.duration; - const durationEnabled = duration !== null && duration !== undefined; + const albumCount = detailQuery?.data?.albumCount; + const songCount = detailQuery?.data?.songCount; + const duration = detailQuery?.data?.duration; + const durationEnabled = duration !== null && duration !== undefined; - const metadataItems = [ - { - enabled: albumCount !== null && albumCount !== undefined, - id: 'albumCount', - secondary: false, - value: t('entity.albumWithCount', { count: albumCount || 0 }), - }, - { - enabled: songCount !== null && songCount !== undefined, - id: 'songCount', - secondary: false, - value: t('entity.trackWithCount', { count: songCount || 0 }), - }, - { - enabled: durationEnabled, - id: 'duration', - secondary: true, - value: durationEnabled && formatDurationString(duration), - }, - ]; + const metadataItems = [ + { + enabled: albumCount !== null && albumCount !== undefined, + id: 'albumCount', + secondary: false, + value: t('entity.albumWithCount', { count: albumCount || 0 }), + }, + { + enabled: songCount !== null && songCount !== undefined, + id: 'songCount', + secondary: false, + value: t('entity.trackWithCount', { count: songCount || 0 }), + }, + { + enabled: durationEnabled, + id: 'duration', + secondary: true, + value: durationEnabled && formatDurationString(duration), + }, + ]; - const { setRating } = usePlayer(); + const { setRating } = usePlayer(); - const handleUpdateRating = (rating: number) => { - if (!detailQuery?.data) return; - - if (detailQuery.data.userRating === rating) { - return setRating( - detailQuery.data._serverId, - [detailQuery.data.id], - LibraryItem.ALBUM_ARTIST, - 0, - ); - } + const handleUpdateRating = (rating: number) => { + if (!detailQuery?.data) return; + if (detailQuery.data.userRating === rating) { return setRating( detailQuery.data._serverId, [detailQuery.data.id], LibraryItem.ALBUM_ARTIST, - rating, + 0, ); - }; + } - const showRating = detailQuery?.data?._serverType === ServerType.NAVIDROME; - - return ( - - - - {metadataItems - .filter((i) => i.enabled) - .map((item, index) => ( - - {index > 0 && } - {item.value} - - ))} - {showRating && ( - <> - - - - )} - - - + return setRating( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM_ARTIST, + rating, ); - }, -); + }; + + const showRating = detailQuery?.data?._serverType === ServerType.NAVIDROME; + + return ( + + + + {metadataItems + .filter((i) => i.enabled) + .map((item, index) => ( + + {index > 0 && } + {item.value} + + ))} + {showRating && ( + <> + + + + )} + + + + ); +}); diff --git a/src/renderer/features/artists/components/album-artist-list-header-filters.tsx b/src/renderer/features/artists/components/album-artist-list-header-filters.tsx index cdfd12a1c..e44c20cdc 100644 --- a/src/renderer/features/artists/components/album-artist-list-header-filters.tsx +++ b/src/renderer/features/artists/components/album-artist-list-header-filters.tsx @@ -3,7 +3,6 @@ import { ListConfigMenu } from '/@/renderer/features/shared/components/list-conf import { ListRefreshButton } from '/@/renderer/features/shared/components/list-refresh-button'; import { ListSortByDropdown } from '/@/renderer/features/shared/components/list-sort-by-dropdown'; import { ListSortOrderToggleButton } from '/@/renderer/features/shared/components/list-sort-order-toggle-button'; -import { useContainerQuery } from '/@/renderer/hooks'; import { Divider } from '/@/shared/components/divider/divider'; import { Flex } from '/@/shared/components/flex/flex'; import { Group } from '/@/shared/components/group/group'; @@ -11,11 +10,9 @@ import { AlbumArtistListSort, LibraryItem, SortOrder } from '/@/shared/types/dom import { ItemListKey } from '/@/shared/types/types'; export const AlbumArtistListHeaderFilters = () => { - const { ref, ...cq } = useContainerQuery(); - return ( - + {} export const AlbumArtistListInfiniteGrid = forwardRef( - ( - { - gap = 'md', - itemsPerPage = 100, - itemsPerRow, - query = { - sortBy: AlbumArtistListSort.NAME, - sortOrder: SortOrder.ASC, - }, - saveScrollOffset = true, - serverId, + ({ + gap = 'md', + itemsPerPage = 100, + itemsPerRow, + query = { + sortBy: AlbumArtistListSort.NAME, + sortOrder: SortOrder.ASC, }, - ref, - ) => { + saveScrollOffset = true, + serverId, + }) => { const listCountQuery = artistsQueries.albumArtistListCount({ query: { ...query }, serverId: serverId, diff --git a/src/renderer/features/artists/components/artist-list-header-filters.tsx b/src/renderer/features/artists/components/artist-list-header-filters.tsx index 0ed1f203c..70c8e3bc1 100644 --- a/src/renderer/features/artists/components/artist-list-header-filters.tsx +++ b/src/renderer/features/artists/components/artist-list-header-filters.tsx @@ -8,7 +8,6 @@ import { ListSelectFilter } from '/@/renderer/features/shared/components/list-se import { ListSortByDropdown } from '/@/renderer/features/shared/components/list-sort-by-dropdown'; import { ListSortOrderToggleButton } from '/@/renderer/features/shared/components/list-sort-order-toggle-button'; import { FILTER_KEYS } from '/@/renderer/features/shared/utils'; -import { useContainerQuery } from '/@/renderer/hooks'; import { useCurrentServer } from '/@/renderer/store'; import { Divider } from '/@/shared/components/divider/divider'; import { Flex } from '/@/shared/components/flex/flex'; @@ -17,14 +16,13 @@ import { ArtistListSort, LibraryItem, SortOrder } from '/@/shared/types/domain-t import { ItemListKey } from '/@/shared/types/types'; export const ArtistListHeaderFilters = () => { - const { ref, ...cq } = useContainerQuery(); const server = useCurrentServer(); const rolesQuery = useQuery(sharedQueries.roles({ query: {}, serverId: server.id })); return ( - + {} export const ArtistListInfiniteGrid = forwardRef( - ( - { - gap = 'md', - itemsPerPage = 100, - itemsPerRow, - query = { - sortBy: ArtistListSort.NAME, - sortOrder: SortOrder.ASC, - }, - saveScrollOffset = true, - serverId, + ({ + gap = 'md', + itemsPerPage = 100, + itemsPerRow, + query = { + sortBy: ArtistListSort.NAME, + sortOrder: SortOrder.ASC, }, - ref, - ) => { + saveScrollOffset = true, + serverId, + }) => { const listCountQuery = artistsQueries.artistListCount({ query: { ...query }, serverId: serverId, diff --git a/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx index 1219ccf68..893e2e520 100644 --- a/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx +++ b/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx @@ -1,8 +1,7 @@ import { useQuery } from '@tanstack/react-query'; -import { useMemo, useRef } from 'react'; +import { useMemo } from 'react'; import { useParams } from 'react-router'; -import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { ListContext } from '/@/renderer/context/list-context'; import { artistsQueries } from '/@/renderer/features/artists/api/artists-api'; import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header'; @@ -13,7 +12,6 @@ import { useCurrentServer } from '/@/renderer/store/auth.store'; import { LibraryItem } from '/@/shared/types/domain-types'; const AlbumArtistDetailTopSongsListRoute = () => { - const tableRef = useRef(null); const { albumArtistId, artistId } = useParams() as { albumArtistId?: string; artistId?: string; diff --git a/src/renderer/features/context-menu/actions/add-to-playlist-action.tsx b/src/renderer/features/context-menu/actions/add-to-playlist-action.tsx index 9efbc39c2..312a941ad 100644 --- a/src/renderer/features/context-menu/actions/add-to-playlist-action.tsx +++ b/src/renderer/features/context-menu/actions/add-to-playlist-action.tsx @@ -52,21 +52,23 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp const { recentPlaylistId } = useRecentPlaylists(serverId); - const fuse = useMemo(() => { - if (!playlistsQuery.data?.items) return null; + const playlists = playlistsQuery.data?.items; - return new Fuse(playlistsQuery.data.items, { + const fuse = useMemo(() => { + if (!playlists) return null; + + return new Fuse(playlists, { fieldNormWeight: 1, ignoreLocation: true, keys: ['name'], threshold: 0.3, }); - }, [playlistsQuery.data?.items]); + }, [playlists]); const recentPlaylist = useMemo(() => { - if (!playlistsQuery.data?.items || !recentPlaylistId) return null; + if (!playlists || !recentPlaylistId) return null; - const playlist = playlistsQuery.data.items.find((p) => p.id === recentPlaylistId); + const playlist = playlists.find((p) => p.id === recentPlaylistId); if (!playlist) return null; if (searchTerm && fuse) { @@ -76,22 +78,22 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp } return playlist; - }, [playlistsQuery.data?.items, recentPlaylistId, searchTerm, fuse]); + }, [playlists, recentPlaylistId, searchTerm, fuse]); const filteredPlaylists = useMemo(() => { - if (!playlistsQuery.data?.items) return []; + if (!playlists) return []; if (!searchTerm || !fuse) { // Exclude recent playlist from the list if it exists return recentPlaylistId - ? playlistsQuery.data.items.filter((p) => p.id !== recentPlaylistId) - : playlistsQuery.data.items; + ? playlists.filter((p) => p.id !== recentPlaylistId) + : playlists; } const results = fuse.search(searchTerm); const filtered = results.map((result) => result.item); // Exclude recent playlist from the filtered results if it exists return recentPlaylistId ? filtered.filter((p) => p.id !== recentPlaylistId) : filtered; - }, [playlistsQuery.data?.items, searchTerm, fuse, recentPlaylistId]); + }, [playlists, searchTerm, fuse, recentPlaylistId]); const getSongsByAlbum = useCallback( async (albumId: string) => { diff --git a/src/renderer/features/context-menu/menus/queue-context-menu.tsx b/src/renderer/features/context-menu/menus/queue-context-menu.tsx index b0b7707df..54b8041a9 100644 --- a/src/renderer/features/context-menu/menus/queue-context-menu.tsx +++ b/src/renderer/features/context-menu/menus/queue-context-menu.tsx @@ -16,10 +16,9 @@ import { LibraryItem, QueueSong } from '/@/shared/types/domain-types'; interface QueueContextMenuProps { items: QueueSong[]; - type: LibraryItem.QUEUE_SONG; } -export const QueueContextMenu = ({ items, type }: QueueContextMenuProps) => { +export const QueueContextMenu = ({ items }: QueueContextMenuProps) => { const { ids } = useMemo(() => { const ids = items.map((item) => item.id); return { ids }; @@ -27,9 +26,7 @@ export const QueueContextMenu = ({ items, type }: QueueContextMenuProps) => { return ( - } + bottomStickyContent={} > diff --git a/src/renderer/features/genres/components/genre-list-infinite-grid.tsx b/src/renderer/features/genres/components/genre-list-infinite-grid.tsx index 8924f2cf1..83dd58576 100644 --- a/src/renderer/features/genres/components/genre-list-infinite-grid.tsx +++ b/src/renderer/features/genres/components/genre-list-infinite-grid.tsx @@ -19,20 +19,17 @@ import { ItemListKey } from '/@/shared/types/types'; interface GenreListInfiniteGridProps extends ItemListGridComponentProps {} export const GenreListInfiniteGrid = forwardRef( - ( - { - gap = 'md', - itemsPerPage = 100, - itemsPerRow, - query = { - sortBy: GenreListSort.NAME, - sortOrder: SortOrder.ASC, - }, - saveScrollOffset = true, - serverId, + ({ + gap = 'md', + itemsPerPage = 100, + itemsPerRow, + query = { + sortBy: GenreListSort.NAME, + sortOrder: SortOrder.ASC, }, - ref, - ) => { + saveScrollOffset = true, + serverId, + }) => { const listCountQuery = genresQueries.listCount({ query: { ...query }, serverId: serverId, diff --git a/src/renderer/features/lyrics/lyrics-actions.tsx b/src/renderer/features/lyrics/lyrics-actions.tsx index 077c11732..37ac245df 100644 --- a/src/renderer/features/lyrics/lyrics-actions.tsx +++ b/src/renderer/features/lyrics/lyrics-actions.tsx @@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next'; import { openLyricSearchModal } from '/@/renderer/features/lyrics/components/lyrics-search-form'; import { - usePlayerSong, useLyricsSettings, + usePlayerSong, useSettingsStore, useSettingsStoreActions, } from '/@/renderer/store'; diff --git a/src/renderer/features/player/components/mobile-fullscreen-player.module.css b/src/renderer/features/player/components/mobile-fullscreen-player.module.css index 1afc8a3df..2fdde9dfd 100644 --- a/src/renderer/features/player/components/mobile-fullscreen-player.module.css +++ b/src/renderer/features/player/components/mobile-fullscreen-player.module.css @@ -44,9 +44,9 @@ .header { display: flex; flex-shrink: 0; + gap: 0.5rem; align-items: center; justify-content: flex-start; - gap: 0.5rem; width: 100%; padding: 1rem; } @@ -80,10 +80,10 @@ box-shadow: 0 8px 24px rgb(0 0 0 / 30%); } -.imageNativeAspectRatio { - aspect-ratio: auto; +.image-native-aspect-ratio { height: auto; max-height: 100%; + aspect-ratio: auto; } .album-image { diff --git a/src/renderer/features/player/components/playerbar-seek-slider.tsx b/src/renderer/features/player/components/playerbar-seek-slider.tsx index a953a0444..c61a48e6e 100644 --- a/src/renderer/features/player/components/playerbar-seek-slider.tsx +++ b/src/renderer/features/player/components/playerbar-seek-slider.tsx @@ -1,11 +1,10 @@ import formatDuration from 'format-duration'; import { useEffect, useRef, useState } from 'react'; -import styles from './playerbar-slider.module.css'; +import { CustomPlayerbarSlider } from './playerbar-slider'; import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { usePlayerTimestamp } from '/@/renderer/store'; -import { CustomPlayerbarSlider } from './playerbar-slider'; interface PlayerbarSeekSliderProps { max: number; diff --git a/src/renderer/features/playlists/components/playlist-list-infinite-grid.tsx b/src/renderer/features/playlists/components/playlist-list-infinite-grid.tsx index d27a823cf..422452086 100644 --- a/src/renderer/features/playlists/components/playlist-list-infinite-grid.tsx +++ b/src/renderer/features/playlists/components/playlist-list-infinite-grid.tsx @@ -19,20 +19,17 @@ import { ItemListKey } from '/@/shared/types/types'; interface PlaylistListInfiniteGridProps extends ItemListGridComponentProps {} export const PlaylistListInfiniteGrid = forwardRef( - ( - { - gap = 'md', - itemsPerPage = 100, - itemsPerRow, - query = { - sortBy: PlaylistListSort.NAME, - sortOrder: SortOrder.ASC, - }, - saveScrollOffset = true, - serverId, + ({ + gap = 'md', + itemsPerPage = 100, + itemsPerRow, + query = { + sortBy: PlaylistListSort.NAME, + sortOrder: SortOrder.ASC, }, - ref, - ) => { + saveScrollOffset = true, + serverId, + }) => { const listCountQuery = playlistsQueries.listCount({ query: { ...query }, serverId: serverId, diff --git a/src/renderer/features/playlists/hooks/use-playlist-list-filters.ts b/src/renderer/features/playlists/hooks/use-playlist-list-filters.ts index bf2c28cd5..a9d1c3550 100644 --- a/src/renderer/features/playlists/hooks/use-playlist-list-filters.ts +++ b/src/renderer/features/playlists/hooks/use-playlist-list-filters.ts @@ -1,8 +1,4 @@ -import { - parseAsJson, - parseAsString, - useQueryState, -} from 'nuqs'; +import { parseAsJson, useQueryState } from 'nuqs'; import { useSearchTermFilter } from '/@/renderer/features/shared/hooks/use-search-term-filter'; import { useSortByFilter } from '/@/renderer/features/shared/hooks/use-sort-by-filter'; @@ -17,16 +13,13 @@ export const usePlaylistListFilters = () => { const { searchTerm, setSearchTerm } = useSearchTermFilter(''); - const [custom, setCustom] = useQueryState( - 'playlistCustom', - parseAsJson(customFiltersSchema), - ); + const [custom, setCustom] = useQueryState('playlistCustom', parseAsJson(customFiltersSchema)); const query = { + _custom: custom ?? undefined, searchTerm: searchTerm ?? undefined, sortBy: sortByFilter[FILTER_KEYS.SHARED.SORT_BY] ?? undefined, sortOrder: sortOrderFilter[FILTER_KEYS.SHARED.SORT_ORDER] ?? undefined, - _custom: custom ?? undefined, }; return { diff --git a/src/renderer/features/search/components/command-palette.tsx b/src/renderer/features/search/components/command-palette.tsx index 18fc4cf9b..314a25ba9 100644 --- a/src/renderer/features/search/components/command-palette.tsx +++ b/src/renderer/features/search/components/command-palette.tsx @@ -3,7 +3,6 @@ import { Fragment, useCallback, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath, useNavigate } from 'react-router'; -import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { searchQueries } from '/@/renderer/features/search/api/search-api'; import { Command, CommandPalettePages } from '/@/renderer/features/search/components/command'; import { CommandItemSelectable } from '/@/renderer/features/search/components/command-item-selectable'; diff --git a/src/renderer/features/search/components/library-command-item.tsx b/src/renderer/features/search/components/library-command-item.tsx index 7a4c0f5ed..fe1cd627e 100644 --- a/src/renderer/features/search/components/library-command-item.tsx +++ b/src/renderer/features/search/components/library-command-item.tsx @@ -40,10 +40,10 @@ export const LibraryCommandItem = ({ (e: SyntheticEvent, id: string, playType: Play) => { e.stopPropagation(); e.preventDefault(); - if (!server?.id) return; + if (!server.id) return; addToQueueByFetch(server.id, [id], itemType, playType); }, - [addToQueueByFetch, itemType, server?.id], + [addToQueueByFetch, itemType, server], ); const [isHovered, setIsHovered] = useState(false); diff --git a/src/renderer/features/settings/components/settings-header.tsx b/src/renderer/features/settings/components/settings-header.tsx index 99bc716ae..c12973a82 100644 --- a/src/renderer/features/settings/components/settings-header.tsx +++ b/src/renderer/features/settings/components/settings-header.tsx @@ -5,7 +5,6 @@ import { PageHeader } from '/@/renderer/components/page-header/page-header'; import { useSettingSearchContext } from '/@/renderer/features/settings/context/search-context'; import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar'; import { SearchInput } from '/@/renderer/features/shared/components/search-input'; -import { useContainerQuery } from '/@/renderer/hooks'; import { useSettingsStoreActions } from '/@/renderer/store/settings.store'; import { Button } from '/@/shared/components/button/button'; import { Flex } from '/@/shared/components/flex/flex'; @@ -22,7 +21,6 @@ export const SettingsHeader = ({ setSearch }: SettingsHeaderProps) => { const { t } = useTranslation(); const { reset } = useSettingsStoreActions(); const search = useSettingSearchContext(); - const { ref, ...cq } = useContainerQuery(); const handleResetToDefault = () => { reset(); @@ -41,7 +39,7 @@ export const SettingsHeader = ({ setSearch }: SettingsHeaderProps) => { }; return ( - + diff --git a/src/renderer/features/shared/hooks/use-music-folder-id-filter.ts b/src/renderer/features/shared/hooks/use-music-folder-id-filter.ts index f34504fab..cc5707c18 100644 --- a/src/renderer/features/shared/hooks/use-music-folder-id-filter.ts +++ b/src/renderer/features/shared/hooks/use-music-folder-id-filter.ts @@ -1,7 +1,7 @@ import { parseAsString, useQueryState } from 'nuqs'; -import { FILTER_KEYS } from '/@/renderer/features/shared/utils'; import { useListFilterPersistence } from '/@/renderer/features/shared/hooks/use-list-filter-persistence'; +import { FILTER_KEYS } from '/@/renderer/features/shared/utils'; import { useCurrentServer } from '/@/renderer/store'; import { ItemListKey } from '/@/shared/types/types'; diff --git a/src/renderer/features/songs/components/jellyfin-song-filters.tsx b/src/renderer/features/songs/components/jellyfin-song-filters.tsx index 09a2a1c85..d280a484f 100644 --- a/src/renderer/features/songs/components/jellyfin-song-filters.tsx +++ b/src/renderer/features/songs/components/jellyfin-song-filters.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { MultiSelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data'; -import { genresQueries, useGenreList } from '/@/renderer/features/genres/api/genres-api'; +import { useGenreList } from '/@/renderer/features/genres/api/genres-api'; import { sharedQueries } from '/@/renderer/features/shared/api/shared-api'; import { useSongListFilters } from '/@/renderer/features/songs/hooks/use-song-list-filters'; import { SongListFilter, useCurrentServer } from '/@/renderer/store'; @@ -14,7 +14,7 @@ import { NumberInput } from '/@/shared/components/number-input/number-input'; import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; import { YesNoSelect } from '/@/shared/components/yes-no-select/yes-no-select'; -import { GenreListSort, LibraryItem, SortOrder } from '/@/shared/types/domain-types'; +import { LibraryItem } from '/@/shared/types/domain-types'; interface JellyfinSongFiltersProps { customFilters?: Partial; diff --git a/src/renderer/features/songs/components/navidrome-song-filters.tsx b/src/renderer/features/songs/components/navidrome-song-filters.tsx index bc03269f7..aae594aa7 100644 --- a/src/renderer/features/songs/components/navidrome-song-filters.tsx +++ b/src/renderer/features/songs/components/navidrome-song-filters.tsx @@ -7,7 +7,7 @@ import { MultiSelectWithInvalidData, SelectWithInvalidData, } from '/@/renderer/components/select-with-invalid-data'; -import { genresQueries, useGenreList } from '/@/renderer/features/genres/api/genres-api'; +import { useGenreList } from '/@/renderer/features/genres/api/genres-api'; import { sharedQueries } from '/@/renderer/features/shared/api/shared-api'; import { SongListFilter, @@ -23,7 +23,7 @@ import { NumberInput } from '/@/shared/components/number-input/number-input'; import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; import { YesNoSelect } from '/@/shared/components/yes-no-select/yes-no-select'; -import { GenreListSort, LibraryItem, SongListQuery, SortOrder } from '/@/shared/types/domain-types'; +import { LibraryItem, SongListQuery } from '/@/shared/types/domain-types'; import { ServerFeature } from '/@/shared/types/features-types'; interface NavidromeSongFiltersProps { diff --git a/src/renderer/features/songs/components/song-list-infinite-grid.tsx b/src/renderer/features/songs/components/song-list-infinite-grid.tsx index 4d6eb045f..bf27ee0f3 100644 --- a/src/renderer/features/songs/components/song-list-infinite-grid.tsx +++ b/src/renderer/features/songs/components/song-list-infinite-grid.tsx @@ -14,20 +14,17 @@ import { ItemListKey } from '/@/shared/types/types'; interface SongListInfiniteGridProps extends ItemListGridComponentProps {} export const SongListInfiniteGrid = forwardRef( - ( - { - gap = 'md', - itemsPerPage = 100, - itemsPerRow, - query = { - sortBy: SongListSort.NAME, - sortOrder: SortOrder.ASC, - }, - saveScrollOffset = true, - serverId, + ({ + gap = 'md', + itemsPerPage = 100, + itemsPerRow, + query = { + sortBy: SongListSort.NAME, + sortOrder: SortOrder.ASC, }, - ref, - ) => { + saveScrollOffset = true, + serverId, + }) => { const listCountQuery = songsQueries.listCount({ query: { ...query }, serverId: serverId, diff --git a/src/shared/components/context-menu/context-menu.module.css b/src/shared/components/context-menu/context-menu.module.css index 731e1f596..4ec739078 100644 --- a/src/shared/components/context-menu/context-menu.module.css +++ b/src/shared/components/context-menu/context-menu.module.css @@ -26,7 +26,6 @@ max-width: 100%; padding: var(--theme-spacing-sm) var(--theme-spacing-md); font-size: var(--theme-font-size-sm); - word-wrap: break-word; overflow-wrap: break-word; white-space: normal; cursor: default; @@ -43,7 +42,6 @@ & > *:not(.left-icon, .right-icon) { flex: 1; min-width: 0; - word-wrap: break-word; overflow-wrap: break-word; }