Add Battlesuit page
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { Image, ThemeUIStyleObject } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
import { AttributeType } from '../../lib/v2-pre/data/types'
|
||||
|
||||
interface AttributeIconProps {
|
||||
attributeType: AttributeType
|
||||
size?: number
|
||||
className?: string
|
||||
sx?: ThemeUIStyleObject
|
||||
}
|
||||
|
||||
const AttributeIcon = ({ size, attributeType, className, sx }: AttributeIconProps) => {
|
||||
return (
|
||||
<Image src={getAttributeIconSrc(attributeType)} width={size} className={className} sx={sx} alt={attributeType} />
|
||||
)
|
||||
}
|
||||
|
||||
export default AttributeIcon
|
||||
|
||||
function getAttributeIconSrc(attributeType: AttributeType) {
|
||||
switch (attributeType) {
|
||||
case 'bio':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarattricons/AvatarShengWu.png`
|
||||
case 'psy':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarattricons/AvatarYiNeng.png`
|
||||
case 'mech':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarattricons/AvatarJiXie.png`
|
||||
case 'qua':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarattricons/AvatarLiangZi.png`
|
||||
case 'img':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarattricons/AvatarXuShu.png`
|
||||
case 'none':
|
||||
default:
|
||||
return `${assetsBucketBaseUrl}/raw/avatarattricons/AvatarNone.png`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Image, ThemeUICSSObject } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
|
||||
interface AvatarFigureImageProps {
|
||||
battlesuitId: string
|
||||
className?: string
|
||||
sx?: ThemeUICSSObject
|
||||
}
|
||||
|
||||
const AvatarFigureImage = ({ battlesuitId, className, sx }: AvatarFigureImageProps) => {
|
||||
return <Image src={getAvatarFigureImageSrc(battlesuitId)} className={className} alt={battlesuitId} sx={sx} />
|
||||
}
|
||||
|
||||
export default AvatarFigureImage
|
||||
|
||||
function getAvatarFigureImageSrc(battlesuitId: string) {
|
||||
if (battlesuitId.length < 4) {
|
||||
return `${assetsBucketBaseUrl}/raw/avatarcardfigures/60${battlesuitId}.png`
|
||||
}
|
||||
return `${assetsBucketBaseUrl}/raw/avatarcardfigures/6${battlesuitId}.png`
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
|
||||
interface AvatarSkillIconProps {
|
||||
icon: string
|
||||
}
|
||||
|
||||
const AvatarSkillIcon = ({ icon: fileName }: AvatarSkillIconProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
background: `no-repeat 50%/80% url(${assetsBucketBaseUrl}/raw/skillicons/${fileName}.png)`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default AvatarSkillIcon
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
|
||||
interface AvatarSubSkillIconProps {
|
||||
icon: string
|
||||
}
|
||||
|
||||
const AvatarSubSkillIcon = ({ icon: fileName }: AvatarSubSkillIconProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
background: `no-repeat 50%/80% url(${assetsBucketBaseUrl}/raw/subskillicons/${fileName}.png)`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default AvatarSubSkillIcon
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
import { AttributeType, BattlesuitCatalogItem } from '../../lib/v2-pre/data/types'
|
||||
|
||||
interface BattlesuitAvatarIconProps {
|
||||
battlesuit: BattlesuitCatalogItem
|
||||
}
|
||||
|
||||
const BattlesuitAvatarIcon = ({ battlesuit }: BattlesuitAvatarIconProps) => {
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
borderRadius: 5,
|
||||
background: `no-repeat 50% / 130px url(${assetsBucketBaseUrl}/raw/avataricon/${
|
||||
battlesuit.id
|
||||
}.png), no-repeat 50% / 130px url(${getAttributeBgImageSrc(battlesuit.attributeType)})`,
|
||||
width: 130,
|
||||
height: 120
|
||||
}}
|
||||
></Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default BattlesuitAvatarIcon
|
||||
|
||||
function getAttributeBgImageSrc(attrId: AttributeType, square = false) {
|
||||
if (square) {
|
||||
switch (attrId) {
|
||||
case 'bio':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrShengWu1.png`
|
||||
case 'psy':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrYiNeng1.png`
|
||||
case 'mech':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrJiXie1.png`
|
||||
case 'qua':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrLiangZi1.png`
|
||||
case 'img':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrXuShu1.png`
|
||||
case 'none':
|
||||
default:
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrDefault.png`
|
||||
}
|
||||
}
|
||||
switch (attrId) {
|
||||
case 'bio':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrShengWu.png`
|
||||
case 'psy':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrYiNeng.png`
|
||||
case 'mech':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrJiXie.png`
|
||||
case 'qua':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrLiangZi.png`
|
||||
case 'img':
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrXuShu.png`
|
||||
case 'none':
|
||||
default:
|
||||
return `${assetsBucketBaseUrl}/raw/avataricon/AttrDefault.png`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { BattlesuitCatalogItem } from '../../lib/v2-pre/data/types'
|
||||
import BattlesuitAvatarIcon from './BattlesuitAvatarIcon'
|
||||
|
||||
interface BattlesuitCatalogItemCardProps {
|
||||
battlesuit: BattlesuitCatalogItem
|
||||
label?: boolean
|
||||
}
|
||||
|
||||
const BattlesuitCatalogItemCard = ({ battlesuit, label = false }: BattlesuitCatalogItemCardProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
mb: 2,
|
||||
transform: 'scale(1)',
|
||||
transition: 'transform 200ms ease-in-out',
|
||||
'&:hover': {
|
||||
transform: 'scale(1.05)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<BattlesuitAvatarIcon battlesuit={battlesuit} />
|
||||
<Box
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
overflow: 'hidden',
|
||||
width: 110,
|
||||
marginLeft: -10,
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
{battlesuit.fullName}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default BattlesuitCatalogItemCard
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
import { CharacterType } from '../../lib/v2-pre/data/types'
|
||||
|
||||
interface ChibiIconProps {
|
||||
id: string
|
||||
}
|
||||
|
||||
const ChibiIcon = ({ id }: ChibiIconProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: 30,
|
||||
height: 30,
|
||||
background: `no-repeat 50% 50% / 30px url(${assetsBucketBaseUrl}/raw/avatarchibiicons/${getChibiIconName(
|
||||
id
|
||||
)}.png)`
|
||||
}}
|
||||
></Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default ChibiIcon
|
||||
|
||||
export function getChibiIconName(idOrType: string | CharacterType) {
|
||||
switch (idOrType) {
|
||||
case 'kiana':
|
||||
return '106'
|
||||
case 'mei':
|
||||
return '206'
|
||||
case 'bronya':
|
||||
return '317'
|
||||
case 'himeko':
|
||||
return '412'
|
||||
case 'theresa':
|
||||
return '502_05_01'
|
||||
case 'fuhua':
|
||||
return '612'
|
||||
case 'rita':
|
||||
return '706'
|
||||
case 'sakura':
|
||||
return '212'
|
||||
case 'kallen':
|
||||
return '111'
|
||||
case 'olenyevas':
|
||||
return '422_05_01'
|
||||
case 'seele':
|
||||
return '713'
|
||||
case 'durandal':
|
||||
return '804'
|
||||
case 'fischl':
|
||||
return '2101'
|
||||
case 'elysia':
|
||||
return '2202'
|
||||
case 'mobius':
|
||||
return '2301'
|
||||
case 'raven':
|
||||
return '2401'
|
||||
case 'carole':
|
||||
return '2501'
|
||||
case 'pardofelis':
|
||||
return '2601'
|
||||
case 'aponia':
|
||||
return '2701'
|
||||
case 'eden':
|
||||
return '2801'
|
||||
case 'griseo':
|
||||
return '2901'
|
||||
case 'vill-v':
|
||||
return '3001'
|
||||
case 'sushang':
|
||||
return '3101'
|
||||
case 'ai':
|
||||
return '3201'
|
||||
case 'susannah':
|
||||
return '3301'
|
||||
case 'hare':
|
||||
return '3401'
|
||||
case 'prometheus':
|
||||
return '3501'
|
||||
case 'kira':
|
||||
return '3601'
|
||||
case 'asuka':
|
||||
return '901'
|
||||
case 'keqing':
|
||||
return '2001'
|
||||
default:
|
||||
return 'IconAvatarQuestion'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Text } from 'theme-ui'
|
||||
import { FormattedTextToken, tokenize } from '../../lib/v2-pre/formattedText/tokenize'
|
||||
|
||||
interface FormattedTextProps {
|
||||
children: string
|
||||
}
|
||||
|
||||
const FormattedText = ({ children }: FormattedTextProps) => {
|
||||
const tokens = tokenize(children)
|
||||
|
||||
return <>{renderTokens(tokens)}</>
|
||||
|
||||
function renderTokens(tokens: FormattedTextToken[]) {
|
||||
return tokens.map((token, index) => {
|
||||
if (token.type === 'element') {
|
||||
return (
|
||||
<Text key={index} style={{ color: adjustColor(token.attributes.color) }}>
|
||||
{renderTokens(token.children)}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
return token.text
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default FormattedText
|
||||
|
||||
function adjustColor(color: unknown): string | undefined {
|
||||
if (typeof color !== 'string') {
|
||||
return undefined
|
||||
}
|
||||
const normalizedColor = color.toUpperCase()
|
||||
|
||||
if (normalizedColor.startsWith('#FEDF4C')) {
|
||||
return '#e6c010'
|
||||
}
|
||||
|
||||
if (normalizedColor.startsWith('#FFC741')) {
|
||||
return '#f0a030'
|
||||
}
|
||||
|
||||
if (
|
||||
normalizedColor.startsWith('#23B2E') ||
|
||||
normalizedColor.startsWith('#23B2E') ||
|
||||
normalizedColor.startsWith('#23B2E')
|
||||
) {
|
||||
return '#1d9ecc'
|
||||
}
|
||||
|
||||
return color
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
import { StarRank } from '../../lib/v2-pre/data/types'
|
||||
|
||||
interface StarIconProps {
|
||||
star: StarRank
|
||||
}
|
||||
|
||||
const StarIcon = ({ star }: StarIconProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: 30,
|
||||
height: 30,
|
||||
background: `no-repeat 50% / 30px url(${getStarIconPath(star)})`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default StarIcon
|
||||
|
||||
function getStarIconPath(star: StarRank) {
|
||||
switch (star) {
|
||||
case 'b':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstar/Star_Avatar_1.png`
|
||||
case 'a':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstar/Star_Avatar_2.png`
|
||||
case 's':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstar/Star_Avatar_3.png`
|
||||
case 'ss':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstar/Star_Avatar_4.png`
|
||||
case 'sss':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstar/Star_Avatar_5.png`
|
||||
case 's1':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstarskill/S1.png`
|
||||
case 's2':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstarskill/S2.png`
|
||||
case 's3':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstarskill/S3.png`
|
||||
case 'ss1':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstarskill/SS1.png`
|
||||
case 'ss2':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstarskill/SS2.png`
|
||||
case 'ss3':
|
||||
return `${assetsBucketBaseUrl}/raw/avatarstarskill/SS3.png`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
import { TagType } from '../../lib/v2-pre/data/types'
|
||||
|
||||
interface TagIconProps {
|
||||
type: TagType
|
||||
strength?: 1 | 2 | 3 | 4
|
||||
size?: 'sm' | 'md'
|
||||
comment?: string
|
||||
}
|
||||
|
||||
const TagIcon = ({ type, strength, size = 'md', comment }: TagIconProps) => {
|
||||
const boxSizePx = size === 'md' ? '30px' : '20px'
|
||||
const iconSizePx = size === 'md' ? '24px' : '16px'
|
||||
return (
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
right: '2px',
|
||||
top: '-2px',
|
||||
fontSize: 0,
|
||||
color: 'white',
|
||||
textShadow:
|
||||
'#555 0px 0px 1px, #555 0px 0px 1px, #555 0px 0px 1px,#555 0px 0px 1px, #555 0px 0px 1px, #555 0px 0px 1px'
|
||||
}}
|
||||
>
|
||||
{strength}
|
||||
</Box>
|
||||
<Box
|
||||
title={comment}
|
||||
sx={{
|
||||
borderRadius: 5,
|
||||
width: boxSizePx,
|
||||
height: boxSizePx,
|
||||
background: `no-repeat 50% / ${iconSizePx} ${iconSizePx} url(${assetsBucketBaseUrl}/raw/newstateicon/${getTagIconFileName(
|
||||
type
|
||||
)}.png), #5a8cb0`
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default TagIcon
|
||||
|
||||
function getTagIconFileName(type: TagType) {
|
||||
switch (type) {
|
||||
case 'branch':
|
||||
return 'State_Branch'
|
||||
case 'charge':
|
||||
return 'State_Charge'
|
||||
case 'physical-dmg':
|
||||
return 'State_Physical'
|
||||
case 'fire-dmg':
|
||||
return 'State_Fire'
|
||||
case 'ice-dmg':
|
||||
return 'State_Ice'
|
||||
case 'lightning-dmg':
|
||||
return 'State_Lightning'
|
||||
case 'freeze':
|
||||
return 'State_Frozen'
|
||||
case 'paralyze':
|
||||
return 'State_Paralysis'
|
||||
case 'stun':
|
||||
return 'State_Stun'
|
||||
case 'ignite':
|
||||
return 'State_Burn'
|
||||
case 'bleed':
|
||||
return 'State_Bleading'
|
||||
case 'heavy-atk':
|
||||
return 'State_Smash'
|
||||
case 'weaken':
|
||||
return 'State_Weak'
|
||||
case 'impair':
|
||||
return 'State_Fragile'
|
||||
case 'float':
|
||||
return 'State_Float'
|
||||
case 'time-mastery':
|
||||
return 'State_WitchTime'
|
||||
case 'gather':
|
||||
return 'State_SlowDown'
|
||||
case 'heal':
|
||||
return 'State_Heal'
|
||||
case 'fast-atk':
|
||||
return 'State_HighFreq'
|
||||
case 'burst':
|
||||
return 'State_Burst'
|
||||
case 'shield':
|
||||
return 'State_Shield'
|
||||
case 'aerial':
|
||||
return 'State_AntiAir'
|
||||
case 'ranged':
|
||||
return 'State_Remote'
|
||||
case 'meele':
|
||||
return 'State_Meele'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Box } from 'theme-ui'
|
||||
import { assetsBucketBaseUrl } from '../../lib/consts'
|
||||
import { WeaponType } from '../../lib/v2-pre/data/types'
|
||||
|
||||
interface WeaponTypeIconProps {
|
||||
type: WeaponType
|
||||
}
|
||||
|
||||
const WeaponTypeIcon = ({ type }: WeaponTypeIconProps) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
borderRadius: 5,
|
||||
width: 30,
|
||||
height: 30,
|
||||
background: `no-repeat 50% 50% / 24px url(${assetsBucketBaseUrl}/raw/weapontypeicons/${getWeaponIconPath(
|
||||
type
|
||||
)}.png), #5a8cb0`
|
||||
}}
|
||||
></Box>
|
||||
)
|
||||
}
|
||||
export default WeaponTypeIcon
|
||||
|
||||
function getWeaponIconPath(type: WeaponType) {
|
||||
switch (type) {
|
||||
case 'pistols':
|
||||
return 'DoublePistolType'
|
||||
case 'cannon':
|
||||
return 'MissileType'
|
||||
case 'katana':
|
||||
return 'SwordType'
|
||||
case 'cross':
|
||||
return 'CrossType'
|
||||
case '2-handed':
|
||||
return 'ClaymoreType'
|
||||
case 'scythe':
|
||||
return 'ScytheType'
|
||||
case 'lance':
|
||||
return 'LanceType'
|
||||
case 'fists':
|
||||
return 'FistType'
|
||||
case 'bow':
|
||||
return 'BowType'
|
||||
case 'chakram':
|
||||
return 'BladeRingType'
|
||||
case 'javelin':
|
||||
return 'JavelinType'
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user