Files
abyss-lab/src/pages/honkai3rd/battlesuits/index.tsx
T

237 lines
6.3 KiB
TypeScript

import { Box, Heading, Flex, Text, Link } from '@theme-ui/components'
import NextLink from 'next/link'
import { pick } from 'ramda'
import React, { useMemo, useState } from 'react'
import FilterButton from '../../../components/atoms/FilterButton'
import SquareImageBox from '../../../components/atoms/SquareImageBox'
import Breadcrumb from '../../../components/organisms/Breadcrumb'
import Honkai3rdNavigator from '../../../components/organisms/Honkai3rdNavigator'
import {
BattlesuitData,
listBattlesuits,
} from '../../../data/honkai3rd/battlesuits'
import { battlesuitStrengths } from '../../../lib/safeData'
type BattlesuitListItemData = Pick<
BattlesuitData,
'id' | 'name' | 'strengths' | 'type' | 'valkyrie'
>
interface BattlesuitListPageProps {
battlesuits: BattlesuitListItemData[]
}
const featureFilterOptions = [
{ value: 'all', label: 'All' },
...battlesuitStrengths,
]
const valkyrieFilterOptions = [
{ value: 'all', label: 'All' },
{ value: 'mecha', label: 'Mecha' },
{ value: 'biologic', label: 'Biologic' },
{ value: 'psychic', label: 'Psychic' },
{ value: 'quantum', label: 'Quantum' },
{ value: 'imaginary', label: 'Imaginary' },
{ value: 'kiana', label: 'Kiana' },
{ value: 'mei', label: 'Mei' },
{ value: 'bronya', label: 'Bronya' },
{ value: 'himeko', label: 'Himeko' },
{ value: 'theresa', label: 'Theresa' },
{ value: 'fuhua', label: 'Fu Hua' },
{ value: 'rita', label: 'Rita' },
{ value: 'sakura', label: 'Sakura' },
{ value: 'kallen', label: 'Kallen' },
{ value: 'olenyevas', label: 'Olenyevas' },
{ value: 'seele', label: 'Seele' },
{ value: 'durandal', label: 'Durandal' },
{ value: 'fischl', label: 'Fischl' },
{ value: 'elysia', label: 'Elysia' },
{ value: 'mobius', label: 'Mobius' },
{ value: 'raven', label: 'Raven' },
{ value: 'carole', label: 'Carole' },
]
const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
const [filter, setFilter] = useState('all')
const battlesuitList = useMemo(() => {
return battlesuits.map((battlesuit) => {
const hidden = isBattlesuitHidden(battlesuit, filter)
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',
'&: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>
<SquareImageBox
alt={battlesuit.name}
src={`/assets/honkai3rd/battlesuits/portrait-${battlesuit.id}.png`}
size={140}
/>
<Box
sx={{
overflow: 'hidden',
textOverflow: 'ellipsis',
width: '100%',
whiteSpace: 'nowrap',
textAlign: 'center',
}}
>
<Text>{battlesuit.name}</Text>
</Box>
</Link>
</NextLink>
</Box>
)
})
}, [battlesuits, filter])
return (
<Box>
<Honkai3rdNavigator />
<Box p={3}>
<Breadcrumb
items={[
{ href: '/honkai3rd', label: 'Honkai 3rd' },
{ href: '/honkai3rd/battlesuits', label: 'Battlesuits' },
]}
/>
<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
key={value}
active={value === filter}
setFilter={setFilter}
value={value}
label={label}
m={1}
/>
)
})}
</Flex>
<Heading as='h3'>Filter by Valkyries</Heading>
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
{valkyrieFilterOptions.map(({ value, label }) => {
return (
<FilterButton
key={value}
active={value === filter}
setFilter={setFilter}
value={value}
label={label}
m={1}
/>
)
})}
</Flex>
</Box>
<Flex
sx={{
flexWrap: 'wrap',
justifyContent: 'space-around',
}}
>
{battlesuitList}
</Flex>
</Box>
</Box>
)
}
export default BattlesuitListPage
export async function getStaticProps() {
return {
props: {
battlesuits: listBattlesuits().map((battlesuit) =>
pick(['id', 'name', 'strengths', 'type', 'valkyrie'], battlesuit)
),
},
}
}
function isBattlesuitHidden(
battlesuit: BattlesuitListItemData,
filter: string
): boolean {
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)
case 'mecha':
case 'biologic':
case 'psychic':
case 'quantum':
case 'imaginary':
return battlesuit.type !== filter
case 'kiana':
case 'mei':
case 'bronya':
case 'himeko':
case 'theresa':
case 'fuhua':
case 'rita':
case 'sakura':
case 'kallen':
case 'olenyevas':
case 'seele':
case 'durandal':
case 'fischl':
case 'elysia':
case 'mobius':
case 'raven':
case 'carole':
return battlesuit.valkyrie !== filter
default:
case 'all':
return false
}
}