Remove legacy pages
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
// const YAML = require('yaml')
|
||||||
|
// const fs = require('fs')
|
||||||
|
// const path = require('path')
|
||||||
|
|
||||||
|
// const rawData = fs.readFileSync(path.join(process.cwd(), 'data/honkai3rd/battlesuits.yaml')).toString()
|
||||||
|
module.exports = [
|
||||||
|
['dw', 3401],
|
||||||
|
['ta', 3501],
|
||||||
|
['vq', 3301],
|
||||||
|
['hof', 106],
|
||||||
|
['hoo', 206],
|
||||||
|
['hotr', 317],
|
||||||
|
['cn', 3201],
|
||||||
|
['jk', 3101],
|
||||||
|
['hoh', 2202],
|
||||||
|
['vill-v', 3001],
|
||||||
|
['griseo', 2901],
|
||||||
|
['aponia', 2701],
|
||||||
|
['eden', 2801],
|
||||||
|
['rc', 2601],
|
||||||
|
['pe', 804],
|
||||||
|
['spa', 706],
|
||||||
|
['sw', 315],
|
||||||
|
['sns', 2501],
|
||||||
|
['io', 2301],
|
||||||
|
['ma', 2401],
|
||||||
|
['mpe', 2201],
|
||||||
|
['hfs', 105],
|
||||||
|
['pv', 2101],
|
||||||
|
['nyx', 713],
|
||||||
|
['hb', 314],
|
||||||
|
['hos', 612],
|
||||||
|
['bh', 901],
|
||||||
|
['da', 803],
|
||||||
|
// ['ft'],
|
||||||
|
// ['ds'],
|
||||||
|
['fr', 705],
|
||||||
|
['hot', 205],
|
||||||
|
['sa', 506],
|
||||||
|
['bke', 802],
|
||||||
|
['vg', 801],
|
||||||
|
['ae', 611],
|
||||||
|
['kasumi', 214],
|
||||||
|
// ['hf', ],
|
||||||
|
['sn', 712],
|
||||||
|
// ['tp', ],
|
||||||
|
['hor', 313],
|
||||||
|
// ['vd', ],
|
||||||
|
['sp', 711],
|
||||||
|
['bb', 421],
|
||||||
|
['mc', 422],
|
||||||
|
// ['dk', ],
|
||||||
|
['aka', 704],
|
||||||
|
// ['stfu', ],
|
||||||
|
['pi', 702],
|
||||||
|
['sj', 114],
|
||||||
|
['ur', 703],
|
||||||
|
['vke', 412],
|
||||||
|
['hov', 113],
|
||||||
|
['kriegs', 411],
|
||||||
|
['ns', 603],
|
||||||
|
['6s', 111],
|
||||||
|
['lk', 511],
|
||||||
|
['px', 604],
|
||||||
|
['sk', 602],
|
||||||
|
['va', 601],
|
||||||
|
['ch', 504],
|
||||||
|
['ri', 112],
|
||||||
|
['bn', 312],
|
||||||
|
['sr', 503],
|
||||||
|
['wd', 311],
|
||||||
|
['vp', 501],
|
||||||
|
['ve', 502],
|
||||||
|
['bs', 403],
|
||||||
|
['br', 404],
|
||||||
|
['ci', 201],
|
||||||
|
['db', 304],
|
||||||
|
['dp', 104],
|
||||||
|
['fs', 213],
|
||||||
|
['meme', 212],
|
||||||
|
['miko', 211],
|
||||||
|
['km', 103],
|
||||||
|
['le', 204],
|
||||||
|
['sf', 402],
|
||||||
|
['sd', 202],
|
||||||
|
['ss', 303],
|
||||||
|
['vb', 203],
|
||||||
|
['vc', 301],
|
||||||
|
['vr', 102],
|
||||||
|
['vt', 401],
|
||||||
|
['wc', 101],
|
||||||
|
['ya', 302]
|
||||||
|
]
|
||||||
+38
-34
@@ -1,98 +1,102 @@
|
|||||||
const { i18n } = require('./next-i18next.config')
|
const { i18n } = require('./next-i18next.config')
|
||||||
|
const legacyRedirects = require('./legacy-redirects.js')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
async redirects() {
|
async redirects() {
|
||||||
return [
|
return [
|
||||||
|
...legacyRedirects.map(([source, dest]) => {
|
||||||
|
console.log(source, dest)
|
||||||
|
return {
|
||||||
|
source: `/honkai3rd/battlesuits/${source}`,
|
||||||
|
destination: `/honkai3rd/battlesuits/${dest}`,
|
||||||
|
permanent: false
|
||||||
|
}
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/elysia-flawless',
|
source: '/honkai3rd/stigmata/elysia-flawless',
|
||||||
destination: '/honkai3rd/stigmata/elysia-pristine',
|
destination: '/honkai3rd/stigmata/elysia-pristine',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/elysia-flawless-top',
|
source: '/honkai3rd/stigmata/elysia-flawless-top',
|
||||||
destination: '/honkai3rd/stigmata/elysia-pristine-top',
|
destination: '/honkai3rd/stigmata/elysia-pristine-top',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/elysia-flawless-mid',
|
source: '/honkai3rd/stigmata/elysia-flawless-mid',
|
||||||
destination: '/honkai3rd/stigmata/elysia-pristine-mid',
|
destination: '/honkai3rd/stigmata/elysia-pristine-mid',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/elysia-flawless-bot',
|
source: '/honkai3rd/stigmata/elysia-flawless-bot',
|
||||||
destination: '/honkai3rd/stigmata/elysia-pristine-bot',
|
destination: '/honkai3rd/stigmata/elysia-pristine-bot',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
|
||||||
{
|
|
||||||
source: '/honkai3rd/stigmata/elysia-flawless',
|
|
||||||
destination: '/honkai3rd/stigmata/bianka-theatre',
|
|
||||||
permanent: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/bianka-stage-top',
|
source: '/honkai3rd/stigmata/bianka-stage-top',
|
||||||
destination: '/honkai3rd/stigmata/bianka-theatre-top',
|
destination: '/honkai3rd/stigmata/bianka-theatre-top',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/bianka-stage-mid',
|
source: '/honkai3rd/stigmata/bianka-stage-mid',
|
||||||
destination: '/honkai3rd/stigmata/bianka-theatre-mid',
|
destination: '/honkai3rd/stigmata/bianka-theatre-mid',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/stigmata/bianka-stage-bot',
|
source: '/honkai3rd/stigmata/bianka-stage-bot',
|
||||||
destination: '/honkai3rd/stigmata/bianka-theatre-bot',
|
destination: '/honkai3rd/stigmata/bianka-theatre-bot',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/elfs/hsd',
|
source: '/honkai3rd/elfs/hsd',
|
||||||
destination: '/honkai3rd/elfs/bd',
|
destination: '/honkai3rd/elfs/bd',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/dream-of-the-past',
|
source: '/honkai3rd/weapons/dream-of-the-past',
|
||||||
destination: '/honkai3rd/weapons/purana-phantasma',
|
destination: '/honkai3rd/weapons/purana-phantasma',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/dream-of-the-past-eyes-of-the-night',
|
source: '/honkai3rd/weapons/dream-of-the-past-eyes-of-the-night',
|
||||||
destination: '/honkai3rd/weapons/purana-phantasma-nighteye',
|
destination: '/honkai3rd/weapons/purana-phantasma-nighteye',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/dark-meteorite-golden-scale',
|
source: '/honkai3rd/weapons/dark-meteorite-golden-scale',
|
||||||
destination: '/honkai3rd/weapons/gilded-librae',
|
destination: '/honkai3rd/weapons/gilded-librae',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/azure-flare',
|
source: '/honkai3rd/weapons/azure-flare',
|
||||||
destination: '/honkai3rd/weapons/cerulean-flare',
|
destination: '/honkai3rd/weapons/cerulean-flare',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/battlesuits/pardofelis',
|
source: '/honkai3rd/battlesuits/pardofelis',
|
||||||
destination: '/honkai3rd/battlesuits/rc',
|
destination: '/honkai3rd/battlesuits/rc',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/prisoner-of-the-past',
|
source: '/honkai3rd/weapons/prisoner-of-the-past',
|
||||||
destination: '/honkai3rd/weapons/lost-conviction',
|
destination: '/honkai3rd/weapons/lost-conviction',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/prisoner-of-the-past-deed-of-fate',
|
source: '/honkai3rd/weapons/prisoner-of-the-past-deed-of-fate',
|
||||||
destination: '/honkai3rd/weapons/lost-conviction-damnation',
|
destination: '/honkai3rd/weapons/lost-conviction-damnation',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/weapons/beautiful-poem-of-the-past',
|
source: '/honkai3rd/weapons/beautiful-poem-of-the-past',
|
||||||
destination: '/honkai3rd/weapons/echo-of-paradise',
|
destination: '/honkai3rd/weapons/echo-of-paradise',
|
||||||
permanent: true,
|
permanent: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/novels/ae/index.html',
|
source: '/novels/ae/index.html',
|
||||||
destination: '/honkai3rd/novels/ae',
|
destination: '/honkai3rd/novels/ae',
|
||||||
permanent: false,
|
permanent: false
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
@@ -100,46 +104,46 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
source: '/ko-KR/honkai3rd/novels/ae',
|
source: '/ko-KR/honkai3rd/novels/ae',
|
||||||
destination: '/novels/ae/ko-KR/index.html',
|
destination: '/novels/ae/ko-KR/index.html',
|
||||||
locale: false,
|
locale: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/en-US/honkai3rd/novels/ae',
|
source: '/en-US/honkai3rd/novels/ae',
|
||||||
destination: '/novels/ae/en-US/index.html',
|
destination: '/novels/ae/en-US/index.html',
|
||||||
locale: false,
|
locale: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/novels/ae',
|
source: '/honkai3rd/novels/ae',
|
||||||
destination: '/novels/ae/en-US/index.html',
|
destination: '/novels/ae/en-US/index.html'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/ko-KR/honkai3rd/novels/duriduri',
|
source: '/ko-KR/honkai3rd/novels/duriduri',
|
||||||
destination: '/novels/duriduri/ko-KR/index.html',
|
destination: '/novels/duriduri/ko-KR/index.html',
|
||||||
locale: false,
|
locale: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/en-US/honkai3rd/novels/duriduri',
|
source: '/en-US/honkai3rd/novels/duriduri',
|
||||||
destination: '/novels/duriduri/en-US/index.html',
|
destination: '/novels/duriduri/en-US/index.html',
|
||||||
locale: false,
|
locale: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/novels/duriduri',
|
source: '/honkai3rd/novels/duriduri',
|
||||||
destination: '/novels/duriduri/en-US/index.html',
|
destination: '/novels/duriduri/en-US/index.html'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/ko-KR/honkai3rd/novels/7s',
|
source: '/ko-KR/honkai3rd/novels/7s',
|
||||||
destination: '/novels/7s/ko-KR/index.html',
|
destination: '/novels/7s/ko-KR/index.html',
|
||||||
locale: false,
|
locale: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/en-US/honkai3rd/novels/7s',
|
source: '/en-US/honkai3rd/novels/7s',
|
||||||
destination: '/novels/7s/en-US/index.html',
|
destination: '/novels/7s/en-US/index.html',
|
||||||
locale: false,
|
locale: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: '/honkai3rd/novels/7s',
|
source: '/honkai3rd/novels/7s',
|
||||||
destination: '/novels/7s/en-US/index.html',
|
destination: '/novels/7s/en-US/index.html'
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
i18n,
|
i18n
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,213 +1,162 @@
|
|||||||
/** @jsxImportSource theme-ui */
|
|
||||||
import { Box, Card, Flex, Heading, Paragraph, Text, Image } from '@theme-ui/components'
|
|
||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import React from 'react'
|
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||||
import BattlesuitFeatureLabel from '../../../components/atoms/BattlesuitFeatureLabel'
|
import AttributeIcon from '../../../components/v2/AttributeIcon'
|
||||||
import BattlesuitRankIcon from '../../../components/atoms/BattlesuitRankIcon'
|
import AvatarFigureImage from '../../../components/v2/AvatarFigureImage'
|
||||||
import PageLink from '../../../components/atoms/PageLink'
|
import AvatarSkillIcon from '../../../components/v2/AvatarSkillIcon'
|
||||||
import SecondaryLabel from '../../../components/atoms/SecondaryLabel'
|
import AvatarSubSkillIcon from '../../../components/v2/AvatarSubSkillIcon'
|
||||||
import TypeLabel from '../../../components/atoms/TypeLabel'
|
import BattlesuitAvatarIcon from '../../../components/v2/BattlesuitAvatarIcon'
|
||||||
import ValkyrieLabel from '../../../components/atoms/ValkyrieLabel'
|
import FormattedText from '../../../components/v2/FormattedText'
|
||||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
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 {
|
import {
|
||||||
BattlesuitData,
|
getAttributeLabel,
|
||||||
battlesuitFeatures,
|
getCharacterTypeLabel,
|
||||||
BattlesuitSkillGroup,
|
getSkillTypeLabel,
|
||||||
battlesuitTypes,
|
getTagTypeLabel,
|
||||||
valkyries
|
getWeaponTypeLabel
|
||||||
} from '../../../lib/honkai3rd/battlesuits'
|
} from '../../../lib/v2/data/text'
|
||||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
import StarIcon from '../../../components/v2/StarIcon'
|
||||||
import { getBattlesuitById, listBattlesuits } from '../../../server/data/honkai3rd/battlesuits'
|
import ChibiIcon from '../../../components/v2/ChibiIcon'
|
||||||
import { translate, useTranslation } from '../../../lib/i18n'
|
import WeaponTypeIcon from '../../../components/v2/WeaponTypeIcon'
|
||||||
import { useRouter } from 'next/router'
|
import { sortBattlesuitSkill } from '../../../lib/v2/data/utils'
|
||||||
import Head from '../../../components/atoms/Head'
|
|
||||||
import { capitalize } from '../../../lib/string'
|
|
||||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
|
||||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import { WeaponData } from '../../../lib/honkai3rd/weapons'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
import { getWeaponMapByIds } from '../../../server/data/honkai3rd/weapons'
|
import Head from '../../../components/atoms/Head'
|
||||||
import { StigmataData } from '../../../lib/honkai3rd/stigmata'
|
import { useTranslation } from 'next-i18next'
|
||||||
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 {
|
interface BattlesuitShowPageProps {
|
||||||
battlesuit: BattlesuitData
|
battlesuit: Battlesuit
|
||||||
weaponMap: WeaponObjectMap
|
|
||||||
stigmataMap: StigmataObjectMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BattlesuitShowPage = ({ battlesuit, weaponMap, stigmataMap }: BattlesuitShowPageProps) => {
|
const BattlesuitShowPage = ({ battlesuit }: BattlesuitShowPageProps) => {
|
||||||
const { t } = useTranslation()
|
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 (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Honkai3rdLayout>
|
||||||
<Head
|
<Head
|
||||||
title={`${battlesuit.name} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
title={`${battlesuit.fullName} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||||
description={`${t('common.honkai-3rd')} ${t(
|
description={`${t('common.honkai-3rd')} ${t('battlesuit-show.battlesuit')} / ${battlesuit.fullName} / ${
|
||||||
'battlesuit-show.battlesuit'
|
battlesuit.attributeType
|
||||||
)} / ${valkyrieName} / ${battlesuitTypeLabel} / ${battlesuit.features
|
} / ${battlesuit.tags
|
||||||
.map(feature => {
|
.map(tag => {
|
||||||
const featureData = battlesuitFeatures.find(aFeature => aFeature.value === feature)
|
return getTagTypeLabel(tag)
|
||||||
if (featureData == null) {
|
|
||||||
return feature
|
|
||||||
}
|
|
||||||
|
|
||||||
const { label, krLabel } = featureData
|
|
||||||
|
|
||||||
return translate(locale, { 'ko-KR': krLabel }, label)
|
|
||||||
})
|
})
|
||||||
.join(', ')}`}
|
.join(', ')}`}
|
||||||
canonicalHref={`/honkai3rd/battlesuits/${battlesuit.id}`}
|
canonicalHref={`/honkai3rd/battlesuits/${battlesuit.id}`}
|
||||||
/>
|
/>
|
||||||
|
<Box p={2}>
|
||||||
|
<Heading as="h1">{battlesuit.fullName}</Heading>
|
||||||
|
|
||||||
<Box p={3}>
|
<AvatarFigureImage battlesuitId={battlesuit.id} sx={{ height: 400 }} />
|
||||||
<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>
|
|
||||||
|
|
||||||
<Box mb={3}>
|
<Box mb={3}>
|
||||||
<Box
|
<BattlesuitAvatarIcon battlesuit={battlesuit} />
|
||||||
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>
|
</Box>
|
||||||
|
|
||||||
<Card
|
<Card mb={3}>
|
||||||
sx={{
|
<Flex sx={{ borderBottom: 'default', p: 1 }}>
|
||||||
overflow: 'hidden'
|
<Flex sx={{ alignItems: 'center' }}>
|
||||||
}}
|
<Box mr={2}>
|
||||||
mb={3}
|
<StarIcon star={battlesuit.initialStar} />
|
||||||
>
|
</Box>
|
||||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
|
||||||
<PageLink
|
<ChibiIcon id={battlesuit.character} />
|
||||||
href={{
|
|
||||||
pathname: '/honkai3rd/battlesuits',
|
<Box ml={1} mr={2}>
|
||||||
query: { valkyrie: battlesuit.valkyrie }
|
{getCharacterTypeLabel(battlesuit.character)}
|
||||||
}}
|
</Box>
|
||||||
>
|
|
||||||
<ValkyrieLabel valkyrie={battlesuit.valkyrie} />
|
<AttributeIcon attributeType={battlesuit.attributeType} size={30} />
|
||||||
</PageLink>
|
<Box ml={1} mr={2}>
|
||||||
</Box>
|
{getAttributeLabel(battlesuit.attributeType)}
|
||||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
</Box>
|
||||||
<PageLink
|
|
||||||
href={{
|
<WeaponTypeIcon type={battlesuit.weapon} />
|
||||||
pathname: '/honkai3rd/battlesuits',
|
<Box ml={1}>{getWeaponTypeLabel(battlesuit.weapon)}</Box>
|
||||||
query: { valkyrie: battlesuit.type }
|
</Flex>
|
||||||
}}
|
</Flex>
|
||||||
>
|
<Flex sx={{ p: 1 }}>
|
||||||
<TypeLabel type={battlesuit.type} />
|
{battlesuit.tags.map(tag => {
|
||||||
</PageLink>
|
|
||||||
</Box>
|
|
||||||
<Flex p={2} sx={{ flexWrap: 'wrap', rowGap: 1 }}>
|
|
||||||
{battlesuit.features.map(feature => {
|
|
||||||
return (
|
return (
|
||||||
<Box mr={2} key={feature}>
|
<Flex key={tag} sx={{ mr: 2, alignItems: 'center' }}>
|
||||||
<PageLink
|
<TagIcon type={tag} />
|
||||||
href={{
|
<Box ml={1}>{getTagTypeLabel(tag)}</Box>
|
||||||
pathname: '/honkai3rd/battlesuits',
|
</Flex>
|
||||||
query: { feature: feature }
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<BattlesuitFeatureLabel feature={feature} />
|
|
||||||
</PageLink>
|
|
||||||
</Box>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{battlesuit.equipment != null && (
|
<Heading as="h2">Skills</Heading>
|
||||||
<Card
|
{battlesuit.skills.sort(sortBattlesuitSkill).map(skill => {
|
||||||
sx={{
|
return (
|
||||||
mb: 3,
|
<Card key={skill.id} mb={3}>
|
||||||
p: 2,
|
<Box sx={{ borderBottom: 'default', p: 1 }}>
|
||||||
overflow: 'hidden'
|
<Flex sx={{ alignItems: 'center' }}>
|
||||||
}}
|
<AvatarSkillIcon icon={skill.icon} />
|
||||||
>
|
<Heading as="h3" sx={{ ml: 1, mb: 0 }}>
|
||||||
{battlesuit.equipment.map(equipmentItem => {
|
<FormattedText>{skill.name}</FormattedText>
|
||||||
return (
|
|
||||||
<Box key={equipmentItem.type}>
|
|
||||||
<Heading
|
|
||||||
as="h3"
|
|
||||||
sx={{
|
|
||||||
mb: 1
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t(`battlesuit-show.equipmentTypes.${equipmentItem.type}`)}
|
|
||||||
</Heading>
|
</Heading>
|
||||||
<Flex sx={{ mx: -1 }}>
|
{skill.tags.length > 0 && (
|
||||||
{equipmentItem.weapon != null && <WeaponCard size="sm" weapon={weaponMap[equipmentItem.weapon]} />}
|
<Flex sx={{ ml: 1 }}>
|
||||||
{equipmentItem.stigmataTop != null && (
|
{skill.tags.map((tag, index) => {
|
||||||
<StigmataCard size="sm" stigmata={stigmataMap[equipmentItem.stigmataTop]} />
|
return <SkillTagItem key={index} tag={tag} />
|
||||||
)}
|
})}
|
||||||
{equipmentItem.stigmataMid != null && (
|
</Flex>
|
||||||
<StigmataCard size="sm" stigmata={stigmataMap[equipmentItem.stigmataMid]} />
|
)}
|
||||||
)}
|
</Flex>
|
||||||
{equipmentItem.stigmataBot != null && (
|
|
||||||
<StigmataCard size="sm" stigmata={stigmataMap[equipmentItem.stigmataBot]} />
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<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} />
|
<Box
|
||||||
|
sx={{
|
||||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.basic-attack')} skillGroup={battlesuit.basic} />
|
whiteSpace: 'pre-wrap',
|
||||||
|
borderBottom: 'default',
|
||||||
{battlesuit.sp != null && (
|
'&:last-child': { borderBottom: 'none' },
|
||||||
<BattlesuitSkillGroupCard heading={t('battlesuit-show.sp-skill')} skillGroup={battlesuit.sp} />
|
p: 1
|
||||||
)}
|
}}
|
||||||
|
>
|
||||||
|
<FormattedText>{formatSubSkillInfo(subSkill)}</FormattedText>
|
||||||
|
</Box>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
{/* <pre>{JSON.stringify(battlesuit, null, 2)}</pre> */}
|
||||||
</Box>
|
</Box>
|
||||||
</Honkai3rdLayout>
|
</Honkai3rdLayout>
|
||||||
)
|
)
|
||||||
@@ -215,103 +164,31 @@ const BattlesuitShowPage = ({ battlesuit, weaponMap, stigmataMap }: BattlesuitSh
|
|||||||
|
|
||||||
export default BattlesuitShowPage
|
export default BattlesuitShowPage
|
||||||
|
|
||||||
export async function getStaticProps({ params, locale }: NextPageContext & { params: { battlesuitId: string } }) {
|
export async function getStaticProps({ locale, params }: NextPageContext & { params: { battlesuitId: string } }) {
|
||||||
const battlesuit = getBattlesuitById(params.battlesuitId, locale)!
|
const battlesuit = loadBattlesuitData(params.battlesuitId)
|
||||||
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 {
|
return {
|
||||||
props: {
|
props: { battlesuit, ...(await getI18NProps(locale)) }
|
||||||
battlesuit,
|
|
||||||
weaponMap,
|
|
||||||
stigmataMap,
|
|
||||||
...(await getI18NProps(locale))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
|
const battlesuitCatalog = loadBattlesuitCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths: generateI18NPaths(
|
paths: battlesuitCatalog.map(catalogItem => {
|
||||||
listBattlesuits().map(battlesuit => {
|
return {
|
||||||
return {
|
params: { battlesuitId: catalogItem.id }
|
||||||
params: { battlesuitId: battlesuit.id }
|
}
|
||||||
}
|
}),
|
||||||
})
|
|
||||||
),
|
|
||||||
fallback: false
|
fallback: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BattlesuitSkillGroupCardProps {
|
interface SkillTagBoxProps {
|
||||||
heading: string
|
tag: SkillTagItem
|
||||||
skillGroup: BattlesuitSkillGroup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BattlesuitSkillGroupCard = ({ heading, skillGroup }: BattlesuitSkillGroupCardProps) => {
|
const SkillTagItem = ({ tag }: SkillTagBoxProps) => {
|
||||||
return (
|
return <TagIcon type={tag.type} strength={tag.strength} comment={tag.comment} size="sm" />
|
||||||
<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,76 +1,22 @@
|
|||||||
/** @jsxImportSource theme-ui */
|
/** @jsxImportSource theme-ui */
|
||||||
import { Box, Heading, Flex, Button } from '@theme-ui/components'
|
import { Box } 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 { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { getI18NProps } from '../../../server/i18n'
|
import { Flex, Link } from 'theme-ui'
|
||||||
import { translate, useTranslation } from '../../../lib/i18n'
|
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 Head from '../../../components/atoms/Head'
|
||||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
type BattlesuitListItemData = Pick<BattlesuitData, 'id' | 'name' | 'features' | 'type' | 'valkyrie'>
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
|
|
||||||
interface BattlesuitListPageProps {
|
interface BattlesuitListPageProps {
|
||||||
battlesuits: BattlesuitListItemData[]
|
battlesuitCatalog: BattlesuitCatalogItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const featureFilterOptions: {
|
const BattlesuitListPage = ({ battlesuitCatalog }: BattlesuitListPageProps) => {
|
||||||
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 { t } = useTranslation()
|
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 (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Honkai3rdLayout>
|
||||||
<Head
|
<Head
|
||||||
@@ -78,89 +24,26 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
|||||||
description={t('battlesuits-list.description')}
|
description={t('battlesuits-list.description')}
|
||||||
canonicalHref={`/honkai3rd/battlesuits`}
|
canonicalHref={`/honkai3rd/battlesuits`}
|
||||||
/>
|
/>
|
||||||
|
<Box p={2}>
|
||||||
<Box p={3}>
|
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
items={[
|
items={[
|
||||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||||
{
|
{
|
||||||
href: '/honkai3rd/battlesuits',
|
href: '/honkai3rd/v2/battlesuits',
|
||||||
label: t('common.battlesuits')
|
label: t('common.battlesuits')
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<h1>{t('battlesuits-list.heading')}</h1>
|
||||||
<Heading as="h1">{t('battlesuits-list.heading')}</Heading>
|
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||||
|
{battlesuitCatalog.map(battlesuit => {
|
||||||
<Box sx={{ display: ['block', 'none'], mb: 2 }}>
|
return (
|
||||||
<Button
|
<Box key={battlesuit.id}>
|
||||||
className={hiddenFilters ? '' : 'active'}
|
<Link href={`/honkai3rd/v2/battlesuits/${battlesuit.id}`}>
|
||||||
sx={{ px: 2, py: 1 }}
|
<BattlesuitCatalogItemCard battlesuit={battlesuit} />
|
||||||
onClick={() => {
|
</Link>
|
||||||
setHiddenFilters(previousValue => !previousValue)
|
</Box>
|
||||||
}}
|
)
|
||||||
>
|
|
||||||
{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} />
|
|
||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -171,67 +54,9 @@ const BattlesuitListPage = ({ battlesuits }: BattlesuitListPageProps) => {
|
|||||||
export default BattlesuitListPage
|
export default BattlesuitListPage
|
||||||
|
|
||||||
export async function getStaticProps({ locale }: NextPageContext) {
|
export async function getStaticProps({ locale }: NextPageContext) {
|
||||||
|
const battlesuitCatalog = loadBattlesuitCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: { battlesuitCatalog, ...(await getI18NProps(locale)) }
|
||||||
battlesuits: listBattlesuits(locale).map(battlesuit => {
|
|
||||||
return {
|
|
||||||
id: battlesuit.id,
|
|
||||||
name: battlesuit.name,
|
|
||||||
features: battlesuit.features,
|
|
||||||
type: battlesuit.type,
|
|
||||||
valkyrie: battlesuit.valkyrie
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
...(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 { NextPageContext } from 'next'
|
||||||
import React from 'react'
|
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||||
import BattlesuitFeatureLabel from '../../../components/atoms/BattlesuitFeatureLabel'
|
import { useMemo } from 'react'
|
||||||
import SecondaryLabel from '../../../components/atoms/SecondaryLabel'
|
import { Elf, ElfSkill } from '../../../lib/v2/data/types'
|
||||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
import { loadElfCatalog, loadElfData } from '../../../lib/v2/server/loadData'
|
||||||
import { ElfData } from '../../../lib/honkai3rd/elfs'
|
import SquareImage from '../../../components/v2/SquareImage'
|
||||||
import { getElfById, listElfs } from '../../../server/data/honkai3rd/elfs'
|
import TagIcon from '../../../components/v2/TagIcon'
|
||||||
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 { assetsBucketBaseUrl } from '../../../lib/consts'
|
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 {
|
interface ElfShowPageProps {
|
||||||
elf: ElfData
|
elf: Elf
|
||||||
}
|
}
|
||||||
|
|
||||||
const ElfShowPage = ({ elf }: ElfShowPageProps) => {
|
const ElfShowPage = ({ elf }: ElfShowPageProps) => {
|
||||||
const { locale } = useRouter()
|
const skillRows = useMemo(() => {
|
||||||
const { t } = useTranslation()
|
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 (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Box>
|
||||||
<Head
|
<Heading as="h1">{elf.fullName}</Heading>
|
||||||
title={`${t('common.honkai-3rd')}: ${elf.name} - ${t(
|
<SquareImage
|
||||||
'common.abyss-lab'
|
src={`${assetsBucketBaseUrl}/raw/elfcardfigures/${elf.figureImage}.png`}
|
||||||
)}`}
|
originalSize={720}
|
||||||
description={`${t('common.honkai-3rd')} ${t(
|
size={480}
|
||||||
'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 p={3}>
|
<Card mb={3}>
|
||||||
<Breadcrumb
|
<Box sx={{ p: 1, borderBottom: 'default' }}>
|
||||||
items={[
|
<Flex>
|
||||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
{elf.tags.map(tag => {
|
||||||
{ href: '/honkai3rd/elfs', label: t('common.elfs') },
|
return (
|
||||||
{
|
<Box key={tag.type} mr={1}>
|
||||||
href: `/honkai3rd/elfs/${elf.id}`,
|
<TagIcon type={tag.type} />
|
||||||
label: elf.name,
|
</Box>
|
||||||
},
|
)
|
||||||
]}
|
})}
|
||||||
/>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
))}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Box>
|
||||||
|
<Box p={1}>
|
||||||
|
Ult CD: {elf.ultSkillCd} / Ult SP Cost: {elf.ultSkillCost}
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
|
||||||
{elf.skillRows.map((row, rowIndex) => {
|
<Heading as="h2">Skills</Heading>
|
||||||
return (
|
|
||||||
<Card key={rowIndex} mb={3}>
|
{skillRows.map((row, index) => {
|
||||||
{row.map((item, columnIndex) => {
|
return (
|
||||||
return (
|
<Card key={index} mb={2}>
|
||||||
<React.Fragment key={columnIndex}>
|
{row.map(skill => {
|
||||||
<Box sx={{ p: 2, borderBottom: 'default' }}>
|
return (
|
||||||
<Heading
|
<Box
|
||||||
as={columnIndex === 0 ? 'h2' : 'h3'}
|
key={skill.id}
|
||||||
sx={{ mb: 1 }}
|
sx={{
|
||||||
>
|
borderBottom: 'default',
|
||||||
{item.name}
|
'&: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>
|
</Heading>
|
||||||
<SecondaryLabel>
|
{/* {skill.id} */}
|
||||||
{t(`elfs-show.${item.type}`)}{' '}
|
<Box sx={{ color: 'textMuted', ml: 1 }}>({skill.skillType})</Box>
|
||||||
{'⭐'.repeat(item.requiredRank)}
|
</Flex>
|
||||||
</SecondaryLabel>
|
</Box>
|
||||||
</Box>
|
<Box sx={{ p: 1 }}>
|
||||||
<Paragraph
|
<FormattedText>{formatSubSkillInfo(skill)}</FormattedText>
|
||||||
sx={{
|
</Box>
|
||||||
p: 2,
|
</Box>
|
||||||
borderBottom: 'default',
|
)
|
||||||
'&:last-child': { borderBottom: 'none' },
|
})}
|
||||||
whiteSpace: 'pre-wrap',
|
</Card>
|
||||||
}}
|
)
|
||||||
>
|
})}
|
||||||
{item.description}
|
</Box>
|
||||||
</Paragraph>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
</Honkai3rdLayout>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ElfShowPage
|
export default ElfShowPage
|
||||||
|
|
||||||
export async function getStaticProps({
|
export async function getStaticProps({ locale, params }: NextPageContext & { params: { elfId: string } }) {
|
||||||
params,
|
const elf = loadElfData(params.elfId)
|
||||||
locale,
|
|
||||||
}: NextPageContext & { params: { elfId: string } }) {
|
|
||||||
const elf = getElfById(params.elfId, locale)
|
|
||||||
return {
|
return {
|
||||||
props: { elf, ...(await getI18NProps(locale)) },
|
props: { elf }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
|
const elfCatalog = loadElfCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths: generateI18NPaths(
|
paths: elfCatalog.map(catalogItem => {
|
||||||
listElfs().map((elf) => {
|
return {
|
||||||
return {
|
params: { elfId: catalogItem.id }
|
||||||
params: { elfId: elf.id },
|
}
|
||||||
}
|
}),
|
||||||
})
|
fallback: false
|
||||||
),
|
|
||||||
fallback: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,61 @@
|
|||||||
/** @jsxImportSource theme-ui */
|
/** @jsxImportSource theme-ui */
|
||||||
import { Box, Heading, Flex } from '@theme-ui/components'
|
import { Box, Card } from '@theme-ui/components'
|
||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { pick } from 'ramda'
|
import { Flex, Link } from 'theme-ui'
|
||||||
import ElfCard from '../../../components/molecules/ElfCard'
|
import { ElfCatalogItem } from '../../../lib/v2/data/types'
|
||||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
import { loadElfCatalog } from '../../../lib/v2/server/loadData'
|
||||||
import { ElfData } from '../../../lib/honkai3rd/elfs'
|
import RarityBar from '../../../components/v2/RarityBar'
|
||||||
import { getI18NProps } from '../../../server/i18n'
|
import ElfIcon from '../../../components/v2/ElfIcon'
|
||||||
import { listElfs } from '../../../server/data/honkai3rd/elfs'
|
|
||||||
import { useTranslation } from '../../../lib/i18n'
|
|
||||||
import Head from '../../../components/atoms/Head'
|
|
||||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
|
||||||
|
|
||||||
interface ElfListPageProps {
|
interface ElfListPageProps {
|
||||||
elfs: Pick<ElfData, 'id' | 'name'>[]
|
elfs: ElfCatalogItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const ElfListPage = ({ elfs }: ElfListPageProps) => {
|
const ElfListPage = ({ elfs }: ElfListPageProps) => {
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Box>
|
||||||
<Head
|
<h1>Elfs</h1>
|
||||||
title={`${t('common.elfs')} - ${t('common.honkai-3rd')} - ${t(
|
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||||
'common.abyss-lab'
|
{elfs
|
||||||
)}`}
|
.sort((a, b) => {
|
||||||
description={t('elfs-list.description')}
|
const aId = getId(a.id)
|
||||||
canonicalHref={`/honkai3rd/elfs`}
|
const bId = getId(b.id)
|
||||||
/>
|
return bId - aId
|
||||||
<Box p={3}>
|
|
||||||
<Breadcrumb
|
|
||||||
items={[
|
|
||||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
|
||||||
{ href: '/honkai3rd/elfs', label: t('common.elfs') },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Heading as='h1'>{t('elfs-list.elfs')}</Heading>
|
function getId(id: string): number {
|
||||||
|
return parseInt(id)
|
||||||
<Flex
|
}
|
||||||
sx={{
|
})
|
||||||
flexWrap: 'wrap',
|
.map(elf => {
|
||||||
justifyContent: 'space-around',
|
return (
|
||||||
}}
|
<Box key={elf.id} m={2}>
|
||||||
>
|
<Link href={`/v2-pre/elfs/${elf.id}`}>
|
||||||
{elfs.map((elf) => {
|
<Card p={1}>
|
||||||
return <ElfCard key={elf.id} elf={elf} />
|
<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>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
</Honkai3rdLayout>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ElfListPage
|
export default ElfListPage
|
||||||
|
|
||||||
export async function getStaticProps({ locale }: NextPageContext) {
|
export async function getStaticProps({ locale }: NextPageContext) {
|
||||||
|
const elfs = loadElfCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: { elfs }
|
||||||
elfs: listElfs(locale).map((elf) => pick(['id', 'name', 'krName'], elf)),
|
|
||||||
...(await getI18NProps(locale)),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { NextPageContext } from 'next'
|
||||||
import { Box, Card, Flex, Heading, Image, Link } from 'theme-ui'
|
import { Box, Card, Flex, Heading, Image, Link } from 'theme-ui'
|
||||||
import AvatarFigureImage from '../../../../../components/v2/AvatarFigureImage'
|
import AvatarFigureImage from '../../../../components/v2/AvatarFigureImage'
|
||||||
import { loadBattlesuitData, loadErBattlesuit, loadErBattlesuitCatalog } from '../../../../../lib/v2/server/loadData'
|
import { loadBattlesuitData, loadErBattlesuit, loadErBattlesuitCatalog } from '../../../../lib/v2/server/loadData'
|
||||||
import { Battlesuit, ErBattlesuit, ErSignet } from '../../../../../lib/v2/data/types'
|
import { Battlesuit, ErBattlesuit, ErSignet } from '../../../../lib/v2/data/types'
|
||||||
import { Fragment, useMemo } from 'react'
|
import { Fragment, useMemo } from 'react'
|
||||||
import { assetsBucketBaseUrl } from '../../../../../lib/consts'
|
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||||
import BattlesuitCatalogItemCard from '../../../../../components/v2/BattlesuitCatalogItemCard'
|
import BattlesuitCatalogItemCard from '../../../../components/v2/BattlesuitCatalogItemCard'
|
||||||
import Honkai3rdLayout from '../../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||||
import Head from '../../../../../components/atoms/Head'
|
import Head from '../../../../components/atoms/Head'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Breadcrumb from '../../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||||
import { getI18NProps } from '../../../../../server/i18n'
|
import { getI18NProps } from '../../../../server/i18n'
|
||||||
|
|
||||||
interface BattlesuitShowPageProps {
|
interface BattlesuitShowPageProps {
|
||||||
battlesuit: Battlesuit
|
battlesuit: Battlesuit
|
||||||
@@ -6,20 +6,20 @@ import {
|
|||||||
loadErBattlesuitCatalog,
|
loadErBattlesuitCatalog,
|
||||||
loadErSigils,
|
loadErSigils,
|
||||||
loadErSupports
|
loadErSupports
|
||||||
} from '../../../../lib/v2/server/loadData'
|
} from '../../../lib/v2/server/loadData'
|
||||||
import { BattlesuitCatalogItem, ErBattlesuitCatalogItem } from '../../../../lib/v2/data/types'
|
import { BattlesuitCatalogItem, ErBattlesuitCatalogItem } from '../../../lib/v2/data/types'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import BattlesuitCatalogItemCard from '../../../../components/v2/BattlesuitCatalogItemCard'
|
import BattlesuitCatalogItemCard from '../../../components/v2/BattlesuitCatalogItemCard'
|
||||||
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
||||||
import SquareImage from '../../../../components/v2/SquareImage'
|
import SquareImage from '../../../components/v2/SquareImage'
|
||||||
import { signetGroups } from '../../../../lib/v2/data/er'
|
import { signetGroups } from '../../../lib/v2/data/er'
|
||||||
import BattlesuitSmallIcon from '../../../../components/v2/BattlesuitSmallIcon'
|
import BattlesuitSmallIcon from '../../../components/v2/BattlesuitSmallIcon'
|
||||||
import MaterialIcon from '../../../../components/v2/MaterialIcon'
|
import MaterialIcon from '../../../components/v2/MaterialIcon'
|
||||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import Head from '../../../../components/atoms/Head'
|
import Head from '../../../components/atoms/Head'
|
||||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { getI18NProps } from '../../../../server/i18n'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
|
|
||||||
interface ErPageProps {
|
interface ErPageProps {
|
||||||
erBattlesuitCatalog: ErBattlesuitCatalogItem[]
|
erBattlesuitCatalog: ErBattlesuitCatalogItem[]
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||||
import Head from '../../../../components/atoms/Head'
|
import Head from '../../../components/atoms/Head'
|
||||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
import MaterialIcon from '../../../../components/v2/MaterialIcon'
|
import MaterialIcon from '../../../components/v2/MaterialIcon'
|
||||||
import { ErSigil } from '../../../../lib/v2/data/types'
|
import { ErSigil } from '../../../lib/v2/data/types'
|
||||||
import { loadErSigils } from '../../../../lib/v2/server/loadData'
|
import { loadErSigils } from '../../../lib/v2/server/loadData'
|
||||||
import { getI18NProps } from '../../../../server/i18n'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
|
|
||||||
interface SigilsPageProps {
|
interface SigilsPageProps {
|
||||||
erSigils: ErSigil[]
|
erSigils: ErSigil[]
|
||||||
+10
-10
@@ -1,17 +1,17 @@
|
|||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||||
import { loadErSignets } from '../../../../../lib/v2/server/loadData'
|
import { loadErSignets } from '../../../../lib/v2/server/loadData'
|
||||||
import { ErSignet, ErSignetGroup } from '../../../../../lib/v2/data/types'
|
import { ErSignet, ErSignetGroup } from '../../../../lib/v2/data/types'
|
||||||
import { Fragment, useMemo } from 'react'
|
import { Fragment, useMemo } from 'react'
|
||||||
import { assetsBucketBaseUrl } from '../../../../../lib/consts'
|
import { assetsBucketBaseUrl } from '../../../../lib/consts'
|
||||||
import { signetGroups } from '../../../../../lib/v2/data/er'
|
import { signetGroups } from '../../../../lib/v2/data/er'
|
||||||
import SquareImage from '../../../../../components/v2/SquareImage'
|
import SquareImage from '../../../../components/v2/SquareImage'
|
||||||
import { getErSignetTypeLabel } from '../../../../../lib/v2/data/text'
|
import { getErSignetTypeLabel } from '../../../../lib/v2/data/text'
|
||||||
import Honkai3rdLayout from '../../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
||||||
import Head from '../../../../../components/atoms/Head'
|
import Head from '../../../../components/atoms/Head'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Breadcrumb from '../../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
||||||
import { getI18NProps } from '../../../../../server/i18n'
|
import { getI18NProps } from '../../../../server/i18n'
|
||||||
|
|
||||||
interface BattlesuitShowPageProps {
|
interface BattlesuitShowPageProps {
|
||||||
group: ErSignetGroup
|
group: ErSignetGroup
|
||||||
@@ -2,13 +2,13 @@ import { NextPageContext } from 'next'
|
|||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { Box, Card, Flex, Heading } from 'theme-ui'
|
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||||
import Head from '../../../../components/atoms/Head'
|
import Head from '../../../components/atoms/Head'
|
||||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
import BattlesuitSmallIcon from '../../../../components/v2/BattlesuitSmallIcon'
|
import BattlesuitSmallIcon from '../../../components/v2/BattlesuitSmallIcon'
|
||||||
import { BattlesuitCatalogItem, ErSupportBattlesuit } from '../../../../lib/v2/data/types'
|
import { BattlesuitCatalogItem, ErSupportBattlesuit } from '../../../lib/v2/data/types'
|
||||||
import { loadBattlesuitCatalog, loadErSupports } from '../../../../lib/v2/server/loadData'
|
import { loadBattlesuitCatalog, loadErSupports } from '../../../lib/v2/server/loadData'
|
||||||
import { getI18NProps } from '../../../../server/i18n'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
|
|
||||||
interface SupportsPageProps {
|
interface SupportsPageProps {
|
||||||
battlesuitCatalog: BattlesuitCatalogItem[]
|
battlesuitCatalog: BattlesuitCatalogItem[]
|
||||||
+10
-10
@@ -1,17 +1,17 @@
|
|||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { Box, Card, Flex, Heading, Link } from 'theme-ui'
|
import { Box, Card, Flex, Heading, Link } from 'theme-ui'
|
||||||
import FormattedText from '../../../../components/v2/FormattedText'
|
import FormattedText from '../../../components/v2/FormattedText'
|
||||||
import { formatSubSkillInfo } from '../../../../lib/v2/data/formatText'
|
import { formatSubSkillInfo } from '../../../lib/v2/data/formatText'
|
||||||
import { loadStigmaData, loadStigmataSetCatalog, loadStigmataSetData } from '../../../../lib/v2/server/loadData'
|
import { loadStigmaData, loadStigmataSetCatalog, loadStigmataSetData } from '../../../lib/v2/server/loadData'
|
||||||
import { RootStigma, StigmataSet } from '../../../../lib/v2/data/types'
|
import { RootStigma, StigmataSet } from '../../../lib/v2/data/types'
|
||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||||
import StigmaFigureImage from '../../../../components/v2/StigmaFigureImage'
|
import StigmaFigureImage from '../../../components/v2/StigmaFigureImage'
|
||||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import Head from '../../../../components/atoms/Head'
|
import Head from '../../../components/atoms/Head'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { getI18NProps } from '../../../../server/i18n'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
|
|
||||||
interface StigmataSetShowPage {
|
interface StigmataSetShowPage {
|
||||||
stigmataSet: StigmataSet
|
stigmataSet: StigmataSet
|
||||||
+7
-7
@@ -3,14 +3,14 @@ import { Box, Card, Heading } from '@theme-ui/components'
|
|||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { Flex, Link } from 'theme-ui'
|
import { Flex, Link } from 'theme-ui'
|
||||||
|
|
||||||
import { StigmataSetCatalogItem } from '../../../../lib/v2/data/types'
|
import { StigmataSetCatalogItem } from '../../../lib/v2/data/types'
|
||||||
import { loadStigmataSetCatalog } from '../../../../lib/v2/server/loadData'
|
import { loadStigmataSetCatalog } from '../../../lib/v2/server/loadData'
|
||||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import Head from '../../../../components/atoms/Head'
|
import Head from '../../../components/atoms/Head'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { getI18NProps } from '../../../../server/i18n'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
|
|
||||||
interface StigmataSetListPageProps {
|
interface StigmataSetListPageProps {
|
||||||
stigmataSetCatalog: StigmataSetCatalogItem[]
|
stigmataSetCatalog: StigmataSetCatalogItem[]
|
||||||
+12
-12
@@ -1,19 +1,19 @@
|
|||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { Box, Card, Flex, Heading, Link } from 'theme-ui'
|
import { Box, Card, Flex, Heading, Link } from 'theme-ui'
|
||||||
import FormattedText from '../../../../components/v2/FormattedText'
|
import FormattedText from '../../../components/v2/FormattedText'
|
||||||
import { formatSubSkillInfo, replaceNewLine } from '../../../../lib/v2/data/formatText'
|
import { formatSubSkillInfo, replaceNewLine } from '../../../lib/v2/data/formatText'
|
||||||
import { loadStigmaData, loadStigmataCatalog, loadStigmataSetData } from '../../../../lib/v2/server/loadData'
|
import { loadStigmaData, loadStigmataCatalog, loadStigmataSetData } from '../../../lib/v2/server/loadData'
|
||||||
import { RootStigma, StigmataSetCatalogItem } from '../../../../lib/v2/data/types'
|
import { RootStigma, StigmataSetCatalogItem } from '../../../lib/v2/data/types'
|
||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
import { getStigmaTypeLabel } from '../../../../lib/v2/data/text'
|
import { getStigmaTypeLabel } from '../../../lib/v2/data/text'
|
||||||
import StigmaTypeIcon from '../../../../components/v2/StigmaTypeIcon'
|
import StigmaTypeIcon from '../../../components/v2/StigmaTypeIcon'
|
||||||
import StigmaIcon from '../../../../components/v2/StigmaIcon'
|
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||||
import StigmaFigureImage from '../../../../components/v2/StigmaFigureImage'
|
import StigmaFigureImage from '../../../components/v2/StigmaFigureImage'
|
||||||
import { getI18NProps } from '../../../../server/i18n'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
import Honkai3rdLayout from '../../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import Head from '../../../../components/atoms/Head'
|
import Head from '../../../components/atoms/Head'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Breadcrumb from '../../../../components/organisms/Breadcrumb'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
|
|
||||||
interface StigmaShowPageProps {
|
interface StigmaShowPageProps {
|
||||||
rootStigma: RootStigma
|
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 */
|
/** @jsxImportSource theme-ui */
|
||||||
import { Box, Heading, Flex } from '@theme-ui/components'
|
import { Box, Card, Heading } from '@theme-ui/components'
|
||||||
import { NextPageContext } from 'next'
|
import { NextPageContext } from 'next'
|
||||||
import { useRouter } from 'next/router'
|
import { Flex, Link } from 'theme-ui'
|
||||||
import { pick } from 'ramda'
|
|
||||||
import { useMemo } from 'react'
|
import { StigmataCatalogItem } from '../../../lib/v2/data/types'
|
||||||
import PageLink from '../../../components/atoms/PageLink'
|
import { loadStigmataCatalog } from '../../../lib/v2/server/loadData'
|
||||||
import StigmataCard from '../../../components/molecules/StigmataCard'
|
import StigmaIcon from '../../../components/v2/StigmaIcon'
|
||||||
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 Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
|
|
||||||
interface StigmataListPageProps {
|
interface StigmataListPageProps {
|
||||||
stigmataDataList: Pick<StigmataData, 'id' | 'name' | 'rarity'>[]
|
stigmataCatalog: StigmataCatalogItem[]
|
||||||
stigmataSetList: Pick<StigmataSet, 'id' | 'name' | 'rarity'>[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const StigmataListPage = ({
|
const StigmataListPage = ({ stigmataCatalog }: StigmataListPageProps) => {
|
||||||
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])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Honkai3rdLayout>
|
||||||
<Head
|
<Box>
|
||||||
title={`${t('common.stigmata')} - ${t('common.honkai-3rd')} - ${t(
|
<Heading as="h1">Stigmata (Single)</Heading>
|
||||||
'common.abyss-lab'
|
|
||||||
)}`}
|
|
||||||
description={t('stigmata-list.description')}
|
|
||||||
canonicalHref={`/honkai3rd/stigmata`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Box p={3}>
|
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||||
<Breadcrumb
|
{stigmataCatalog
|
||||||
items={[
|
.filter(filterStigmata)
|
||||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
.sort(sortStigmata)
|
||||||
{ href: '/honkai3rd/stigmata', label: t('common.stigmata') },
|
.map(stigma => {
|
||||||
]}
|
return (
|
||||||
/>
|
<Box key={stigma.id} m={2}>
|
||||||
|
<Link href={`/v2-pre/stigmata/${stigma.id}`}>
|
||||||
<Heading as='h1'>{t('stigmata-list.stigmata')}</Heading>
|
<Card p={1}>
|
||||||
|
<Flex sx={{ justifyContent: 'center' }}>
|
||||||
<Flex mb={3}>
|
<StigmaIcon icon={stigma.icon} rarity={stigma.maxRarity} />
|
||||||
<PageLink
|
</Flex>
|
||||||
href={{
|
<Box
|
||||||
query: listMode === 'set' ? { list: 'single' } : { list: 'set' },
|
sx={{
|
||||||
}}
|
overflow: 'hidden',
|
||||||
shallow={true}
|
textOverflow: 'ellipsis',
|
||||||
m={1}
|
whiteSpace: 'nowrap',
|
||||||
py={1}
|
px: 1,
|
||||||
px={2}
|
width: 112,
|
||||||
className={listMode === 'set' ? 'active' : ''}
|
textAlign: 'center'
|
||||||
sx={{ display: 'flex' }}
|
}}
|
||||||
variant='buttons.primary'
|
>
|
||||||
>
|
{stigma.name}
|
||||||
{t('stigmata-list.set-list')}
|
</Box>
|
||||||
</PageLink>
|
{/* {stigma.id} */}
|
||||||
</Flex>
|
</Card>
|
||||||
|
</Link>
|
||||||
<Flex
|
</Box>
|
||||||
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>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
</Honkai3rdLayout>
|
</Honkai3rdLayout>
|
||||||
@@ -101,15 +58,21 @@ const StigmataListPage = ({
|
|||||||
export default StigmataListPage
|
export default StigmataListPage
|
||||||
|
|
||||||
export async function getStaticProps({ locale }: NextPageContext) {
|
export async function getStaticProps({ locale }: NextPageContext) {
|
||||||
|
const stigmataCatalog = loadStigmataCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: { stigmataCatalog, ...(await getI18NProps(locale)) }
|
||||||
stigmataDataList: listStigmata(locale).map((stigmata) =>
|
|
||||||
pick(['id', 'name', 'rarity'], stigmata)
|
|
||||||
),
|
|
||||||
stigmataSetList: listStigmataSet(locale).map((stigmataSet) =>
|
|
||||||
pick(['id', 'name', 'rarity'], stigmataSet)
|
|
||||||
),
|
|
||||||
...(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 { NextPageContext } from 'next'
|
||||||
import SquareImageBox from '../../../components/atoms/SquareImageBox'
|
import { Box, Card, Flex, Heading } from 'theme-ui'
|
||||||
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
import FormattedText from '../../../components/v2/FormattedText'
|
||||||
import { weaponCategories, WeaponData } from '../../../lib/honkai3rd/weapons'
|
import { formatSubSkillInfo, replaceNewLine } from '../../../lib/v2/data/formatText'
|
||||||
import { generateI18NPaths, getI18NProps } from '../../../server/i18n'
|
import { loadWeaponCatalog, loadWeaponData } from '../../../lib/v2/server/loadData'
|
||||||
import { getWeaponById, getWeaponMapByIds, listWeapons } from '../../../server/data/honkai3rd/weapons'
|
import { RootWeaponData } from '../../../lib/v2/data/types'
|
||||||
import { useTranslation } from '../../../lib/i18n'
|
import { Fragment } from 'react'
|
||||||
import Head from '../../../components/atoms/Head'
|
import { getWeaponTypeLabel } from '../../../lib/v2/data/text'
|
||||||
import PageLink from '../../../components/atoms/PageLink'
|
import WeaponTypeIcon from '../../../components/v2/WeaponTypeIcon'
|
||||||
import { assetsBucketBaseUrl } from '../../../lib/consts'
|
import WeaponIcon from '../../../components/v2/WeaponIcon'
|
||||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
import { getBattlesuitMapByIds } from '../../../server/data/honkai3rd/battlesuits'
|
import Head from '../../../components/atoms/Head'
|
||||||
import { BattlesuitData } from '../../../lib/honkai3rd/battlesuits'
|
import { useTranslation } from 'next-i18next'
|
||||||
import BattlesuitCard from '../../../components/molecules/BattlesuitCard'
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
import WeaponCard from '../../../components/molecules/WeaponCard'
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
|
|
||||||
interface WeaponShowPageProps {
|
interface WeaponShowPageProps {
|
||||||
weapon: WeaponData
|
rootWeapon: RootWeaponData
|
||||||
battlesuitMap: { [key: string]: BattlesuitData }
|
|
||||||
weaponMap: { [key: string]: WeaponData }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const WeaponShowPage = ({ weapon, battlesuitMap, weaponMap }: WeaponShowPageProps) => {
|
const WeaponShowPage = ({ rootWeapon }: WeaponShowPageProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const weapon = rootWeapon.weapons[rootWeapon.weapons.length - 1]
|
||||||
|
|
||||||
const weaponCategoryName = t(`weapons-show.${weapon.category}`)
|
const weaponTypeLabel = getWeaponTypeLabel(weapon.type)
|
||||||
const weaponCategory = weaponCategories.find(category => category.value === weapon.category)
|
const atk = Math.floor(weapon.attackBase + weapon.attackAdd * (weapon.maxLv - 1))
|
||||||
|
const crt = Math.floor(weapon.criticalBase + weapon.criticalAdd * (weapon.maxLv - 1))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Honkai3rdLayout>
|
||||||
@@ -34,112 +32,78 @@ const WeaponShowPage = ({ weapon, battlesuitMap, weaponMap }: WeaponShowPageProp
|
|||||||
title={`${weapon.name} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
title={`${weapon.name} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||||
description={`${t('common.honkai-3rd')} ${t('weapons-show.weapon')} / ${'⭐'.repeat(
|
description={`${t('common.honkai-3rd')} ${t('weapons-show.weapon')} / ${'⭐'.repeat(
|
||||||
weapon.rarity
|
weapon.rarity
|
||||||
)} / ${weaponCategoryName} / ATK : ${weapon.atk} / CRT : ${weapon.crt}`}
|
)} / ${weaponTypeLabel} / ATK : ${atk} / CRT : ${crt}`}
|
||||||
canonicalHref={`/honkai3rd/weapons/${weapon.id}`}
|
canonicalHref={`/honkai3rd/v2/weapons/${weapon.id}`}
|
||||||
/>
|
/>
|
||||||
|
<Box p={2}>
|
||||||
<Box p={3}>
|
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
items={[
|
items={[
|
||||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
||||||
{ href: '/honkai3rd/weapons', label: t('common.weapons') },
|
{ href: '/honkai3rd/v2/weapons', label: t('common.weapons') },
|
||||||
{
|
{ href: `/honkai3rd/v2/weapons/${weapon.id}`, label: weapon.name }
|
||||||
href: `/honkai3rd/weapons/${weapon.id}`,
|
|
||||||
label: weapon.name
|
|
||||||
}
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Heading as="h1">{weapon.name}</Heading>
|
<Heading as="h1">{weapon.name}</Heading>
|
||||||
|
|
||||||
<Box mb={3}>
|
<Box mb={3}>
|
||||||
<SquareImageBox
|
<WeaponIcon key={weapon.id} icon={weapon.icon} rarity={weapon.rarity} />
|
||||||
size={100}
|
|
||||||
alt={weapon.name}
|
|
||||||
src={`${assetsBucketBaseUrl}/honkai3rd/weapons/${weapon.id}.png`}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Card mb={3}>
|
<Card mb={3}>
|
||||||
<Box p={2} sx={{ borderBottom: 'default' }}>
|
<Box sx={{ p: 1, borderBottom: 'default' }}>{replaceNewLine(weapon.description)}</Box>
|
||||||
<PageLink
|
<Flex sx={{ alignItems: 'center', p: 1, borderBottom: 'default' }}>
|
||||||
href={{
|
<WeaponTypeIcon type={weapon.type} />
|
||||||
pathname: '/honkai3rd/weapons',
|
<Box ml={1}>{getWeaponTypeLabel(weapon.type)}</Box>
|
||||||
query: { category: weapon.category }
|
</Flex>
|
||||||
}}
|
<Box sx={{ p: 1 }}>
|
||||||
>
|
ATK : {atk} / CRT : {crt} (at Max Lv {weapon.maxLv})
|
||||||
<Flex>
|
|
||||||
{weaponCategory != null && (
|
|
||||||
<SquareImageBox
|
|
||||||
size={30}
|
|
||||||
src={`${assetsBucketBaseUrl}/honkai3rd/${weaponCategory.icon}.png`}
|
|
||||||
alt={weaponCategoryName}
|
|
||||||
mr={1}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{weaponCategoryName}
|
|
||||||
</Flex>
|
|
||||||
</PageLink>
|
|
||||||
</Box>
|
</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>
|
</Card>
|
||||||
|
|
||||||
<Box>
|
<Heading as="h2">Skills</Heading>
|
||||||
|
<Card>
|
||||||
{weapon.skills.map(skill => {
|
{weapon.skills.map(skill => {
|
||||||
return (
|
return (
|
||||||
<Card key={skill.name} mb={3}>
|
<Fragment key={skill.id}>
|
||||||
<Heading as="h3" p={2} m={0} sx={{ borderBottom: 'default' }}>
|
<Box sx={{ borderBottom: 'default' }}>
|
||||||
{skill.name}
|
<Heading
|
||||||
</Heading>
|
as="h3"
|
||||||
<Paragraph
|
sx={{
|
||||||
p={2}
|
p: 1,
|
||||||
|
m: 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{skill.name}
|
||||||
|
</Heading>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
whiteSpace: 'pre-wrap'
|
p: 1,
|
||||||
|
borderBottom: 'default',
|
||||||
|
'&:last-child': {
|
||||||
|
borderBottom: 'none'
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{skill.description}
|
<FormattedText>
|
||||||
</Paragraph>
|
{formatSubSkillInfo({
|
||||||
</Card>
|
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>
|
</Box>
|
||||||
</Honkai3rdLayout>
|
</Honkai3rdLayout>
|
||||||
)
|
)
|
||||||
@@ -147,43 +111,23 @@ const WeaponShowPage = ({ weapon, battlesuitMap, weaponMap }: WeaponShowPageProp
|
|||||||
|
|
||||||
export default WeaponShowPage
|
export default WeaponShowPage
|
||||||
|
|
||||||
export async function getStaticProps({ params, locale }: NextPageContext & { params: { weaponId: string } }) {
|
export async function getStaticProps({ locale, params }: NextPageContext & { params: { weaponId: string } }) {
|
||||||
const weapon = getWeaponById(params.weaponId, locale)
|
const rootWeapon = loadWeaponData(params.weaponId)
|
||||||
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 {
|
return {
|
||||||
props: {
|
props: { rootWeapon, ...(await getI18NProps(locale)) }
|
||||||
weapon,
|
|
||||||
battlesuitMap,
|
|
||||||
weaponMap,
|
|
||||||
...(await getI18NProps(locale))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
|
const weaponCatalog = loadWeaponCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths: generateI18NPaths(
|
paths: weaponCatalog.map(catalogItem => {
|
||||||
listWeapons().map(weapon => {
|
return {
|
||||||
return {
|
params: { weaponId: catalogItem.id }
|
||||||
params: { weaponId: weapon.id }
|
}
|
||||||
}
|
}),
|
||||||
})
|
|
||||||
),
|
|
||||||
fallback: false
|
fallback: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +1,68 @@
|
|||||||
/** @jsxImportSource theme-ui */
|
/** @jsxImportSource theme-ui */
|
||||||
import { Box, Heading, Flex } from '@theme-ui/components'
|
import { Box, Card } 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 { NextPageContext } from 'next'
|
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 Head from '../../../components/atoms/Head'
|
||||||
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
import Honkai3rdLayout from '../../../components/layouts/Honkai3rdLayout'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
type WeaponListItemData = Pick<WeaponData, 'id' | 'name' | 'rarity' | 'category'>
|
import { getI18NProps } from '../../../server/i18n'
|
||||||
|
import Breadcrumb from '../../../components/organisms/Breadcrumb'
|
||||||
|
|
||||||
interface WeaponListPageProps {
|
interface WeaponListPageProps {
|
||||||
weaponDataList: WeaponListItemData[]
|
weaponCatalog: WeaponCatalogItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const weaponFilterOptions = [{ value: 'all', label: 'All', krLabel: '전체', icon: undefined }, ...weaponCategories]
|
const WeaponListPage = ({ weaponCatalog }: WeaponListPageProps) => {
|
||||||
|
|
||||||
const WeaponListPage = ({ weaponDataList }: WeaponListPageProps) => {
|
|
||||||
const { query, locale } = useRouter()
|
|
||||||
const { t } = useTranslation()
|
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 (
|
return (
|
||||||
<Honkai3rdLayout>
|
<Honkai3rdLayout>
|
||||||
<Box>
|
<Head
|
||||||
<Head
|
title={`${t('common.weapons')} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
||||||
title={`${t('common.weapons')} - ${t('common.honkai-3rd')} - ${t('common.abyss-lab')}`}
|
description={t('weapons-list.description')}
|
||||||
description={t('weapons-list.description')}
|
canonicalHref={`/honkai3rd/v2/weapons`}
|
||||||
canonicalHref={`/honkai3rd/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>
|
||||||
<Box p={3}>
|
<Flex sx={{ flexWrap: 'wrap' }}>
|
||||||
<Breadcrumb
|
{weaponCatalog
|
||||||
items={[
|
.filter(filterWeapons)
|
||||||
{ href: '/honkai3rd', label: t('common.honkai-3rd') },
|
.sort(sortWeapons)
|
||||||
{ href: '/honkai3rd/weapons', label: t('common.weapons') }
|
.map(weapon => {
|
||||||
]}
|
return (
|
||||||
/>
|
<Box key={weapon.id} m={1}>
|
||||||
|
<Link href={`/honkai3rd/v2/weapons/${weapon.id}`}>
|
||||||
<Heading as="h1">{t('weapons-list.weapons')}</Heading>
|
<Card p={1}>
|
||||||
<Box>
|
<Flex sx={{ justifyContent: 'center' }}>
|
||||||
<Heading as="h3">{t('weapons-list.filter-by-category')}</Heading>
|
<WeaponIcon icon={weapon.icon} rarity={weapon.maxRarity} />
|
||||||
<Flex mb={2} sx={{ flexWrap: 'wrap' }}>
|
</Flex>
|
||||||
{weaponFilterOptions.map(({ value, label, krLabel, icon }) => {
|
<Box
|
||||||
return (
|
sx={{
|
||||||
<FilterButton
|
overflow: 'hidden',
|
||||||
key={value}
|
textOverflow: 'ellipsis',
|
||||||
href={`?category=${value}`}
|
whiteSpace: 'nowrap',
|
||||||
active={value === categoryFilter}
|
px: 1,
|
||||||
icon={icon}
|
width: 112,
|
||||||
label={translate(locale, { 'ko-KR': krLabel }, label)}
|
textAlign: 'center'
|
||||||
m={1}
|
}}
|
||||||
/>
|
>
|
||||||
)
|
{weapon.name}
|
||||||
})}
|
</Box>
|
||||||
</Flex>
|
{/* {weapon.id} */}
|
||||||
</Box>
|
</Card>
|
||||||
<Flex
|
</Link>
|
||||||
sx={{
|
</Box>
|
||||||
flexWrap: 'wrap',
|
)
|
||||||
justifyContent: 'space-around'
|
})}
|
||||||
}}
|
</Flex>
|
||||||
>
|
|
||||||
{weaponList}
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Honkai3rdLayout>
|
</Honkai3rdLayout>
|
||||||
)
|
)
|
||||||
@@ -93,32 +71,76 @@ const WeaponListPage = ({ weaponDataList }: WeaponListPageProps) => {
|
|||||||
export default WeaponListPage
|
export default WeaponListPage
|
||||||
|
|
||||||
export async function getStaticProps({ locale }: NextPageContext) {
|
export async function getStaticProps({ locale }: NextPageContext) {
|
||||||
|
const weaponCatalog = loadWeaponCatalog()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: { weaponCatalog, ...(await getI18NProps(locale)) }
|
||||||
weaponDataList: listWeapons(locale).map(weapon => {
|
|
||||||
return pick(['name', 'id', 'rarity', 'category'], weapon)
|
|
||||||
}),
|
|
||||||
...(await getI18NProps(locale))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isWeaponHidden(weapon: WeaponListItemData, filter: string): boolean {
|
function filterWeapons(weapon: WeaponCatalogItem) {
|
||||||
switch (filter) {
|
// Valid weapons
|
||||||
case 'pistol':
|
// 24XXX EX Weapons
|
||||||
case 'katana':
|
// 21XXX Sprit Weapon
|
||||||
case 'cannon':
|
// 19XXX Alloy Weapons
|
||||||
case 'greatsword':
|
// 10XXX Regular Weapons
|
||||||
case 'cross':
|
|
||||||
case 'gauntlet':
|
// Event Weapon?
|
||||||
case 'scythe':
|
if (weapon.id.startsWith('18') && weapon.id.length === 5) {
|
||||||
case 'lance':
|
return false
|
||||||
case 'bow':
|
}
|
||||||
case 'chakram':
|
// Test Data?
|
||||||
case 'javelin':
|
if (weapon.id.startsWith('1023') && weapon.id.length === 6) {
|
||||||
return weapon.category !== filter
|
return false
|
||||||
default:
|
}
|
||||||
case 'all':
|
// 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
|
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