mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-14 04:20:07 +02:00
add new artist list
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { useSelectFilter } from '/@/renderer/features/shared/hooks/use-select-filter';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
||||
import { Select } from '/@/shared/components/select/select';
|
||||
import { ItemListKey } from '/@/shared/types/types';
|
||||
|
||||
export type SelectOption = string | { label: string; value: string };
|
||||
|
||||
interface ListSelectFilterProps {
|
||||
data?: Array<SelectOption>;
|
||||
filterKey: string;
|
||||
listKey: ItemListKey;
|
||||
}
|
||||
|
||||
export const ListSelectFilter = ({ data, filterKey, listKey }: ListSelectFilterProps) => {
|
||||
const selectData = data || [];
|
||||
|
||||
const { setValue, value } = useSelectFilter(filterKey, '', listKey);
|
||||
|
||||
const handleSetValue = (newValue: string) => {
|
||||
if (newValue === value) {
|
||||
setValue('');
|
||||
return;
|
||||
}
|
||||
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
const getOptionLabel = (option: SelectOption): string => {
|
||||
if (typeof option === 'string') {
|
||||
return option;
|
||||
}
|
||||
return option.label;
|
||||
};
|
||||
|
||||
const getOptionValue = (option: SelectOption): string => {
|
||||
if (typeof option === 'string') {
|
||||
return option;
|
||||
}
|
||||
return option.value;
|
||||
};
|
||||
|
||||
const selectedOption = selectData.find((option) => getOptionValue(option) === value);
|
||||
const selectedLabel = selectedOption ? getOptionLabel(selectedOption) : '—';
|
||||
|
||||
return (
|
||||
<Select
|
||||
data={selectData}
|
||||
onChange={(value) => handleSetValue(value ?? '')}
|
||||
value={value ?? ''}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenu position="bottom-start">
|
||||
<DropdownMenu.Target>
|
||||
<Button variant="subtle">{selectedLabel}</Button>
|
||||
</DropdownMenu.Target>
|
||||
<DropdownMenu.Dropdown>
|
||||
{selectData.map((option) => {
|
||||
const optionValue = getOptionValue(option);
|
||||
const optionLabel = getOptionLabel(option);
|
||||
|
||||
return (
|
||||
<DropdownMenu.Item
|
||||
isSelected={value === optionValue}
|
||||
key={`${filterKey}-${optionValue}`}
|
||||
onClick={() => handleSetValue(optionValue)}
|
||||
value={optionValue}
|
||||
>
|
||||
{optionLabel}
|
||||
</DropdownMenu.Item>
|
||||
);
|
||||
})}
|
||||
</DropdownMenu.Dropdown>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
||||
import {
|
||||
AlbumArtistListSort,
|
||||
AlbumListSort,
|
||||
ArtistListSort,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
@@ -445,6 +446,92 @@ const ALBUM_ARTIST_LIST_FILTERS: Partial<
|
||||
],
|
||||
};
|
||||
|
||||
const ARTIST_LIST_FILTERS: Partial<
|
||||
Record<ServerType, Array<{ defaultOrder: SortOrder; name: string; value: string }>>
|
||||
> = {
|
||||
[ServerType.JELLYFIN]: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.album', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RECENTLY_ADDED,
|
||||
},
|
||||
],
|
||||
[ServerType.NAVIDROME]: [
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.SONG_COUNT,
|
||||
},
|
||||
],
|
||||
[ServerType.SUBSONIC]: [
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RATING,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const GENRE_LIST_FILTERS: Partial<
|
||||
Record<ServerType, Array<{ defaultOrder: SortOrder; name: string; value: string }>>
|
||||
> = {
|
||||
@@ -474,6 +561,7 @@ const GENRE_LIST_FILTERS: Partial<
|
||||
const FILTERS: Partial<Record<LibraryItem, any>> = {
|
||||
[LibraryItem.ALBUM]: ALBUM_LIST_FILTERS,
|
||||
[LibraryItem.ALBUM_ARTIST]: ALBUM_ARTIST_LIST_FILTERS,
|
||||
[LibraryItem.ARTIST]: ARTIST_LIST_FILTERS,
|
||||
[LibraryItem.GENRE]: GENRE_LIST_FILTERS,
|
||||
[LibraryItem.SONG]: SONG_LIST_FILTERS,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { parseAsString, useQueryState } from 'nuqs';
|
||||
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
||||
import { ItemListKey } from '/@/shared/types/types';
|
||||
|
||||
export const useSelectFilter = (
|
||||
filterKey: string,
|
||||
defaultValue: null | string,
|
||||
listKey: ItemListKey,
|
||||
) => {
|
||||
const server = useCurrentServer();
|
||||
|
||||
const [persisted, setPersisted] = useLocalStorage({
|
||||
defaultValue: defaultValue || '',
|
||||
key: getPersistenceKey(server.id, listKey, filterKey),
|
||||
});
|
||||
|
||||
const [value, setValue] = useQueryState(filterKey, getDefaultValue(defaultValue, persisted));
|
||||
|
||||
const handleSetValue = (newValue: string) => {
|
||||
setValue(newValue);
|
||||
setPersisted(newValue);
|
||||
};
|
||||
|
||||
return {
|
||||
[filterKey]: value ?? undefined,
|
||||
setValue: handleSetValue,
|
||||
value: value ?? undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const getDefaultValue = (defaultValue: null | string, persisted: null | string) => {
|
||||
if (persisted) {
|
||||
return parseAsString.withDefault(persisted);
|
||||
}
|
||||
|
||||
if (defaultValue) {
|
||||
return parseAsString.withDefault(defaultValue);
|
||||
}
|
||||
|
||||
return parseAsString;
|
||||
};
|
||||
|
||||
const getPersistenceKey = (serverId: string, listKey: ItemListKey, filterKey: string) => {
|
||||
return `${serverId}-list-${listKey}-${filterKey}`;
|
||||
};
|
||||
@@ -36,12 +36,17 @@ enum AlbumFilterKeys {
|
||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||
}
|
||||
|
||||
enum ArtistFilterKeys {
|
||||
ROLE = 'role',
|
||||
}
|
||||
|
||||
enum SharedFilterKeys {
|
||||
MUSIC_FOLDER_ID = 'musicFolderId',
|
||||
SEARCH_TERM = 'searchTerm',
|
||||
SORT_BY = 'sortBy',
|
||||
SORT_ORDER = 'sortOrder',
|
||||
}
|
||||
|
||||
enum SongFilterKeys {
|
||||
_CUSTOM = '_custom',
|
||||
ALBUM_IDS = 'albumIds',
|
||||
@@ -59,6 +64,7 @@ const PaginationFilterKeys = {
|
||||
|
||||
export const FILTER_KEYS = {
|
||||
ALBUM: AlbumFilterKeys,
|
||||
ARTIST: ArtistFilterKeys,
|
||||
PAGINATION: PaginationFilterKeys,
|
||||
SHARED: SharedFilterKeys,
|
||||
SONG: SongFilterKeys,
|
||||
|
||||
Reference in New Issue
Block a user