Remove legacy pages
This commit is contained in:
@@ -1,213 +1,162 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Card, Flex, Heading, Paragraph, Text, Image } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import React from 'react'
|
||||
import BattlesuitFeatureLabel from '../../../components/atoms/BattlesuitFeatureLabel'
|
||||
import BattlesuitRankIcon from '../../../components/atoms/BattlesuitRankIcon'
|
||||
import PageLink from '../../../components/atoms/PageLink'
|
||||
import SecondaryLabel from '../../../components/atoms/SecondaryLabel'
|
||||
import TypeLabel from '../../../components/atoms/TypeLabel'
|
||||
import ValkyrieLabel from '../../../components/atoms/ValkyrieLabel'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import AttributeIcon from '../../../components/v2/AttributeIcon'
|
||||
import AvatarFigureImage from '../../../components/v2/AvatarFigureImage'
|
||||
import AvatarSkillIcon from '../../../components/v2/AvatarSkillIcon'
|
||||
import AvatarSubSkillIcon from '../../../components/v2/AvatarSubSkillIcon'
|
||||
import BattlesuitAvatarIcon from '../../../components/v2/BattlesuitAvatarIcon'
|
||||
import FormattedText from '../../../components/v2/FormattedText'
|
||||
import { formatSkillInfo, formatSubSkillInfo } from '../../../lib/v2/data/formatText'
|
||||
import { loadBattlesuitCatalog, loadBattlesuitData } from '../../../lib/v2/server/loadData'
|
||||
import { Battlesuit, SkillTagItem } from '../../../lib/v2/data/types'
|
||||
import { Fragment } from 'react'
|
||||
import TagIcon from '../../../components/v2/TagIcon'
|
||||
import {
|
||||
BattlesuitData,
|
||||
battlesuitFeatures,
|
||||
BattlesuitSkillGroup,
|
||||
battlesuitTypes,
|
||||
valkyries
|
||||
} from '../../../lib/honkai3rd/battlesuits'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
||||
import { getBattlesuitById, listBattlesuits } from '../../../server/data/honkai3rd/battlesuits'
|
||||
import { translate, useTranslation } from '../../../lib/i18n'
|
||||
import { useRouter } from 'next/router'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { capitalize } from '../../../lib/string'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
getAttributeLabel,
|
||||
getCharacterTypeLabel,
|
||||
getSkillTypeLabel,
|
||||
getTagTypeLabel,
|
||||
getWeaponTypeLabel
|
||||
} from '../../../lib/v2/data/text'
|
||||
import StarIcon from '../../../components/v2/StarIcon'
|
||||
import ChibiIcon from '../../../components/v2/ChibiIcon'
|
||||
import WeaponTypeIcon from '../../../components/v2/WeaponTypeIcon'
|
||||
import { sortBattlesuitSkill } from '../../../lib/v2/data/utils'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { WeaponData } from '../../../lib/honkai3rd/weapons'
|
||||
import { getWeaponMapByIds } from '../../../server/data/honkai3rd/weapons'
|
||||
import { StigmataData } from '../../../lib/honkai3rd/stigmata'
|
||||
import WeaponCard from '../../../components/molecules/WeaponCard'
|
||||
import StigmataCard from '../../../components/molecules/StigmataCard'
|
||||
import { getStigmataMapByIds } from '../../../server/data/honkai3rd/stigmata'
|
||||
|
||||
type WeaponObjectMap = { [key: string]: WeaponData }
|
||||
type StigmataObjectMap = { [key: string]: StigmataData }
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
interface BattlesuitShowPageProps {
|
||||
battlesuit: BattlesuitData
|
||||
weaponMap: WeaponObjectMap
|
||||
stigmataMap: StigmataObjectMap
|
||||
battlesuit: Battlesuit
|
||||
}
|
||||
|
||||
const BattlesuitShowPage = ({ battlesuit, weaponMap, stigmataMap }: BattlesuitShowPageProps) => {
|
||||
const BattlesuitShowPage = ({ battlesuit }: BattlesuitShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useRouter()
|
||||
|
||||
const { label: valkyrieLabel, krLabel } = valkyries.find(aValkyrie => aValkyrie.value === battlesuit.valkyrie) || {
|
||||
label: battlesuit.valkyrie,
|
||||
krLabel: battlesuit.valkyrie
|
||||
}
|
||||
|
||||
const valkyrieName = translate(locale, { 'ko-KR': krLabel }, valkyrieLabel)
|
||||
|
||||
const battlesuitType = battlesuitTypes.find(aType => aType.value === battlesuit.type)
|
||||
const battlesuitTypeLabel = battlesuitType
|
||||
? translate(locale, { 'ko-KR': battlesuitType.krLabel }, battlesuitType.label)
|
||||
: capitalize(battlesuit.type)
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${battlesuit.name} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${t(
|
||||
'battlesuit-show.battlesuit'
|
||||
)} / ${valkyrieName} / ${battlesuitTypeLabel} / ${battlesuit.features
|
||||
.map(feature => {
|
||||
const featureData = battlesuitFeatures.find(aFeature => aFeature.value === feature)
|
||||
if (featureData == null) {
|
||||
return feature
|
||||
}
|
||||
|
||||
const { label, krLabel } = featureData
|
||||
|
||||
return translate(locale, { 'ko-KR': krLabel }, label)
|
||||
title={`${battlesuit.fullName} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${t('battlesuit-show.battlesuit')} / ${battlesuit.fullName} / ${
|
||||
battlesuit.attributeType
|
||||
} / ${battlesuit.tags
|
||||
.map(tag => {
|
||||
return getTagTypeLabel(tag)
|
||||
})
|
||||
.join(', ')}`}
|
||||
canonicalHref={`/honkai3rd/battlesuits/${battlesuit.id}`}
|
||||
/>
|
||||
<Box p={2}>
|
||||
<Heading as="h1">{battlesuit.fullName}</Heading>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/battlesuits',
|
||||
label: t('common.battlesuits')
|
||||
},
|
||||
{
|
||||
href: `/honkai3rd/battlesuits/${battlesuit.id}`,
|
||||
label: battlesuit.name
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as="h1">{battlesuit.name}</Heading>
|
||||
<AvatarFigureImage battlesuitId={battlesuit.id} sx={{ height: 400 }} />
|
||||
|
||||
<Box mb={3}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
maxWidth: [300, 400]
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
alt={battlesuit.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/battlesuits/${battlesuit.id}.png`}
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</Box>
|
||||
<BattlesuitAvatarIcon battlesuit={battlesuit} />
|
||||
</Box>
|
||||
|
||||
<Card
|
||||
sx={{
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
mb={3}
|
||||
>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/battlesuits',
|
||||
query: { valkyrie: battlesuit.valkyrie }
|
||||
}}
|
||||
>
|
||||
<ValkyrieLabel valkyrie={battlesuit.valkyrie} />
|
||||
</PageLink>
|
||||
</Box>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/battlesuits',
|
||||
query: { valkyrie: battlesuit.type }
|
||||
}}
|
||||
>
|
||||
<TypeLabel type={battlesuit.type} />
|
||||
</PageLink>
|
||||
</Box>
|
||||
<Flex p={2} sx={{ flexWrap: 'wrap', rowGap: 1 }}>
|
||||
{battlesuit.features.map(feature => {
|
||||
<Card mb={3}>
|
||||
<Flex sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<Box mr={2}>
|
||||
<StarIcon star={battlesuit.initialStar} />
|
||||
</Box>
|
||||
|
||||
<ChibiIcon id={battlesuit.character} />
|
||||
|
||||
<Box ml={1} mr={2}>
|
||||
{getCharacterTypeLabel(battlesuit.character)}
|
||||
</Box>
|
||||
|
||||
<AttributeIcon attributeType={battlesuit.attributeType} size={30} />
|
||||
<Box ml={1} mr={2}>
|
||||
{getAttributeLabel(battlesuit.attributeType)}
|
||||
</Box>
|
||||
|
||||
<WeaponTypeIcon type={battlesuit.weapon} />
|
||||
<Box ml={1}>{getWeaponTypeLabel(battlesuit.weapon)}</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex sx={{ p: 1 }}>
|
||||
{battlesuit.tags.map(tag => {
|
||||
return (
|
||||
<Box mr={2} key={feature}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/battlesuits',
|
||||
query: { feature: feature }
|
||||
}}
|
||||
>
|
||||
<BattlesuitFeatureLabel feature={feature} />
|
||||
</PageLink>
|
||||
</Box>
|
||||
<Flex key={tag} sx={{ mr: 2, alignItems: 'center' }}>
|
||||
<TagIcon type={tag} />
|
||||
<Box ml={1}>{getTagTypeLabel(tag)}</Box>
|
||||
</Flex>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
{battlesuit.equipment != null && (
|
||||
<Card
|
||||
sx={{
|
||||
mb: 3,
|
||||
p: 2,
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
{battlesuit.equipment.map(equipmentItem => {
|
||||
return (
|
||||
<Box key={equipmentItem.type}>
|
||||
<Heading
|
||||
as="h3"
|
||||
sx={{
|
||||
mb: 1
|
||||
}}
|
||||
>
|
||||
{t(`battlesuit-show.equipmentTypes.${equipmentItem.type}`)}
|
||||
<Heading as="h2">Skills</Heading>
|
||||
{battlesuit.skills.sort(sortBattlesuitSkill).map(skill => {
|
||||
return (
|
||||
<Card key={skill.id} mb={3}>
|
||||
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<AvatarSkillIcon icon={skill.icon} />
|
||||
<Heading as="h3" sx={{ ml: 1, mb: 0 }}>
|
||||
<FormattedText>{skill.name}</FormattedText>
|
||||
</Heading>
|
||||
<Flex sx={{ mx: -1 }}>
|
||||
{equipmentItem.weapon != null && <WeaponCard size="sm" weapon={weaponMap[equipmentItem.weapon]} />}
|
||||
{equipmentItem.stigmataTop != null && (
|
||||
<StigmataCard size="sm" stigmata={stigmataMap[equipmentItem.stigmataTop]} />
|
||||
)}
|
||||
{equipmentItem.stigmataMid != null && (
|
||||
<StigmataCard size="sm" stigmata={stigmataMap[equipmentItem.stigmataMid]} />
|
||||
)}
|
||||
{equipmentItem.stigmataBot != null && (
|
||||
<StigmataCard size="sm" stigmata={stigmataMap[equipmentItem.stigmataBot]} />
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)}
|
||||
{skill.tags.length > 0 && (
|
||||
<Flex sx={{ ml: 1 }}>
|
||||
{skill.tags.map((tag, index) => {
|
||||
return <SkillTagItem key={index} tag={tag} />
|
||||
})}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.leader')} skillGroup={battlesuit.leader} />
|
||||
<Box>{getSkillTypeLabel(skill.skillType)}</Box>
|
||||
</Box>
|
||||
<Box sx={{ whiteSpace: 'pre-wrap', borderBottom: 'default', p: 1 }}>
|
||||
<FormattedText>{formatSkillInfo(skill)}</FormattedText>
|
||||
</Box>
|
||||
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.passive')} skillGroup={battlesuit.passive} />
|
||||
{skill.subSkills.map(subSkill => {
|
||||
return (
|
||||
<Fragment key={subSkill.id}>
|
||||
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<AvatarSubSkillIcon icon={subSkill.icon} />
|
||||
<Heading as="h4" sx={{ ml: 1, mb: 0 }}>
|
||||
<FormattedText>{subSkill.name}</FormattedText>
|
||||
</Heading>
|
||||
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.evasion')} skillGroup={battlesuit.evasion} />
|
||||
{subSkill.unlockStar.localeCompare(battlesuit.initialStar) > 0 && (
|
||||
<Box ml={2}>
|
||||
<StarIcon star={subSkill.unlockStar} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.special-attack')} skillGroup={battlesuit.special} />
|
||||
{subSkill.tags.length > 0 && (
|
||||
<Flex sx={{ ml: 2 }}>
|
||||
{subSkill.tags.map((tag, index) => {
|
||||
return <SkillTagItem key={index} tag={tag} />
|
||||
})}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.ultimate')} skillGroup={battlesuit.ultimate} />
|
||||
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.basic-attack')} skillGroup={battlesuit.basic} />
|
||||
|
||||
{battlesuit.sp != null && (
|
||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.sp-skill')} skillGroup={battlesuit.sp} />
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
borderBottom: 'default',
|
||||
'&:last-child': { borderBottom: 'none' },
|
||||
p: 1
|
||||
}}
|
||||
>
|
||||
<FormattedText>{formatSubSkillInfo(subSkill)}</FormattedText>
|
||||
</Box>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
{/* <pre>{JSON.stringify(battlesuit, null, 2)}</pre> */}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
@@ -215,103 +164,31 @@ const BattlesuitShowPage = ({ battlesuit, weaponMap, stigmataMap }: BattlesuitSh
|
||||
|
||||
export default BattlesuitShowPage
|
||||
|
||||
export async function getStaticProps({ params, locale }: NextPageContext & { params: { battlesuitId: string } }) {
|
||||
const battlesuit = getBattlesuitById(params.battlesuitId, locale)!
|
||||
const { weaponIds, stigmataIds } = (battlesuit.equipment || []).reduce<{
|
||||
weaponIds: string[]
|
||||
stigmataIds: string[]
|
||||
}>(
|
||||
(acc, equipmentItem) => {
|
||||
acc.weaponIds.push(equipmentItem.weapon)
|
||||
acc.stigmataIds.push(equipmentItem.stigmataTop, equipmentItem.stigmataMid, equipmentItem.stigmataBot)
|
||||
return acc
|
||||
},
|
||||
{ weaponIds: [], stigmataIds: [] }
|
||||
)
|
||||
const weaponMap = getWeaponMapByIds(weaponIds, locale)
|
||||
|
||||
const stigmataMap = getStigmataMapByIds(stigmataIds, locale)
|
||||
export async function getStaticProps({ locale, params }: NextPageContext & { params: { battlesuitId: string } }) {
|
||||
const battlesuit = loadBattlesuitData(params.battlesuitId)
|
||||
|
||||
return {
|
||||
props: {
|
||||
battlesuit,
|
||||
weaponMap,
|
||||
stigmataMap,
|
||||
...(await getI18NProps(locale))
|
||||
}
|
||||
props: { battlesuit, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const battlesuitCatalog = loadBattlesuitCatalog()
|
||||
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
listBattlesuits().map(battlesuit => {
|
||||
return {
|
||||
params: { battlesuitId: battlesuit.id }
|
||||
}
|
||||
})
|
||||
),
|
||||
paths: battlesuitCatalog.map(catalogItem => {
|
||||
return {
|
||||
params: { battlesuitId: catalogItem.id }
|
||||
}
|
||||
}),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
|
||||
interface BattlesuitSkillGroupCardProps {
|
||||
heading: string
|
||||
skillGroup: BattlesuitSkillGroup
|
||||
interface SkillTagBoxProps {
|
||||
tag: SkillTagItem
|
||||
}
|
||||
|
||||
const BattlesuitSkillGroupCard = ({ heading, skillGroup }: BattlesuitSkillGroupCardProps) => {
|
||||
return (
|
||||
<Card mb={3}>
|
||||
<Box
|
||||
sx={{
|
||||
p: 2,
|
||||
borderBottom: 'default'
|
||||
}}
|
||||
>
|
||||
<Heading as="h2" mb={1}>
|
||||
{skillGroup.core.name}
|
||||
</Heading>
|
||||
<SecondaryLabel>{heading}</SecondaryLabel>
|
||||
</Box>
|
||||
|
||||
<Paragraph p={2} sx={{ whiteSpace: 'pre-wrap', borderBottom: 'default' }}>
|
||||
{skillGroup.core.description}
|
||||
</Paragraph>
|
||||
|
||||
{skillGroup.subskills.map(subskill => {
|
||||
return (
|
||||
<React.Fragment key={subskill.name}>
|
||||
<Heading as="h3" p={2} m={0} sx={{ borderBottom: 'default' }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<Text>{subskill.name}</Text>
|
||||
{subskill.requiredRank != null ? (
|
||||
/^[0-9]/.test(subskill.requiredRank) ? (
|
||||
<Box ml={2} sx={{ height: 30, lineHeight: '30px', fontSize: 2 }}>
|
||||
⭐{subskill.requiredRank.slice(0, 1)}
|
||||
</Box>
|
||||
) : (
|
||||
<BattlesuitRankIcon rank={subskill.requiredRank} size={30} ml={2} />
|
||||
)
|
||||
) : (
|
||||
<Box sx={{ height: 30 }} />
|
||||
)}
|
||||
</Flex>
|
||||
</Heading>
|
||||
|
||||
<Paragraph
|
||||
p={2}
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
borderBottom: 'default',
|
||||
'&:last-child': { borderBottom: 'none' }
|
||||
}}
|
||||
>
|
||||
{subskill.description}
|
||||
</Paragraph>
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
const SkillTagItem = ({ tag }: SkillTagBoxProps) => {
|
||||
return <TagIcon type={tag.type} strength={tag.strength} comment={tag.comment} size="sm" />
|
||||
}
|
||||
|
||||
@@ -1,76 +1,22 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex, Button } from '@theme-ui/components'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import FilterButton from '../../../components/atoms/FilterButton'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { listBattlesuits } from '../../../server/data/honkai3rd/battlesuits'
|
||||
import { BattlesuitData, battlesuitFeatures, battlesuitTypes, valkyries } from '../../../lib/honkai3rd/battlesuits'
|
||||
import BattlesuitCard from '../../../components/molecules/BattlesuitCard'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Box } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { translate, useTranslation } from '../../../lib/i18n'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
import { loadBattlesuitCatalog } from '../../../lib/v2/server/loadData'
|
||||
import { BattlesuitCatalogItem } from '../../../lib/v2/data/types'
|
||||
import BattlesuitCatalogItemCard from '../../../components/v2/BattlesuitCatalogItemCard'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
|
||||
type BattlesuitListItemData = Pick<BattlesuitData, 'id' | 'name' | 'features' | 'type' | 'valkyrie'>
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
|
||||
interface BattlesuitListPageProps {
|
||||
battlesuits: BattlesuitListItemData[]
|
||||
battlesuitCatalog: BattlesuitCatalogItem[]
|
||||
}
|
||||
|
||||
const featureFilterOptions: {
|
||||
value: string
|
||||
label: string
|
||||
icon?: string
|
||||
krLabel?: string
|
||||
}[] = [{ value: 'all', label: 'All', krLabel: '전체' }, ...battlesuitFeatures]
|
||||
|
||||
const valkyrieFilterOptions: {
|
||||
value: string
|
||||
label: string
|
||||
icon?: string
|
||||
krLabel?: string
|
||||
}[] = [{ value: 'all', label: 'All', krLabel: '전체' }, ...battlesuitTypes, ...valkyries]
|
||||
|
||||
const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
||||
const { query, locale } = useRouter()
|
||||
const BattlesuitListPage = ({ battlesuitCatalog }: BattlesuitListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [hiddenFilters, setHiddenFilters] = useState(true)
|
||||
|
||||
const closeFilters = useCallback(() => {
|
||||
setHiddenFilters(true)
|
||||
}, [])
|
||||
|
||||
const valkyrieFilter = useMemo(() => {
|
||||
if (query.valkyrie == null) {
|
||||
return 'all'
|
||||
}
|
||||
|
||||
return typeof query.valkyrie === 'string' ? query.valkyrie : query.valkyrie[0]
|
||||
}, [query])
|
||||
|
||||
const featureFilter = useMemo(() => {
|
||||
if (query.feature == null) {
|
||||
return 'all'
|
||||
}
|
||||
|
||||
return typeof query.feature === 'string' ? query.feature : query.feature[0]
|
||||
}, [query])
|
||||
|
||||
const battlesuitsFiteredByValkyrie = useMemo(() => {
|
||||
return battlesuits.filter(battlesuit => isValkyrieFilterMatching(battlesuit, valkyrieFilter))
|
||||
}, [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 (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
@@ -78,89 +24,26 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
||||
description={t('battlesuits-list.description')}
|
||||
canonicalHref={`/honkai3rd/battlesuits`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Box p={2}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/battlesuits',
|
||||
href: '/honkai3rd/v2/battlesuits',
|
||||
label: t('common.battlesuits')
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as="h1">{t('battlesuits-list.heading')}</Heading>
|
||||
|
||||
<Box sx={{ display: ['block', 'none'], mb: 2 }}>
|
||||
<Button
|
||||
className={hiddenFilters ? '' : 'active'}
|
||||
sx={{ px: 2, py: 1 }}
|
||||
onClick={() => {
|
||||
setHiddenFilters(previousValue => !previousValue)
|
||||
}}
|
||||
>
|
||||
{t('battlesuits-list.filters')}
|
||||
</Button>
|
||||
</Box>
|
||||
<Box
|
||||
className={hiddenFilters ? 'hidden' : ''}
|
||||
sx={{
|
||||
display: 'block',
|
||||
'&.hidden': {
|
||||
display: ['none', 'block']
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Heading as="h3">{t('battlesuits-list.filter-by-valkyries')}</Heading>
|
||||
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
|
||||
{valkyrieFilterOptions.map(({ value, label, icon, krLabel }) => {
|
||||
return (
|
||||
<FilterButton
|
||||
key={value}
|
||||
active={value === valkyrieFilter}
|
||||
href={`?valkyrie=${value}`}
|
||||
label={translate(locale, { 'ko-KR': krLabel }, label)}
|
||||
icon={icon}
|
||||
m={1}
|
||||
close={closeFilters}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
<Heading as="h3">{t('battlesuits-list.filter-by-features')}</Heading>
|
||||
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
|
||||
{featureFilterOptions
|
||||
.filter(filterOption => {
|
||||
if (filterOption.value === 'all') {
|
||||
return true
|
||||
}
|
||||
return availableFeatureSet.has(filterOption.value)
|
||||
})
|
||||
.map(({ value, label, icon, krLabel }) => {
|
||||
return (
|
||||
<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>
|
||||
</Box>
|
||||
|
||||
<Flex
|
||||
sx={{
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around'
|
||||
}}
|
||||
>
|
||||
{battlesuitsFilteredByFeature.map(battlesuit => {
|
||||
return <BattlesuitCard key={battlesuit.id} battlesuit={battlesuit} />
|
||||
<h1>{t('battlesuits-list.heading')}</h1>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{battlesuitCatalog.map(battlesuit => {
|
||||
return (
|
||||
<Box key={battlesuit.id}>
|
||||
<Link href={`/honkai3rd/v2/battlesuits/${battlesuit.id}`}>
|
||||
<BattlesuitCatalogItemCard battlesuit={battlesuit} />
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
@@ -171,67 +54,9 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
||||
export default BattlesuitListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const battlesuitCatalog = loadBattlesuitCatalog()
|
||||
|
||||
return {
|
||||
props: {
|
||||
battlesuits: listBattlesuits(locale).map(battlesuit => {
|
||||
return {
|
||||
id: battlesuit.id,
|
||||
name: battlesuit.name,
|
||||
features: battlesuit.features,
|
||||
type: battlesuit.type,
|
||||
valkyrie: battlesuit.valkyrie
|
||||
}
|
||||
}),
|
||||
...(await getI18NProps(locale))
|
||||
}
|
||||
props: { battlesuitCatalog, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
function isValkyrieFilterMatching(battlesuit: BattlesuitListItemData, valkyrieFilter: string) {
|
||||
switch (valkyrieFilter) {
|
||||
case 'mecha':
|
||||
case 'biologic':
|
||||
case 'psychic':
|
||||
case 'quantum':
|
||||
case 'imaginary':
|
||||
return battlesuit.type === valkyrieFilter
|
||||
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':
|
||||
case 'asuka':
|
||||
case 'pardofelis':
|
||||
case 'aponia':
|
||||
case 'eden':
|
||||
case 'griseo':
|
||||
case 'sushang':
|
||||
case 'ai':
|
||||
case 'susannah':
|
||||
case 'misteln':
|
||||
case 'prometheus':
|
||||
return battlesuit.valkyrie === valkyrieFilter
|
||||
default:
|
||||
case 'all':
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function isFeatureFilterMatching(battlesuit: BattlesuitListItemData, featureFilter: string) {
|
||||
if (featureFilter === 'all') {
|
||||
return true
|
||||
}
|
||||
return battlesuit.features.some(feature => feature === featureFilter)
|
||||
}
|
||||
|
||||
@@ -1,164 +1,117 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Flex,
|
||||
Heading,
|
||||
Paragraph,
|
||||
Image,
|
||||
} from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import React from 'react'
|
||||
import BattlesuitFeatureLabel from '../../../components/atoms/BattlesuitFeatureLabel'
|
||||
import SecondaryLabel from '../../../components/atoms/SecondaryLabel'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { ElfData } from '../../../lib/honkai3rd/elfs'
|
||||
import { getElfById, listElfs } from '../../../server/data/honkai3rd/elfs'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
||||
import { translate, useTranslation } from '../../../lib/i18n'
|
||||
import { useRouter } from 'next/router'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { battlesuitFeatures } from '../../../lib/honkai3rd/battlesuits'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import { useMemo } from 'react'
|
||||
import { Elf, ElfSkill } from '../../../lib/v2/data/types'
|
||||
import { loadElfCatalog, loadElfData } from '../../../lib/v2/server/loadData'
|
||||
import SquareImage from '../../../components/v2/SquareImage'
|
||||
import TagIcon from '../../../components/v2/TagIcon'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { ListMap } from '../../../lib/utils'
|
||||
import FormattedText from '../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo } from '../../../lib/v2/data/formatText'
|
||||
|
||||
interface ElfShowPageProps {
|
||||
elf: ElfData
|
||||
elf: Elf
|
||||
}
|
||||
|
||||
const ElfShowPage = ({ elf }: ElfShowPageProps) => {
|
||||
const { locale } = useRouter()
|
||||
const { t } = useTranslation()
|
||||
const skillRows = useMemo(() => {
|
||||
const rowSkillListMap = elf.skills.reduce<ListMap<string, ElfSkill>>((map, skill) => {
|
||||
map.set(skill.row.toString(), skill)
|
||||
return map
|
||||
}, new ListMap())
|
||||
|
||||
return [...rowSkillListMap.values()]
|
||||
}, [elf.skills])
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.honkai-3rd')}: ${elf.name} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
description={`${t('common.honkai-3rd')} ${t(
|
||||
'elfs-show.elf'
|
||||
)} / ${'⭐'.repeat(elf.baseRank)} / ${elf.features
|
||||
.map((feature) => {
|
||||
const featureData = battlesuitFeatures.find(
|
||||
(aFeature) => aFeature.value === feature
|
||||
)
|
||||
if (featureData == null) {
|
||||
return feature
|
||||
}
|
||||
|
||||
const { label, krLabel } = featureData
|
||||
|
||||
return translate(locale, { 'ko-KR': krLabel }, label)
|
||||
})
|
||||
.join(', ')}`}
|
||||
canonicalHref={`/honkai3rd/elfs/${elf.id}`}
|
||||
<Box>
|
||||
<Heading as="h1">{elf.fullName}</Heading>
|
||||
<SquareImage
|
||||
src={`${assetsBucketBaseUrl}/raw/elfcardfigures/${elf.figureImage}.png`}
|
||||
originalSize={720}
|
||||
size={480}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/elfs', label: t('common.elfs') },
|
||||
{
|
||||
href: `/honkai3rd/elfs/${elf.id}`,
|
||||
label: elf.name,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as='h1'>{elf.name}</Heading>
|
||||
|
||||
<Box mb={3}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
width: [300, 400],
|
||||
height: [300, 400],
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
alt={elf.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/elfs/${elf.id}.png`}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Card mb={3}>
|
||||
<Box sx={{ p: 2, borderBottom: 'default' }}>
|
||||
{'⭐'.repeat(elf.baseRank)}
|
||||
</Box>
|
||||
<Flex p={2}>
|
||||
{elf.features.map((feature) => (
|
||||
<Box key={feature} mr={2}>
|
||||
<BattlesuitFeatureLabel feature={feature} />
|
||||
</Box>
|
||||
))}
|
||||
<Card mb={3}>
|
||||
<Box sx={{ p: 1, borderBottom: 'default' }}>
|
||||
<Flex>
|
||||
{elf.tags.map(tag => {
|
||||
return (
|
||||
<Box key={tag.type} mr={1}>
|
||||
<TagIcon type={tag.type} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Card>
|
||||
</Box>
|
||||
<Box p={1}>
|
||||
Ult CD: {elf.ultSkillCd} / Ult SP Cost: {elf.ultSkillCost}
|
||||
</Box>
|
||||
</Card>
|
||||
|
||||
{elf.skillRows.map((row, rowIndex) => {
|
||||
return (
|
||||
<Card key={rowIndex} mb={3}>
|
||||
{row.map((item, columnIndex) => {
|
||||
return (
|
||||
<React.Fragment key={columnIndex}>
|
||||
<Box sx={{ p: 2, borderBottom: 'default' }}>
|
||||
<Heading
|
||||
as={columnIndex === 0 ? 'h2' : 'h3'}
|
||||
sx={{ mb: 1 }}
|
||||
>
|
||||
{item.name}
|
||||
<Heading as="h2">Skills</Heading>
|
||||
|
||||
{skillRows.map((row, index) => {
|
||||
return (
|
||||
<Card key={index} mb={2}>
|
||||
{row.map(skill => {
|
||||
return (
|
||||
<Box
|
||||
key={skill.id}
|
||||
sx={{
|
||||
borderBottom: 'default',
|
||||
'&:last-child': {
|
||||
borderBottom: 'none'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<Box sx={{ flexShrink: 0 }}>
|
||||
<SquareImage
|
||||
src={`${assetsBucketBaseUrl}/raw/elf_skill_icon/${skill.icon}.png`}
|
||||
originalSize={40}
|
||||
/>
|
||||
</Box>
|
||||
<Heading as={'h3'} sx={{ my: 0, ml: 1 }}>
|
||||
<FormattedText>{skill.name}</FormattedText>
|
||||
</Heading>
|
||||
<SecondaryLabel>
|
||||
{t(`elfs-show.${item.type}`)}{' '}
|
||||
{'⭐'.repeat(item.requiredRank)}
|
||||
</SecondaryLabel>
|
||||
</Box>
|
||||
<Paragraph
|
||||
sx={{
|
||||
p: 2,
|
||||
borderBottom: 'default',
|
||||
'&:last-child': { borderBottom: 'none' },
|
||||
whiteSpace: 'pre-wrap',
|
||||
}}
|
||||
>
|
||||
{item.description}
|
||||
</Paragraph>
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
{/* {skill.id} */}
|
||||
<Box sx={{ color: 'textMuted', ml: 1 }}>({skill.skillType})</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box sx={{ p: 1 }}>
|
||||
<FormattedText>{formatSubSkillInfo(skill)}</FormattedText>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElfShowPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { elfId: string } }) {
|
||||
const elf = getElfById(params.elfId, locale)
|
||||
export async function getStaticProps({ locale, params }: NextPageContext & { params: { elfId: string } }) {
|
||||
const elf = loadElfData(params.elfId)
|
||||
|
||||
return {
|
||||
props: { elf, ...(await getI18NProps(locale)) },
|
||||
props: { elf }
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const elfCatalog = loadElfCatalog()
|
||||
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
listElfs().map((elf) => {
|
||||
return {
|
||||
params: { elfId: elf.id },
|
||||
}
|
||||
})
|
||||
),
|
||||
fallback: false,
|
||||
paths: elfCatalog.map(catalogItem => {
|
||||
return {
|
||||
params: { elfId: catalogItem.id }
|
||||
}
|
||||
}),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +1,61 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex } from '@theme-ui/components'
|
||||
import { Box, Card } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { pick } from 'ramda'
|
||||
import ElfCard from '../../../components/molecules/ElfCard'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { ElfData } from '../../../lib/honkai3rd/elfs'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { listElfs } from '../../../server/data/honkai3rd/elfs'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
import { ElfCatalogItem } from '../../../lib/v2/data/types'
|
||||
import { loadElfCatalog } from '../../../lib/v2/server/loadData'
|
||||
import RarityBar from '../../../components/v2/RarityBar'
|
||||
import ElfIcon from '../../../components/v2/ElfIcon'
|
||||
|
||||
interface ElfListPageProps {
|
||||
elfs: Pick<ElfData, 'id' | 'name'>[]
|
||||
elfs: ElfCatalogItem[]
|
||||
}
|
||||
|
||||
const ElfListPage = ({ elfs }: ElfListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.elfs')} - ${t('common.honkai-3rd')} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
description={t('elfs-list.description')}
|
||||
canonicalHref={`/honkai3rd/elfs`}
|
||||
/>
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/elfs', label: t('common.elfs') },
|
||||
]}
|
||||
/>
|
||||
<Box>
|
||||
<h1>Elfs</h1>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{elfs
|
||||
.sort((a, b) => {
|
||||
const aId = getId(a.id)
|
||||
const bId = getId(b.id)
|
||||
return bId - aId
|
||||
|
||||
<Heading as='h1'>{t('elfs-list.elfs')}</Heading>
|
||||
|
||||
<Flex
|
||||
sx={{
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around',
|
||||
}}
|
||||
>
|
||||
{elfs.map((elf) => {
|
||||
return <ElfCard key={elf.id} elf={elf} />
|
||||
function getId(id: string): number {
|
||||
return parseInt(id)
|
||||
}
|
||||
})
|
||||
.map(elf => {
|
||||
return (
|
||||
<Box key={elf.id} m={2}>
|
||||
<Link href={`/v2-pre/elfs/${elf.id}`}>
|
||||
<Card p={1}>
|
||||
<Box>
|
||||
<ElfIcon icon={elf.cardIcon} />
|
||||
<RarityBar rarity={elf.rarity} />
|
||||
</Box>
|
||||
<Box
|
||||
sx={{ textAlign: 'center', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{elf.fullName}
|
||||
</Box>
|
||||
</Card>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElfListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const elfs = loadElfCatalog()
|
||||
|
||||
return {
|
||||
props: {
|
||||
elfs: listElfs(locale).map((elf) => pick(['id', 'name', 'krName'], elf)),
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
props: { elfs }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Image } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import { BattlesuitData } from '../../../../lib/honkai3rd/battlesuits'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../../server/i18n'
|
||||
import { getBattlesuitById } from '../../../../server/data/honkai3rd/battlesuits'
|
||||
import { useTranslation } from '../../../../lib/i18n'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import { WeaponData } from '../../../../lib/honkai3rd/weapons'
|
||||
import { getWeaponMapByIds } from '../../../../server/data/honkai3rd/weapons'
|
||||
import { StigmataData } from '../../../../lib/honkai3rd/stigmata'
|
||||
import { getStigmataMapByIds } from '../../../../server/data/honkai3rd/stigmata'
|
||||
import { getSignetGroupById } from '../../../../server/data/honkai3rd/elysianRealm'
|
||||
import { erBattlesuits, SignetSet } from '../../../../lib/honkai3rd/elysianRealm'
|
||||
import SignetCard from '../../../../components/molecules/SignetCard'
|
||||
|
||||
type WeaponObjectMap = { [key: string]: WeaponData }
|
||||
type StigmataObjectMap = { [key: string]: StigmataData }
|
||||
|
||||
interface BattlesuitShowPageProps {
|
||||
battlesuit: BattlesuitData
|
||||
weaponMap: WeaponObjectMap
|
||||
stigmataMap: StigmataObjectMap
|
||||
signetSet: SignetSet
|
||||
}
|
||||
|
||||
const BattlesuitShowPage = ({ battlesuit, weaponMap, stigmataMap, signetSet }: BattlesuitShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${battlesuit.name} (${t('common.elysian-realm')}) - ${t('common.honkai-3rd')} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
description={`${t('common.honkai-3rd')} ${t('common.elysian-realm')} ${t('battlesuit-show.battlesuit')}`}
|
||||
canonicalHref={`/honkai3rd/elysian-realm/battlesuits/${battlesuit.id}`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm',
|
||||
label: t('common.elysian-realm')
|
||||
},
|
||||
{
|
||||
href: `/honkai3rd/elysian-realm/battlesuits/${battlesuit.id}`,
|
||||
label: battlesuit.name
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as="h1">{battlesuit.name}</Heading>
|
||||
|
||||
<Box mb={3}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
maxWidth: [300, 400]
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
alt={battlesuit.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/battlesuits/${battlesuit.id}.png`}
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Heading as="h2">{t('elysian-realm.exclusive-signets')}</Heading>
|
||||
|
||||
<Box>
|
||||
{signetSet.signets.map(signet => {
|
||||
return <SignetCard key={signet.id} signet={signet} />
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default BattlesuitShowPage
|
||||
|
||||
export async function getStaticProps({ params, locale }: NextPageContext & { params: { battlesuitId: string } }) {
|
||||
try {
|
||||
const battlesuit = getBattlesuitById(params.battlesuitId, locale)!
|
||||
const { weaponIds, stigmataIds } = (battlesuit.equipment || []).reduce<{
|
||||
weaponIds: string[]
|
||||
stigmataIds: string[]
|
||||
}>(
|
||||
(acc, equipmentItem) => {
|
||||
acc.weaponIds.push(equipmentItem.weapon)
|
||||
acc.stigmataIds.push(equipmentItem.stigmataTop, equipmentItem.stigmataMid, equipmentItem.stigmataBot)
|
||||
return acc
|
||||
},
|
||||
{ weaponIds: [], stigmataIds: [] }
|
||||
)
|
||||
const weaponMap = getWeaponMapByIds(weaponIds)
|
||||
|
||||
const stigmataMap = getStigmataMapByIds(stigmataIds)
|
||||
|
||||
const signetGroup = getSignetGroupById('elysia', locale)
|
||||
const signetSet = signetGroup.sets.find(set => {
|
||||
return set.id === `elysia-${params.battlesuitId}`
|
||||
})
|
||||
|
||||
return {
|
||||
props: {
|
||||
battlesuit,
|
||||
weaponMap,
|
||||
stigmataMap,
|
||||
signetSet,
|
||||
...(await getI18NProps(locale))
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
erBattlesuits.map(battlesuitId => {
|
||||
return {
|
||||
params: { battlesuitId: battlesuitId }
|
||||
}
|
||||
})
|
||||
),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex, Card, Text } from '@theme-ui/components'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { getBattlesuitMapByIds } from '../../../server/data/honkai3rd/battlesuits'
|
||||
import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
|
||||
import BattlesuitCard from '../../../components/molecules/BattlesuitCard'
|
||||
import { NextPageContext } from 'next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { erVersions } from '../../../lib/honkai3rd/elysianRealm'
|
||||
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import PageLink from '../../../components/atoms/PageLink'
|
||||
import SignetGroupNavigator from '../../../components/organisms/SignetGroupNavigator'
|
||||
import {
|
||||
getRemembranceSigils as getRemembranceSigils,
|
||||
getSupportBattlesuits,
|
||||
} from '../../../server/data/honkai3rd/elysianRealm'
|
||||
import Link from 'next/link'
|
||||
|
||||
type BattlesuitListItemData = Pick<
|
||||
BattlesuitData,
|
||||
'id' | 'name' | 'features' | 'type' | 'valkyrie'
|
||||
>
|
||||
|
||||
interface BattlesuitListPageProps {
|
||||
battlesuitMap: { [id: string]: BattlesuitListItemData }
|
||||
supportBattlesuits: { id: string; name: string }[]
|
||||
remembranceSigils: { id: string; name: string }[]
|
||||
}
|
||||
|
||||
const ElysianRealmIndexPage = ({
|
||||
battlesuitMap,
|
||||
supportBattlesuits,
|
||||
remembranceSigils,
|
||||
}: BattlesuitListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.elysian-realm')} - ${t('common.honkai-3rd')} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
description={t('common.elysian-realm')}
|
||||
canonicalHref={`/honkai3rd/elysian-realm`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm',
|
||||
label: t('common.elysian-realm'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as='h1'>{t('common.elysian-realm')}</Heading>
|
||||
|
||||
<Heading as='h2'>{t('common.battlesuits')}</Heading>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
{erVersions.map((erVersion) => {
|
||||
return (
|
||||
<Box key={erVersion.version} sx={{ mb: 2 }}>
|
||||
<Heading as='h3' m={0}>
|
||||
{erVersion.version}
|
||||
</Heading>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{erVersion.battlesuits.map((battlesuitId) => {
|
||||
return (
|
||||
<Box
|
||||
key={battlesuitId}
|
||||
sx={{ width: [135, 135, 200], m: 1 }}
|
||||
>
|
||||
<BattlesuitCard
|
||||
m={0}
|
||||
battlesuit={battlesuitMap[battlesuitId]}
|
||||
size={'sm'}
|
||||
href={`/honkai3rd/elysian-realm/battlesuits/${battlesuitId}`}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Heading as='h2'>{t('elysian-realm.signets')}</Heading>
|
||||
|
||||
<SignetGroupNavigator />
|
||||
</Box>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Heading as='h2'>{t('elysian-realm.supports')}</Heading>
|
||||
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{supportBattlesuits.map((battlesuit) => {
|
||||
return (
|
||||
<Box key={battlesuit.id} sx={{ width: [135, 135, 200], m: 1 }}>
|
||||
<BattlesuitCard
|
||||
m={0}
|
||||
battlesuit={battlesuit}
|
||||
size={'sm'}
|
||||
href={`/honkai3rd/elysian-realm/support-battlesuits#${battlesuit.id}`}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Heading as='h2'>{t('elysian-realm.remembrance-sigil')}</Heading>
|
||||
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{remembranceSigils.map(({ id, name }) => {
|
||||
return (
|
||||
<Card
|
||||
key={id}
|
||||
sx={{ p: 1, m: 1, width: [135, 135, 200] }}
|
||||
title={name}
|
||||
>
|
||||
<PageLink
|
||||
href={`/honkai3rd/elysian-realm/remembrance-sigils#${id}`}
|
||||
>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<SquareImageBox
|
||||
size={30}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/elysian-realm/remembrance-sigils/${id}.png`}
|
||||
/>
|
||||
<Text
|
||||
sx={{
|
||||
ml: 2,
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
</Flex>
|
||||
</PageLink>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href='/honkai3rd/elysian-realm/utils/gen-guide'>
|
||||
Guide Generator (KR Only)
|
||||
</Link>
|
||||
</Box>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElysianRealmIndexPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const erBattlesuitIds = erVersions.reduce<string[]>((list, version) => {
|
||||
list.push(...version.battlesuits)
|
||||
return list
|
||||
}, [])
|
||||
|
||||
const supportBattlesuits = getSupportBattlesuits(locale).map(
|
||||
({ id, name }) => {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const remembranceSigils = getRemembranceSigils(locale).map(({ id, name }) => {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
props: {
|
||||
battlesuitMap: getBattlesuitMapByIds(erBattlesuitIds, locale),
|
||||
supportBattlesuits,
|
||||
remembranceSigils,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex, Card, Paragraph } from '@theme-ui/components'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
import { NextPageContext } from 'next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { RemembranceSigil } from '../../../lib/honkai3rd/elysianRealm'
|
||||
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import { getRemembranceSigils } from '../../../server/data/honkai3rd/elysianRealm'
|
||||
|
||||
interface BattlesuitListPageProps {
|
||||
remembranceSigils: RemembranceSigil[]
|
||||
}
|
||||
|
||||
const ElysianRealmIndexPage = ({
|
||||
remembranceSigils,
|
||||
}: BattlesuitListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('elysian-realm.remembrance-sigil')} (${t(
|
||||
'common.elysian-realm'
|
||||
)}) - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.elysian-realm')} ${t(
|
||||
'elysian-realm.supports'
|
||||
)}`}
|
||||
canonicalHref={`/honkai3rd/elysian-realm/remembrance-sigils`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm',
|
||||
label: t('common.elysian-realm'),
|
||||
},
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm/remembrance-sigils',
|
||||
label: t('elysian-realm.remembrance-sigil'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as='h1' mb={3}>
|
||||
{t('elysian-realm.remembrance-sigil')}
|
||||
</Heading>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
{remembranceSigils.map(({ id, name, description }) => {
|
||||
return (
|
||||
<Card key={id} sx={{ p: 2, mb: 2 }} id={id}>
|
||||
<Flex>
|
||||
<SquareImageBox
|
||||
size={50}
|
||||
alt={name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/elysian-realm/remembrance-sigils/${id}.png`}
|
||||
mr={2}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Heading as='h3' mb={2}>
|
||||
{name}
|
||||
</Heading>
|
||||
<Paragraph sx={{ whiteSpace: 'pre-wrap' }}>
|
||||
{description}
|
||||
</Paragraph>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElysianRealmIndexPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const remembranceSigils = getRemembranceSigils(locale)
|
||||
|
||||
return {
|
||||
props: {
|
||||
remembranceSigils,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex, Text } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
|
||||
import { generateI18NPaths, getI18NProps } from '../../../../server/i18n'
|
||||
import { useTranslation } from '../../../../lib/i18n'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import {
|
||||
PopulatedSignetGroup,
|
||||
signetGroups,
|
||||
} from '../../../../lib/honkai3rd/elysianRealm'
|
||||
import { getSignetGroupById } from '../../../../server/data/honkai3rd/elysianRealm'
|
||||
import SignetCard from '../../../../components/molecules/SignetCard'
|
||||
import SignetGroupNavigator from '../../../../components/organisms/SignetGroupNavigator'
|
||||
import SquareImageBox from '../../../../components/atoms/SquareImageBox'
|
||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||
import PageLink from '../../../../components/atoms/PageLink'
|
||||
|
||||
interface SignetShowPageProps {
|
||||
signetId: string
|
||||
signetGroup: PopulatedSignetGroup
|
||||
}
|
||||
|
||||
const SignetShowPage = ({ signetId, signetGroup }: SignetShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${signetGroup.name} ${t('elysian-realm.signets')} (${t(
|
||||
'common.elysian-realm'
|
||||
)}) - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${signetGroup.name} ${t(
|
||||
'elysian-realm.signets'
|
||||
)}`}
|
||||
canonicalHref={`/honkai3rd/elysian-realm/signets/${signetId}`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm',
|
||||
label: t('common.elysian-realm'),
|
||||
},
|
||||
{
|
||||
href: `/honkai3rd/elysian-realm/signets/${signetId}`,
|
||||
label: signetGroup.name,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<SignetGroupNavigator />
|
||||
</Box>
|
||||
<Heading as='h1' sx={{ mb: 4, display: 'flex', alignItems: 'center' }}>
|
||||
<SquareImageBox
|
||||
mr={2}
|
||||
size={40}
|
||||
alt={signetGroup.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/elysian-realm/signets/${signetGroup.id}.png`}
|
||||
/>{' '}
|
||||
{signetGroup.altName}({signetGroup.name}) {t('elysian-realm.signets')}
|
||||
</Heading>
|
||||
|
||||
{signetGroup.sets.map((set) => {
|
||||
const signetType = set.id.split('-')[1]
|
||||
return (
|
||||
<Box key={set.id} sx={{ mb: 4 }}>
|
||||
<Heading as='h2' sx={{ mb: 3 }}>
|
||||
{signetGroup.id === 'elysia' ? (
|
||||
<PageLink
|
||||
href={`/honkai3rd/elysian-realm/battlesuits/${signetType}`}
|
||||
>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<SquareImageBox
|
||||
size={30}
|
||||
mr={2}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/battlesuits/portrait-${signetType}.png`}
|
||||
/>
|
||||
<Text>{set.name}</Text>
|
||||
</Flex>
|
||||
</PageLink>
|
||||
) : (
|
||||
set.name
|
||||
)}
|
||||
</Heading>
|
||||
<Box>
|
||||
{set.signets.map((signet) => {
|
||||
return <SignetCard key={signet.id} signet={signet} />
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default SignetShowPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { signetId: string } }) {
|
||||
const { signetId } = params
|
||||
|
||||
return {
|
||||
props: {
|
||||
signetId,
|
||||
signetGroup: getSignetGroupById(signetId, locale),
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
signetGroups.map((signet) => {
|
||||
return {
|
||||
params: { signetId: signet.id },
|
||||
}
|
||||
})
|
||||
),
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import {
|
||||
Box,
|
||||
Heading,
|
||||
Flex,
|
||||
Card,
|
||||
Paragraph,
|
||||
Badge,
|
||||
} from '@theme-ui/components'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
import { NextPageContext } from 'next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { SupportBattlesuit } from '../../../lib/honkai3rd/elysianRealm'
|
||||
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import { getSupportBattlesuits } from '../../../server/data/honkai3rd/elysianRealm'
|
||||
|
||||
interface BattlesuitListPageProps {
|
||||
supportBattlesuits: SupportBattlesuit[]
|
||||
}
|
||||
|
||||
const ElysianRealmIndexPage = ({
|
||||
supportBattlesuits,
|
||||
}: BattlesuitListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('elysian-realm.supports')} (${t(
|
||||
'common.elysian-realm'
|
||||
)}) - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.elysian-realm')} ${t(
|
||||
'elysian-realm.supports'
|
||||
)}`}
|
||||
canonicalHref={`/honkai3rd/elysian-realm/support-battlesuits`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm',
|
||||
label: t('common.elysian-realm'),
|
||||
},
|
||||
{
|
||||
href: '/honkai3rd/elysian-realm/support-battlesuits',
|
||||
label: t('elysian-realm.supports'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as='h1' mb={3}>
|
||||
{t('elysian-realm.supports')}
|
||||
</Heading>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
{supportBattlesuits.map(
|
||||
({ id, name, skillName, description, cooldown }) => {
|
||||
return (
|
||||
<Card key={id} sx={{ p: 2, mb: 2 }} id={id}>
|
||||
<Flex>
|
||||
<SquareImageBox
|
||||
size={50}
|
||||
alt={name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/battlesuits/portrait-${id}.png`}
|
||||
mr={2}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Heading as='h3' mb={0}>
|
||||
{name} - {skillName}
|
||||
</Heading>
|
||||
<Badge variant='secondary'>Cooldown: {cooldown}s</Badge>
|
||||
<Paragraph sx={{ whiteSpace: 'pre-wrap' }}>
|
||||
{description}
|
||||
</Paragraph>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElysianRealmIndexPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const supportBattlesuits = getSupportBattlesuits(locale)
|
||||
|
||||
return {
|
||||
props: {
|
||||
supportBattlesuits,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/* eslint-disable @next/next/no-page-custom-font */
|
||||
import { NextPageContext } from 'next'
|
||||
import { useRouter } from 'next/router'
|
||||
import { pick } from 'ramda'
|
||||
import { Box, Button, Flex, Heading } from 'theme-ui'
|
||||
import ERGuideGenerator from '../../../../components/organisms/ERGuideGenerator/ERGuideGenerator'
|
||||
import { BattlesuitData } from '../../../../lib/honkai3rd/battlesuits'
|
||||
import {
|
||||
PopulatedSignetGroup,
|
||||
RemembranceSigil,
|
||||
} from '../../../../lib/honkai3rd/elysianRealm'
|
||||
import { WeaponData } from '../../../../lib/honkai3rd/weapons'
|
||||
import { StigmataData } from '../../../../lib/honkai3rd/stigmata'
|
||||
import { listBattlesuits } from '../../../../server/data/honkai3rd/battlesuits'
|
||||
import {
|
||||
getRemembranceSigils,
|
||||
getSignetGroupById,
|
||||
} from '../../../../server/data/honkai3rd/elysianRealm'
|
||||
import { listStigmata } from '../../../../server/data/honkai3rd/stigmata'
|
||||
import { listWeapons } from '../../../../server/data/honkai3rd/weapons'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
interface GenerateGuidePageProps {
|
||||
weapons: WeaponData[]
|
||||
stigmata: StigmataData[]
|
||||
battlesuits: BattlesuitData[]
|
||||
exSignetGroup: PopulatedSignetGroup
|
||||
sigils: RemembranceSigil[]
|
||||
}
|
||||
|
||||
const GenerateGuidePage = ({
|
||||
weapons,
|
||||
stigmata,
|
||||
battlesuits,
|
||||
exSignetGroup,
|
||||
sigils,
|
||||
}: GenerateGuidePageProps) => {
|
||||
const router = useRouter()
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Head
|
||||
title={`ER Guide Generator- ${t('common.honkai-3rd')} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
canonicalHref={`/honkai3rd/elysian-realm/utils/gen-guide`}
|
||||
/>
|
||||
<Flex m={2} sx={{ alignItems: 'center' }}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
router.push('/honkai3rd')
|
||||
}}
|
||||
mr={2}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Heading>ER Guide Generator</Heading>
|
||||
</Flex>
|
||||
<ERGuideGenerator
|
||||
weapons={weapons}
|
||||
stigmata={stigmata}
|
||||
battlesuits={battlesuits}
|
||||
exSignetGroup={exSignetGroup}
|
||||
sigils={sigils}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default GenerateGuidePage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
return {
|
||||
props: {
|
||||
weapons: listWeapons('ko-KR').map((weapon) => {
|
||||
return pick(['name', 'id', 'rarity', 'category'], weapon)
|
||||
}),
|
||||
stigmata: listStigmata('ko-KR').map((stigmata) => {
|
||||
return pick(['name', 'id', 'type'], stigmata)
|
||||
}),
|
||||
battlesuits: listBattlesuits('ko-KR').map((battlesuit) => {
|
||||
return {
|
||||
id: battlesuit.id,
|
||||
name: battlesuit.name,
|
||||
type: battlesuit.type,
|
||||
valkyrie: battlesuit.valkyrie,
|
||||
}
|
||||
}),
|
||||
exSignetGroup: getSignetGroupById('elysia', 'ko-KR'),
|
||||
sigils: getRemembranceSigils('ko-KR'),
|
||||
...(await getI18NProps('ko-KR')),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading } from '@theme-ui/components'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { NextPageContext } from 'next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { times } from 'ramda'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
|
||||
const enemyIdList = [
|
||||
...times((i) => i + 0, 1000).map((i) => {
|
||||
const stringified = i.toString()
|
||||
return `BOSS_${'0'.repeat(3 - stringified.length) + stringified}`
|
||||
}),
|
||||
// ...times((i) => i + 65, 26)
|
||||
// .reduce<[number, number][]>((array, first) => {
|
||||
// array.push(
|
||||
// ...times((i) => i + 65, 26).map<[number, number]>((second) => [
|
||||
// first,
|
||||
// second,
|
||||
// ])
|
||||
// )
|
||||
// return array
|
||||
// }, [])
|
||||
// .map(([first, second]) => {
|
||||
// return String.fromCharCode(first) + String.fromCharCode(second)
|
||||
// })
|
||||
// .reduce<string[]>((idList, prefix) => {
|
||||
// idList.push(
|
||||
// ...times((i) => i + 12, 1).map((i) => {
|
||||
// const stringified = i.toString()
|
||||
// return `${prefix}_${'0'.repeat(3 - stringified.length) + stringified}`
|
||||
// })
|
||||
// )
|
||||
// return idList
|
||||
// }, []),
|
||||
]
|
||||
|
||||
// console.log(
|
||||
// times((i) => i + 65, 26)
|
||||
// .reduce<[number, number][]>((array, first) => {
|
||||
// array.push(
|
||||
// ...times((i) => i + 65, 26).map<[number, number]>((second) => [
|
||||
// first,
|
||||
// second,
|
||||
// ])
|
||||
// )
|
||||
// return array
|
||||
// }, [])
|
||||
// .map(([first, second]) => {
|
||||
// return String.fromCharCode(first) + String.fromCharCode(second)
|
||||
// })
|
||||
// .reduce<string[]>((idList, prefix) => {
|
||||
// idList.push(
|
||||
// ...times((i) => i + 10, 1).map((i) => {
|
||||
// const stringified = i.toString()
|
||||
// return `${prefix}_${'0'.repeat(3 - stringified.length) + stringified}`
|
||||
// })
|
||||
// )
|
||||
// return idList
|
||||
// }, [])
|
||||
// )
|
||||
|
||||
// console.log(
|
||||
// times(i => i + 65, 26).map(code => {
|
||||
// return [...times((i) => i + 10, 10).map((i) => {
|
||||
// const stringified = i.toString()
|
||||
// return `_${'0'.repeat(3 - stringified.length) + stringified}`
|
||||
// })]
|
||||
// })
|
||||
// )
|
||||
|
||||
const Honkai3rdIndexPage = () => {
|
||||
const { t } = useTranslation()
|
||||
const [validList, setValidList] = useState<string[]>([])
|
||||
const validMap = useMemo(() => {
|
||||
return new Map(validList.map((id) => [id, id]))
|
||||
}, [validList])
|
||||
const initializedRef = useRef(false)
|
||||
|
||||
const appendValidList = useCallback((enemyId: string) => {
|
||||
setValidList((previousList) => {
|
||||
return [...previousList, enemyId]
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let data = validList
|
||||
if (!initializedRef.current) {
|
||||
initializedRef.current = true
|
||||
let rawValidEnemyIdList = localStorage.getItem('valid-enemy-id-list')
|
||||
try {
|
||||
console.log('load')
|
||||
data = JSON.parse(rawValidEnemyIdList || '[]')
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error('data must be array')
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
data = []
|
||||
}
|
||||
setValidList(data)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('save')
|
||||
localStorage.setItem('valid-enemy-id-list', JSON.stringify(data))
|
||||
}, [validList])
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`Enemies - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={t('index.description')}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[{ href: 'honkai3rd', label: t('common.honkai-3rd') }]}
|
||||
/>
|
||||
<Heading as='h1'>Enemies </Heading>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
{enemyIdList
|
||||
.filter((enemyId) => !validMap.get(enemyId))
|
||||
.map((enemyId) => {
|
||||
return (
|
||||
<Box key={enemyId}>
|
||||
<img
|
||||
alt={enemyId}
|
||||
src={`https://upload-os-bbs.mihoyo.com/game_record/honkai3rd/global/SpriteOutput/OpenWorld/QuestBossIcon/${enemyId}.png`}
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
appendValidList(enemyId)
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
<h2>Valid</h2>
|
||||
<Box>
|
||||
{validList.map((enemyId) => {
|
||||
return (
|
||||
<Box key={enemyId}>
|
||||
<img
|
||||
alt={enemyId}
|
||||
src={`https://upload-os-bbs.mihoyo.com/game_record/honkai3rd/global/SpriteOutput/OpenWorld/QuestBossIcon/${enemyId}.png`}
|
||||
/>
|
||||
{enemyId}
|
||||
<button
|
||||
onClick={() => {
|
||||
appendValidList(enemyId)
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
return {
|
||||
props: {
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default Honkai3rdIndexPage
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading, Image, Link } from 'theme-ui'
|
||||
import AvatarFigureImage from '../../../../../components/v2/AvatarFigureImage'
|
||||
import { loadBattlesuitData, loadErBattlesuit, loadErBattlesuitCatalog } from '../../../../../lib/v2/server/loadData'
|
||||
import { Battlesuit, ErBattlesuit, ErSignet } from '../../../../../lib/v2/data/types'
|
||||
import AvatarFigureImage from '../../../../components/v2/AvatarFigureImage'
|
||||
import { loadBattlesuitData, loadErBattlesuit, loadErBattlesuitCatalog } from '../../../../lib/v2/server/loadData'
|
||||
import { Battlesuit, ErBattlesuit, ErSignet } from '../../../../lib/v2/data/types'
|
||||
import { Fragment, useMemo } from 'react'
|
||||
import { assetsBucketBaseUrl } from '../../../../../lib/consts'
|
||||
import BattlesuitCatalogItemCard from '../../../../../components/v2/BattlesuitCatalogItemCard'
|
||||
import Honkai3rdLayout from '../../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../../components/atoms/Head'
|
||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||
import BattlesuitCatalogItemCard from '../../../../components/v2/BattlesuitCatalogItemCard'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Breadcrumb from '../../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../../../server/i18n'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
|
||||
interface BattlesuitShowPageProps {
|
||||
battlesuit: Battlesuit
|
||||
@@ -6,20 +6,20 @@ import {
|
||||
loadErBattlesuitCatalog,
|
||||
loadErSigils,
|
||||
loadErSupports
|
||||
} from '../../../../lib/v2/server/loadData'
|
||||
import { BattlesuitCatalogItem, ErBattlesuitCatalogItem } from '../../../../lib/v2/data/types'
|
||||
} from '../../../lib/v2/server/loadData'
|
||||
import { BattlesuitCatalogItem, ErBattlesuitCatalogItem } from '../../../lib/v2/data/types'
|
||||
import { useMemo } from 'react'
|
||||
import BattlesuitCatalogItemCard from '../../../../components/v2/BattlesuitCatalogItemCard'
|
||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||
import SquareImage from '../../../../components/v2/SquareImage'
|
||||
import { signetGroups } from '../../../../lib/v2/data/er'
|
||||
import BattlesuitSmallIcon from '../../../../components/v2/BattlesuitSmallIcon'
|
||||
import MaterialIcon from '../../../../components/v2/MaterialIcon'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import BattlesuitCatalogItemCard from '../../../components/v2/BattlesuitCatalogItemCard'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import SquareImage from '../../../components/v2/SquareImage'
|
||||
import { signetGroups } from '../../../lib/v2/data/er'
|
||||
import BattlesuitSmallIcon from '../../../components/v2/BattlesuitSmallIcon'
|
||||
import MaterialIcon from '../../../components/v2/MaterialIcon'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
|
||||
interface ErPageProps {
|
||||
erBattlesuitCatalog: ErBattlesuitCatalogItem[]
|
||||
@@ -1,13 +1,13 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import MaterialIcon from '../../../../components/v2/MaterialIcon'
|
||||
import { ErSigil } from '../../../../lib/v2/data/types'
|
||||
import { loadErSigils } from '../../../../lib/v2/server/loadData'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import MaterialIcon from '../../../components/v2/MaterialIcon'
|
||||
import { ErSigil } from '../../../lib/v2/data/types'
|
||||
import { loadErSigils } from '../../../lib/v2/server/loadData'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
|
||||
interface SigilsPageProps {
|
||||
erSigils: ErSigil[]
|
||||
+10
-10
@@ -1,17 +1,17 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import { loadErSignets } from '../../../../../lib/v2/server/loadData'
|
||||
import { ErSignet, ErSignetGroup } from '../../../../../lib/v2/data/types'
|
||||
import { loadErSignets } from '../../../../lib/v2/server/loadData'
|
||||
import { ErSignet, ErSignetGroup } from '../../../../lib/v2/data/types'
|
||||
import { Fragment, useMemo } from 'react'
|
||||
import { assetsBucketBaseUrl } from '../../../../../lib/consts'
|
||||
import { signetGroups } from '../../../../../lib/v2/data/er'
|
||||
import SquareImage from '../../../../../components/v2/SquareImage'
|
||||
import { getErSignetTypeLabel } from '../../../../../lib/v2/data/text'
|
||||
import Honkai3rdLayout from '../../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../../components/atoms/Head'
|
||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||
import { signetGroups } from '../../../../lib/v2/data/er'
|
||||
import SquareImage from '../../../../components/v2/SquareImage'
|
||||
import { getErSignetTypeLabel } from '../../../../lib/v2/data/text'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Breadcrumb from '../../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../../../server/i18n'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
|
||||
interface BattlesuitShowPageProps {
|
||||
group: ErSignetGroup
|
||||
@@ -2,13 +2,13 @@ import { NextPageContext } from 'next'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useMemo } from 'react'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import BattlesuitSmallIcon from '../../../../components/v2/BattlesuitSmallIcon'
|
||||
import { BattlesuitCatalogItem, ErSupportBattlesuit } from '../../../../lib/v2/data/types'
|
||||
import { loadBattlesuitCatalog, loadErSupports } from '../../../../lib/v2/server/loadData'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import BattlesuitSmallIcon from '../../../components/v2/BattlesuitSmallIcon'
|
||||
import { BattlesuitCatalogItem, ErSupportBattlesuit } from '../../../lib/v2/data/types'
|
||||
import { loadBattlesuitCatalog, loadErSupports } from '../../../lib/v2/server/loadData'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
|
||||
interface SupportsPageProps {
|
||||
battlesuitCatalog: BattlesuitCatalogItem[]
|
||||
+10
-10
@@ -1,17 +1,17 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading, Link } from 'theme-ui'
|
||||
import FormattedText from '../../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo } from '../../../../lib/v2/data/formatText'
|
||||
import { loadStigmaData, loadStigmataSetCatalog, loadStigmataSetData } from '../../../../lib/v2/server/loadData'
|
||||
import { RootStigma, StigmataSet } from '../../../../lib/v2/data/types'
|
||||
import FormattedText from '../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo } from '../../../lib/v2/data/formatText'
|
||||
import { loadStigmaData, loadStigmataSetCatalog, loadStigmataSetData } from '../../../lib/v2/server/loadData'
|
||||
import { RootStigma, StigmataSet } from '../../../lib/v2/data/types'
|
||||
import { Fragment } from 'react'
|
||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
||||
import StigmaFigureImage from '../../../../components/v2/StigmaFigureImage'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||
import StigmaFigureImage from '../../../components/v2/StigmaFigureImage'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface StigmataSetShowPage {
|
||||
stigmataSet: StigmataSet
|
||||
+7
-7
@@ -3,14 +3,14 @@ import { Box, Card, Heading } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
|
||||
import { StigmataSetCatalogItem } from '../../../../lib/v2/data/types'
|
||||
import { loadStigmataSetCatalog } from '../../../../lib/v2/server/loadData'
|
||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { StigmataSetCatalogItem } from '../../../lib/v2/data/types'
|
||||
import { loadStigmataSetCatalog } from '../../../lib/v2/server/loadData'
|
||||
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface StigmataSetListPageProps {
|
||||
stigmataSetCatalog: StigmataSetCatalogItem[]
|
||||
+12
-12
@@ -1,19 +1,19 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading, Link } from 'theme-ui'
|
||||
import FormattedText from '../../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo, replaceNewLine } from '../../../../lib/v2/data/formatText'
|
||||
import { loadStigmaData, loadStigmataCatalog, loadStigmataSetData } from '../../../../lib/v2/server/loadData'
|
||||
import { RootStigma, StigmataSetCatalogItem } from '../../../../lib/v2/data/types'
|
||||
import FormattedText from '../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo, replaceNewLine } from '../../../lib/v2/data/formatText'
|
||||
import { loadStigmaData, loadStigmataCatalog, loadStigmataSetData } from '../../../lib/v2/server/loadData'
|
||||
import { RootStigma, StigmataSetCatalogItem } from '../../../lib/v2/data/types'
|
||||
import { Fragment } from 'react'
|
||||
import { getStigmaTypeLabel } from '../../../../lib/v2/data/text'
|
||||
import StigmaTypeIcon from '../../../../components/v2/StigmaTypeIcon'
|
||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
||||
import StigmaFigureImage from '../../../../components/v2/StigmaFigureImage'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { getStigmaTypeLabel } from '../../../lib/v2/data/text'
|
||||
import StigmaTypeIcon from '../../../components/v2/StigmaTypeIcon'
|
||||
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||
import StigmaFigureImage from '../../../components/v2/StigmaFigureImage'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface StigmaShowPageProps {
|
||||
rootStigma: RootStigma
|
||||
@@ -1,80 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { NextPageContext } from 'next'
|
||||
import SingleStigmataPage, {
|
||||
SingleStigmataPageProps,
|
||||
} from '../../../components/pages/SingleStigmataPage'
|
||||
import StigmataSetPage, {
|
||||
StigmataSetProps,
|
||||
} from '../../../components/pages/StigmataSetPage'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
||||
import {
|
||||
listStigmata,
|
||||
getStigmaById,
|
||||
getStigmataListBySetId,
|
||||
getStigmataSetBySetId,
|
||||
listStigmataSet,
|
||||
} from '../../../server/data/honkai3rd/stigmata'
|
||||
|
||||
type StigmataShowPageProps = SingleStigmataPageProps | StigmataSetProps
|
||||
|
||||
const StigmataListPage = (props: StigmataShowPageProps) => {
|
||||
if (props.type === 'single') {
|
||||
return <SingleStigmataPage {...props} />
|
||||
}
|
||||
|
||||
return <StigmataSetPage {...props} />
|
||||
}
|
||||
|
||||
export default StigmataListPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { stigmataId: string } }) {
|
||||
const stigmataData = getStigmaById(params.stigmataId, locale)!
|
||||
if (stigmataData != null) {
|
||||
return {
|
||||
props: {
|
||||
type: 'single',
|
||||
stigmataData: stigmataData,
|
||||
stigmataSetList: (
|
||||
(stigmataData.set != null &&
|
||||
getStigmataListBySetId(stigmataData.set!, locale)) ||
|
||||
[]
|
||||
).sort((a, b) => -a.type.localeCompare(b.type)),
|
||||
stigmataSet: getStigmataSetBySetId(stigmataData.set!, locale) || null,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
const [stigmataSetId] = params.stigmataId.split('-set')
|
||||
const stigmataSet = getStigmataSetBySetId(stigmataSetId, locale)!
|
||||
return {
|
||||
props: {
|
||||
type: 'set',
|
||||
stigmataSet,
|
||||
stigmataSetList: (
|
||||
getStigmataListBySetId(stigmataSet.id, locale) || []
|
||||
).sort((a, b) => -a.type.localeCompare(b.type)),
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths([
|
||||
...listStigmata().map((stigmata) => {
|
||||
return {
|
||||
params: { stigmataId: stigmata.id },
|
||||
}
|
||||
}),
|
||||
...listStigmataSet().map((stigmataSet) => {
|
||||
return {
|
||||
params: { stigmataId: `${stigmataSet.id}-set` },
|
||||
}
|
||||
}),
|
||||
]),
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
@@ -1,97 +1,54 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex } from '@theme-ui/components'
|
||||
import { Box, Card, Heading } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { useRouter } from 'next/router'
|
||||
import { pick } from 'ramda'
|
||||
import { useMemo } from 'react'
|
||||
import PageLink from '../../../components/atoms/PageLink'
|
||||
import StigmataCard from '../../../components/molecules/StigmataCard'
|
||||
import StigmataSetCard from '../../../components/molecules/StigmataSetCard'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { StigmataData, StigmataSet } from '../../../lib/honkai3rd/stigmata'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import {
|
||||
listStigmata,
|
||||
listStigmataSet,
|
||||
} from '../../../server/data/honkai3rd/stigmata'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
|
||||
import { StigmataCatalogItem } from '../../../lib/v2/data/types'
|
||||
import { loadStigmataCatalog } from '../../../lib/v2/server/loadData'
|
||||
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
|
||||
interface StigmataListPageProps {
|
||||
stigmataDataList: Pick<StigmataData, 'id' | 'name' | 'rarity'>[]
|
||||
stigmataSetList: Pick<StigmataSet, 'id' | 'name' | 'rarity'>[]
|
||||
stigmataCatalog: StigmataCatalogItem[]
|
||||
}
|
||||
|
||||
const StigmataListPage = ({
|
||||
stigmataDataList,
|
||||
stigmataSetList,
|
||||
}: StigmataListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { query } = useRouter()
|
||||
|
||||
const listMode = useMemo(() => {
|
||||
if (query.list == null) {
|
||||
return 'set'
|
||||
}
|
||||
return typeof query.list === 'string' ? query.list : query.list[0]
|
||||
}, [query])
|
||||
|
||||
const StigmataListPage = ({ stigmataCatalog }: StigmataListPageProps) => {
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.stigmata')} - ${t('common.honkai-3rd')} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
description={t('stigmata-list.description')}
|
||||
canonicalHref={`/honkai3rd/stigmata`}
|
||||
/>
|
||||
<Box>
|
||||
<Heading as="h1">Stigmata (Single)</Heading>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/stigmata', label: t('common.stigmata') },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as='h1'>{t('stigmata-list.stigmata')}</Heading>
|
||||
|
||||
<Flex mb={3}>
|
||||
<PageLink
|
||||
href={{
|
||||
query: listMode === 'set' ? { list: 'single' } : { list: 'set' },
|
||||
}}
|
||||
shallow={true}
|
||||
m={1}
|
||||
py={1}
|
||||
px={2}
|
||||
className={listMode === 'set' ? 'active' : ''}
|
||||
sx={{ display: 'flex' }}
|
||||
variant='buttons.primary'
|
||||
>
|
||||
{t('stigmata-list.set-list')}
|
||||
</PageLink>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
sx={{
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around',
|
||||
}}
|
||||
>
|
||||
{listMode === 'set'
|
||||
? stigmataSetList.map((stigmataSet) => {
|
||||
return (
|
||||
<StigmataSetCard
|
||||
key={stigmataSet.id}
|
||||
stigmataSet={stigmataSet}
|
||||
/>
|
||||
)
|
||||
})
|
||||
: stigmataDataList.map((stigmata) => {
|
||||
return <StigmataCard key={stigmata.id} stigmata={stigmata} />
|
||||
})}
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{stigmataCatalog
|
||||
.filter(filterStigmata)
|
||||
.sort(sortStigmata)
|
||||
.map(stigma => {
|
||||
return (
|
||||
<Box key={stigma.id} m={2}>
|
||||
<Link href={`/v2-pre/stigmata/${stigma.id}`}>
|
||||
<Card p={1}>
|
||||
<Flex sx={{ justifyContent: 'center' }}>
|
||||
<StigmaIcon icon={stigma.icon} rarity={stigma.maxRarity} />
|
||||
</Flex>
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
px: 1,
|
||||
width: 112,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
{stigma.name}
|
||||
</Box>
|
||||
{/* {stigma.id} */}
|
||||
</Card>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
@@ -101,15 +58,21 @@ const StigmataListPage = ({
|
||||
export default StigmataListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const stigmataCatalog = loadStigmataCatalog()
|
||||
|
||||
return {
|
||||
props: {
|
||||
stigmataDataList: listStigmata(locale).map((stigmata) =>
|
||||
pick(['id', 'name', 'rarity'], stigmata)
|
||||
),
|
||||
stigmataSetList: listStigmataSet(locale).map((stigmataSet) =>
|
||||
pick(['id', 'name', 'rarity'], stigmataSet)
|
||||
),
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
props: { stigmataCatalog, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
function filterStigmata(weapon: StigmataCatalogItem) {
|
||||
return true
|
||||
}
|
||||
|
||||
function sortStigmata(a: StigmataCatalogItem, b: StigmataCatalogItem) {
|
||||
let aId = parseInt(a.id)
|
||||
|
||||
let bId = parseInt(b.id)
|
||||
|
||||
return bId - aId
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/* eslint-disable jsx-a11y/alt-text */
|
||||
import { times } from 'ramda'
|
||||
|
||||
interface BossSearchPageProps {}
|
||||
|
||||
// const AZArray = times((index) => {
|
||||
// const charCode = 'A'.charCodeAt(0) + index
|
||||
// const result = String.fromCharCode(charCode)
|
||||
// return result
|
||||
// }, 26)
|
||||
const NumberArray = times((index) => {
|
||||
if (index / 100 >= 1) {
|
||||
return index
|
||||
}
|
||||
if (index / 10 >= 1) {
|
||||
return '0' + index
|
||||
}
|
||||
return '00' + index
|
||||
}, 1000)
|
||||
|
||||
const BossSearchPage = ({}: BossSearchPageProps) => {
|
||||
return NumberArray.map((item) => {
|
||||
return (
|
||||
<img
|
||||
key={item}
|
||||
src={`https://upload-os-bbs.mihoyo.com/game_record/honkai3rd/global/SpriteOutput/OpenWorld/QuestBossIcon/QT_${item}.png`}
|
||||
/>
|
||||
)
|
||||
})
|
||||
// return AZArray.reduce<string[]>((array, firstChar) => {
|
||||
// return [
|
||||
// ...array,
|
||||
// ...AZArray.map((secondChar) => firstChar + secondChar + '_110.png'),
|
||||
// ]
|
||||
// }, []).map((item) => {
|
||||
// return (
|
||||
// <img
|
||||
// key={item}
|
||||
// src={`https://upload-os-bbs.mihoyo.com/game_record/honkai3rd/global/SpriteOutput/OpenWorld/QuestBossIcon/${item}`}
|
||||
// />
|
||||
// )
|
||||
// })
|
||||
}
|
||||
|
||||
export default BossSearchPage
|
||||
|
||||
// PSY : UL
|
||||
// MECHA : RO
|
||||
// BIO : DG
|
||||
@@ -1,328 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Flex,
|
||||
Heading,
|
||||
Paragraph,
|
||||
Text,
|
||||
Image,
|
||||
} from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import React from 'react'
|
||||
import BattlesuitFeatureLabel from '../../../../../components/atoms/BattlesuitFeatureLabel'
|
||||
import BattlesuitRankIcon from '../../../../../components/atoms/BattlesuitRankIcon'
|
||||
import PageLink from '../../../../../components/atoms/PageLink'
|
||||
import SecondaryLabel from '../../../../../components/atoms/SecondaryLabel'
|
||||
import TypeLabel from '../../../../../components/atoms/TypeLabel'
|
||||
import ValkyrieLabel from '../../../../../components/atoms/ValkyrieLabel'
|
||||
import {
|
||||
BattlesuitData,
|
||||
BattlesuitSkillGroup,
|
||||
} from '../../../../../lib/honkai3rd/battlesuits'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../../../server/i18n'
|
||||
import {
|
||||
getBattlesuitById,
|
||||
listBattlesuits,
|
||||
} from '../../../../../server/data/honkai3rd/battlesuits'
|
||||
import { useTranslation } from '../../../../../lib/i18n'
|
||||
import { assetsBucketBaseUrl } from '../../../../../lib/consts'
|
||||
import { WeaponData } from '../../../../../lib/honkai3rd/weapons'
|
||||
import { getWeaponMapByIds } from '../../../../../server/data/honkai3rd/weapons'
|
||||
import { StigmataData } from '../../../../../lib/honkai3rd/stigmata'
|
||||
import WeaponCard from '../../../../../components/molecules/WeaponCard'
|
||||
import StigmataCard from '../../../../../components/molecules/StigmataCard'
|
||||
import { getStigmataMapByIds } from '../../../../../server/data/honkai3rd/stigmata'
|
||||
|
||||
type WeaponObjectMap = { [key: string]: WeaponData }
|
||||
type StigmataObjectMap = { [key: string]: StigmataData }
|
||||
|
||||
interface BattlesuitShowPageProps {
|
||||
battlesuit: BattlesuitData
|
||||
weaponMap: WeaponObjectMap
|
||||
stigmataMap: StigmataObjectMap
|
||||
}
|
||||
|
||||
const BattlesuitShowPage = ({
|
||||
battlesuit,
|
||||
weaponMap,
|
||||
stigmataMap,
|
||||
}: BattlesuitShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Box p={3}>
|
||||
<Heading as='h1'>{battlesuit.name}</Heading>
|
||||
|
||||
<Box mb={3}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
maxWidth: [300, 400],
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
alt={battlesuit.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/battlesuits/${battlesuit.id}.png`}
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Card
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
mb={3}
|
||||
>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/battlesuits',
|
||||
query: { filter: battlesuit.valkyrie },
|
||||
}}
|
||||
>
|
||||
<ValkyrieLabel valkyrie={battlesuit.valkyrie} />
|
||||
</PageLink>
|
||||
</Box>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/battlesuits',
|
||||
query: { filter: battlesuit.type },
|
||||
}}
|
||||
>
|
||||
<TypeLabel type={battlesuit.type} />
|
||||
</PageLink>
|
||||
</Box>
|
||||
<Flex p={2} sx={{ flexWrap: 'wrap', rowGap: 1 }}>
|
||||
{battlesuit.features.map((feature) => {
|
||||
return (
|
||||
<Box mr={2} key={feature}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/battlesuits',
|
||||
query: { filter: feature },
|
||||
}}
|
||||
>
|
||||
<BattlesuitFeatureLabel feature={feature} />
|
||||
</PageLink>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
{battlesuit.equipment != null && (
|
||||
<Card
|
||||
sx={{
|
||||
mb: 3,
|
||||
p: 2,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{battlesuit.equipment.map((equipmentItem) => {
|
||||
return (
|
||||
<Box key={equipmentItem.type}>
|
||||
<Heading
|
||||
as='h3'
|
||||
sx={{
|
||||
mb: 1,
|
||||
}}
|
||||
>
|
||||
{t(`battlesuit-show.equipmentTypes.${equipmentItem.type}`)}
|
||||
</Heading>
|
||||
<Flex sx={{ mx: -1 }}>
|
||||
{equipmentItem.weapon != null && (
|
||||
<WeaponCard
|
||||
size='sm'
|
||||
weapon={weaponMap[equipmentItem.weapon]}
|
||||
/>
|
||||
)}
|
||||
{equipmentItem.stigmataTop != null && (
|
||||
<StigmataCard
|
||||
size='sm'
|
||||
stigmata={stigmataMap[equipmentItem.stigmataTop]}
|
||||
/>
|
||||
)}
|
||||
{equipmentItem.stigmataMid != null && (
|
||||
<StigmataCard
|
||||
size='sm'
|
||||
stigmata={stigmataMap[equipmentItem.stigmataMid]}
|
||||
/>
|
||||
)}
|
||||
{equipmentItem.stigmataBot != null && (
|
||||
<StigmataCard
|
||||
size='sm'
|
||||
stigmata={stigmataMap[equipmentItem.stigmataBot]}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.leader')}
|
||||
skillGroup={battlesuit.leader}
|
||||
/>
|
||||
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.passive')}
|
||||
skillGroup={battlesuit.passive}
|
||||
/>
|
||||
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.evasion')}
|
||||
skillGroup={battlesuit.evasion}
|
||||
/>
|
||||
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.special-attack')}
|
||||
skillGroup={battlesuit.special}
|
||||
/>
|
||||
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.ultimate')}
|
||||
skillGroup={battlesuit.ultimate}
|
||||
/>
|
||||
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.basic-attack')}
|
||||
skillGroup={battlesuit.basic}
|
||||
/>
|
||||
|
||||
{battlesuit.sp != null && (
|
||||
<BattlesuitSkillGroupCard
|
||||
heading={t('battlesuit-show.sp-skill')}
|
||||
skillGroup={battlesuit.sp}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default BattlesuitShowPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { battlesuitId: string } }) {
|
||||
const battlesuit = getBattlesuitById(params.battlesuitId, locale)!
|
||||
const { weaponIds, stigmataIds } = (battlesuit.equipment || []).reduce<{
|
||||
weaponIds: string[]
|
||||
stigmataIds: string[]
|
||||
}>(
|
||||
(acc, equipmentItem) => {
|
||||
acc.weaponIds.push(equipmentItem.weapon)
|
||||
acc.stigmataIds.push(
|
||||
equipmentItem.stigmataTop,
|
||||
equipmentItem.stigmataMid,
|
||||
equipmentItem.stigmataBot
|
||||
)
|
||||
return acc
|
||||
},
|
||||
{ weaponIds: [], stigmataIds: [] }
|
||||
)
|
||||
const weaponMap = getWeaponMapByIds(weaponIds, locale)
|
||||
|
||||
const stigmataMap = getStigmataMapByIds(stigmataIds, locale)
|
||||
|
||||
return {
|
||||
props: {
|
||||
battlesuit,
|
||||
weaponMap,
|
||||
stigmataMap,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
listBattlesuits().map((battlesuit) => {
|
||||
return {
|
||||
params: { battlesuitId: battlesuit.id },
|
||||
}
|
||||
})
|
||||
),
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
|
||||
interface BattlesuitSkillGroupCardProps {
|
||||
heading: string
|
||||
skillGroup: BattlesuitSkillGroup
|
||||
}
|
||||
|
||||
const BattlesuitSkillGroupCard = ({
|
||||
heading,
|
||||
skillGroup,
|
||||
}: BattlesuitSkillGroupCardProps) => {
|
||||
return (
|
||||
<Card mb={3}>
|
||||
<Box
|
||||
sx={{
|
||||
p: 2,
|
||||
borderBottom: 'default',
|
||||
}}
|
||||
>
|
||||
<Heading as='h2' mb={1}>
|
||||
{skillGroup.core.name}
|
||||
</Heading>
|
||||
<SecondaryLabel>{heading}</SecondaryLabel>
|
||||
</Box>
|
||||
|
||||
<Paragraph p={2} sx={{ whiteSpace: 'pre-wrap', borderBottom: 'default' }}>
|
||||
{skillGroup.core.description}
|
||||
</Paragraph>
|
||||
|
||||
{skillGroup.subskills.map((subskill) => {
|
||||
return (
|
||||
<React.Fragment key={subskill.name}>
|
||||
<Heading as='h3' p={2} m={0} sx={{ borderBottom: 'default' }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<Text>{subskill.name}</Text>
|
||||
{subskill.requiredRank != null ? (
|
||||
/^[0-9]/.test(subskill.requiredRank) ? (
|
||||
<Box
|
||||
ml={2}
|
||||
sx={{ height: 30, lineHeight: '30px', fontSize: 2 }}
|
||||
>
|
||||
⭐{subskill.requiredRank.slice(0, 1)}
|
||||
</Box>
|
||||
) : (
|
||||
<BattlesuitRankIcon
|
||||
rank={subskill.requiredRank}
|
||||
size={30}
|
||||
ml={2}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Box sx={{ height: 30 }} />
|
||||
)}
|
||||
</Flex>
|
||||
</Heading>
|
||||
|
||||
<Paragraph
|
||||
p={2}
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
borderBottom: 'default',
|
||||
'&:last-child': { borderBottom: 'none' },
|
||||
}}
|
||||
>
|
||||
{subskill.description}
|
||||
</Paragraph>
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { NextPageContext } from 'next'
|
||||
import React from 'react'
|
||||
import PageLink from '../../../../../components/atoms/PageLink'
|
||||
import { StigmataSetProps } from '../../../../../components/pages/StigmataSetPage'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../../../server/i18n'
|
||||
import {
|
||||
listStigmata,
|
||||
getStigmataListBySetId,
|
||||
getStigmataSetBySetId,
|
||||
listStigmataSet,
|
||||
getStigmaById,
|
||||
} from '../../../../../server/data/honkai3rd/stigmata'
|
||||
import { Box, Card, Flex, Heading, Paragraph } from 'theme-ui'
|
||||
import SecondaryLabel from '../../../../../components/atoms/SecondaryLabel'
|
||||
import StigmataCard from '../../../../../components/molecules/StigmataCard'
|
||||
import { useTranslation } from '../../../../../lib/i18n'
|
||||
import { SingleStigmataPageProps } from '../../../../../components/pages/SingleStigmataPage'
|
||||
|
||||
type StigmataShowPageProps = StigmataSetProps | SingleStigmataPageProps
|
||||
|
||||
const StigmataListPage = (props: StigmataShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (props.type === 'single') {
|
||||
return null
|
||||
}
|
||||
|
||||
const { stigmataSet, stigmataSetList } = props
|
||||
|
||||
return (
|
||||
<Box p={3}>
|
||||
<Box mb={3}>
|
||||
<Heading as='h1' mb={0}>
|
||||
{stigmataSet.name}
|
||||
</Heading>
|
||||
<SecondaryLabel>{stigmataSet.altName}</SecondaryLabel>
|
||||
</Box>
|
||||
|
||||
<Card mb={3}>
|
||||
<Flex
|
||||
p={2}
|
||||
sx={{
|
||||
borderBottom: 'default',
|
||||
justifyContent: 'space-around',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
{stigmataSetList.map((stigmataSetItem) => {
|
||||
return (
|
||||
<StigmataCard
|
||||
key={stigmataSetItem.id}
|
||||
stigmata={stigmataSetItem}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
{stigmataSetList.map((stigmataSetItem) => {
|
||||
return (
|
||||
<React.Fragment key={stigmataSetItem.id}>
|
||||
<Box sx={{ p: 2, borderBottom: 'default' }}>
|
||||
<Heading as='h2' mb={1}>
|
||||
<PageLink href={`/honkai3rd/stigmata/${stigmataSetItem.id}`}>
|
||||
{stigmataSetItem.name}
|
||||
</PageLink>
|
||||
</Heading>
|
||||
<SecondaryLabel>
|
||||
{t(`stigmata-show.${stigmataSetItem.type}`)}
|
||||
</SecondaryLabel>
|
||||
</Box>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
HP : {stigmataSetItem.hp} / ATK : {stigmataSetItem.atk} / DEF :{' '}
|
||||
{stigmataSetItem.def} / CRT : {stigmataSetItem.crt}
|
||||
</Box>
|
||||
<Paragraph
|
||||
m={0}
|
||||
p={2}
|
||||
sx={{
|
||||
borderBottom: 'default',
|
||||
'&:last-child': { borderBottom: 'none' },
|
||||
}}
|
||||
>
|
||||
{stigmataSetItem.skill.description}
|
||||
</Paragraph>
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<Heading as='h2' m={0} p={2} sx={{ borderBottom: 'default' }}>
|
||||
{stigmataSet.twoSetSkill.name}
|
||||
</Heading>
|
||||
<Paragraph m={0} p={2} sx={{ borderBottom: 'default' }}>
|
||||
{stigmataSet.twoSetSkill.description}
|
||||
</Paragraph>
|
||||
<Heading as='h2' m={0} p={2} sx={{ borderBottom: 'default' }}>
|
||||
{stigmataSet.threeSetSkill.name}
|
||||
</Heading>
|
||||
<Paragraph m={0} p={2}>
|
||||
{stigmataSet.threeSetSkill.description}
|
||||
</Paragraph>
|
||||
</Card>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default StigmataListPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { stigmataId: string } }) {
|
||||
const stigmataData = getStigmaById(params.stigmataId, locale)!
|
||||
if (stigmataData != null) {
|
||||
return {
|
||||
props: {
|
||||
type: 'single',
|
||||
stigmataData: stigmataData,
|
||||
stigmataSetList: (
|
||||
getStigmataListBySetId(stigmataData.set!, locale) || []
|
||||
).sort((a, b) => -a.type.localeCompare(b.type)),
|
||||
stigmataSet: getStigmataSetBySetId(stigmataData.set!, locale) || null,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
const [stigmataSetId] = params.stigmataId.split('-set')
|
||||
const stigmataSet = getStigmataSetBySetId(stigmataSetId, locale)!
|
||||
return {
|
||||
props: {
|
||||
type: 'set',
|
||||
stigmataSet,
|
||||
stigmataSetList: (
|
||||
getStigmataListBySetId(stigmataSet.id, locale) || []
|
||||
).sort((a, b) => -a.type.localeCompare(b.type)),
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths([
|
||||
...listStigmata().map((stigmata) => {
|
||||
return {
|
||||
params: { stigmataId: stigmata.id },
|
||||
}
|
||||
}),
|
||||
...listStigmataSet().map((stigmataSet) => {
|
||||
return {
|
||||
params: { stigmataId: `${stigmataSet.id}-set` },
|
||||
}
|
||||
}),
|
||||
]),
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Flex, Box, Card, Heading, Paragraph } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import SquareImageBox from '../../../../../components/atoms/SquareImageBox'
|
||||
import {
|
||||
weaponCategories,
|
||||
WeaponData,
|
||||
} from '../../../../../lib/honkai3rd/weapons'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../../../server/i18n'
|
||||
import {
|
||||
getWeaponById,
|
||||
getWeaponMapByIds,
|
||||
listWeapons,
|
||||
} from '../../../../../server/data/honkai3rd/weapons'
|
||||
import { useTranslation } from '../../../../../lib/i18n'
|
||||
import PageLink from '../../../../../components/atoms/PageLink'
|
||||
import { assetsBucketBaseUrl } from '../../../../../lib/consts'
|
||||
import { getBattlesuitMapByIds } from '../../../../../server/data/honkai3rd/battlesuits'
|
||||
import { BattlesuitData } from '../../../../../lib/honkai3rd/battlesuits'
|
||||
import BattlesuitCard from '../../../../../components/molecules/BattlesuitCard'
|
||||
import WeaponCard from '../../../../../components/molecules/WeaponCard'
|
||||
|
||||
interface WeaponShowPageProps {
|
||||
weapon: WeaponData
|
||||
battlesuitMap: { [key: string]: BattlesuitData }
|
||||
weaponMap: { [key: string]: WeaponData }
|
||||
}
|
||||
|
||||
const WeaponShowPage = ({
|
||||
weapon,
|
||||
battlesuitMap,
|
||||
weaponMap,
|
||||
}: WeaponShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const weaponCategoryName = t(`weapons-show.${weapon.category}`)
|
||||
const weaponCategory = weaponCategories.find(
|
||||
(category) => category.value === weapon.category
|
||||
)
|
||||
|
||||
return (
|
||||
<Box p={3}>
|
||||
<Heading as='h1'>{weapon.name}</Heading>
|
||||
|
||||
<Box mb={3}>
|
||||
<SquareImageBox
|
||||
size={100}
|
||||
alt={weapon.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/weapons/${weapon.id}.png`}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Card mb={3}>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/weapons',
|
||||
query: { filter: weapon.category },
|
||||
}}
|
||||
>
|
||||
<Flex>
|
||||
{weaponCategory != null && (
|
||||
<SquareImageBox
|
||||
size={30}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/${weaponCategory.icon}.png`}
|
||||
alt={weaponCategoryName}
|
||||
mr={1}
|
||||
/>
|
||||
)}
|
||||
{weaponCategoryName}
|
||||
</Flex>
|
||||
</PageLink>
|
||||
</Box>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
{'⭐'.repeat(weapon.rarity)}
|
||||
</Box>
|
||||
<Box p={2}>
|
||||
ATK : {weapon.atk} / CRT : {weapon.crt}
|
||||
</Box>
|
||||
{weapon.battlesuits != null && weapon.battlesuits.length > 0 && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as='h4'>{t('weapons-show.best-on')}</Heading>
|
||||
{weapon.battlesuits.map(({ id: battlesuitId }) => {
|
||||
return (
|
||||
<BattlesuitCard
|
||||
key={battlesuitId}
|
||||
size='sm'
|
||||
battlesuit={battlesuitMap[battlesuitId]}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
)}
|
||||
{weapon.priWeapon != null && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as='h4'>{t('weapons-show.pri-weapon')}</Heading>
|
||||
<WeaponCard size='sm' weapon={weaponMap[weapon.priWeapon]} />
|
||||
</Box>
|
||||
)}
|
||||
{weapon.originalWeapons != null && weapon.originalWeapons.length > 0 && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as='h4'>{t('weapons-show.original-weapon')}</Heading>
|
||||
{weapon.originalWeapons.map((originalWeaponId) => {
|
||||
return (
|
||||
<WeaponCard
|
||||
key={originalWeaponId}
|
||||
size='sm'
|
||||
weapon={weaponMap[originalWeaponId]}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
)}
|
||||
{/* {weapon.sources != null && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as='h4'>{t('weapons-show.sources')}</Heading>
|
||||
{weapon.sources
|
||||
.sort((a, b) => a.type.localeCompare(b.type))
|
||||
.map((source) => {
|
||||
return <SourceCard key={source.type} source={source} />
|
||||
})}
|
||||
</Box>
|
||||
)} */}
|
||||
</Card>
|
||||
|
||||
<Box>
|
||||
{weapon.skills.map((skill) => {
|
||||
return (
|
||||
<Card key={skill.name} mb={3}>
|
||||
<Heading as='h3' p={2} m={0} sx={{ borderBottom: 'default' }}>
|
||||
{skill.name}
|
||||
</Heading>
|
||||
<Paragraph
|
||||
p={2}
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
}}
|
||||
>
|
||||
{skill.description}
|
||||
</Paragraph>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default WeaponShowPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { weaponId: string } }) {
|
||||
const weapon = getWeaponById(params.weaponId, locale)
|
||||
const battlesuitMap = getBattlesuitMapByIds(
|
||||
weapon != null && weapon.battlesuits != null
|
||||
? weapon.battlesuits.map(({ id }) => id)
|
||||
: [],
|
||||
locale
|
||||
)
|
||||
|
||||
const weaponIds = []
|
||||
if (weapon != null) {
|
||||
if (weapon.priWeapon != null) {
|
||||
weaponIds.push(weapon.priWeapon)
|
||||
}
|
||||
if (weapon.originalWeapons != null) {
|
||||
weaponIds.push(...weapon.originalWeapons)
|
||||
}
|
||||
}
|
||||
const weaponMap = getWeaponMapByIds(weaponIds, locale)
|
||||
|
||||
return {
|
||||
props: {
|
||||
weapon,
|
||||
battlesuitMap,
|
||||
weaponMap,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
listWeapons().map((weapon) => {
|
||||
return {
|
||||
params: { weaponId: weapon.id },
|
||||
}
|
||||
})
|
||||
),
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import AttributeIcon from '../../../../components/v2/AttributeIcon'
|
||||
import AvatarFigureImage from '../../../../components/v2/AvatarFigureImage'
|
||||
import AvatarSkillIcon from '../../../../components/v2/AvatarSkillIcon'
|
||||
import AvatarSubSkillIcon from '../../../../components/v2/AvatarSubSkillIcon'
|
||||
import BattlesuitAvatarIcon from '../../../../components/v2/BattlesuitAvatarIcon'
|
||||
import FormattedText from '../../../../components/v2/FormattedText'
|
||||
import { formatSkillInfo, formatSubSkillInfo } from '../../../../lib/v2/data/formatText'
|
||||
import { loadBattlesuitCatalog, loadBattlesuitData } from '../../../../lib/v2/server/loadData'
|
||||
import { Battlesuit, SkillTagItem } from '../../../../lib/v2/data/types'
|
||||
import { Fragment } from 'react'
|
||||
import TagIcon from '../../../../components/v2/TagIcon'
|
||||
import {
|
||||
getAttributeLabel,
|
||||
getCharacterTypeLabel,
|
||||
getSkillTypeLabel,
|
||||
getTagTypeLabel,
|
||||
getWeaponTypeLabel
|
||||
} from '../../../../lib/v2/data/text'
|
||||
import StarIcon from '../../../../components/v2/StarIcon'
|
||||
import ChibiIcon from '../../../../components/v2/ChibiIcon'
|
||||
import WeaponTypeIcon from '../../../../components/v2/WeaponTypeIcon'
|
||||
import { sortBattlesuitSkill } from '../../../../lib/v2/data/utils'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
interface BattlesuitShowPageProps {
|
||||
battlesuit: Battlesuit
|
||||
}
|
||||
|
||||
const BattlesuitShowPage = ({ battlesuit }: BattlesuitShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${battlesuit.fullName} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${t('battlesuit-show.battlesuit')} / ${battlesuit.fullName} / ${
|
||||
battlesuit.attributeType
|
||||
} / ${battlesuit.tags
|
||||
.map(tag => {
|
||||
return getTagTypeLabel(tag)
|
||||
})
|
||||
.join(', ')}`}
|
||||
canonicalHref={`/honkai3rd/battlesuits/${battlesuit.id}`}
|
||||
/>
|
||||
<Box p={2}>
|
||||
<Heading as="h1">{battlesuit.fullName}</Heading>
|
||||
|
||||
<AvatarFigureImage battlesuitId={battlesuit.id} sx={{ height: 400 }} />
|
||||
|
||||
<Box mb={3}>
|
||||
<BattlesuitAvatarIcon battlesuit={battlesuit} />
|
||||
</Box>
|
||||
|
||||
<Card mb={3}>
|
||||
<Flex sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<Box mr={2}>
|
||||
<StarIcon star={battlesuit.initialStar} />
|
||||
</Box>
|
||||
|
||||
<ChibiIcon id={battlesuit.character} />
|
||||
|
||||
<Box ml={1} mr={2}>
|
||||
{getCharacterTypeLabel(battlesuit.character)}
|
||||
</Box>
|
||||
|
||||
<AttributeIcon attributeType={battlesuit.attributeType} size={30} />
|
||||
<Box ml={1} mr={2}>
|
||||
{getAttributeLabel(battlesuit.attributeType)}
|
||||
</Box>
|
||||
|
||||
<WeaponTypeIcon type={battlesuit.weapon} />
|
||||
<Box ml={1}>{getWeaponTypeLabel(battlesuit.weapon)}</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex sx={{ p: 1 }}>
|
||||
{battlesuit.tags.map(tag => {
|
||||
return (
|
||||
<Flex key={tag} sx={{ mr: 2, alignItems: 'center' }}>
|
||||
<TagIcon type={tag} />
|
||||
<Box ml={1}>{getTagTypeLabel(tag)}</Box>
|
||||
</Flex>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
<Heading as="h2">Skills</Heading>
|
||||
{battlesuit.skills.sort(sortBattlesuitSkill).map(skill => {
|
||||
return (
|
||||
<Card key={skill.id} mb={3}>
|
||||
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<AvatarSkillIcon icon={skill.icon} />
|
||||
<Heading as="h3" sx={{ ml: 1, mb: 0 }}>
|
||||
<FormattedText>{skill.name}</FormattedText>
|
||||
</Heading>
|
||||
{skill.tags.length > 0 && (
|
||||
<Flex sx={{ ml: 1 }}>
|
||||
{skill.tags.map((tag, index) => {
|
||||
return <SkillTagItem key={index} tag={tag} />
|
||||
})}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Box>{getSkillTypeLabel(skill.skillType)}</Box>
|
||||
</Box>
|
||||
<Box sx={{ whiteSpace: 'pre-wrap', borderBottom: 'default', p: 1 }}>
|
||||
<FormattedText>{formatSkillInfo(skill)}</FormattedText>
|
||||
</Box>
|
||||
|
||||
{skill.subSkills.map(subSkill => {
|
||||
return (
|
||||
<Fragment key={subSkill.id}>
|
||||
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<AvatarSubSkillIcon icon={subSkill.icon} />
|
||||
<Heading as="h4" sx={{ ml: 1, mb: 0 }}>
|
||||
<FormattedText>{subSkill.name}</FormattedText>
|
||||
</Heading>
|
||||
|
||||
{subSkill.unlockStar.localeCompare(battlesuit.initialStar) > 0 && (
|
||||
<Box ml={2}>
|
||||
<StarIcon star={subSkill.unlockStar} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{subSkill.tags.length > 0 && (
|
||||
<Flex sx={{ ml: 2 }}>
|
||||
{subSkill.tags.map((tag, index) => {
|
||||
return <SkillTagItem key={index} tag={tag} />
|
||||
})}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
borderBottom: 'default',
|
||||
'&:last-child': { borderBottom: 'none' },
|
||||
p: 1
|
||||
}}
|
||||
>
|
||||
<FormattedText>{formatSubSkillInfo(subSkill)}</FormattedText>
|
||||
</Box>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
{/* <pre>{JSON.stringify(battlesuit, null, 2)}</pre> */}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default BattlesuitShowPage
|
||||
|
||||
export async function getStaticProps({ locale, params }: NextPageContext & { params: { battlesuitId: string } }) {
|
||||
const battlesuit = loadBattlesuitData(params.battlesuitId)
|
||||
|
||||
return {
|
||||
props: { battlesuit, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const battlesuitCatalog = loadBattlesuitCatalog()
|
||||
|
||||
return {
|
||||
paths: battlesuitCatalog.map(catalogItem => {
|
||||
return {
|
||||
params: { battlesuitId: catalogItem.id }
|
||||
}
|
||||
}),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
|
||||
interface SkillTagBoxProps {
|
||||
tag: SkillTagItem
|
||||
}
|
||||
|
||||
const SkillTagItem = ({ tag }: SkillTagBoxProps) => {
|
||||
return <TagIcon type={tag.type} strength={tag.strength} comment={tag.comment} size="sm" />
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
import { loadBattlesuitCatalog } from '../../../../lib/v2/server/loadData'
|
||||
import { BattlesuitCatalogItem } from '../../../../lib/v2/data/types'
|
||||
import BattlesuitCatalogItemCard from '../../../../components/v2/BattlesuitCatalogItemCard'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
|
||||
interface BattlesuitListPageProps {
|
||||
battlesuitCatalog: BattlesuitCatalogItem[]
|
||||
}
|
||||
|
||||
const BattlesuitListPage = ({ battlesuitCatalog }: BattlesuitListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.battlesuits')} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={t('battlesuits-list.description')}
|
||||
canonicalHref={`/honkai3rd/battlesuits`}
|
||||
/>
|
||||
<Box p={2}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{
|
||||
href: '/honkai3rd/v2/battlesuits',
|
||||
label: t('common.battlesuits')
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<h1>{t('battlesuits-list.heading')}</h1>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{battlesuitCatalog.map(battlesuit => {
|
||||
return (
|
||||
<Box key={battlesuit.id}>
|
||||
<Link href={`/honkai3rd/v2/battlesuits/${battlesuit.id}`}>
|
||||
<BattlesuitCatalogItemCard battlesuit={battlesuit} />
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default BattlesuitListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const battlesuitCatalog = loadBattlesuitCatalog()
|
||||
|
||||
return {
|
||||
props: { battlesuitCatalog, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import { useMemo } from 'react'
|
||||
import { Elf, ElfSkill } from '../../../../lib/v2/data/types'
|
||||
import { loadElfCatalog, loadElfData } from '../../../../lib/v2/server/loadData'
|
||||
import SquareImage from '../../../../components/v2/SquareImage'
|
||||
import TagIcon from '../../../../components/v2/TagIcon'
|
||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||
import { ListMap } from '../../../../lib/utils'
|
||||
import FormattedText from '../../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo } from '../../../../lib/v2/data/formatText'
|
||||
|
||||
interface ElfShowPageProps {
|
||||
elf: Elf
|
||||
}
|
||||
|
||||
const ElfShowPage = ({ elf }: ElfShowPageProps) => {
|
||||
const skillRows = useMemo(() => {
|
||||
const rowSkillListMap = elf.skills.reduce<ListMap<string, ElfSkill>>((map, skill) => {
|
||||
map.set(skill.row.toString(), skill)
|
||||
return map
|
||||
}, new ListMap())
|
||||
|
||||
return [...rowSkillListMap.values()]
|
||||
}, [elf.skills])
|
||||
return (
|
||||
<Box>
|
||||
<Heading as="h1">{elf.fullName}</Heading>
|
||||
<SquareImage
|
||||
src={`${assetsBucketBaseUrl}/raw/elfcardfigures/${elf.figureImage}.png`}
|
||||
originalSize={720}
|
||||
size={480}
|
||||
/>
|
||||
|
||||
<Card mb={3}>
|
||||
<Box sx={{ p: 1, borderBottom: 'default' }}>
|
||||
<Flex>
|
||||
{elf.tags.map(tag => {
|
||||
return (
|
||||
<Box key={tag.type} mr={1}>
|
||||
<TagIcon type={tag.type} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box p={1}>
|
||||
Ult CD: {elf.ultSkillCd} / Ult SP Cost: {elf.ultSkillCost}
|
||||
</Box>
|
||||
</Card>
|
||||
|
||||
<Heading as="h2">Skills</Heading>
|
||||
|
||||
{skillRows.map((row, index) => {
|
||||
return (
|
||||
<Card key={index} mb={2}>
|
||||
{row.map(skill => {
|
||||
return (
|
||||
<Box
|
||||
key={skill.id}
|
||||
sx={{
|
||||
borderBottom: 'default',
|
||||
'&:last-child': {
|
||||
borderBottom: 'none'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
<Box sx={{ flexShrink: 0 }}>
|
||||
<SquareImage
|
||||
src={`${assetsBucketBaseUrl}/raw/elf_skill_icon/${skill.icon}.png`}
|
||||
originalSize={40}
|
||||
/>
|
||||
</Box>
|
||||
<Heading as={'h3'} sx={{ my: 0, ml: 1 }}>
|
||||
<FormattedText>{skill.name}</FormattedText>
|
||||
</Heading>
|
||||
{/* {skill.id} */}
|
||||
<Box sx={{ color: 'textMuted', ml: 1 }}>({skill.skillType})</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box sx={{ p: 1 }}>
|
||||
<FormattedText>{formatSubSkillInfo(skill)}</FormattedText>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElfShowPage
|
||||
|
||||
export async function getStaticProps({ locale, params }: NextPageContext & { params: { elfId: string } }) {
|
||||
const elf = loadElfData(params.elfId)
|
||||
|
||||
return {
|
||||
props: { elf }
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const elfCatalog = loadElfCatalog()
|
||||
|
||||
return {
|
||||
paths: elfCatalog.map(catalogItem => {
|
||||
return {
|
||||
params: { elfId: catalogItem.id }
|
||||
}
|
||||
}),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Card } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
import { ElfCatalogItem } from '../../../../lib/v2/data/types'
|
||||
import { loadElfCatalog } from '../../../../lib/v2/server/loadData'
|
||||
import RarityBar from '../../../../components/v2/RarityBar'
|
||||
import ElfIcon from '../../../../components/v2/ElfIcon'
|
||||
|
||||
interface ElfListPageProps {
|
||||
elfs: ElfCatalogItem[]
|
||||
}
|
||||
|
||||
const ElfListPage = ({ elfs }: ElfListPageProps) => {
|
||||
return (
|
||||
<Box>
|
||||
<h1>Elfs</h1>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{elfs
|
||||
.sort((a, b) => {
|
||||
const aId = getId(a.id)
|
||||
const bId = getId(b.id)
|
||||
return bId - aId
|
||||
|
||||
function getId(id: string): number {
|
||||
return parseInt(id)
|
||||
}
|
||||
})
|
||||
.map(elf => {
|
||||
return (
|
||||
<Box key={elf.id} m={2}>
|
||||
<Link href={`/v2-pre/elfs/${elf.id}`}>
|
||||
<Card p={1}>
|
||||
<Box>
|
||||
<ElfIcon icon={elf.cardIcon} />
|
||||
<RarityBar rarity={elf.rarity} />
|
||||
</Box>
|
||||
<Box
|
||||
sx={{ textAlign: 'center', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{elf.fullName}
|
||||
</Box>
|
||||
</Card>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default ElfListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const elfs = loadElfCatalog()
|
||||
|
||||
return {
|
||||
props: { elfs }
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import { Box } from 'theme-ui'
|
||||
|
||||
const HomePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>V2 Pre</h1>
|
||||
<Box>
|
||||
<Link href="/v2-pre/battlesuits">Battlesuits</Link>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href="/v2-pre/weapons">Weapons</Link>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href="/v2-pre/stigmata">Stigmata</Link>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href="/v2-pre/stigmata-sets">StigmataSets</Link>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href="/v2-pre/elfs">Elfs</Link>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href="/v2-pre/er">Elysian Realm</Link>
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HomePage
|
||||
@@ -1,78 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Card, Heading } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { Flex, Link } from 'theme-ui'
|
||||
|
||||
import { StigmataCatalogItem } from '../../../../lib/v2/data/types'
|
||||
import { loadStigmataCatalog } from '../../../../lib/v2/server/loadData'
|
||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
|
||||
interface StigmataListPageProps {
|
||||
stigmataCatalog: StigmataCatalogItem[]
|
||||
}
|
||||
|
||||
const StigmataListPage = ({ stigmataCatalog }: StigmataListPageProps) => {
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Box>
|
||||
<Heading as="h1">Stigmata (Single)</Heading>
|
||||
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{stigmataCatalog
|
||||
.filter(filterStigmata)
|
||||
.sort(sortStigmata)
|
||||
.map(stigma => {
|
||||
return (
|
||||
<Box key={stigma.id} m={2}>
|
||||
<Link href={`/v2-pre/stigmata/${stigma.id}`}>
|
||||
<Card p={1}>
|
||||
<Flex sx={{ justifyContent: 'center' }}>
|
||||
<StigmaIcon icon={stigma.icon} rarity={stigma.maxRarity} />
|
||||
</Flex>
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
px: 1,
|
||||
width: 112,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
{stigma.name}
|
||||
</Box>
|
||||
{/* {stigma.id} */}
|
||||
</Card>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default StigmataListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const stigmataCatalog = loadStigmataCatalog()
|
||||
|
||||
return {
|
||||
props: { stigmataCatalog, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
function filterStigmata(weapon: StigmataCatalogItem) {
|
||||
return true
|
||||
}
|
||||
|
||||
function sortStigmata(a: StigmataCatalogItem, b: StigmataCatalogItem) {
|
||||
let aId = parseInt(a.id)
|
||||
|
||||
let bId = parseInt(b.id)
|
||||
|
||||
return bId - aId
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
import { NextPageContext } from 'next'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import FormattedText from '../../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo, replaceNewLine } from '../../../../lib/v2/data/formatText'
|
||||
import { loadWeaponCatalog, loadWeaponData } from '../../../../lib/v2/server/loadData'
|
||||
import { RootWeaponData } from '../../../../lib/v2/data/types'
|
||||
import { Fragment } from 'react'
|
||||
import { getWeaponTypeLabel } from '../../../../lib/v2/data/text'
|
||||
import WeaponTypeIcon from '../../../../components/v2/WeaponTypeIcon'
|
||||
import WeaponIcon from '../../../../components/v2/WeaponIcon'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface WeaponShowPageProps {
|
||||
rootWeapon: RootWeaponData
|
||||
}
|
||||
|
||||
const WeaponShowPage = ({ rootWeapon }: WeaponShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
const weapon = rootWeapon.weapons[rootWeapon.weapons.length - 1]
|
||||
|
||||
const weaponTypeLabel = getWeaponTypeLabel(weapon.type)
|
||||
const atk = Math.floor(weapon.attackBase + weapon.attackAdd * (weapon.maxLv - 1))
|
||||
const crt = Math.floor(weapon.criticalBase + weapon.criticalAdd * (weapon.maxLv - 1))
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${weapon.name} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${t('weapons-show.weapon')} / ${'⭐'.repeat(
|
||||
weapon.rarity
|
||||
)} / ${weaponTypeLabel} / ATK : ${atk} / CRT : ${crt}`}
|
||||
canonicalHref={`/honkai3rd/v2/weapons/${weapon.id}`}
|
||||
/>
|
||||
<Box p={2}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/v2/weapons', label: t('common.weapons') },
|
||||
{ href: `/honkai3rd/v2/weapons/${weapon.id}`, label: weapon.name }
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as="h1">{weapon.name}</Heading>
|
||||
|
||||
<Box mb={3}>
|
||||
<WeaponIcon key={weapon.id} icon={weapon.icon} rarity={weapon.rarity} />
|
||||
</Box>
|
||||
|
||||
<Card mb={3}>
|
||||
<Box sx={{ p: 1, borderBottom: 'default' }}>{replaceNewLine(weapon.description)}</Box>
|
||||
<Flex sx={{ alignItems: 'center', p: 1, borderBottom: 'default' }}>
|
||||
<WeaponTypeIcon type={weapon.type} />
|
||||
<Box ml={1}>{getWeaponTypeLabel(weapon.type)}</Box>
|
||||
</Flex>
|
||||
<Box sx={{ p: 1 }}>
|
||||
ATK : {atk} / CRT : {crt} (at Max Lv {weapon.maxLv})
|
||||
</Box>
|
||||
</Card>
|
||||
|
||||
<Heading as="h2">Skills</Heading>
|
||||
<Card>
|
||||
{weapon.skills.map(skill => {
|
||||
return (
|
||||
<Fragment key={skill.id}>
|
||||
<Box sx={{ borderBottom: 'default' }}>
|
||||
<Heading
|
||||
as="h3"
|
||||
sx={{
|
||||
p: 1,
|
||||
m: 1
|
||||
}}
|
||||
>
|
||||
{skill.name}
|
||||
</Heading>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
p: 1,
|
||||
borderBottom: 'default',
|
||||
'&:last-child': {
|
||||
borderBottom: 'none'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormattedText>
|
||||
{formatSubSkillInfo({
|
||||
info: skill.info,
|
||||
maxLv: weapon.maxLv,
|
||||
paramBase1: skill.param1,
|
||||
paramBase2: skill.param2,
|
||||
paramBase3: skill.param3,
|
||||
paramAdd1: skill.param1Add,
|
||||
paramAdd2: skill.param2Add,
|
||||
paramAdd3: skill.param3Add
|
||||
})}
|
||||
</FormattedText>
|
||||
</Box>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
{/* <pre>{JSON.stringify(weapon, null, 2)}</pre> */}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default WeaponShowPage
|
||||
|
||||
export async function getStaticProps({ locale, params }: NextPageContext & { params: { weaponId: string } }) {
|
||||
const rootWeapon = loadWeaponData(params.weaponId)
|
||||
|
||||
return {
|
||||
props: { rootWeapon, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const weaponCatalog = loadWeaponCatalog()
|
||||
|
||||
return {
|
||||
paths: weaponCatalog.map(catalogItem => {
|
||||
return {
|
||||
params: { weaponId: catalogItem.id }
|
||||
}
|
||||
}),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Card } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { Flex, Heading, Link } from 'theme-ui'
|
||||
import { loadWeaponCatalog } from '../../../../lib/v2/server/loadData'
|
||||
import { WeaponCatalogItem } from '../../../../lib/v2/data/types'
|
||||
import WeaponIcon from '../../../../components/v2/WeaponIcon'
|
||||
import Head from '../../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../../server/i18n'
|
||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface WeaponListPageProps {
|
||||
weaponCatalog: WeaponCatalogItem[]
|
||||
}
|
||||
|
||||
const WeaponListPage = ({ weaponCatalog }: WeaponListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.weapons')} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={t('weapons-list.description')}
|
||||
canonicalHref={`/honkai3rd/v2/weapons`}
|
||||
/>
|
||||
<Box p={2}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/v2/weapons', label: t('common.weapons') }
|
||||
]}
|
||||
/>
|
||||
<Heading as="h1">{t('common.weapons')}</Heading>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{weaponCatalog
|
||||
.filter(filterWeapons)
|
||||
.sort(sortWeapons)
|
||||
.map(weapon => {
|
||||
return (
|
||||
<Box key={weapon.id} m={1}>
|
||||
<Link href={`/honkai3rd/v2/weapons/${weapon.id}`}>
|
||||
<Card p={1}>
|
||||
<Flex sx={{ justifyContent: 'center' }}>
|
||||
<WeaponIcon icon={weapon.icon} rarity={weapon.maxRarity} />
|
||||
</Flex>
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
px: 1,
|
||||
width: 112,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
{weapon.name}
|
||||
</Box>
|
||||
{/* {weapon.id} */}
|
||||
</Card>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default WeaponListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const weaponCatalog = loadWeaponCatalog()
|
||||
|
||||
return {
|
||||
props: { weaponCatalog, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
function filterWeapons(weapon: WeaponCatalogItem) {
|
||||
// Valid weapons
|
||||
// 24XXX EX Weapons
|
||||
// 21XXX Sprit Weapon
|
||||
// 19XXX Alloy Weapons
|
||||
// 10XXX Regular Weapons
|
||||
|
||||
// Event Weapon?
|
||||
if (weapon.id.startsWith('18') && weapon.id.length === 5) {
|
||||
return false
|
||||
}
|
||||
// Test Data?
|
||||
if (weapon.id.startsWith('1023') && weapon.id.length === 6) {
|
||||
return false
|
||||
}
|
||||
// Unreleased(Number looks good but lacking info)
|
||||
switch (weapon.id) {
|
||||
case '24000': // 2nd relic alpha
|
||||
case '24040': // Removed 7 Thunders
|
||||
case '24034': // PE Temp Lance
|
||||
case '24024': // keqing ex
|
||||
case '20765': // ?
|
||||
case '10243': // No Name
|
||||
case '10219': // ?
|
||||
case '10179': // ?
|
||||
return false
|
||||
}
|
||||
|
||||
// Divine Keys
|
||||
switch (weapon.id) {
|
||||
case '20000': // Taixuan Sword
|
||||
case '10248': // Abyss Flower
|
||||
case '10267': // Eden's star anti entropy
|
||||
case '10263': // 7 Thunders
|
||||
case '10247': // Abyss
|
||||
case '10235': // Fenghuang pistols
|
||||
case '10234': // Fenghuang fists
|
||||
case '10223': // Eden twin stars
|
||||
case '10212': // Pledge of Sakura
|
||||
case '10211': // Pledge of Judah
|
||||
case '10209': // Might of an utu
|
||||
case '10199': // Cleaver of Shamash
|
||||
case '10163': // Shamash pistols
|
||||
// The below don't have duplicated data
|
||||
// case '10180': // Eden's star
|
||||
// case '10169': // Taxiuan fists
|
||||
// case '10158': // Jizo Mitama
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function sortWeapons(a: WeaponCatalogItem, b: WeaponCatalogItem) {
|
||||
let aId = parseInt(a.id)
|
||||
|
||||
const aTypeOrder = aId > 21000 && aId < 22000 ? 2 : aId > 19000 && aId < 20000 ? 1 : 0
|
||||
|
||||
let bId = parseInt(b.id)
|
||||
const bTypeOrder = bId > 21000 && bId < 22000 ? 2 : bId > 19000 && bId < 20000 ? 1 : 0
|
||||
if (aTypeOrder !== bTypeOrder) {
|
||||
return aTypeOrder - bTypeOrder
|
||||
}
|
||||
|
||||
return bId - aId
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex, Text, Paragraph } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import GanttChart from '../../../components/organisms/GanttChart'
|
||||
import {
|
||||
getVersion,
|
||||
listVersionData,
|
||||
} from '../../../server/data/honkai3rd/versions'
|
||||
import { format as formatDate } from 'date-fns'
|
||||
import { getBattlesuitById } from '../../../server/data/honkai3rd/battlesuits'
|
||||
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
||||
import { getWeaponById } from '../../../server/data/honkai3rd/weapons'
|
||||
import ScrollContainer from 'react-indiana-drag-scroll'
|
||||
import { addDateToDateString, getDateString } from '../../../lib/string'
|
||||
import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
|
||||
import { WeaponData } from '../../../lib/honkai3rd/weapons'
|
||||
import { VersionData } from '../../../lib/honkai3rd/versions'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import PageLink from '../../../components/atoms/PageLink'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { useEffect, useState } from 'react'
|
||||
import BossTable from '../../../components/organisms/BossTable'
|
||||
import StigmataSetCard from '../../../components/molecules/StigmataSetCard'
|
||||
import WeaponCard from '../../../components/molecules/WeaponCard'
|
||||
import BattlesuitCard from '../../../components/molecules/BattlesuitCard'
|
||||
import { getStigmataSetBySetId } from '../../../server/data/honkai3rd/stigmata'
|
||||
import { StigmataSet } from '../../../lib/honkai3rd/stigmata'
|
||||
|
||||
interface VersionShowPageProps {
|
||||
versionData: VersionData
|
||||
battlesuits: BattlesuitData[]
|
||||
weapons: WeaponData[]
|
||||
stigmataSets: StigmataSet[]
|
||||
}
|
||||
|
||||
const VersionShowPage = ({
|
||||
versionData,
|
||||
battlesuits,
|
||||
weapons,
|
||||
stigmataSets,
|
||||
}: VersionShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [today, setToday] = useState<Date | null>(null)
|
||||
useEffect(() => {
|
||||
setToday(new Date(getDateString(new Date())))
|
||||
}, [])
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`v${versionData.version} ${versionData.name} - ${t(
|
||||
'common.honkai-3rd'
|
||||
)} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${t('versions.version')} ${
|
||||
versionData.name
|
||||
} / ${t('versions.new-battlesuits')}: ${battlesuits
|
||||
.map((battlesuit) => {
|
||||
return battlesuit.name
|
||||
})
|
||||
.join(',')} / ${t('versions.new-weapons')}: ${weapons
|
||||
.map((weapon) => {
|
||||
return weapon.name
|
||||
})
|
||||
.join(',')}`}
|
||||
canonicalHref={`/honkai3rd/versions/${versionData.version}`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/versions', label: t('common.versions') },
|
||||
{
|
||||
href: `/honkai3rd/versions/${versionData.version}`,
|
||||
label: versionData.version,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Box>
|
||||
<Box mb={2}>
|
||||
{versionData.previousVersion != null && (
|
||||
<PageLink
|
||||
href={`/honkai3rd/versions/${versionData.previousVersion}`}
|
||||
mr={2}
|
||||
>
|
||||
{t('versions.previous')} (v{versionData.previousVersion})
|
||||
</PageLink>
|
||||
)}
|
||||
{versionData.nextVersion != null && (
|
||||
<PageLink href={`/honkai3rd/versions/${versionData.nextVersion}`}>
|
||||
{t('versions.next')} (v{versionData.nextVersion})
|
||||
</PageLink>
|
||||
)}
|
||||
</Box>
|
||||
<Heading as='h1'>
|
||||
v{versionData.version} : {versionData.name}
|
||||
</Heading>
|
||||
<Box mb={4}>
|
||||
{formatDate(new Date(versionData.duration[0]), 'PP')} -{' '}
|
||||
{versionData.duration[1] != null
|
||||
? formatDate(new Date(versionData.duration[1]), 'PP')
|
||||
: ''}
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Heading as='h3' mb={2}>
|
||||
{t('versions.new-battlesuits')}
|
||||
</Heading>
|
||||
<Box mb={2} sx={{ display: 'inline-block' }}>
|
||||
{battlesuits.map((battlesuit) => {
|
||||
return (
|
||||
<BattlesuitCard
|
||||
key={battlesuit.id}
|
||||
battlesuit={battlesuit}
|
||||
size='sm'
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
|
||||
<Heading as='h3' mb={2}>
|
||||
{t('versions.new-weapons')}
|
||||
</Heading>
|
||||
<Box mb={2} sx={{ display: 'inline-block' }}>
|
||||
{weapons.map((weapon) => {
|
||||
return <WeaponCard key={weapon.id} weapon={weapon} size='sm' />
|
||||
})}
|
||||
</Box>
|
||||
|
||||
<Heading as='h3' mb={2}>
|
||||
{t('versions.new-stigmata-sets')}
|
||||
</Heading>
|
||||
<Box mb={2} sx={{ display: 'inline-block' }}>
|
||||
{stigmataSets.map((stigmataSet) => {
|
||||
return (
|
||||
<StigmataSetCard
|
||||
key={stigmataSet.id}
|
||||
stigmataSet={stigmataSet}
|
||||
size='sm'
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Heading as='h3' mb={2}>
|
||||
{t('versions.weekly-bosses')}
|
||||
</Heading>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<BossTable versionData={versionData} today={today} />
|
||||
</Box>
|
||||
|
||||
<Heading as='h3' mb={2}>
|
||||
{t('versions.supply-events')}
|
||||
</Heading>
|
||||
<Box mb={2}>
|
||||
<ScrollContainer vertical={false}>
|
||||
<GanttChart
|
||||
items={versionData.supplyEvents.map((supplyEventData) => {
|
||||
const imgSrc = getIconSrcFromItem(supplyEventData.featured[0])
|
||||
return {
|
||||
id: `${supplyEventData.duration[0]}/${supplyEventData.duration[1]}/${supplyEventData.name}`,
|
||||
label: (
|
||||
<Flex sx={{ alignItems: 'center' }}>
|
||||
{!supplyEventData.verified && (
|
||||
<Text sx={{ flexShrink: 0 }}>❓</Text>
|
||||
)}
|
||||
{imgSrc != null && (
|
||||
<SquareImageBox
|
||||
size={20}
|
||||
src={imgSrc}
|
||||
alt={supplyEventData.featured[0].id}
|
||||
mr={1}
|
||||
/>
|
||||
)}
|
||||
<Text>{supplyEventData.name}</Text>
|
||||
</Flex>
|
||||
),
|
||||
duration: supplyEventData.duration,
|
||||
row: supplyEventData.track,
|
||||
}
|
||||
})}
|
||||
today={today}
|
||||
startDate={versionData.duration[0]}
|
||||
endDate={
|
||||
versionData.duration[1] != null
|
||||
? versionData.duration[1]
|
||||
: addDateToDateString(versionData.duration[0], {
|
||||
weeks: 6,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</ScrollContainer>
|
||||
</Box>
|
||||
<Paragraph mb={4}>{t('versions.supply-events-disclaimer')}</Paragraph>
|
||||
</Box>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default VersionShowPage
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
locale,
|
||||
}: NextPageContext & { params: { versionId: string } }) {
|
||||
const versionData = getVersion(params.versionId, locale)!
|
||||
|
||||
const battlesuits = versionData.newBattlesuits.map((battlesuitId) => {
|
||||
return getBattlesuitById(battlesuitId, locale)
|
||||
})
|
||||
const weapons = versionData.newWeapons.map((weaponId) => {
|
||||
return getWeaponById(weaponId, locale)
|
||||
})
|
||||
const stigmataSets = versionData.newStigmataSets.map((stigmataSetId) => {
|
||||
return getStigmataSetBySetId(stigmataSetId, locale)
|
||||
})
|
||||
|
||||
return {
|
||||
props: {
|
||||
versionData,
|
||||
battlesuits,
|
||||
weapons,
|
||||
stigmataSets,
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
listVersionData().map((versionData) => {
|
||||
return {
|
||||
params: {
|
||||
versionId: versionData.version.toString(),
|
||||
},
|
||||
}
|
||||
})
|
||||
),
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
|
||||
function getIconSrcFromItem(item: { type: string; id: string }): string | null {
|
||||
switch (item.type) {
|
||||
case 'battlesuit':
|
||||
return `${assetsBucketBaseUrl}/honkai3rd/battlesuits/portrait-${item.id}.png`
|
||||
case 'weapon':
|
||||
return `${assetsBucketBaseUrl}/honkai3rd/weapons/${item.id}.png`
|
||||
case 'stigmata':
|
||||
return `${assetsBucketBaseUrl}/honkai3rd/stigmata/icon-${item.id}.png`
|
||||
case 'elf':
|
||||
return `${assetsBucketBaseUrl}/honkai3rd/elfs/icon-${item.id}.png`
|
||||
case 'outfit':
|
||||
return `${assetsBucketBaseUrl}/honkai3rd/outfits/portrait-${item.id}.webp`
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Link } from '@theme-ui/components'
|
||||
import NextLink from 'next/link'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { listVersionData } from '../../../server/data/honkai3rd/versions'
|
||||
import { format as formatDate } from 'date-fns'
|
||||
import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
|
||||
import { WeaponData } from '../../../lib/honkai3rd/weapons'
|
||||
import { VersionData } from '../../../lib/honkai3rd/versions'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { NextPageContext } from 'next'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { StigmataSet } from '../../../lib/honkai3rd/stigmata'
|
||||
|
||||
interface VersionIndexPageProps {
|
||||
versionDataList: VersionData[]
|
||||
currentVersionData: VersionData
|
||||
currentVersionNewBattlesuits: BattlesuitData[]
|
||||
currentVersionNewWeapons: WeaponData[]
|
||||
currentVersionNewStigmataSets: StigmataSet[]
|
||||
}
|
||||
|
||||
const VersionIndexPage = ({ versionDataList }: VersionIndexPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Head
|
||||
title={`${t('common.versions')} - ${t('common.honkai-3rd')} - ${t(
|
||||
'common.abyss-lab'
|
||||
)}`}
|
||||
description={t('versions.list-page-description')}
|
||||
canonicalHref={`/honkai3rd/versions`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/versions', label: t('common.versions') },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as='h1' mb={3}>
|
||||
{t('versions.versions')}
|
||||
</Heading>
|
||||
<Box>
|
||||
{versionDataList.map((versionData) => {
|
||||
return (
|
||||
<Box key={versionData.version} mb={2}>
|
||||
<Heading as='h3'>
|
||||
<NextLink
|
||||
href={`/honkai3rd/versions/${versionData.version}`}
|
||||
passHref
|
||||
>
|
||||
<Link>
|
||||
{versionData.version} : {versionData.name} (
|
||||
{formatDate(new Date(versionData.duration[0]), 'PP')} -{' '}
|
||||
{versionData.duration[1] != null
|
||||
? formatDate(new Date(versionData.duration[1]), 'PP')
|
||||
: ''}
|
||||
)
|
||||
</Link>
|
||||
</NextLink>
|
||||
</Heading>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
return {
|
||||
props: {
|
||||
versionDataList: listVersionData(locale),
|
||||
...(await getI18NProps(locale)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default VersionIndexPage
|
||||
@@ -1,32 +1,30 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Flex, Box, Card, Heading, Paragraph } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { weaponCategories, WeaponData } from '../../../lib/honkai3rd/weapons'
|
||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
||||
import { getWeaponById, getWeaponMapByIds, listWeapons } from '../../../server/data/honkai3rd/weapons'
|
||||
import { useTranslation } from '../../../lib/i18n'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import PageLink from '../../../components/atoms/PageLink'
|
||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||
import FormattedText from '../../../components/v2/FormattedText'
|
||||
import { formatSubSkillInfo, replaceNewLine } from '../../../lib/v2/data/formatText'
|
||||
import { loadWeaponCatalog, loadWeaponData } from '../../../lib/v2/server/loadData'
|
||||
import { RootWeaponData } from '../../../lib/v2/data/types'
|
||||
import { Fragment } from 'react'
|
||||
import { getWeaponTypeLabel } from '../../../lib/v2/data/text'
|
||||
import WeaponTypeIcon from '../../../components/v2/WeaponTypeIcon'
|
||||
import WeaponIcon from '../../../components/v2/WeaponIcon'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
import { getBattlesuitMapByIds } from '../../../server/data/honkai3rd/battlesuits'
|
||||
import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
|
||||
import BattlesuitCard from '../../../components/molecules/BattlesuitCard'
|
||||
import WeaponCard from '../../../components/molecules/WeaponCard'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface WeaponShowPageProps {
|
||||
weapon: WeaponData
|
||||
battlesuitMap: { [key: string]: BattlesuitData }
|
||||
weaponMap: { [key: string]: WeaponData }
|
||||
rootWeapon: RootWeaponData
|
||||
}
|
||||
|
||||
const WeaponShowPage = ({ weapon, battlesuitMap, weaponMap }: WeaponShowPageProps) => {
|
||||
const WeaponShowPage = ({ rootWeapon }: WeaponShowPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
const weapon = rootWeapon.weapons[rootWeapon.weapons.length - 1]
|
||||
|
||||
const weaponCategoryName = t(`weapons-show.${weapon.category}`)
|
||||
const weaponCategory = weaponCategories.find(category => category.value === weapon.category)
|
||||
const weaponTypeLabel = getWeaponTypeLabel(weapon.type)
|
||||
const atk = Math.floor(weapon.attackBase + weapon.attackAdd * (weapon.maxLv - 1))
|
||||
const crt = Math.floor(weapon.criticalBase + weapon.criticalAdd * (weapon.maxLv - 1))
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
@@ -34,112 +32,78 @@ const WeaponShowPage = ({ weapon, battlesuitMap, weaponMap }: WeaponShowPageProp
|
||||
title={`${weapon.name} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={`${t('common.honkai-3rd')} ${t('weapons-show.weapon')} / ${'⭐'.repeat(
|
||||
weapon.rarity
|
||||
)} / ${weaponCategoryName} / ATK : ${weapon.atk} / CRT : ${weapon.crt}`}
|
||||
canonicalHref={`/honkai3rd/weapons/${weapon.id}`}
|
||||
)} / ${weaponTypeLabel} / ATK : ${atk} / CRT : ${crt}`}
|
||||
canonicalHref={`/honkai3rd/v2/weapons/${weapon.id}`}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Box p={2}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/weapons', label: t('common.weapons') },
|
||||
{
|
||||
href: `/honkai3rd/weapons/${weapon.id}`,
|
||||
label: weapon.name
|
||||
}
|
||||
{ href: '/honkai3rd/v2/weapons', label: t('common.weapons') },
|
||||
{ href: `/honkai3rd/v2/weapons/${weapon.id}`, label: weapon.name }
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as="h1">{weapon.name}</Heading>
|
||||
|
||||
<Box mb={3}>
|
||||
<SquareImageBox
|
||||
size={100}
|
||||
alt={weapon.name}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/weapons/${weapon.id}.png`}
|
||||
/>
|
||||
<WeaponIcon key={weapon.id} icon={weapon.icon} rarity={weapon.rarity} />
|
||||
</Box>
|
||||
|
||||
<Card mb={3}>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
<PageLink
|
||||
href={{
|
||||
pathname: '/honkai3rd/weapons',
|
||||
query: { category: weapon.category }
|
||||
}}
|
||||
>
|
||||
<Flex>
|
||||
{weaponCategory != null && (
|
||||
<SquareImageBox
|
||||
size={30}
|
||||
src={`${assetsBucketBaseUrl}/honkai3rd/${weaponCategory.icon}.png`}
|
||||
alt={weaponCategoryName}
|
||||
mr={1}
|
||||
/>
|
||||
)}
|
||||
{weaponCategoryName}
|
||||
</Flex>
|
||||
</PageLink>
|
||||
<Box sx={{ p: 1, borderBottom: 'default' }}>{replaceNewLine(weapon.description)}</Box>
|
||||
<Flex sx={{ alignItems: 'center', p: 1, borderBottom: 'default' }}>
|
||||
<WeaponTypeIcon type={weapon.type} />
|
||||
<Box ml={1}>{getWeaponTypeLabel(weapon.type)}</Box>
|
||||
</Flex>
|
||||
<Box sx={{ p: 1 }}>
|
||||
ATK : {atk} / CRT : {crt} (at Max Lv {weapon.maxLv})
|
||||
</Box>
|
||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
||||
{'⭐'.repeat(weapon.rarity)}
|
||||
</Box>
|
||||
<Box p={2}>
|
||||
ATK : {weapon.atk} / CRT : {weapon.crt}
|
||||
</Box>
|
||||
{weapon.battlesuits != null && weapon.battlesuits.length > 0 && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as="h4">{t('weapons-show.best-on')}</Heading>
|
||||
{weapon.battlesuits.map(({ id: battlesuitId }) => {
|
||||
return <BattlesuitCard key={battlesuitId} size="sm" battlesuit={battlesuitMap[battlesuitId]} />
|
||||
})}
|
||||
</Box>
|
||||
)}
|
||||
{weapon.priWeapon != null && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as="h4">{t('weapons-show.pri-weapon')}</Heading>
|
||||
<WeaponCard size="sm" weapon={weaponMap[weapon.priWeapon]} />
|
||||
</Box>
|
||||
)}
|
||||
{weapon.originalWeapons != null && weapon.originalWeapons.length > 0 && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as="h4">{t('weapons-show.original-weapon')}</Heading>
|
||||
{weapon.originalWeapons.map(originalWeaponId => {
|
||||
return <WeaponCard key={originalWeaponId} size="sm" weapon={weaponMap[originalWeaponId]} />
|
||||
})}
|
||||
</Box>
|
||||
)}
|
||||
{/* {weapon.sources != null && (
|
||||
<Box sx={{ p: 2, borderTop: 'default' }}>
|
||||
<Heading as='h4'>{t('weapons-show.sources')}</Heading>
|
||||
{weapon.sources
|
||||
.sort((a, b) => a.type.localeCompare(b.type))
|
||||
.map((source) => {
|
||||
return <SourceCard key={source.type} source={source} />
|
||||
})}
|
||||
</Box>
|
||||
)} */}
|
||||
</Card>
|
||||
|
||||
<Box>
|
||||
<Heading as="h2">Skills</Heading>
|
||||
<Card>
|
||||
{weapon.skills.map(skill => {
|
||||
return (
|
||||
<Card key={skill.name} mb={3}>
|
||||
<Heading as="h3" p={2} m={0} sx={{ borderBottom: 'default' }}>
|
||||
{skill.name}
|
||||
</Heading>
|
||||
<Paragraph
|
||||
p={2}
|
||||
<Fragment key={skill.id}>
|
||||
<Box sx={{ borderBottom: 'default' }}>
|
||||
<Heading
|
||||
as="h3"
|
||||
sx={{
|
||||
p: 1,
|
||||
m: 1
|
||||
}}
|
||||
>
|
||||
{skill.name}
|
||||
</Heading>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap'
|
||||
p: 1,
|
||||
borderBottom: 'default',
|
||||
'&:last-child': {
|
||||
borderBottom: 'none'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{skill.description}
|
||||
</Paragraph>
|
||||
</Card>
|
||||
<FormattedText>
|
||||
{formatSubSkillInfo({
|
||||
info: skill.info,
|
||||
maxLv: weapon.maxLv,
|
||||
paramBase1: skill.param1,
|
||||
paramBase2: skill.param2,
|
||||
paramBase3: skill.param3,
|
||||
paramAdd1: skill.param1Add,
|
||||
paramAdd2: skill.param2Add,
|
||||
paramAdd3: skill.param3Add
|
||||
})}
|
||||
</FormattedText>
|
||||
</Box>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</Card>
|
||||
{/* <pre>{JSON.stringify(weapon, null, 2)}</pre> */}
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
@@ -147,43 +111,23 @@ const WeaponShowPage = ({ weapon, battlesuitMap, weaponMap }: WeaponShowPageProp
|
||||
|
||||
export default WeaponShowPage
|
||||
|
||||
export async function getStaticProps({ params, locale }: NextPageContext & { params: { weaponId: string } }) {
|
||||
const weapon = getWeaponById(params.weaponId, locale)
|
||||
const battlesuitMap = getBattlesuitMapByIds(
|
||||
weapon != null && weapon.battlesuits != null ? weapon.battlesuits.map(({ id }) => id) : [],
|
||||
locale
|
||||
)
|
||||
|
||||
const weaponIds = []
|
||||
if (weapon != null) {
|
||||
if (weapon.priWeapon != null) {
|
||||
weaponIds.push(weapon.priWeapon)
|
||||
}
|
||||
if (weapon.originalWeapons != null) {
|
||||
weaponIds.push(...weapon.originalWeapons)
|
||||
}
|
||||
}
|
||||
const weaponMap = getWeaponMapByIds(weaponIds, locale)
|
||||
export async function getStaticProps({ locale, params }: NextPageContext & { params: { weaponId: string } }) {
|
||||
const rootWeapon = loadWeaponData(params.weaponId)
|
||||
|
||||
return {
|
||||
props: {
|
||||
weapon,
|
||||
battlesuitMap,
|
||||
weaponMap,
|
||||
...(await getI18NProps(locale))
|
||||
}
|
||||
props: { rootWeapon, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const weaponCatalog = loadWeaponCatalog()
|
||||
|
||||
return {
|
||||
paths: generateI18NPaths(
|
||||
listWeapons().map(weapon => {
|
||||
return {
|
||||
params: { weaponId: weapon.id }
|
||||
}
|
||||
})
|
||||
),
|
||||
paths: weaponCatalog.map(catalogItem => {
|
||||
return {
|
||||
params: { weaponId: catalogItem.id }
|
||||
}
|
||||
}),
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,68 @@
|
||||
/** @jsxImportSource theme-ui */
|
||||
import { Box, Heading, Flex } from '@theme-ui/components'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
import { listWeapons } from '../../../server/data/honkai3rd/weapons'
|
||||
import { pick } from 'ramda'
|
||||
import { useMemo } from 'react'
|
||||
import FilterButton from '../../../components/atoms/FilterButton'
|
||||
import { useRouter } from 'next/router'
|
||||
import { weaponCategories, WeaponData } from '../../../lib/honkai3rd/weapons'
|
||||
import WeaponCard from '../../../components/molecules/WeaponCard'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import { Box, Card } from '@theme-ui/components'
|
||||
import { NextPageContext } from 'next'
|
||||
import { useTranslation, translate } from '../../../lib/i18n'
|
||||
import { Flex, Heading, Link } from 'theme-ui'
|
||||
import { loadWeaponCatalog } from '../../../lib/v2/server/loadData'
|
||||
import { WeaponCatalogItem } from '../../../lib/v2/data/types'
|
||||
import WeaponIcon from '../../../components/v2/WeaponIcon'
|
||||
import Head from '../../../components/atoms/Head'
|
||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||
|
||||
type WeaponListItemData = Pick<WeaponData, 'id' | 'name' | 'rarity' | 'category'>
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { getI18NProps } from '../../../server/i18n'
|
||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||
|
||||
interface WeaponListPageProps {
|
||||
weaponDataList: WeaponListItemData[]
|
||||
weaponCatalog: WeaponCatalogItem[]
|
||||
}
|
||||
|
||||
const weaponFilterOptions = [{ value: 'all', label: 'All', krLabel: '전체', icon: undefined }, ...weaponCategories]
|
||||
|
||||
const WeaponListPage = ({ weaponDataList }: WeaponListPageProps) => {
|
||||
const { query, locale } = useRouter()
|
||||
const WeaponListPage = ({ weaponCatalog }: WeaponListPageProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const categoryFilter = useMemo(() => {
|
||||
if (query.category == null) {
|
||||
return 'all'
|
||||
}
|
||||
|
||||
return typeof query.category === 'string' ? query.category : query.category[0]
|
||||
}, [query])
|
||||
|
||||
const weaponList = useMemo(() => {
|
||||
return weaponDataList.map(weapon => {
|
||||
const hidden = isWeaponHidden(weapon, categoryFilter)
|
||||
return <WeaponCard key={weapon.id} weapon={weapon} hidden={hidden} />
|
||||
})
|
||||
}, [weaponDataList, categoryFilter])
|
||||
|
||||
return (
|
||||
<Honkai3rdLayout>
|
||||
<Box>
|
||||
<Head
|
||||
title={`${t('common.weapons')} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={t('weapons-list.description')}
|
||||
canonicalHref={`/honkai3rd/weapons`}
|
||||
<Head
|
||||
title={`${t('common.weapons')} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||
description={t('weapons-list.description')}
|
||||
canonicalHref={`/honkai3rd/v2/weapons`}
|
||||
/>
|
||||
<Box p={2}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/v2/weapons', label: t('common.weapons') }
|
||||
]}
|
||||
/>
|
||||
|
||||
<Box p={3}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||
{ href: '/honkai3rd/weapons', label: t('common.weapons') }
|
||||
]}
|
||||
/>
|
||||
|
||||
<Heading as="h1">{t('weapons-list.weapons')}</Heading>
|
||||
<Box>
|
||||
<Heading as="h3">{t('weapons-list.filter-by-category')}</Heading>
|
||||
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
|
||||
{weaponFilterOptions.map(({ value, label, krLabel, icon }) => {
|
||||
return (
|
||||
<FilterButton
|
||||
key={value}
|
||||
href={`?category=${value}`}
|
||||
active={value === categoryFilter}
|
||||
icon={icon}
|
||||
label={translate(locale, { 'ko-KR': krLabel }, label)}
|
||||
m={1}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
<Flex
|
||||
sx={{
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around'
|
||||
}}
|
||||
>
|
||||
{weaponList}
|
||||
</Flex>
|
||||
</Box>
|
||||
<Heading as="h1">{t('common.weapons')}</Heading>
|
||||
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||
{weaponCatalog
|
||||
.filter(filterWeapons)
|
||||
.sort(sortWeapons)
|
||||
.map(weapon => {
|
||||
return (
|
||||
<Box key={weapon.id} m={1}>
|
||||
<Link href={`/honkai3rd/v2/weapons/${weapon.id}`}>
|
||||
<Card p={1}>
|
||||
<Flex sx={{ justifyContent: 'center' }}>
|
||||
<WeaponIcon icon={weapon.icon} rarity={weapon.maxRarity} />
|
||||
</Flex>
|
||||
<Box
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
px: 1,
|
||||
width: 112,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
{weapon.name}
|
||||
</Box>
|
||||
{/* {weapon.id} */}
|
||||
</Card>
|
||||
</Link>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Honkai3rdLayout>
|
||||
)
|
||||
@@ -93,32 +71,76 @@ const WeaponListPage = ({ weaponDataList }: WeaponListPageProps) => {
|
||||
export default WeaponListPage
|
||||
|
||||
export async function getStaticProps({ locale }: NextPageContext) {
|
||||
const weaponCatalog = loadWeaponCatalog()
|
||||
|
||||
return {
|
||||
props: {
|
||||
weaponDataList: listWeapons(locale).map(weapon => {
|
||||
return pick(['name', 'id', 'rarity', 'category'], weapon)
|
||||
}),
|
||||
...(await getI18NProps(locale))
|
||||
}
|
||||
props: { weaponCatalog, ...(await getI18NProps(locale)) }
|
||||
}
|
||||
}
|
||||
|
||||
function isWeaponHidden(weapon: WeaponListItemData, filter: string): boolean {
|
||||
switch (filter) {
|
||||
case 'pistol':
|
||||
case 'katana':
|
||||
case 'cannon':
|
||||
case 'greatsword':
|
||||
case 'cross':
|
||||
case 'gauntlet':
|
||||
case 'scythe':
|
||||
case 'lance':
|
||||
case 'bow':
|
||||
case 'chakram':
|
||||
case 'javelin':
|
||||
return weapon.category !== filter
|
||||
default:
|
||||
case 'all':
|
||||
function filterWeapons(weapon: WeaponCatalogItem) {
|
||||
// Valid weapons
|
||||
// 24XXX EX Weapons
|
||||
// 21XXX Sprit Weapon
|
||||
// 19XXX Alloy Weapons
|
||||
// 10XXX Regular Weapons
|
||||
|
||||
// Event Weapon?
|
||||
if (weapon.id.startsWith('18') && weapon.id.length === 5) {
|
||||
return false
|
||||
}
|
||||
// Test Data?
|
||||
if (weapon.id.startsWith('1023') && weapon.id.length === 6) {
|
||||
return false
|
||||
}
|
||||
// Unreleased(Number looks good but lacking info)
|
||||
switch (weapon.id) {
|
||||
case '24000': // 2nd relic alpha
|
||||
case '24040': // Removed 7 Thunders
|
||||
case '24034': // PE Temp Lance
|
||||
case '24024': // keqing ex
|
||||
case '20765': // ?
|
||||
case '10243': // No Name
|
||||
case '10219': // ?
|
||||
case '10179': // ?
|
||||
return false
|
||||
}
|
||||
|
||||
// Divine Keys
|
||||
switch (weapon.id) {
|
||||
case '20000': // Taixuan Sword
|
||||
case '10248': // Abyss Flower
|
||||
case '10267': // Eden's star anti entropy
|
||||
case '10263': // 7 Thunders
|
||||
case '10247': // Abyss
|
||||
case '10235': // Fenghuang pistols
|
||||
case '10234': // Fenghuang fists
|
||||
case '10223': // Eden twin stars
|
||||
case '10212': // Pledge of Sakura
|
||||
case '10211': // Pledge of Judah
|
||||
case '10209': // Might of an utu
|
||||
case '10199': // Cleaver of Shamash
|
||||
case '10163': // Shamash pistols
|
||||
// The below don't have duplicated data
|
||||
// case '10180': // Eden's star
|
||||
// case '10169': // Taxiuan fists
|
||||
// case '10158': // Jizo Mitama
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function sortWeapons(a: WeaponCatalogItem, b: WeaponCatalogItem) {
|
||||
let aId = parseInt(a.id)
|
||||
|
||||
const aTypeOrder = aId > 21000 && aId < 22000 ? 2 : aId > 19000 && aId < 20000 ? 1 : 0
|
||||
|
||||
let bId = parseInt(b.id)
|
||||
const bTypeOrder = bId > 21000 && bId < 22000 ? 2 : bId > 19000 && bId < 20000 ? 1 : 0
|
||||
if (aTypeOrder !== bTypeOrder) {
|
||||
return aTypeOrder - bTypeOrder
|
||||
}
|
||||
|
||||
return bId - aId
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user