From 58290aeeedc1295d162d287a9d33cd1848e523ca Mon Sep 17 00:00:00 2001 From: sk1982 Date: Mon, 18 Mar 2024 02:04:24 -0400 Subject: [PATCH] chuni: add favorites to music list --- src/components/chuni/music-list.tsx | 32 ++++++++++++++++++++--------- src/components/filter-sorter.tsx | 13 +++++++++--- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/components/chuni/music-list.tsx b/src/components/chuni/music-list.tsx index c4fe189..ef35f42 100644 --- a/src/components/chuni/music-list.tsx +++ b/src/components/chuni/music-list.tsx @@ -61,7 +61,11 @@ const searcher = (query: string, data: ChuniMusicListProps['music'][number]) => return data.title?.toLowerCase().includes(query) || data.artist?.toLowerCase().includes(query); }; -const MusicGrid = ({ music, size, setMusicList }: ChuniMusicListProps & { size: 'sm' | 'lg' | 'xs', setMusicList: (m: typeof music) => void }) => { +const MusicGrid = ({ music, size, setMusicList, fullMusicList }: ChuniMusicListProps & { + size: 'sm' | 'lg' | 'xs', + setMusicList: (m: typeof music) => void, + fullMusicList: ChuniMusicListProps['music'] +}) => { let itemWidth = 0; let itemHeight = 0; let itemClass = ''; @@ -114,7 +118,7 @@ const MusicGrid = ({ music, size, setMusicList }: ChuniMusicListProps & { size: onPress={() => { if (pendingFavorite) return; const favorite = item.favorite; - setMusicList(music.map(m => { + setMusicList(fullMusicList.map(m => { if (m.songId !== item.songId) return m; return { ...m, favorite: !favorite }; @@ -123,7 +127,7 @@ const MusicGrid = ({ music, size, setMusicList }: ChuniMusicListProps & { size: (item.favorite ? removeFavoriteMusic : addFavoriteMusic)(item.songId!) .then(res => { if (res?.error) { - setMusicList(music.map(m => { + setMusicList(fullMusicList.map(m => { if (m.songId !== item.songId) return m; return { ...m, favorite }; @@ -198,7 +202,7 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { name: 'difficulty', label: 'Difficulty', value: new Set(), - className: 'col-span-6 md:col-span-3 5xl:col-span-1', + className: 'col-span-6 md:col-span-3 lg:col-span-2 5xl:col-span-1', props: { children: CHUNI_DIFFICULTIES.map((name, i) => {name} @@ -211,7 +215,7 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { name: 'genre', label: 'Genre', value: new Set(), - className: 'col-span-6 md:col-span-3 5xl:col-span-1', + className: 'col-span-6 md:col-span-3 lg:col-span-2 5xl:col-span-1', props: { children: [...genres].sort() .map(g => {g}), @@ -264,7 +268,7 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { name: 'score', label: 'Score', value: new Set(), - className: 'col-span-full sm:col-span-6 md:col-span-4 lg:col-span-2 xl:col-span-2 5xl:col-span-1', + className: 'col-span-6 sm:col-span-6 md:col-span-3 lg:col-span-2 xl:col-span-2 2xl:col-span-3 5xl:col-span-1', props: { children: CHUNI_SCORE_RANKS .map((s, i) => {s}) @@ -272,12 +276,19 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { selectionMode: 'multiple' }, filter: (val: Set, data) => !val.size || val.has(data.scoreRank?.toString()!) + }, { + type: 'switch', + name: 'favorite', + label: 'Favorites', + value: false, + className: 'justify-self-end col-span-6 md:col-span-3 md:col-start-10 lg:col-span-2 lg:col-start-auto 2xl:col-span-1 5xl:col-start-12', + filter: (val: boolean, data) => !val || data.favorite }, { type: 'slider', name: 'worldsEndStars', label: 'World\'s End Stars', value: [1, 5], - className: 'col-span-full sm:col-span-6 md:col-span-4 5xl:col-span-2', + className: 'col-span-full md:col-span-6 md:col-start-4 md:row-start-2 lg:row-start-auto lg:col-start-auto lg:col-span-4 5xl:col-span-2 5xl:row-start-1 5xl:col-start-6', filter: ([a, b]: number[], val) => { if (!val.worldsEndTag) return true; const stars = Math.ceil(val.level! / 2); @@ -296,7 +307,7 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { name: 'level', label: 'Level', value: [0, 90], - className: 'col-span-full md:col-span-4 5xl:col-span-2', + className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2 5xl:row-start-1 5xl:col-start-8', filter: ([a, b]: number[], val) => { if (val.worldsEndTag) return true; a = getLevelValFromStop(a); @@ -314,7 +325,7 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { name: 'rating', label: 'Rating', value: [0, 17.55], - className: 'col-span-full md:col-span-full lg:col-span-4 5xl:col-span-3', + className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2 5xl:row-start-1 5xl:col-start-10', filter: ([a, b]: number[], val) => { if (val.worldsEndTag) return true; return +val.rating >= a && +val.rating <= b; @@ -333,7 +344,8 @@ export const ChuniMusicList = ({ music }: ChuniMusicListProps) => { {(displayMode, data) =>
- +
}
); }; diff --git a/src/components/filter-sorter.tsx b/src/components/filter-sorter.tsx index a36a432..a185ec6 100644 --- a/src/components/filter-sorter.tsx +++ b/src/components/filter-sorter.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Accordion, AccordionItem, Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Input, Pagination, Select, SelectItem, Slider, Spinner, Tooltip } from '@nextui-org/react'; +import { Accordion, AccordionItem, Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Input, Pagination, Select, SelectItem, Slider, Spinner, Switch, Tooltip } from '@nextui-org/react'; import React, { ReactNode, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { Awaitable } from '@auth/core/types'; import { XMarkIcon } from '@heroicons/react/16/solid'; @@ -12,12 +12,14 @@ import { SearchIcon } from '@nextui-org/shared-icons'; type ValueType = { slider: React.ComponentProps['value'], - select: React.ComponentProps['selectedKeys'] + select: React.ComponentProps['selectedKeys'], + switch: React.ComponentProps['isSelected'] }; type FilterTypes = { select: typeof Select, - slider: typeof Slider + slider: typeof Slider, + switch: typeof Switch }; type FilterField = { @@ -263,6 +265,11 @@ const FilterSorterComponent = ; + else if (filter.type === 'switch') + return setFilterState(f => ({ ...f, [filter.name]: selected }))}> + {filter.label} + })}