Implement filter by features for battlesuit list
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
"name": "Drive Kometa",
|
"name": "Drive Kometa",
|
||||||
"type": "psychic",
|
"type": "psychic",
|
||||||
"valkyrie": "bronya",
|
"valkyrie": "bronya",
|
||||||
"strengths": [],
|
"strengths": ["physical", "gather", "weaken", "burst", "time mastery"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Mental Sync",
|
"name": "Mental Sync",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Danzai Spectramancer",
|
"name": "Danzai Spectramancer",
|
||||||
"type": "mecha",
|
"type": "mecha",
|
||||||
"valkyrie": "mei",
|
"valkyrie": "mei",
|
||||||
"strengths": [],
|
"strengths": ["physical"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Phantom Outbreak",
|
"name": "Phantom Outbreak",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Fervent Tempo Δ",
|
"name": "Fervent Tempo Δ",
|
||||||
"type": "psychic",
|
"type": "psychic",
|
||||||
"valkyrie": "olenyevas",
|
"valkyrie": "olenyevas",
|
||||||
"strengths": [],
|
"strengths": ["physical"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "SHOWTIME!",
|
"name": "SHOWTIME!",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Hawk of the Fog",
|
"name": "Hawk of the Fog",
|
||||||
"type": "psychic",
|
"type": "psychic",
|
||||||
"valkyrie": "fuhua",
|
"valkyrie": "fuhua",
|
||||||
"strengths": [],
|
"strengths": ["lightning dmg", "heavy atk", "paralyze", "time mastery"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Chelonic Unity",
|
"name": "Chelonic Unity",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Herrscher of Flamescion",
|
"name": "Herrscher of Flamescion",
|
||||||
"type": "psychic",
|
"type": "psychic",
|
||||||
"valkyrie": "kiana",
|
"valkyrie": "kiana",
|
||||||
"strengths": ["fire dmg", "heal", "time mastery", "gather"],
|
"strengths": ["fire dmg", "heal", "time mastery", "gather", "aerial"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Nameless Knight-Errant's Path",
|
"name": "Nameless Knight-Errant's Path",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Herrscher of the Void",
|
"name": "Herrscher of the Void",
|
||||||
"type": "biologic",
|
"type": "biologic",
|
||||||
"valkyrie": "kiana",
|
"valkyrie": "kiana",
|
||||||
"strengths": ["physical", "time mastery", "fast atk"],
|
"strengths": ["physical", "time mastery", "fast atk", "aerial"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Void Throne",
|
"name": "Void Throne",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Infinite Ouroboros",
|
"name": "Infinite Ouroboros",
|
||||||
"type": "mecha",
|
"type": "mecha",
|
||||||
"valkyrie": "mobius",
|
"valkyrie": "mobius",
|
||||||
"strengths": ["lightning dmg", "time mastery"],
|
"strengths": ["lightning dmg", "time mastery", "aerial"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Infinite Fate",
|
"name": "Infinite Fate",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Miss Pink Elf♪",
|
"name": "Miss Pink Elf♪",
|
||||||
"type": "psychic",
|
"type": "psychic",
|
||||||
"valkyrie": "elysia",
|
"valkyrie": "elysia",
|
||||||
"strengths": ["physical", "time mastery", "fast atk"],
|
"strengths": ["physical", "time mastery", "fast atk", "aerial"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "An Ode to Love and Compassion",
|
"name": "An Ode to Love and Compassion",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Prinzessin der Verurteilung!",
|
"name": "Prinzessin der Verurteilung!",
|
||||||
"type": "biologic",
|
"type": "biologic",
|
||||||
"valkyrie": "fischl",
|
"valkyrie": "fischl",
|
||||||
"strengths": ["lightning dmg", "time mastery", "fast atk"],
|
"strengths": ["lightning dmg", "time mastery", "fast atk", "aerial"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Evernight Suite",
|
"name": "Evernight Suite",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Sweet 'n' Spicy",
|
"name": "Sweet 'n' Spicy",
|
||||||
"type": "mecha",
|
"type": "mecha",
|
||||||
"valkyrie": "carole",
|
"valkyrie": "carole",
|
||||||
"strengths": ["physical", "time mastery", "stun", "gather"],
|
"strengths": ["physical", "time mastery", "stun", "gather", "aerial"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Star of Hope",
|
"name": "Star of Hope",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Striker Fulminata",
|
"name": "Striker Fulminata",
|
||||||
"type": "biologic",
|
"type": "biologic",
|
||||||
"valkyrie": "mei",
|
"valkyrie": "mei",
|
||||||
"strengths": [],
|
"strengths": ["physical", "burst", "fast atk", "paralyze"],
|
||||||
"leader": {
|
"leader": {
|
||||||
"core": {
|
"core": {
|
||||||
"name": "Sakura Aura",
|
"name": "Sakura Aura",
|
||||||
|
|||||||
@@ -86,6 +86,27 @@ export const theme: Theme = {
|
|||||||
lineHeight: 'heading',
|
lineHeight: 'heading',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
buttons: {
|
||||||
|
primary: {
|
||||||
|
color: 'primary',
|
||||||
|
borderColor: 'primary',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderWidth: 1,
|
||||||
|
bg: 'background',
|
||||||
|
'&:hover, &.active': {
|
||||||
|
color: 'background',
|
||||||
|
bg: 'primary',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
color: 'background',
|
||||||
|
bg: 'secondary',
|
||||||
|
},
|
||||||
|
gray: {
|
||||||
|
color: 'background',
|
||||||
|
bg: 'gray',
|
||||||
|
},
|
||||||
|
},
|
||||||
styles: {
|
styles: {
|
||||||
root: {
|
root: {
|
||||||
fontFamily: 'body',
|
fontFamily: 'body',
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Box, Heading, Flex, Text, Link } from '@theme-ui/components'
|
import { Box, Heading, Flex, Text, Link, Button } from '@theme-ui/components'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import NextLink from 'next/link'
|
import NextLink from 'next/link'
|
||||||
import { pick } from 'ramda'
|
import { pick } from 'ramda'
|
||||||
import React from 'react'
|
import React, { useCallback, useMemo, useState } from 'react'
|
||||||
|
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
||||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
|
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
|
||||||
import {
|
import {
|
||||||
@@ -10,11 +11,133 @@ import {
|
|||||||
listBattlesuits,
|
listBattlesuits,
|
||||||
} from '../../../data/honkai3rd/battlesuits'
|
} from '../../../data/honkai3rd/battlesuits'
|
||||||
|
|
||||||
|
type BattlesuitListItemData = Pick<BattlesuitData, 'id' | 'name' | 'strengths'>
|
||||||
|
|
||||||
interface BattlesuitListPageProps {
|
interface BattlesuitListPageProps {
|
||||||
battlesuits: Pick<BattlesuitData, 'id' | 'name'>[]
|
battlesuits: BattlesuitListItemData[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureFilterOptions = [
|
||||||
|
{ value: 'all', label: 'All' },
|
||||||
|
{ value: 'physical', label: 'Physical' },
|
||||||
|
{ value: 'fire dmg', label: 'Fire DMG' },
|
||||||
|
{ value: 'ice dmg', label: 'Ice DMG' },
|
||||||
|
{ value: 'lightning dmg', label: 'Lightning DMG' },
|
||||||
|
{ value: 'freeze', label: 'Freeze' },
|
||||||
|
{ value: 'paralyze', label: 'Paralyze' },
|
||||||
|
{ value: 'stun', label: 'Stun' },
|
||||||
|
{ value: 'ignite', label: 'Ignite' },
|
||||||
|
{ value: 'bleed', label: 'Bleed' },
|
||||||
|
{ value: 'heavy atk', label: 'Heavy ATK' },
|
||||||
|
{ value: 'weaken', label: 'Weaken' },
|
||||||
|
{ value: 'impair', label: 'Impair' },
|
||||||
|
{ value: 'time mastery', label: 'Time Mastery' },
|
||||||
|
{ value: 'gather', label: 'Gather' },
|
||||||
|
{ value: 'heal', label: 'Heal' },
|
||||||
|
{ value: 'fast atk', label: 'Fast ATK' },
|
||||||
|
{ value: 'burst', label: 'Burst' },
|
||||||
|
{ value: 'aerial', label: 'Aerial' },
|
||||||
|
]
|
||||||
|
|
||||||
const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
||||||
|
const [filter, setFilter] = useState('all')
|
||||||
|
|
||||||
|
const isBattlesuitHidden = useCallback(
|
||||||
|
(battlesuit: BattlesuitListItemData) => {
|
||||||
|
switch (filter) {
|
||||||
|
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.strengths.some((strength) => strength === filter)
|
||||||
|
default:
|
||||||
|
case 'all':
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[filter]
|
||||||
|
)
|
||||||
|
|
||||||
|
const battlesuitList = useMemo(() => {
|
||||||
|
return battlesuits.map((battlesuit) => {
|
||||||
|
const hidden = isBattlesuitHidden(battlesuit)
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
key={battlesuit.id}
|
||||||
|
className={hidden ? 'hidden' : ''}
|
||||||
|
sx={{
|
||||||
|
width: '160px',
|
||||||
|
padding: 2,
|
||||||
|
margin: 1,
|
||||||
|
borderColor: 'gray.3',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderRadius: 8,
|
||||||
|
transition:
|
||||||
|
'box-shadow 200ms ease-in-out, opacity 200ms ease-in-out',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'gray.3',
|
||||||
|
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)',
|
||||||
|
},
|
||||||
|
'&.hidden': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<NextLink
|
||||||
|
href={`/honkai3rd/battlesuits/${battlesuit.id}`}
|
||||||
|
key={battlesuit.id}
|
||||||
|
passHref={true}
|
||||||
|
>
|
||||||
|
<Link>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
overflow: 'hidden',
|
||||||
|
width: '140px',
|
||||||
|
height: '140px',
|
||||||
|
borderRadius: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
alt={battlesuit.name}
|
||||||
|
layout='fill'
|
||||||
|
objectFit='cover'
|
||||||
|
src={`/assets/honkai3rd/battlesuits/portrait-${battlesuit.id}.png`}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
width: '100%',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text>{battlesuit.name}</Text>
|
||||||
|
</Box>
|
||||||
|
</Link>
|
||||||
|
</NextLink>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}, [battlesuits, isBattlesuitHidden])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Honkai3rdNavigator />
|
<Honkai3rdNavigator />
|
||||||
@@ -28,6 +151,60 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Heading as='h1'>Battlesuits</Heading>
|
<Heading as='h1'>Battlesuits</Heading>
|
||||||
|
<Box>
|
||||||
|
<Heading as='h3'>Filter by Features</Heading>
|
||||||
|
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
|
||||||
|
{featureFilterOptions.map(({ value, label }) => {
|
||||||
|
return (
|
||||||
|
<FilterButton
|
||||||
|
active={value === filter}
|
||||||
|
setFilter={setFilter}
|
||||||
|
value={value}
|
||||||
|
label={label}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Heading as='h3'>Filter by Valkyries</Heading>
|
||||||
|
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
|
||||||
|
<FilterButton setFilter={setFilter} value='all' label='ALL' />
|
||||||
|
<FilterButton setFilter={setFilter} value='mecha' label='MECHA' />
|
||||||
|
<FilterButton setFilter={setFilter} value='bio' label='BIO' />
|
||||||
|
<FilterButton setFilter={setFilter} value='psy' label='PSY' />
|
||||||
|
<FilterButton setFilter={setFilter} value='qua' label='QUA' />
|
||||||
|
<FilterButton setFilter={setFilter} value='img' label='IMG' />
|
||||||
|
<FilterButton setFilter={setFilter} value='kiana' label='Kiana' />
|
||||||
|
<FilterButton setFilter={setFilter} value='mei' label='Mei' />
|
||||||
|
<FilterButton setFilter={setFilter} value='bronya' label='Bronya' />
|
||||||
|
<FilterButton setFilter={setFilter} value='himeko' label='Himeko' />
|
||||||
|
<FilterButton
|
||||||
|
setFilter={setFilter}
|
||||||
|
value='theresa'
|
||||||
|
label='Theresa'
|
||||||
|
/>
|
||||||
|
<FilterButton setFilter={setFilter} value='fu hua' label='Fu Hua' />
|
||||||
|
<FilterButton setFilter={setFilter} value='rita' label='Rita' />
|
||||||
|
<FilterButton setFilter={setFilter} value='sakura' label='Sakura' />
|
||||||
|
<FilterButton setFilter={setFilter} value='kallen' label='Kallen' />
|
||||||
|
<FilterButton
|
||||||
|
setFilter={setFilter}
|
||||||
|
value='olenyevas'
|
||||||
|
label='Olenyevas'
|
||||||
|
/>
|
||||||
|
<FilterButton setFilter={setFilter} value='seele' label='Seele' />
|
||||||
|
<FilterButton
|
||||||
|
setFilter={setFilter}
|
||||||
|
value='durandal'
|
||||||
|
label='Durandal'
|
||||||
|
/>
|
||||||
|
<FilterButton setFilter={setFilter} value='fischl' label='Fischl' />
|
||||||
|
<FilterButton setFilter={setFilter} value='elysia' label='Elysia' />
|
||||||
|
<FilterButton setFilter={setFilter} value='mobius' label='Mobius' />
|
||||||
|
<FilterButton setFilter={setFilter} value='raven' label='Raven' />
|
||||||
|
<FilterButton setFilter={setFilter} value='carole' label='Carole' />
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
@@ -35,63 +212,7 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
|||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{battlesuits.map((battlesuit) => {
|
{battlesuitList}
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
key={battlesuit.id}
|
|
||||||
sx={{
|
|
||||||
width: '160px',
|
|
||||||
padding: 2,
|
|
||||||
margin: 1,
|
|
||||||
borderColor: 'gray.3',
|
|
||||||
borderWidth: 1,
|
|
||||||
borderStyle: 'solid',
|
|
||||||
borderRadius: 8,
|
|
||||||
'&:hover': {
|
|
||||||
borderColor: 'gray.3',
|
|
||||||
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)',
|
|
||||||
transition: 'box-shadow 200ms ease-in-out',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NextLink
|
|
||||||
href={`/honkai3rd/battlesuits/${battlesuit.id}`}
|
|
||||||
key={battlesuit.id}
|
|
||||||
passHref={true}
|
|
||||||
>
|
|
||||||
<Link>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: 'relative',
|
|
||||||
overflow: 'hidden',
|
|
||||||
width: '140px',
|
|
||||||
height: '140px',
|
|
||||||
borderRadius: 4,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
alt={battlesuit.name}
|
|
||||||
layout='fill'
|
|
||||||
objectFit='cover'
|
|
||||||
src={`/assets/honkai3rd/battlesuits/portrait-${battlesuit.id}.png`}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
width: '100%',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
textAlign: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text>{battlesuit.name}</Text>
|
|
||||||
</Box>
|
|
||||||
</Link>
|
|
||||||
</NextLink>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -104,8 +225,46 @@ export async function getStaticProps() {
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
battlesuits: listBattlesuits().map((battlesuit) =>
|
battlesuits: listBattlesuits().map((battlesuit) =>
|
||||||
pick(['id', 'name'], battlesuit)
|
pick(['id', 'name', 'strengths'], battlesuit)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FilterButtonProps {
|
||||||
|
active?: boolean
|
||||||
|
icon?: string
|
||||||
|
label: string
|
||||||
|
setFilter: (filter: string) => void
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const FilterButton = ({
|
||||||
|
active = false,
|
||||||
|
setFilter,
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
}: FilterButtonProps) => {
|
||||||
|
const selectFilter = useCallback(() => {
|
||||||
|
setFilter(value)
|
||||||
|
}, [setFilter, value])
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
m={1}
|
||||||
|
py={1}
|
||||||
|
px={2}
|
||||||
|
onClick={selectFilter}
|
||||||
|
className={active ? 'active' : ''}
|
||||||
|
>
|
||||||
|
{icon != null && (
|
||||||
|
<SquareImageBox
|
||||||
|
src={`/assets/honkai3rd/icons/${icon}.png`}
|
||||||
|
alt={label}
|
||||||
|
size={30}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user