Add reps for grid objects
These reps act like the existing PartyRep except for Characters and Summons, as well as a new component just for Weapons. They only render the grid of objects and nothing else. Eventually PartyRep will use WeaponRep
This commit is contained in:
parent
ee37fea4d7
commit
bad870a546
6 changed files with 576 additions and 0 deletions
75
components/reps/CharacterRep/index.scss
Normal file
75
components/reps/CharacterRep/index.scss
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
.CharacterRep {
|
||||
aspect-ratio: 2/0.99;
|
||||
border-radius: $card-corner;
|
||||
grid-gap: $unit-half; /* add a gap of 8px between grid items */
|
||||
height: $rep-height;
|
||||
|
||||
.Character {
|
||||
background: var(--card-bg);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.GridCharacters {
|
||||
display: grid; /* make the right-images container a grid */
|
||||
grid-template-columns: repeat(
|
||||
4,
|
||||
1fr
|
||||
); /* create 3 columns, each taking up 1 fraction */
|
||||
gap: $unit-half;
|
||||
}
|
||||
|
||||
.Grid.Character {
|
||||
aspect-ratio: 16 / 33;
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
overflow: hidden;
|
||||
|
||||
&.MC {
|
||||
border-color: transparent;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
aspect-ratio: 32 / 66;
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.fire {
|
||||
background: var(--fire-hover-bg);
|
||||
border-color: var(--fire-bg);
|
||||
}
|
||||
|
||||
&.water {
|
||||
background: var(--water-hover-bg);
|
||||
border-color: var(--water-bg);
|
||||
}
|
||||
|
||||
&.wind {
|
||||
background: var(--wind-hover-bg);
|
||||
border-color: var(--wind-bg);
|
||||
}
|
||||
|
||||
&.earth {
|
||||
background: var(--earth-hover-bg);
|
||||
border-color: var(--earth-bg);
|
||||
}
|
||||
|
||||
&.light {
|
||||
background: var(--light-hover-bg);
|
||||
border-color: var(--light-bg);
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background: var(--dark-hover-bg);
|
||||
border-color: var(--dark-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Grid.Character img[src*='jpg'] {
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
132
components/reps/CharacterRep/index.tsx
Normal file
132
components/reps/CharacterRep/index.tsx
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import 'fix-date'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props {
|
||||
job?: Job
|
||||
gender?: number
|
||||
element?: number
|
||||
grid: GridArray<GridCharacter>
|
||||
}
|
||||
|
||||
const CHARACTERS_COUNT = 3
|
||||
|
||||
const CharacterRep = (props: Props) => {
|
||||
// Localization for alt tags
|
||||
const router = useRouter()
|
||||
const { t } = useTranslation('common')
|
||||
const locale =
|
||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||
|
||||
// Component state
|
||||
const [characters, setCharacters] = useState<GridArray<Character>>({})
|
||||
const [grid, setGrid] = useState<GridArray<GridCharacter>>({})
|
||||
|
||||
// On grid update
|
||||
useEffect(() => {
|
||||
const newCharacters = Array(CHARACTERS_COUNT)
|
||||
const gridCharacters = Array(CHARACTERS_COUNT)
|
||||
|
||||
if (props.grid) {
|
||||
for (const [key, value] of Object.entries(props.grid)) {
|
||||
if (value) {
|
||||
newCharacters[value.position] = value.object
|
||||
gridCharacters[value.position] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCharacters(newCharacters)
|
||||
setGrid(gridCharacters)
|
||||
}, [props.grid])
|
||||
|
||||
// Convert element to string
|
||||
function numberToElement() {
|
||||
switch (props.element) {
|
||||
case 1:
|
||||
return 'wind'
|
||||
case 2:
|
||||
return 'fire'
|
||||
case 3:
|
||||
return 'water'
|
||||
case 4:
|
||||
return 'earth'
|
||||
case 5:
|
||||
return 'dark'
|
||||
case 6:
|
||||
return 'light'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// Methods: Image generation
|
||||
function generateMCImage() {
|
||||
let source = ''
|
||||
|
||||
if (props.job) {
|
||||
const slug = props.job.name.en.replaceAll(' ', '-').toLowerCase()
|
||||
const gender = props.gender == 1 ? 'b' : 'a'
|
||||
source = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/job-portraits/${slug}_${gender}.png`
|
||||
}
|
||||
|
||||
return props.job && props.job.id !== '-1' ? (
|
||||
<img alt={props.job ? props.job?.name[locale] : ''} src={source} />
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
function generateGridImage(position: number) {
|
||||
let url = ''
|
||||
|
||||
const character = characters[position]
|
||||
const gridCharacter = grid[position]
|
||||
|
||||
if (character && gridCharacter) {
|
||||
// Change the image based on the uncap level
|
||||
let suffix = '01'
|
||||
if (gridCharacter.transcendence_step > 0) suffix = '04'
|
||||
else if (gridCharacter.uncap_level >= 5) suffix = '03'
|
||||
else if (gridCharacter.uncap_level > 2) suffix = '02'
|
||||
|
||||
if (character.element == 0) {
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-main/${character.granblue_id}_${props.element}.jpg`
|
||||
} else {
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-main/${character.granblue_id}_${suffix}.jpg`
|
||||
}
|
||||
}
|
||||
|
||||
return characters[position] ? (
|
||||
<img alt={characters[position]?.name[locale]} src={url} />
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
// Render
|
||||
return (
|
||||
<div className="CharacterRep Rep">
|
||||
<ul className="GridCharacters">
|
||||
<li
|
||||
key="characters-job"
|
||||
className={`Grid Character MC ${numberToElement()}`}
|
||||
>
|
||||
{generateMCImage()}
|
||||
</li>
|
||||
{Array.from(Array(CHARACTERS_COUNT)).map((x, i) => {
|
||||
return (
|
||||
<li key={`characters-${i}`} className="Grid Character">
|
||||
{generateGridImage(i)}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CharacterRep
|
||||
45
components/reps/SummonRep/index.scss
Normal file
45
components/reps/SummonRep/index.scss
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
.SummonRep {
|
||||
aspect-ratio: 2/1.045;
|
||||
border-radius: $card-corner;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2.25fr; /* left column takes up 1 fraction, right column takes up 3 fractions */
|
||||
grid-gap: $unit-half; /* add a gap of 8px between grid items */
|
||||
height: $rep-height;
|
||||
|
||||
.Summon {
|
||||
background: var(--card-bg);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.Main.Summon {
|
||||
aspect-ratio: 56/97;
|
||||
display: grid;
|
||||
grid-column: 1 / 2; /* spans one column */
|
||||
}
|
||||
|
||||
.GridSummons {
|
||||
display: grid; /* make the right-images container a grid */
|
||||
grid-template-columns: repeat(
|
||||
2,
|
||||
1fr
|
||||
); /* create 3 columns, each taking up 1 fraction */
|
||||
grid-template-rows: repeat(
|
||||
2,
|
||||
1fr
|
||||
); /* create 3 rows, each taking up 1 fraction */
|
||||
gap: $unit-half;
|
||||
// column-gap: $unit;
|
||||
// row-gap: $unit-2x;
|
||||
}
|
||||
|
||||
.Grid.Summon {
|
||||
aspect-ratio: 184 / 138;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.Main.Summon img[src*='jpg'],
|
||||
.Grid.Summon img[src*='jpg'] {
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
172
components/reps/SummonRep/index.tsx
Normal file
172
components/reps/SummonRep/index.tsx
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import 'fix-date'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props {
|
||||
grid: {
|
||||
mainSummon: GridSummon | undefined
|
||||
friendSummon: GridSummon | undefined
|
||||
allSummons: GridArray<GridSummon>
|
||||
}
|
||||
}
|
||||
|
||||
const SUMMONS_COUNT = 4
|
||||
|
||||
const SummonRep = (props: Props) => {
|
||||
// Localization for alt tags
|
||||
const router = useRouter()
|
||||
const { t } = useTranslation('common')
|
||||
const locale =
|
||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||
|
||||
// Component state
|
||||
const [mainSummon, setMainSummon] = useState<GridSummon>()
|
||||
const [summons, setSummons] = useState<GridArray<Summon>>({})
|
||||
const [grid, setGrid] = useState<GridArray<GridSummon>>({})
|
||||
|
||||
// On grid update
|
||||
useEffect(() => {
|
||||
const newSummons = Array(SUMMONS_COUNT)
|
||||
const gridSummons = Array(SUMMONS_COUNT)
|
||||
|
||||
if (props.grid.mainSummon) {
|
||||
setMainSummon(props.grid.mainSummon)
|
||||
}
|
||||
|
||||
if (props.grid.allSummons) {
|
||||
for (const [key, value] of Object.entries(props.grid.allSummons)) {
|
||||
if (value) {
|
||||
newSummons[value.position] = value.object
|
||||
gridSummons[value.position] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSummons(newSummons)
|
||||
setGrid(gridSummons)
|
||||
}, [props.grid])
|
||||
|
||||
// Methods: Image generation
|
||||
function generateMainImage() {
|
||||
let url = ''
|
||||
|
||||
const upgradedSummons = [
|
||||
'2040094000',
|
||||
'2040100000',
|
||||
'2040080000',
|
||||
'2040098000',
|
||||
'2040090000',
|
||||
'2040084000',
|
||||
'2040003000',
|
||||
'2040056000',
|
||||
'2040020000',
|
||||
'2040034000',
|
||||
'2040028000',
|
||||
'2040027000',
|
||||
'2040046000',
|
||||
'2040047000',
|
||||
]
|
||||
|
||||
if (mainSummon) {
|
||||
// Change the image based on the uncap level
|
||||
let suffix = ''
|
||||
if (mainSummon.object.uncap.xlb && mainSummon.uncap_level == 6) {
|
||||
if (
|
||||
mainSummon.transcendence_step >= 1 &&
|
||||
mainSummon.transcendence_step < 5
|
||||
) {
|
||||
suffix = '_03'
|
||||
} else if (mainSummon.transcendence_step === 5) {
|
||||
suffix = '_04'
|
||||
}
|
||||
} else if (
|
||||
upgradedSummons.indexOf(mainSummon.object.granblue_id.toString()) !=
|
||||
-1 &&
|
||||
mainSummon.uncap_level == 5
|
||||
) {
|
||||
suffix = '_02'
|
||||
}
|
||||
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-main/${mainSummon.object.granblue_id}${suffix}.jpg`
|
||||
}
|
||||
|
||||
return mainSummon ? (
|
||||
<img alt={mainSummon.object.name[locale]} src={url} />
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
function generateGridImage(position: number) {
|
||||
let url = ''
|
||||
|
||||
const summon = summons[position]
|
||||
const gridSummon = grid[position]
|
||||
|
||||
const upgradedSummons = [
|
||||
'2040094000',
|
||||
'2040100000',
|
||||
'2040080000',
|
||||
'2040098000',
|
||||
'2040090000',
|
||||
'2040084000',
|
||||
'2040003000',
|
||||
'2040056000',
|
||||
'2040020000',
|
||||
'2040034000',
|
||||
'2040028000',
|
||||
'2040027000',
|
||||
'2040046000',
|
||||
'2040047000',
|
||||
]
|
||||
|
||||
if (summon && gridSummon) {
|
||||
// Change the image based on the uncap level
|
||||
let suffix = ''
|
||||
if (gridSummon.object.uncap.xlb && gridSummon.uncap_level == 6) {
|
||||
if (
|
||||
gridSummon.transcendence_step >= 1 &&
|
||||
gridSummon.transcendence_step < 5
|
||||
) {
|
||||
suffix = '_03'
|
||||
} else if (gridSummon.transcendence_step === 5) {
|
||||
suffix = '_04'
|
||||
}
|
||||
} else if (
|
||||
upgradedSummons.indexOf(summon.granblue_id.toString()) != -1 &&
|
||||
gridSummon.uncap_level == 5
|
||||
) {
|
||||
suffix = '_02'
|
||||
}
|
||||
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-grid/${summon.granblue_id}${suffix}.jpg`
|
||||
}
|
||||
|
||||
return summons[position] ? (
|
||||
<img alt={summons[position]?.name[locale]} src={url} />
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
// Render
|
||||
return (
|
||||
<div className="SummonRep Rep">
|
||||
<div className="Main Summon">{generateMainImage()}</div>
|
||||
<ul className="GridSummons">
|
||||
{Array.from(Array(SUMMONS_COUNT)).map((x, i) => {
|
||||
return (
|
||||
<li key={`summons-${i + 1}`} className="Grid Summon">
|
||||
{generateGridImage(i + 1)}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SummonRep
|
||||
46
components/reps/WeaponRep/index.scss
Normal file
46
components/reps/WeaponRep/index.scss
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
.WeaponRep {
|
||||
aspect-ratio: 2/0.95;
|
||||
border-radius: $card-corner;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 3.39fr; /* left column takes up 1 fraction, right column takes up 3 fractions */
|
||||
grid-gap: $unit-half; /* add a gap of 8px between grid items */
|
||||
height: $rep-height;
|
||||
|
||||
.Weapon {
|
||||
background: var(--card-bg);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.Mainhand.Weapon {
|
||||
aspect-ratio: 73/153;
|
||||
display: grid;
|
||||
grid-column: 1 / 2; /* spans one column */
|
||||
max-height: 149px;
|
||||
}
|
||||
|
||||
.GridWeapons {
|
||||
display: grid; /* make the right-images container a grid */
|
||||
grid-template-columns: repeat(
|
||||
3,
|
||||
1fr
|
||||
); /* create 3 columns, each taking up 1 fraction */
|
||||
grid-template-rows: repeat(
|
||||
3,
|
||||
1fr
|
||||
); /* create 3 rows, each taking up 1 fraction */
|
||||
gap: $unit-half;
|
||||
// column-gap: $unit;
|
||||
// row-gap: $unit-2x;
|
||||
}
|
||||
|
||||
.Grid.Weapon {
|
||||
aspect-ratio: 280 / 160;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.Mainhand.Weapon img[src*='jpg'],
|
||||
.Grid.Weapon img[src*='jpg'] {
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
106
components/reps/WeaponRep/index.tsx
Normal file
106
components/reps/WeaponRep/index.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import 'fix-date'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props {
|
||||
grid: {
|
||||
mainWeapon: GridWeapon | undefined
|
||||
allWeapons: GridArray<GridWeapon>
|
||||
}
|
||||
}
|
||||
|
||||
const WEAPONS_COUNT = 9
|
||||
|
||||
const WeaponRep = (props: Props) => {
|
||||
// Localization for alt tags
|
||||
const router = useRouter()
|
||||
const { t } = useTranslation('common')
|
||||
const locale =
|
||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||
|
||||
// Component state
|
||||
const [mainhand, setMainhand] = useState<GridWeapon>()
|
||||
const [weapons, setWeapons] = useState<GridArray<Weapon>>({})
|
||||
const [grid, setGrid] = useState<GridArray<GridWeapon>>({})
|
||||
|
||||
// On grid update
|
||||
useEffect(() => {
|
||||
const newWeapons = Array(WEAPONS_COUNT)
|
||||
const gridWeapons = Array(WEAPONS_COUNT)
|
||||
|
||||
if (props.grid.mainWeapon) {
|
||||
setMainhand(props.grid.mainWeapon)
|
||||
} else {
|
||||
setMainhand(undefined)
|
||||
}
|
||||
|
||||
if (props.grid.allWeapons) {
|
||||
for (const [key, value] of Object.entries(props.grid.allWeapons)) {
|
||||
if (value) {
|
||||
newWeapons[value.position] = value.object
|
||||
gridWeapons[value.position] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setWeapons(newWeapons)
|
||||
setGrid(gridWeapons)
|
||||
}, [props.grid])
|
||||
|
||||
// Methods: Image generation
|
||||
function generateMainhandImage() {
|
||||
let url = ''
|
||||
|
||||
if (mainhand && mainhand.object) {
|
||||
if (mainhand.object.element == 0 && mainhand.element) {
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.object.granblue_id}_${mainhand.element}.jpg`
|
||||
} else {
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.object.granblue_id}.jpg`
|
||||
}
|
||||
}
|
||||
|
||||
return mainhand ? <img alt={mainhand.object.name[locale]} src={url} /> : ''
|
||||
}
|
||||
|
||||
function generateGridImage(position: number) {
|
||||
let url = ''
|
||||
|
||||
const weapon = weapons[position]
|
||||
const gridWeapon = grid[position]
|
||||
|
||||
if (weapon && gridWeapon) {
|
||||
if (weapon.element == 0 && gridWeapon.element) {
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}_${gridWeapon.element}.jpg`
|
||||
} else {
|
||||
url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}.jpg`
|
||||
}
|
||||
}
|
||||
|
||||
return weapons[position] ? (
|
||||
<img alt={weapons[position]?.name[locale]} src={url} />
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
// Render
|
||||
return (
|
||||
<div className="WeaponRep Rep">
|
||||
<div className="Mainhand Weapon">{generateMainhandImage()}</div>
|
||||
<ul className="GridWeapons">
|
||||
{Array.from(Array(WEAPONS_COUNT)).map((x, i) => {
|
||||
return (
|
||||
<li key={`weapons-${i}`} className="Grid Weapon">
|
||||
{generateGridImage(i)}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default WeaponRep
|
||||
Loading…
Reference in a new issue