Improve battlesuit filter behavior

This commit is contained in:
Sakura Knoll
2022-07-18 12:33:05 +09:00 Unverified
parent 073ebb3448
commit efbd3e447e
4 changed files with 93 additions and 72 deletions
+4 -4
View File
@@ -8,7 +8,7 @@ interface FilterButtonProps {
active?: boolean active?: boolean
icon?: string icon?: string
label: string label: string
value: string href: string
m?: string | number m?: string | number
close?: () => void close?: () => void
} }
@@ -17,14 +17,14 @@ const FilterButton = ({
active = false, active = false,
icon, icon,
label, label,
value, href,
m, m,
close, close,
}: FilterButtonProps) => { }: FilterButtonProps) => {
const { push } = useRouter() const { push } = useRouter()
return ( return (
<Link <Link
href={`?filter=${value}`} href={href}
m={m} m={m}
py={1} py={1}
px={2} px={2}
@@ -36,7 +36,7 @@ const FilterButton = ({
if (close != null) { if (close != null) {
close() close()
} }
push({ query: { filter: value } }, undefined, { shallow: true }) push(href, href, { shallow: true })
}} }}
> >
{icon != null && ( {icon != null && (
+79 -61
View File
@@ -54,26 +54,43 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
setHiddenFilters(true) setHiddenFilters(true)
}, []) }, [])
const filter = useMemo(() => { const valkyrieFilter = useMemo(() => {
if (query.filter == null) { if (query.valkyrie == null) {
return 'all' return 'all'
} }
return typeof query.filter === 'string' ? query.filter : query.filter[0] return typeof query.valkyrie === 'string'
? query.valkyrie
: query.valkyrie[0]
}, [query]) }, [query])
const battlesuitList = useMemo(() => { const featureFilter = useMemo(() => {
return battlesuits.map((battlesuit) => { if (query.feature == null) {
const hidden = isBattlesuitHidden(battlesuit, filter) return 'all'
return ( }
<BattlesuitCard
key={battlesuit.id} return typeof query.feature === 'string' ? query.feature : query.feature[0]
battlesuit={battlesuit} }, [query])
hidden={hidden}
/> const battlesuitsFiteredByValkyrie = useMemo(() => {
) return battlesuits.filter((battlesuit) =>
}) isValkyrieFilterMatching(battlesuit, valkyrieFilter)
}, [battlesuits, filter]) )
}, [battlesuits, valkyrieFilter])
const availableFeatureSet = battlesuitsFiteredByValkyrie.reduce(
(set, battlesuit) => {
battlesuit.features.forEach((feature) => set.add(feature))
return set
},
new Set()
)
const battlesuitsFilteredByFeature = useMemo(() => {
return battlesuitsFiteredByValkyrie.filter((battlesuit) =>
isFeatureFilterMatching(battlesuit, featureFilter)
)
}, [battlesuitsFiteredByValkyrie, featureFilter])
return ( return (
<Honkai3rdLayout> <Honkai3rdLayout>
@@ -117,14 +134,14 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
}, },
}} }}
> >
<Heading as='h3'>{t('battlesuits-list.filter-by-features')}</Heading> <Heading as='h3'>{t('battlesuits-list.filter-by-valkyries')}</Heading>
<Flex mb={2} sx={{ flexWrap: 'wrap' }}> <Flex mb={2} sx={{ flexWrap: 'wrap' }}>
{featureFilterOptions.map(({ value, label, icon, krLabel }) => { {valkyrieFilterOptions.map(({ value, label, icon, krLabel }) => {
return ( return (
<FilterButton <FilterButton
key={value} key={value}
active={value === filter} active={value === valkyrieFilter}
value={value} href={`?valkyrie=${value}`}
label={translate(locale, { 'ko-KR': krLabel }, label)} label={translate(locale, { 'ko-KR': krLabel }, label)}
icon={icon} icon={icon}
m={1} m={1}
@@ -133,22 +150,28 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
) )
})} })}
</Flex> </Flex>
<Heading as='h3'>{t('battlesuits-list.filter-by-features')}</Heading>
<Heading as='h3'>{t('battlesuits-list.filter-by-valkyries')}</Heading>
<Flex mb={2} sx={{ flexWrap: 'wrap' }}> <Flex mb={2} sx={{ flexWrap: 'wrap' }}>
{valkyrieFilterOptions.map(({ value, label, icon, krLabel }) => { {featureFilterOptions
return ( .filter((filterOption) => {
<FilterButton if (filterOption.value === 'all') {
key={value} return true
active={value === filter} }
value={value} return availableFeatureSet.has(filterOption.value)
label={translate(locale, { 'ko-KR': krLabel }, label)} })
icon={icon} .map(({ value, label, icon, krLabel }) => {
m={1} return (
close={closeFilters} <FilterButton
/> key={value}
) active={value === featureFilter}
})} href={`?valkyrie=${valkyrieFilter}&feature=${value}`}
label={translate(locale, { 'ko-KR': krLabel }, label)}
icon={icon}
m={1}
close={closeFilters}
/>
)
})}
</Flex> </Flex>
</Box> </Box>
@@ -158,7 +181,11 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
justifyContent: 'space-around', justifyContent: 'space-around',
}} }}
> >
{battlesuitList} {battlesuitsFilteredByFeature.map((battlesuit) => {
return (
<BattlesuitCard key={battlesuit.id} battlesuit={battlesuit} />
)
})}
</Flex> </Flex>
</Box> </Box>
</Honkai3rdLayout> </Honkai3rdLayout>
@@ -184,36 +211,17 @@ export async function getStaticProps({ locale }: NextPageContext) {
} }
} }
function isBattlesuitHidden( function isValkyrieFilterMatching(
battlesuit: BattlesuitListItemData, battlesuit: BattlesuitListItemData,
filter: string valkyrieFilter: string
): boolean { ) {
switch (filter) { switch (valkyrieFilter) {
case 'physical':
case 'fire-dmg':
case 'ice-dmg':
case 'lightning-dmg':
case 'freeze':
case 'paralyze':
case 'stun':
case 'ignite':
case 'bleed':
case 'heavy-atk':
case 'weaken':
case 'impair':
case 'time mastery':
case 'gather':
case 'heal':
case 'fast atk':
case 'burst':
case 'aerial':
return !battlesuit.features.some((feature) => feature === filter)
case 'mecha': case 'mecha':
case 'biologic': case 'biologic':
case 'psychic': case 'psychic':
case 'quantum': case 'quantum':
case 'imaginary': case 'imaginary':
return battlesuit.type !== filter return battlesuit.type === valkyrieFilter
case 'kiana': case 'kiana':
case 'mei': case 'mei':
case 'bronya': case 'bronya':
@@ -237,9 +245,19 @@ function isBattlesuitHidden(
case 'eden': case 'eden':
case 'griseo': case 'griseo':
case 'vill-v': case 'vill-v':
return battlesuit.valkyrie !== filter return battlesuit.valkyrie === valkyrieFilter
default: default:
case 'all': case 'all':
return false return true
} }
} }
function isFeatureFilterMatching(
battlesuit: BattlesuitListItemData,
featureFilter: string
) {
if (featureFilter === 'all') {
return true
}
return battlesuit.features.some((feature) => feature === featureFilter)
}
+9 -7
View File
@@ -41,20 +41,22 @@ const WeaponListPage = ({ weaponDataList }: WeaponListPageProps) => {
const { query, locale } = useRouter() const { query, locale } = useRouter()
const { t } = useTranslation() const { t } = useTranslation()
const filter = useMemo(() => { const categoryFilter = useMemo(() => {
if (query.filter == null) { if (query.category == null) {
return 'all' return 'all'
} }
return typeof query.filter === 'string' ? query.filter : query.filter[0] return typeof query.category === 'string'
? query.category
: query.category[0]
}, [query]) }, [query])
const weaponList = useMemo(() => { const weaponList = useMemo(() => {
return weaponDataList.map((weapon) => { return weaponDataList.map((weapon) => {
const hidden = isWeaponHidden(weapon, filter) const hidden = isWeaponHidden(weapon, categoryFilter)
return <WeaponCard key={weapon.id} weapon={weapon} hidden={hidden} /> return <WeaponCard key={weapon.id} weapon={weapon} hidden={hidden} />
}) })
}, [weaponDataList, filter]) }, [weaponDataList, categoryFilter])
return ( return (
<Honkai3rdLayout> <Honkai3rdLayout>
@@ -82,8 +84,8 @@ const WeaponListPage = ({ weaponDataList }: WeaponListPageProps) => {
return ( return (
<FilterButton <FilterButton
key={value} key={value}
active={value === filter} href={`?category=${value}`}
value={value} active={value === categoryFilter}
label={translate(locale, { 'ko-KR': krLabel }, label)} label={translate(locale, { 'ko-KR': krLabel }, label)}
m={1} m={1}
/> />
+1
View File
@@ -13,6 +13,7 @@
"module": "esnext", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"resolveJsonModule": true, "resolveJsonModule": true,
"downlevelIteration": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "preserve",
"baseUrl": "./src" "baseUrl": "./src"