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:
Justin Edmund 2023-04-16 03:48:47 -07:00
parent ee37fea4d7
commit bad870a546
6 changed files with 576 additions and 0 deletions

View 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%;
}
}

View 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

View 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%;
}
}

View 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

View 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%;
}
}

View 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