commit
492c2b40ed
36 changed files with 1343 additions and 214 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -51,6 +51,8 @@ public/images/weapon*
|
|||
public/images/summon*
|
||||
public/images/chara*
|
||||
public/images/job*
|
||||
public/images/awakening*
|
||||
public/images/ax*
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
|
|
|||
31
components/AwakeningSelect/index.scss
Normal file
31
components/AwakeningSelect/index.scss
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
.AwakeningSelect .AwakeningSet {
|
||||
.errors {
|
||||
color: $error;
|
||||
display: none;
|
||||
padding: $unit 0;
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.fields {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $unit;
|
||||
width: 100%;
|
||||
|
||||
.SelectTrigger {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.Label {
|
||||
flex-grow: 0;
|
||||
|
||||
.Input {
|
||||
min-width: $unit * 12;
|
||||
width: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
192
components/AwakeningSelect/index.tsx
Normal file
192
components/AwakeningSelect/index.tsx
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
import React, { ForwardedRef, useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import Input from '~components/Input'
|
||||
import Select from '~components/Select'
|
||||
import SelectItem from '~components/SelectItem'
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { weaponAwakening, characterAwakening } from '~utils/awakening'
|
||||
import type { Awakening } from '~utils/awakening'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props {
|
||||
object: 'character' | 'weapon'
|
||||
awakeningType?: number
|
||||
awakeningLevel?: number
|
||||
sendValidity: (isValid: boolean) => void
|
||||
sendValues: (type: number, level: number) => void
|
||||
}
|
||||
|
||||
const AwakeningSelect = (props: Props) => {
|
||||
const router = useRouter()
|
||||
const locale =
|
||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
// Refs
|
||||
const awakeningLevelInput = React.createRef<HTMLInputElement>()
|
||||
|
||||
// States
|
||||
const [awakeningType, setAwakeningType] = useState(-1)
|
||||
const [awakeningLevel, setAwakeningLevel] = useState(1)
|
||||
|
||||
const [maxValue, setMaxValue] = useState(1)
|
||||
|
||||
const [error, setError] = useState('')
|
||||
|
||||
// Classes
|
||||
const inputClasses = classNames({
|
||||
Bound: true,
|
||||
Hidden: awakeningType === -1,
|
||||
})
|
||||
|
||||
const errorClasses = classNames({
|
||||
errors: true,
|
||||
visible: error !== '',
|
||||
})
|
||||
|
||||
// Set max value based on object type
|
||||
useEffect(() => {
|
||||
if (props.object === 'character') setMaxValue(9)
|
||||
else if (props.object === 'weapon') setMaxValue(15)
|
||||
}, [props.object])
|
||||
|
||||
// Set default awakening and level based on object type
|
||||
useEffect(() => {
|
||||
let defaultAwakening = 0
|
||||
if (props.object === 'weapon') defaultAwakening = -1
|
||||
|
||||
setAwakeningType(
|
||||
props.awakeningType != undefined ? props.awakeningType : defaultAwakening
|
||||
)
|
||||
setAwakeningLevel(props.awakeningLevel ? props.awakeningLevel : 1)
|
||||
}, [props.object, props.awakeningType, props.awakeningLevel])
|
||||
|
||||
// Send awakening type and level when changed
|
||||
useEffect(() => {
|
||||
props.sendValues(awakeningType, awakeningLevel)
|
||||
}, [props.sendValues, awakeningType, awakeningLevel])
|
||||
|
||||
// Send validity of form when awakening level changes
|
||||
useEffect(() => {
|
||||
props.sendValidity(awakeningLevel > 0 && error === '')
|
||||
}, [props.sendValidity, awakeningLevel, error])
|
||||
|
||||
// Classes
|
||||
function changeOpen() {
|
||||
setOpen(!open)
|
||||
}
|
||||
|
||||
function generateOptions(object: 'character' | 'weapon') {
|
||||
let options: Awakening[] = []
|
||||
if (object === 'character') options = characterAwakening
|
||||
else if (object === 'weapon') options = weaponAwakening
|
||||
else return
|
||||
|
||||
let optionElements: React.ReactNode[] = options.map((awakening, i) => {
|
||||
return (
|
||||
<SelectItem key={i} value={awakening.id}>
|
||||
{awakening.name[locale]}
|
||||
</SelectItem>
|
||||
)
|
||||
})
|
||||
|
||||
if (object === 'weapon') {
|
||||
optionElements?.unshift(
|
||||
<SelectItem key={-1} value={-1}>
|
||||
{t('awakening.no_type')}
|
||||
</SelectItem>
|
||||
)
|
||||
}
|
||||
|
||||
return optionElements
|
||||
}
|
||||
|
||||
function handleSelectChange(rawValue: string) {
|
||||
const value = parseInt(rawValue)
|
||||
setAwakeningType(value)
|
||||
}
|
||||
|
||||
function handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
const value = parseFloat(event.target.value)
|
||||
if (handleLevelError(value)) setAwakeningLevel(value)
|
||||
}
|
||||
|
||||
function handleLevelError(value: number) {
|
||||
let error = ''
|
||||
if (value < 1) {
|
||||
error = t('awakening.errors.value_too_low', {
|
||||
minValue: 1,
|
||||
})
|
||||
} else if (value > maxValue) {
|
||||
error = t('awakening.errors.value_too_high', {
|
||||
maxValue: maxValue,
|
||||
})
|
||||
} else if (value % 1 != 0) {
|
||||
error = t('awakening.errors.value_not_whole')
|
||||
} else if (!value || value <= 0) {
|
||||
error = t('awakening.errors.value_empty')
|
||||
} else {
|
||||
error = ''
|
||||
}
|
||||
|
||||
setError(error)
|
||||
|
||||
return error.length === 0
|
||||
}
|
||||
|
||||
const rangeString = (object: 'character' | 'weapon') => {
|
||||
let minValue = 1
|
||||
let maxValue = 1
|
||||
|
||||
if (object === 'weapon') {
|
||||
minValue = 1
|
||||
maxValue = 15
|
||||
} else if (object === 'character') {
|
||||
minValue = 1
|
||||
maxValue = 9
|
||||
} else return
|
||||
|
||||
return `${minValue}~${maxValue}`
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="AwakeningSelect">
|
||||
<div className="AwakeningSet">
|
||||
<div className="fields">
|
||||
<Select
|
||||
key="awakening_type"
|
||||
value={`${awakeningType}`}
|
||||
open={open}
|
||||
onValueChange={handleSelectChange}
|
||||
onClick={() => changeOpen()}
|
||||
triggerClass="modal"
|
||||
>
|
||||
{generateOptions(props.object)}
|
||||
</Select>
|
||||
|
||||
<Input
|
||||
value={awakeningLevel}
|
||||
className={inputClasses}
|
||||
type="number"
|
||||
placeholder={rangeString(props.object)}
|
||||
min={1}
|
||||
max={maxValue}
|
||||
step="1"
|
||||
onChange={handleInputChange}
|
||||
ref={awakeningLevelInput}
|
||||
/>
|
||||
</div>
|
||||
<p className={errorClasses}>{error}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AwakeningSelect
|
||||
|
|
@ -23,25 +23,24 @@
|
|||
flex-direction: row;
|
||||
gap: $unit;
|
||||
|
||||
select {
|
||||
.SelectTrigger {
|
||||
flex-grow: 1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Input {
|
||||
input {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border: none;
|
||||
background-color: $grey-90;
|
||||
border-radius: 6px;
|
||||
border-radius: $input-corner;
|
||||
box-sizing: border-box;
|
||||
color: $grey-15;
|
||||
height: $unit * 6;
|
||||
display: block;
|
||||
font-size: $font-regular;
|
||||
padding: $unit;
|
||||
display: none;
|
||||
text-align: right;
|
||||
min-width: 100px;
|
||||
min-width: $unit-14x;
|
||||
width: 100px;
|
||||
|
||||
&.Visible {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import React, { ForwardedRef, useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import Select from '~components/Select'
|
||||
import SelectItem from '~components/SelectItem'
|
||||
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { axData } from '~utils/axData'
|
||||
|
|
@ -32,6 +35,9 @@ const AXSelect = (props: Props) => {
|
|||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
const [openAX1, setOpenAX1] = useState(false)
|
||||
const [openAX2, setOpenAX2] = useState(false)
|
||||
|
||||
// Set up form states and error handling
|
||||
const [errors, setErrors] = useState<ErrorMap>({
|
||||
axValue1: '',
|
||||
|
|
@ -49,9 +55,9 @@ const AXSelect = (props: Props) => {
|
|||
})
|
||||
|
||||
// Refs
|
||||
const primaryAxModifierSelect = React.createRef<HTMLSelectElement>()
|
||||
const primaryAxModifierSelect = React.createRef<HTMLButtonElement>()
|
||||
const primaryAxValueInput = React.createRef<HTMLInputElement>()
|
||||
const secondaryAxModifierSelect = React.createRef<HTMLSelectElement>()
|
||||
const secondaryAxModifierSelect = React.createRef<HTMLButtonElement>()
|
||||
const secondaryAxValueInput = React.createRef<HTMLInputElement>()
|
||||
|
||||
// States
|
||||
|
|
@ -61,19 +67,8 @@ const AXSelect = (props: Props) => {
|
|||
const [secondaryAxValue, setSecondaryAxValue] = useState(0.0)
|
||||
|
||||
useEffect(() => {
|
||||
if (props.currentSkills && props.currentSkills[0]) {
|
||||
if (props.currentSkills[0].modifier != null)
|
||||
setPrimaryAxModifier(props.currentSkills[0].modifier)
|
||||
|
||||
setPrimaryAxValue(props.currentSkills[0].strength)
|
||||
}
|
||||
|
||||
if (props.currentSkills && props.currentSkills[1]) {
|
||||
if (props.currentSkills[1].modifier != null)
|
||||
setSecondaryAxModifier(props.currentSkills[1].modifier)
|
||||
|
||||
setSecondaryAxValue(props.currentSkills[1].strength)
|
||||
}
|
||||
setupAx1()
|
||||
setupAx2()
|
||||
}, [props.currentSkills])
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -92,10 +87,68 @@ const AXSelect = (props: Props) => {
|
|||
])
|
||||
|
||||
useEffect(() => {
|
||||
props.sendValidity(
|
||||
primaryAxValue > 0 && errors.axValue1 === '' && errors.axValue2 === ''
|
||||
if (
|
||||
props.currentSkills &&
|
||||
props.currentSkills[0].modifier != null &&
|
||||
props.currentSkills[0].modifier >= 0
|
||||
) {
|
||||
setPrimaryAxModifier(props.currentSkills[0].modifier)
|
||||
setPrimaryAxValue(props.currentSkills[0].strength)
|
||||
} else setPrimaryAxModifier(-1)
|
||||
}, [props.currentSkills, setPrimaryAxModifier])
|
||||
|
||||
useEffect(() => {
|
||||
if (props.currentSkills && props.currentSkills[1].modifier) {
|
||||
setSecondaryAxModifier(props.currentSkills[1].modifier)
|
||||
setSecondaryAxValue(props.currentSkills[1].strength)
|
||||
} else {
|
||||
setSecondaryAxModifier(-1)
|
||||
}
|
||||
}, [props.currentSkills, setSecondaryAxModifier])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(
|
||||
primaryAxModifier,
|
||||
primaryAxValue,
|
||||
secondaryAxModifier,
|
||||
secondaryAxValue
|
||||
)
|
||||
}, [props, primaryAxValue, errors])
|
||||
|
||||
let noErrors = false
|
||||
|
||||
if (errors.axValue1 === '' && errors.axValue2 === '') {
|
||||
if (primaryAxModifier === -1 && secondaryAxModifier === -1)
|
||||
noErrors = true
|
||||
else if (
|
||||
primaryAxModifier >= 0 &&
|
||||
primaryAxValue > 0 &&
|
||||
secondaryAxModifier === -1
|
||||
)
|
||||
noErrors = true
|
||||
else if (
|
||||
primaryAxModifier >= 0 &&
|
||||
primaryAxValue > 0 &&
|
||||
secondaryAxModifier >= 0 &&
|
||||
secondaryAxValue > 0
|
||||
)
|
||||
noErrors = true
|
||||
else
|
||||
console.log(
|
||||
primaryAxModifier >= 0,
|
||||
primaryAxValue > 0,
|
||||
secondaryAxModifier >= 0,
|
||||
secondaryAxValue > 0
|
||||
)
|
||||
}
|
||||
|
||||
props.sendValidity(noErrors)
|
||||
}, [
|
||||
primaryAxModifier,
|
||||
primaryAxValue,
|
||||
secondaryAxModifier,
|
||||
secondaryAxValue,
|
||||
errors,
|
||||
])
|
||||
|
||||
// Classes
|
||||
const secondarySetClasses = classNames({
|
||||
|
|
@ -103,6 +156,62 @@ const AXSelect = (props: Props) => {
|
|||
hidden: primaryAxModifier < 0,
|
||||
})
|
||||
|
||||
function setupAx1() {
|
||||
if (
|
||||
props.currentSkills &&
|
||||
props.currentSkills[0] &&
|
||||
// Should this be > -1 or != null
|
||||
props.currentSkills[0].modifier != null
|
||||
) {
|
||||
setPrimaryAxModifier(props.currentSkills[0].modifier)
|
||||
setPrimaryAxValue(props.currentSkills[0].strength)
|
||||
|
||||
if (props.currentSkills[0].modifier > -1 && primaryAxValueInput.current) {
|
||||
const modifier = props.currentSkills[0].modifier
|
||||
const axSkill = axData[props.axType - 1][modifier]
|
||||
setupInput(axSkill, primaryAxValueInput.current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupAx2() {
|
||||
if (
|
||||
props.currentSkills &&
|
||||
props.currentSkills[1] &&
|
||||
// Should this be > -1 or != null
|
||||
props.currentSkills[1].modifier != null
|
||||
) {
|
||||
const firstSkill = props.currentSkills[0]
|
||||
const primaryAxSkill = axData[props.axType - 1][firstSkill.modifier]
|
||||
const secondaryAxSkill = findSecondaryAxSkill(
|
||||
primaryAxSkill,
|
||||
props.currentSkills[1]
|
||||
)
|
||||
|
||||
if (
|
||||
props.currentSkills[1].modifier > -1 &&
|
||||
secondaryAxValueInput.current
|
||||
) {
|
||||
setupInput(secondaryAxSkill, secondaryAxValueInput.current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findSecondaryAxSkill(
|
||||
axSkill: AxSkill | undefined,
|
||||
skillAtIndex: SimpleAxSkill
|
||||
) {
|
||||
if (axSkill)
|
||||
return axSkill.secondary
|
||||
? axSkill.secondary.find((skill) => skill.id === skillAtIndex.modifier)
|
||||
: undefined
|
||||
}
|
||||
|
||||
function openSelect(ref: ForwardedRef<HTMLButtonElement>) {
|
||||
if (ref === primaryAxModifierSelect) setOpenAX1(!openAX1)
|
||||
if (ref === secondaryAxModifierSelect) setOpenAX2(!openAX2)
|
||||
}
|
||||
|
||||
function generateOptions(modifierSet: number) {
|
||||
const axOptions = axData[props.axType - 1]
|
||||
|
||||
|
|
@ -110,9 +219,9 @@ const AXSelect = (props: Props) => {
|
|||
if (modifierSet == 0) {
|
||||
axOptionElements = axOptions.map((ax, i) => {
|
||||
return (
|
||||
<option key={i} value={ax.id}>
|
||||
<SelectItem key={i} value={ax.id}>
|
||||
{ax.name[locale]}
|
||||
</option>
|
||||
</SelectItem>
|
||||
)
|
||||
})
|
||||
} else {
|
||||
|
|
@ -129,9 +238,9 @@ const AXSelect = (props: Props) => {
|
|||
const secondaryAxOptions = primarySkill.secondary
|
||||
axOptionElements = secondaryAxOptions.map((ax, i) => {
|
||||
return (
|
||||
<option key={i} value={ax.id}>
|
||||
<SelectItem key={i} value={ax.id}>
|
||||
{ax.name[locale]}
|
||||
</option>
|
||||
</SelectItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -139,39 +248,47 @@ const AXSelect = (props: Props) => {
|
|||
}
|
||||
|
||||
axOptionElements?.unshift(
|
||||
<option key={-1} value={-1}>
|
||||
<SelectItem key={-1} value={-1}>
|
||||
{t('ax.no_skill')}
|
||||
</option>
|
||||
</SelectItem>
|
||||
)
|
||||
return axOptionElements
|
||||
}
|
||||
|
||||
function handleSelectChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||
const value = parseInt(event.target.value)
|
||||
function handleAX1SelectChange(rawValue: string) {
|
||||
const value = parseInt(rawValue)
|
||||
setPrimaryAxModifier(value)
|
||||
|
||||
if (primaryAxModifierSelect.current == event.target) {
|
||||
setPrimaryAxModifier(value)
|
||||
if (
|
||||
primaryAxValueInput.current &&
|
||||
secondaryAxModifierSelect.current &&
|
||||
secondaryAxValueInput.current
|
||||
) {
|
||||
setupInput(axData[props.axType - 1][value], primaryAxValueInput.current)
|
||||
setPrimaryAxValue(0)
|
||||
primaryAxValueInput.current.value = ''
|
||||
|
||||
if (
|
||||
primaryAxValueInput.current &&
|
||||
secondaryAxModifierSelect.current &&
|
||||
secondaryAxValueInput.current
|
||||
) {
|
||||
setupInput(axData[props.axType - 1][value], primaryAxValueInput.current)
|
||||
// Reset the secondary AX modifier, reset the AX value and hide the input
|
||||
setSecondaryAxModifier(-1)
|
||||
setSecondaryAxValue(0)
|
||||
secondaryAxValueInput.current.className = 'Input Contained'
|
||||
secondaryAxValueInput.current.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
secondaryAxModifierSelect.current.value = '-1'
|
||||
secondaryAxValueInput.current.value = ''
|
||||
}
|
||||
} else {
|
||||
setSecondaryAxModifier(value)
|
||||
function handleAX2SelectChange(rawValue: string) {
|
||||
const value = parseInt(rawValue)
|
||||
setSecondaryAxModifier(value)
|
||||
|
||||
const primaryAxSkill = axData[props.axType - 1][primaryAxModifier]
|
||||
const currentAxSkill = primaryAxSkill.secondary
|
||||
? primaryAxSkill.secondary.find((skill) => skill.id == value)
|
||||
: undefined
|
||||
const primaryAxSkill = axData[props.axType - 1][primaryAxModifier]
|
||||
const currentAxSkill = primaryAxSkill.secondary
|
||||
? primaryAxSkill.secondary.find((skill) => skill.id == value)
|
||||
: undefined
|
||||
|
||||
if (secondaryAxValueInput.current)
|
||||
setupInput(currentAxSkill, secondaryAxValueInput.current)
|
||||
if (secondaryAxValueInput.current) {
|
||||
setupInput(currentAxSkill, secondaryAxValueInput.current)
|
||||
setSecondaryAxValue(0)
|
||||
secondaryAxValueInput.current.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +316,7 @@ const AXSelect = (props: Props) => {
|
|||
} else if (value > primaryAxSkill.maxValue) {
|
||||
newErrors.axValue1 = t('ax.errors.value_too_high', {
|
||||
name: primaryAxSkill.name[locale],
|
||||
maxValue: primaryAxSkill.minValue,
|
||||
maxValue: primaryAxSkill.maxValue,
|
||||
suffix: primaryAxSkill.suffix ? primaryAxSkill.suffix : '',
|
||||
})
|
||||
} else if (!value || value <= 0) {
|
||||
|
|
@ -234,7 +351,7 @@ const AXSelect = (props: Props) => {
|
|||
} else if (value > secondaryAxSkill.maxValue) {
|
||||
newErrors.axValue2 = t('ax.errors.value_too_high', {
|
||||
name: secondaryAxSkill.name[locale],
|
||||
maxValue: secondaryAxSkill.minValue,
|
||||
maxValue: secondaryAxSkill.maxValue,
|
||||
suffix: secondaryAxSkill.suffix ? secondaryAxSkill.suffix : '',
|
||||
})
|
||||
} else if (!secondaryAxSkill.suffix && value % 1 !== 0) {
|
||||
|
|
@ -260,6 +377,7 @@ const AXSelect = (props: Props) => {
|
|||
if (ax) {
|
||||
const rangeString = `${ax.minValue}~${ax.maxValue}${ax.suffix || ''}`
|
||||
|
||||
element.className = 'Input Bound Visible'
|
||||
element.disabled = false
|
||||
element.placeholder = rangeString
|
||||
element.min = `${ax.minValue}`
|
||||
|
|
@ -268,10 +386,12 @@ const AXSelect = (props: Props) => {
|
|||
} else {
|
||||
if (primaryAxValueInput.current && secondaryAxValueInput.current) {
|
||||
if (primaryAxValueInput.current == element) {
|
||||
primaryAxValueInput.current.className = 'Input Contained'
|
||||
primaryAxValueInput.current.disabled = true
|
||||
primaryAxValueInput.current.placeholder = ''
|
||||
}
|
||||
|
||||
secondaryAxValueInput.current.className = 'Input Contained'
|
||||
secondaryAxValueInput.current.disabled = true
|
||||
secondaryAxValueInput.current.placeholder = ''
|
||||
}
|
||||
|
|
@ -282,29 +402,26 @@ const AXSelect = (props: Props) => {
|
|||
<div className="AXSelect">
|
||||
<div className="AXSet">
|
||||
<div className="fields">
|
||||
<select
|
||||
<Select
|
||||
key="ax1"
|
||||
defaultValue={
|
||||
props.currentSkills && props.currentSkills[0]
|
||||
? props.currentSkills[0].modifier
|
||||
: -1
|
||||
}
|
||||
onChange={handleSelectChange}
|
||||
ref={primaryAxModifierSelect}
|
||||
value={`${primaryAxModifier}`}
|
||||
open={openAX1}
|
||||
onValueChange={handleAX1SelectChange}
|
||||
onClick={() => openSelect(primaryAxModifierSelect)}
|
||||
triggerClass="modal"
|
||||
>
|
||||
{generateOptions(0)}
|
||||
</select>
|
||||
</Select>
|
||||
|
||||
<input
|
||||
defaultValue={
|
||||
props.currentSkills && props.currentSkills[0]
|
||||
? props.currentSkills[0].strength
|
||||
: 0
|
||||
}
|
||||
className="Input"
|
||||
type="number"
|
||||
onChange={handleInputChange}
|
||||
ref={primaryAxValueInput}
|
||||
disabled={primaryAxValue != 0}
|
||||
/>
|
||||
</div>
|
||||
<p className={primaryErrorClasses}>{errors.axValue1}</p>
|
||||
|
|
@ -312,29 +429,26 @@ const AXSelect = (props: Props) => {
|
|||
|
||||
<div className={secondarySetClasses}>
|
||||
<div className="fields">
|
||||
<select
|
||||
<Select
|
||||
key="ax2"
|
||||
defaultValue={
|
||||
props.currentSkills && props.currentSkills[1]
|
||||
? props.currentSkills[1].modifier
|
||||
: -1
|
||||
}
|
||||
onChange={handleSelectChange}
|
||||
value={`${secondaryAxModifier}`}
|
||||
open={openAX2}
|
||||
onValueChange={handleAX2SelectChange}
|
||||
onClick={() => openSelect(secondaryAxModifierSelect)}
|
||||
triggerClass="modal"
|
||||
ref={secondaryAxModifierSelect}
|
||||
>
|
||||
{generateOptions(1)}
|
||||
</select>
|
||||
</Select>
|
||||
<input
|
||||
defaultValue={
|
||||
props.currentSkills && props.currentSkills[1]
|
||||
? props.currentSkills[1].strength
|
||||
: 0
|
||||
}
|
||||
className="Input"
|
||||
type="number"
|
||||
onChange={handleInputChange}
|
||||
ref={secondaryAxValueInput}
|
||||
disabled={secondaryAxValue != 0}
|
||||
/>
|
||||
</div>
|
||||
<p className={secondaryErrorClasses}>{errors.axValue2}</p>
|
||||
|
|
|
|||
|
|
@ -60,6 +60,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: var(--button-bg-disabled);
|
||||
color: var(--button-text-disabled);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--button-bg-disabled);
|
||||
color: var(--button-text-disabled);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
&.medium {
|
||||
height: $unit * 5.5;
|
||||
padding: ($unit * 1.5) $unit-2x;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
.ToggleGroup {
|
||||
$height: 36px;
|
||||
|
||||
border: 1px solid rgba(0, 0, 0, 0.14);
|
||||
background-color: var(--toggle-bg);
|
||||
border: 1px solid var(--toggle-stroke);
|
||||
border-radius: $height;
|
||||
display: flex;
|
||||
height: $height;
|
||||
|
|
@ -9,10 +10,10 @@
|
|||
padding: calc($unit / 2);
|
||||
|
||||
.ToggleItem {
|
||||
background: $grey-100;
|
||||
background: var(--toggle-bg);
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
color: $grey-50;
|
||||
color: var(--input-secondary);
|
||||
flex-grow: 1;
|
||||
font-size: $font-regular;
|
||||
padding: ($unit) $unit * 2;
|
||||
|
|
@ -32,33 +33,33 @@
|
|||
color: $grey-15;
|
||||
|
||||
&.fire {
|
||||
background: $fire-bg-20;
|
||||
color: $fire-text-10;
|
||||
background: var(--fire-bg);
|
||||
color: var(--fire-text);
|
||||
}
|
||||
|
||||
&.water {
|
||||
background: $water-bg-20;
|
||||
color: $water-text-10;
|
||||
background: var(--water-bg);
|
||||
color: var(--water-text);
|
||||
}
|
||||
|
||||
&.earth {
|
||||
background: $earth-bg-20;
|
||||
color: $earth-text-10;
|
||||
background: var(--earth-bg);
|
||||
color: var(--earth-text);
|
||||
}
|
||||
|
||||
&.wind {
|
||||
background: $wind-bg-20;
|
||||
color: $wind-text-10;
|
||||
background: var(--wind-bg);
|
||||
color: var(--wind-text);
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background: $dark-bg-10;
|
||||
color: $dark-text-10;
|
||||
background: var(--dark-bg);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
&.light {
|
||||
background: $light-bg-20;
|
||||
color: $light-text-10;
|
||||
background: var(--light-bg);
|
||||
color: var(--light-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
padding: ($unit * 1.5) $unit-2x;
|
||||
padding: $unit-2x;
|
||||
width: 100%;
|
||||
|
||||
&.Bound {
|
||||
|
|
@ -15,6 +15,10 @@
|
|||
background-color: var(--input-bound-bg-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&.Hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.InputError {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props
|
||||
|
|
@ -11,12 +12,26 @@ interface Props
|
|||
label?: string
|
||||
}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, Props>(function input(
|
||||
const Input = React.forwardRef<HTMLInputElement, Props>(function Input(
|
||||
props: Props,
|
||||
forwardedRef
|
||||
) {
|
||||
// States
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
|
||||
// Classes
|
||||
const classes = classNames({ Input: true }, props.className)
|
||||
const { value, ...inputProps } = props
|
||||
const { defaultValue, ...inputProps } = props
|
||||
|
||||
// Change value when prop updates
|
||||
useEffect(() => {
|
||||
if (props.value) setInputValue(`${props.value}`)
|
||||
}, [props.value])
|
||||
|
||||
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setInputValue(event.target.value)
|
||||
if (props.onChange) props.onChange(event)
|
||||
}
|
||||
|
||||
return (
|
||||
<label className="Label" htmlFor={props.name}>
|
||||
|
|
@ -24,8 +39,9 @@ const Input = React.forwardRef<HTMLInputElement, Props>(function input(
|
|||
{...inputProps}
|
||||
autoComplete="off"
|
||||
className={classes}
|
||||
defaultValue={props.value || ''}
|
||||
value={inputValue}
|
||||
ref={forwardedRef}
|
||||
onChange={handleChange}
|
||||
formNoValidate
|
||||
/>
|
||||
{props.label}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,6 @@ const Party = (props: Props) => {
|
|||
},
|
||||
}
|
||||
|
||||
console.log(body)
|
||||
|
||||
return await api.endpoints.parties.create(body)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
&.fire {
|
||||
.Segment input:checked + label {
|
||||
background: $fire-bg-10;
|
||||
color: $fire-text-10;
|
||||
background: var(--fire-bg);
|
||||
color: var(--fire-text);
|
||||
}
|
||||
|
||||
.Segment:hover label {
|
||||
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
&.water {
|
||||
.Segment input:checked + label {
|
||||
background: $water-bg-10;
|
||||
color: $water-text-10;
|
||||
background: var(--water-bg);
|
||||
color: var(--water-text);
|
||||
}
|
||||
|
||||
.Segment:hover label {
|
||||
|
|
@ -39,8 +39,8 @@
|
|||
|
||||
&.earth {
|
||||
.Segment input:checked + label {
|
||||
background: $earth-bg-10;
|
||||
color: $earth-text-10;
|
||||
background: var(--earth-bg);
|
||||
color: var(--earth-text);
|
||||
}
|
||||
|
||||
.Segment:hover label {
|
||||
|
|
@ -51,8 +51,8 @@
|
|||
|
||||
&.wind {
|
||||
.Segment input:checked + label {
|
||||
background: $wind-bg-10;
|
||||
color: $wind-text-10;
|
||||
background: var(--wind-bg);
|
||||
color: var(--wind-text);
|
||||
}
|
||||
|
||||
.Segment:hover label {
|
||||
|
|
@ -63,8 +63,8 @@
|
|||
|
||||
&.light {
|
||||
.Segment input:checked + label {
|
||||
background: $light-bg-10;
|
||||
color: $light-text-10;
|
||||
background: var(--light-bg);
|
||||
color: var(--light-text);
|
||||
}
|
||||
|
||||
.Segment:hover label {
|
||||
|
|
@ -75,8 +75,8 @@
|
|||
|
||||
&.dark {
|
||||
.Segment input:checked + label {
|
||||
background: $dark-bg-10;
|
||||
color: $dark-text-10;
|
||||
background: var(--dark-bg);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
.Segment:hover label {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,22 @@
|
|||
display: flex;
|
||||
padding: $unit-2x $unit-2x;
|
||||
|
||||
&.modal {
|
||||
background-color: var(--select-modal-bg);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--select-modal-bg-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--input-bg-hover);
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
|
||||
&[data-placeholder] > span:not(.SelectIcon) {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-placeholder] > span:not(.SelectIcon) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ interface Props
|
|||
triggerClass?: string
|
||||
}
|
||||
|
||||
const Select = (props: Props) => {
|
||||
const Select = React.forwardRef<HTMLButtonElement, Props>(function Select(
|
||||
props: Props,
|
||||
forwardedRef
|
||||
) {
|
||||
const [value, setValue] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -33,7 +36,6 @@ const Select = (props: Props) => {
|
|||
if (props.onValueChange) props.onValueChange(newValue)
|
||||
}
|
||||
|
||||
console.log(value)
|
||||
return (
|
||||
<RadixSelect.Root
|
||||
value={value !== '' ? value : undefined}
|
||||
|
|
@ -42,6 +44,7 @@ const Select = (props: Props) => {
|
|||
<RadixSelect.Trigger
|
||||
className={classNames('SelectTrigger', props.triggerClass)}
|
||||
placeholder={props.placeholder}
|
||||
ref={forwardedRef}
|
||||
>
|
||||
<RadixSelect.Value placeholder={props.placeholder} />
|
||||
<RadixSelect.Icon className="SelectIcon">
|
||||
|
|
@ -62,6 +65,6 @@ const Select = (props: Props) => {
|
|||
</RadixSelect.Portal>
|
||||
</RadixSelect.Root>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default Select
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.SelectItem {
|
||||
border-radius: $item-corner;
|
||||
border: 2px solid transparent;
|
||||
color: var(--text-secondary);
|
||||
color: var(--text-tertiary);
|
||||
font-size: $font-regular;
|
||||
padding: ($unit * 1.5) $unit-2x;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
import Select from '~components/Select'
|
||||
import SelectGroup from '~components/SelectGroup'
|
||||
import SelectItem from '~components/SelectItem'
|
||||
import api from '~utils/api'
|
||||
|
||||
import './index.scss'
|
||||
|
|
@ -9,32 +12,27 @@ interface Props {
|
|||
currentValue?: WeaponKey
|
||||
series: number
|
||||
slot: number
|
||||
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void
|
||||
onBlur?: (event: React.ChangeEvent<HTMLSelectElement>) => void
|
||||
onChange?: (value: string, slot: number) => void
|
||||
}
|
||||
|
||||
const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
|
||||
const WeaponKeySelect = React.forwardRef<HTMLButtonElement, Props>(
|
||||
function useFieldSet(props, ref) {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [keys, setKeys] = useState<WeaponKey[][]>([])
|
||||
const [currentKey, setCurrentKey] = useState('')
|
||||
|
||||
const pendulumNames = [
|
||||
{ en: 'Pendulum', jp: '' },
|
||||
{ en: 'Chain', jp: '' },
|
||||
{ en: 'Pendulum', jp: 'ペンデュラム' },
|
||||
{ en: 'Chain', jp: 'チェイン' },
|
||||
]
|
||||
|
||||
const telumaNames = [{ en: 'Teluma', jp: '' }]
|
||||
const emblemNames = [{ en: 'Emblem', jp: '' }]
|
||||
const telumaNames = [{ en: 'Teluma', jp: 'テルマ' }]
|
||||
const emblemNames = [{ en: 'Emblem', jp: 'エンブレム' }]
|
||||
const gauphNames = [
|
||||
{ en: 'Gauph Key', jp: '' },
|
||||
{ en: 'Ultima Key', jp: '' },
|
||||
{ en: 'Gate of Omnipotence', jp: '' },
|
||||
{ en: 'Gauph Key', jp: 'ガフスキー' },
|
||||
{ en: 'Ultima Key', jp: 'ガフスキーΩ' },
|
||||
{ en: 'Gate of Omnipotence', jp: 'ガフスキー' },
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
if (props.currentValue) setCurrentKey(props.currentValue.id)
|
||||
}, [props.currentValue])
|
||||
|
||||
useEffect(() => {
|
||||
const filterParams = {
|
||||
params: {
|
||||
|
|
@ -50,22 +48,26 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
|
|||
)
|
||||
let groupedKeys = []
|
||||
for (let i = 0; i <= numGroups; i++) {
|
||||
groupedKeys[i] = weaponKeys.filter((key) => key.group == i)
|
||||
const values = weaponKeys.filter((key) => key.group == i)
|
||||
if (values.length > 0) groupedKeys[i] = values
|
||||
}
|
||||
|
||||
setKeys(groupedKeys)
|
||||
setKeys(groupedKeys.filter(() => true))
|
||||
}
|
||||
|
||||
function fetchWeaponKeys() {
|
||||
api.endpoints.weapon_keys.getAll(filterParams).then((response) => {
|
||||
const keys = response.data.map((k: any) => k.weapon_key)
|
||||
organizeWeaponKeys(keys)
|
||||
})
|
||||
api.endpoints.weapon_keys
|
||||
.getAll(filterParams)
|
||||
.then((response) => organizeWeaponKeys(response.data))
|
||||
}
|
||||
|
||||
fetchWeaponKeys()
|
||||
}, [props.series, props.slot])
|
||||
|
||||
function openSelect() {
|
||||
setOpen(!open)
|
||||
}
|
||||
|
||||
function weaponKeyGroup(index: number) {
|
||||
;['α', 'β', 'γ', 'Δ'].sort((a, b) => a.localeCompare(b, 'el'))
|
||||
|
||||
|
|
@ -78,9 +80,9 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
|
|||
keys[index].length > 0 &&
|
||||
keys[index].sort(sortByOrder).map((item, i) => {
|
||||
return (
|
||||
<option key={i} value={item.id}>
|
||||
<SelectItem key={i} value={item.id}>
|
||||
{item.name.en}
|
||||
</option>
|
||||
</SelectItem>
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -88,26 +90,25 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
|
|||
if (props.series == 2 && index == 0) name = pendulumNames[0]
|
||||
else if (props.series == 2 && props.slot == 1 && index == 1)
|
||||
name = pendulumNames[1]
|
||||
else if (props.series == 3) name = telumaNames[index]
|
||||
else if (props.series == 3) name = telumaNames[0]
|
||||
else if (props.series == 17) name = gauphNames[props.slot]
|
||||
else if (props.series == 22) name = emblemNames[index]
|
||||
else if (props.series == 24) name = emblemNames[index]
|
||||
|
||||
return (
|
||||
<optgroup
|
||||
<SelectGroup
|
||||
key={index}
|
||||
label={
|
||||
props.series == 17 && props.slot == 2 ? name.en : `${name.en}s`
|
||||
}
|
||||
separator={false}
|
||||
>
|
||||
{options}
|
||||
</optgroup>
|
||||
</SelectGroup>
|
||||
)
|
||||
}
|
||||
|
||||
function handleChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||
if (props.onChange) props.onChange(event)
|
||||
|
||||
setCurrentKey(event.currentTarget.value)
|
||||
function handleChange(value: string) {
|
||||
if (props.onChange) props.onChange(value, props.slot)
|
||||
}
|
||||
|
||||
const emptyOption = () => {
|
||||
|
|
@ -115,28 +116,30 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
|
|||
if (props.series == 2) name = pendulumNames[0].en
|
||||
else if (props.series == 3) name = telumaNames[0].en
|
||||
else if (props.series == 17) name = gauphNames[props.slot].en
|
||||
else if (props.series == 22) name = emblemNames[0].en
|
||||
else if (props.series == 24) name = emblemNames[0].en
|
||||
|
||||
return `No ${name}`
|
||||
}
|
||||
|
||||
return (
|
||||
<select
|
||||
<Select
|
||||
key={`weapon-key-${props.slot}`}
|
||||
value={currentKey}
|
||||
onBlur={props.onBlur}
|
||||
onChange={handleChange}
|
||||
value={props.currentValue ? props.currentValue.id : 'no-key'}
|
||||
open={open}
|
||||
onValueChange={handleChange}
|
||||
onClick={openSelect}
|
||||
ref={ref}
|
||||
triggerClass="modal"
|
||||
>
|
||||
<option key="-1" value="-1">
|
||||
<SelectItem key="no-key" value="no-key">
|
||||
{emptyOption()}
|
||||
</option>
|
||||
</SelectItem>
|
||||
{Array.from(Array(keys?.length)).map((x, i) => {
|
||||
return weaponKeyGroup(i)
|
||||
})}
|
||||
</select>
|
||||
</Select>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export default WeaponKeyDropdown
|
||||
export default WeaponKeySelect
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { getCookie } from 'cookies-next'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
|
@ -7,8 +7,9 @@ import { AxiosResponse } from 'axios'
|
|||
import * as Dialog from '@radix-ui/react-dialog'
|
||||
|
||||
import AXSelect from '~components/AxSelect'
|
||||
import AwakeningSelect from '~components/AwakeningSelect'
|
||||
import ElementToggle from '~components/ElementToggle'
|
||||
import WeaponKeyDropdown from '~components/WeaponKeyDropdown'
|
||||
import WeaponKeySelect from '~components/WeaponKeySelect'
|
||||
import Button from '~components/Button'
|
||||
|
||||
import api from '~utils/api'
|
||||
|
|
@ -27,6 +28,8 @@ interface GridWeaponObject {
|
|||
ax_modifier2?: number
|
||||
ax_strength1?: number
|
||||
ax_strength2?: number
|
||||
awakening_type?: number
|
||||
awakening_level?: Number
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,21 +53,43 @@ const WeaponModal = (props: Props) => {
|
|||
? { Authorization: `Bearer ${accountData.token}` }
|
||||
: {}
|
||||
|
||||
// Refs
|
||||
const weaponKey1Select = React.createRef<HTMLSelectElement>()
|
||||
const weaponKey2Select = React.createRef<HTMLSelectElement>()
|
||||
const weaponKey3Select = React.createRef<HTMLSelectElement>()
|
||||
|
||||
// State
|
||||
const [open, setOpen] = useState(false)
|
||||
const [formValid, setFormValid] = useState(false)
|
||||
|
||||
const [element, setElement] = useState(-1)
|
||||
|
||||
const [awakeningType, setAwakeningType] = useState(-1)
|
||||
const [awakeningLevel, setAwakeningLevel] = useState(1)
|
||||
|
||||
const [primaryAxModifier, setPrimaryAxModifier] = useState(-1)
|
||||
const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1)
|
||||
const [primaryAxValue, setPrimaryAxValue] = useState(0.0)
|
||||
const [secondaryAxValue, setSecondaryAxValue] = useState(0.0)
|
||||
|
||||
const [weaponKey1, setWeaponKey1] = useState<WeaponKey | undefined>()
|
||||
const [weaponKey2, setWeaponKey2] = useState<WeaponKey | undefined>()
|
||||
const [weaponKey3, setWeaponKey3] = useState<WeaponKey | undefined>()
|
||||
const [weaponKey1Id, setWeaponKey1Id] = useState('')
|
||||
const [weaponKey2Id, setWeaponKey2Id] = useState('')
|
||||
const [weaponKey3Id, setWeaponKey3Id] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
setElement(props.gridWeapon.element)
|
||||
|
||||
if (props.gridWeapon.weapon_keys) {
|
||||
props.gridWeapon.weapon_keys.forEach((key) => {
|
||||
if (key.slot + 1 === 1) {
|
||||
setWeaponKey1(key)
|
||||
} else if (key.slot + 1 === 2) {
|
||||
setWeaponKey2(key)
|
||||
} else if (key.slot + 1 === 3) {
|
||||
setWeaponKey3(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [props])
|
||||
|
||||
function receiveAxValues(
|
||||
primaryAxModifier: number,
|
||||
primaryAxValue: number,
|
||||
|
|
@ -78,10 +103,15 @@ const WeaponModal = (props: Props) => {
|
|||
setSecondaryAxValue(secondaryAxValue)
|
||||
}
|
||||
|
||||
function receiveAxValidity(isValid: boolean) {
|
||||
function receiveValidity(isValid: boolean) {
|
||||
setFormValid(isValid)
|
||||
}
|
||||
|
||||
function receiveAwakeningValues(type: number, level: number) {
|
||||
setAwakeningType(type)
|
||||
setAwakeningLevel(level)
|
||||
}
|
||||
|
||||
function receiveElementValue(element: string) {
|
||||
setElement(parseInt(element))
|
||||
}
|
||||
|
|
@ -91,14 +121,18 @@ const WeaponModal = (props: Props) => {
|
|||
|
||||
if (props.gridWeapon.object.element == 0) object.weapon.element = element
|
||||
|
||||
if ([2, 3, 17, 24].includes(props.gridWeapon.object.series))
|
||||
object.weapon.weapon_key1_id = weaponKey1Select.current?.value
|
||||
if (
|
||||
[2, 3, 17, 24].includes(props.gridWeapon.object.series) &&
|
||||
weaponKey1Id
|
||||
) {
|
||||
object.weapon.weapon_key1_id = weaponKey1Id
|
||||
}
|
||||
|
||||
if ([2, 3, 17].includes(props.gridWeapon.object.series))
|
||||
object.weapon.weapon_key2_id = weaponKey2Select.current?.value
|
||||
if ([2, 3, 17].includes(props.gridWeapon.object.series) && weaponKey2Id)
|
||||
object.weapon.weapon_key2_id = weaponKey2Id
|
||||
|
||||
if (props.gridWeapon.object.series == 17)
|
||||
object.weapon.weapon_key3_id = weaponKey3Select.current?.value
|
||||
if (props.gridWeapon.object.series == 17 && weaponKey3Id)
|
||||
object.weapon.weapon_key3_id = weaponKey3Id
|
||||
|
||||
if (props.gridWeapon.object.ax > 0) {
|
||||
object.weapon.ax_modifier1 = primaryAxModifier
|
||||
|
|
@ -107,6 +141,11 @@ const WeaponModal = (props: Props) => {
|
|||
object.weapon.ax_strength2 = secondaryAxValue
|
||||
}
|
||||
|
||||
if (props.gridWeapon.object.awakening) {
|
||||
object.weapon.awakening_type = awakeningType
|
||||
object.weapon.awakening_level = awakeningLevel
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +158,7 @@ const WeaponModal = (props: Props) => {
|
|||
}
|
||||
|
||||
function processResult(response: AxiosResponse) {
|
||||
const gridWeapon: GridWeapon = response.data.grid_weapon
|
||||
const gridWeapon: GridWeapon = response.data
|
||||
|
||||
if (gridWeapon.mainhand) appState.grid.weapons.mainWeapon = gridWeapon
|
||||
else appState.grid.weapons.allWeapons[gridWeapon.position] = gridWeapon
|
||||
|
|
@ -131,12 +170,18 @@ const WeaponModal = (props: Props) => {
|
|||
console.error(error)
|
||||
}
|
||||
|
||||
function receiveWeaponKey(value: string, slot: number) {
|
||||
if (slot === 0) setWeaponKey1Id(value)
|
||||
if (slot === 1) setWeaponKey2Id(value)
|
||||
if (slot === 2) setWeaponKey3Id(value)
|
||||
}
|
||||
|
||||
const elementSelect = () => {
|
||||
return (
|
||||
<section>
|
||||
<h3>{t('modals.weapon.subtitles.element')}</h3>
|
||||
<ElementToggle
|
||||
currentElement={props.gridWeapon.element}
|
||||
currentElement={element}
|
||||
sendValue={receiveElementValue}
|
||||
/>
|
||||
</section>
|
||||
|
|
@ -148,45 +193,45 @@ const WeaponModal = (props: Props) => {
|
|||
<section>
|
||||
<h3>{t('modals.weapon.subtitles.weapon_keys')}</h3>
|
||||
{[2, 3, 17, 22].includes(props.gridWeapon.object.series) ? (
|
||||
<WeaponKeyDropdown
|
||||
currentValue={
|
||||
props.gridWeapon.weapon_keys
|
||||
? props.gridWeapon.weapon_keys[0]
|
||||
: undefined
|
||||
}
|
||||
<WeaponKeySelect
|
||||
currentValue={weaponKey1 != null ? weaponKey1 : undefined}
|
||||
series={props.gridWeapon.object.series}
|
||||
slot={0}
|
||||
ref={weaponKey1Select}
|
||||
onChange={receiveWeaponKey}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{[2, 3, 17].includes(props.gridWeapon.object.series) ? (
|
||||
<WeaponKeyDropdown
|
||||
currentValue={
|
||||
props.gridWeapon.weapon_keys
|
||||
? props.gridWeapon.weapon_keys[1]
|
||||
: undefined
|
||||
}
|
||||
<WeaponKeySelect
|
||||
currentValue={weaponKey2 != null ? weaponKey2 : undefined}
|
||||
series={props.gridWeapon.object.series}
|
||||
slot={1}
|
||||
ref={weaponKey2Select}
|
||||
onChange={receiveWeaponKey}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{props.gridWeapon.object.series == 17 ? (
|
||||
<WeaponKeyDropdown
|
||||
currentValue={
|
||||
props.gridWeapon.weapon_keys
|
||||
? props.gridWeapon.weapon_keys[2]
|
||||
: undefined
|
||||
}
|
||||
<WeaponKeySelect
|
||||
currentValue={weaponKey3 != null ? weaponKey3 : undefined}
|
||||
series={props.gridWeapon.object.series}
|
||||
slot={2}
|
||||
ref={weaponKey3Select}
|
||||
onChange={receiveWeaponKey}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{props.gridWeapon.object.series == 24 &&
|
||||
props.gridWeapon.object.uncap.ulb ? (
|
||||
<WeaponKeySelect
|
||||
currentValue={weaponKey1 != null ? weaponKey1 : undefined}
|
||||
series={props.gridWeapon.object.series}
|
||||
slot={0}
|
||||
onChange={receiveWeaponKey}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
|
|
@ -202,19 +247,39 @@ const WeaponModal = (props: Props) => {
|
|||
<AXSelect
|
||||
axType={props.gridWeapon.object.ax}
|
||||
currentSkills={props.gridWeapon.ax}
|
||||
sendValidity={receiveAxValidity}
|
||||
sendValidity={receiveValidity}
|
||||
sendValues={receiveAxValues}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const awakeningSelect = () => {
|
||||
return (
|
||||
<section>
|
||||
<h3>{t('modals.weapon.subtitles.awakening')}</h3>
|
||||
<AwakeningSelect
|
||||
object="weapon"
|
||||
awakeningType={props.gridWeapon.awakening?.type}
|
||||
awakeningLevel={props.gridWeapon.awakening?.level}
|
||||
sendValidity={receiveValidity}
|
||||
sendValues={receiveAwakeningValues}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function openChange(open: boolean) {
|
||||
setFormValid(false)
|
||||
if (props.gridWeapon.object.ax > 0 || props.gridWeapon.object.awakening) {
|
||||
setFormValid(false)
|
||||
} else {
|
||||
setFormValid(true)
|
||||
}
|
||||
setOpen(open)
|
||||
}
|
||||
|
||||
return (
|
||||
// TODO: Refactor into Dialog component
|
||||
<Dialog.Root open={open} onOpenChange={openChange}>
|
||||
<Dialog.Trigger asChild>{props.children}</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
|
|
@ -244,9 +309,11 @@ const WeaponModal = (props: Props) => {
|
|||
? keySelect()
|
||||
: ''}
|
||||
{props.gridWeapon.object.ax > 0 ? axSelect() : ''}
|
||||
{props.gridWeapon.awakening ? awakeningSelect() : ''}
|
||||
<Button
|
||||
contained={true}
|
||||
onClick={updateWeapon}
|
||||
disabled={props.gridWeapon.object.ax > 0 && !formValid}
|
||||
disabled={!formValid}
|
||||
text={t('modals.weapon.buttons.confirm')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,23 @@
|
|||
width: 200px;
|
||||
height: auto;
|
||||
|
||||
.Awakening {
|
||||
width: 40%;
|
||||
height: auto;
|
||||
top: 67%;
|
||||
left: -3.5%;
|
||||
}
|
||||
|
||||
.Modifiers > .Skills {
|
||||
bottom: 12%;
|
||||
right: -3.5%;
|
||||
|
||||
& > .Skill {
|
||||
width: 25%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $medium-screen) {
|
||||
width: 25vw;
|
||||
}
|
||||
|
|
@ -56,6 +73,23 @@
|
|||
width: 160px;
|
||||
height: auto;
|
||||
|
||||
.Awakening {
|
||||
width: 30%;
|
||||
height: auto;
|
||||
top: 14%;
|
||||
left: -3.5%;
|
||||
}
|
||||
|
||||
.Modifiers > .Skills {
|
||||
bottom: 12%;
|
||||
left: -3.5%;
|
||||
|
||||
& > .Skill {
|
||||
width: 20%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $medium-screen) {
|
||||
width: 20vw;
|
||||
}
|
||||
|
|
@ -81,7 +115,7 @@
|
|||
position: absolute;
|
||||
left: $unit;
|
||||
top: $unit;
|
||||
z-index: 3;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
h3 {
|
||||
|
|
@ -102,12 +136,37 @@
|
|||
justify-content: center;
|
||||
margin-bottom: calc($unit / 4);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: all 0.18s ease-in-out;
|
||||
|
||||
&:hover .icon svg {
|
||||
fill: var(--icon-secondary-hover);
|
||||
}
|
||||
|
||||
.Awakening {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.Modifiers {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
|
||||
.Skills {
|
||||
display: flex;
|
||||
gap: $unit-fourth;
|
||||
justify-content: flex-end;
|
||||
padding: $unit-half;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ import WeaponHovercard from '~components/WeaponHovercard'
|
|||
import UncapIndicator from '~components/UncapIndicator'
|
||||
import Button from '~components/Button'
|
||||
|
||||
import { ButtonType } from '~utils/enums'
|
||||
import type { SearchableObject } from '~types'
|
||||
|
||||
import { appState } from '~utils/appState'
|
||||
import { axData } from '~utils/axData'
|
||||
import { weaponAwakening } from '~utils/awakening'
|
||||
|
||||
import PlusIcon from '~public/icons/Add.svg'
|
||||
import SettingsIcon from '~public/icons/Settings.svg'
|
||||
import './index.scss'
|
||||
|
|
@ -71,6 +74,265 @@ const WeaponUnit = (props: Props) => {
|
|||
setImageUrl(imgSrc)
|
||||
}
|
||||
|
||||
function awakeningImage() {
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.awakening &&
|
||||
props.gridWeapon.awakening &&
|
||||
props.gridWeapon.awakening.type >= 0
|
||||
) {
|
||||
const awakening = weaponAwakening.find(
|
||||
(awakening) => awakening.id === props.gridWeapon?.awakening?.type
|
||||
)
|
||||
const name = awakening?.name[locale]
|
||||
|
||||
return (
|
||||
<img
|
||||
alt={`${name} Lv${props.gridWeapon.awakening.level}`}
|
||||
className="Awakening"
|
||||
src={`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/awakening/weapon_${props.gridWeapon.awakening.type}.png`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function telumaImage(index: number) {
|
||||
const baseUrl = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-keys/`
|
||||
let filename = ''
|
||||
let altText = ''
|
||||
|
||||
// If there is a grid weapon, it is a Draconic Weapon and it has keys
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.series === 3 &&
|
||||
props.gridWeapon.weapon_keys
|
||||
) {
|
||||
if (index === 0 && props.gridWeapon.weapon_keys[0]) {
|
||||
altText = `${props.gridWeapon.weapon_keys[0].name[locale]}`
|
||||
filename = `${props.gridWeapon.weapon_keys[0].slug}.png`
|
||||
} else if (index === 1 && props.gridWeapon.weapon_keys[1]) {
|
||||
altText = `${props.gridWeapon.weapon_keys[1].name[locale]}`
|
||||
|
||||
const element = props.gridWeapon.object.element
|
||||
filename = `${props.gridWeapon.weapon_keys[1].slug}-${element}.png`
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
alt={altText}
|
||||
key={altText}
|
||||
className="Skill"
|
||||
src={`${baseUrl}${filename}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function telumaImages() {
|
||||
let images: JSX.Element[] = []
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.series === 3 &&
|
||||
props.gridWeapon.weapon_keys &&
|
||||
props.gridWeapon.weapon_keys.length > 0
|
||||
) {
|
||||
for (let i = 0; i < props.gridWeapon.weapon_keys.length; i++) {
|
||||
const image = telumaImage(i)
|
||||
if (image) images.push(image)
|
||||
}
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
function ultimaImage(index: number) {
|
||||
const baseUrl = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-keys/`
|
||||
let filename = ''
|
||||
let altText = ''
|
||||
|
||||
// If there is a grid weapon, it is a Dark Opus Weapon and it has keys
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.series === 17 &&
|
||||
props.gridWeapon.weapon_keys
|
||||
) {
|
||||
if (
|
||||
props.gridWeapon.weapon_keys[index] &&
|
||||
(props.gridWeapon.weapon_keys[index].slot === 1 ||
|
||||
props.gridWeapon.weapon_keys[index].slot === 2)
|
||||
) {
|
||||
altText = `${props.gridWeapon.weapon_keys[index].name[locale]}`
|
||||
filename = `${props.gridWeapon.weapon_keys[index].slug}.png`
|
||||
} else if (
|
||||
props.gridWeapon.weapon_keys[index] &&
|
||||
props.gridWeapon.weapon_keys[index].slot === 0
|
||||
) {
|
||||
altText = `${props.gridWeapon.weapon_keys[index].name[locale]}`
|
||||
|
||||
const weapon = props.gridWeapon.object.proficiency
|
||||
|
||||
const suffix = `${weapon}`
|
||||
filename = `${props.gridWeapon.weapon_keys[index].slug}-${suffix}.png`
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<img alt={`${altText}`} className="Skill" src={`${baseUrl}${filename}`} />
|
||||
)
|
||||
}
|
||||
|
||||
function ultimaImages() {
|
||||
let images: JSX.Element[] = []
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.series === 17 &&
|
||||
props.gridWeapon.weapon_keys &&
|
||||
props.gridWeapon.weapon_keys.length > 0
|
||||
) {
|
||||
for (let i = 0; i < props.gridWeapon.weapon_keys.length; i++) {
|
||||
const image = ultimaImage(i)
|
||||
if (image) images.push(image)
|
||||
}
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
function opusImage(index: number) {
|
||||
const baseUrl = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-keys/`
|
||||
let filename = ''
|
||||
let altText = ''
|
||||
|
||||
// If there is a grid weapon, it is a Dark Opus Weapon and it has keys
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.series === 2 &&
|
||||
props.gridWeapon.weapon_keys
|
||||
) {
|
||||
if (
|
||||
props.gridWeapon.weapon_keys[index] &&
|
||||
props.gridWeapon.weapon_keys[index].slot === 0
|
||||
) {
|
||||
altText = `${props.gridWeapon.weapon_keys[index].name[locale]}`
|
||||
filename = `${props.gridWeapon.weapon_keys[index].slug}.png`
|
||||
} else if (
|
||||
props.gridWeapon.weapon_keys[index] &&
|
||||
props.gridWeapon.weapon_keys[index].slot === 1
|
||||
) {
|
||||
altText = `${props.gridWeapon.weapon_keys[index].name[locale]}`
|
||||
|
||||
const element = props.gridWeapon.object.element
|
||||
const mod = props.gridWeapon.object.name.en.includes('Repudiation')
|
||||
? 'primal'
|
||||
: 'magna'
|
||||
|
||||
const suffix = `${mod}-${element}`
|
||||
const weaponKey = props.gridWeapon.weapon_keys[index]
|
||||
|
||||
if (
|
||||
[
|
||||
'pendulum-strength',
|
||||
'pendulum-zeal',
|
||||
'pendulum-strife',
|
||||
'chain-temperament',
|
||||
'chain-restoration',
|
||||
'chain-glorification',
|
||||
].includes(weaponKey.slug)
|
||||
) {
|
||||
filename = `${props.gridWeapon.weapon_keys[index].slug}-${suffix}.png`
|
||||
} else {
|
||||
filename = `${props.gridWeapon.weapon_keys[index].slug}.png`
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
alt={altText}
|
||||
key={altText}
|
||||
className="Skill"
|
||||
src={`${baseUrl}${filename}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function opusImages() {
|
||||
let images: JSX.Element[] = []
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.series === 2 &&
|
||||
props.gridWeapon.weapon_keys &&
|
||||
props.gridWeapon.weapon_keys.length > 0
|
||||
) {
|
||||
for (let i = 0; i < props.gridWeapon.weapon_keys.length; i++) {
|
||||
const image = opusImage(i)
|
||||
if (image) images.push(image)
|
||||
}
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
function axImage(index: number) {
|
||||
const axSkill = getCanonicalAxSkill(index)
|
||||
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.ax &&
|
||||
props.gridWeapon.object.ax > 0 &&
|
||||
props.gridWeapon.ax &&
|
||||
axSkill
|
||||
) {
|
||||
return (
|
||||
<img
|
||||
alt={`axskill`}
|
||||
className="Skill"
|
||||
src={`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/ax/${axSkill.slug}.png`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function axImages() {
|
||||
let images: JSX.Element[] = []
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.ax > 0 &&
|
||||
props.gridWeapon.ax &&
|
||||
props.gridWeapon.ax.length > 0
|
||||
) {
|
||||
for (let i = 0; i < props.gridWeapon.ax.length; i++) {
|
||||
const image = axImage(i)
|
||||
if (image) images.push(image)
|
||||
}
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
function getCanonicalAxSkill(index: number) {
|
||||
if (
|
||||
props.gridWeapon &&
|
||||
props.gridWeapon.object.ax &&
|
||||
props.gridWeapon.object.ax > 0 &&
|
||||
props.gridWeapon.ax
|
||||
) {
|
||||
const axOptions = axData[props.gridWeapon.object.ax - 1]
|
||||
const weaponAxSkill: SimpleAxSkill = props.gridWeapon.ax[0]
|
||||
|
||||
let axSkill = axOptions.find((ax) => ax.id === weaponAxSkill.modifier)
|
||||
|
||||
if (index !== 0 && axSkill && axSkill.secondary) {
|
||||
const weaponSubAxSkill: SimpleAxSkill = props.gridWeapon.ax[1]
|
||||
axSkill = axSkill.secondary.find(
|
||||
(ax) => ax.id === weaponSubAxSkill.modifier
|
||||
)
|
||||
}
|
||||
|
||||
return axSkill
|
||||
} else return
|
||||
}
|
||||
|
||||
function passUncapData(uncap: number) {
|
||||
if (props.gridWeapon)
|
||||
props.updateUncap(props.gridWeapon.id, props.position, uncap)
|
||||
|
|
@ -81,12 +343,22 @@ const WeaponUnit = (props: Props) => {
|
|||
|
||||
return (
|
||||
weapon.ax > 0 ||
|
||||
weapon.awakening ||
|
||||
(weapon.series && [2, 3, 17, 22, 24].includes(weapon.series))
|
||||
)
|
||||
}
|
||||
|
||||
const image = (
|
||||
<div className="WeaponImage">
|
||||
<div className="Modifiers">
|
||||
{awakeningImage()}
|
||||
<div className="Skills">
|
||||
{axImages()}
|
||||
{telumaImages()}
|
||||
{opusImages()}
|
||||
{ultimaImages()}
|
||||
</div>
|
||||
</div>
|
||||
<img alt={weapon?.name.en} className="grid_image" src={imageUrl} />
|
||||
{props.editable ? (
|
||||
<span className="icon">
|
||||
|
|
|
|||
|
|
@ -4,17 +4,20 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
|||
import Party from '~components/Party'
|
||||
|
||||
import { appState } from '~utils/appState'
|
||||
import { groupWeaponKeys } from '~utils/groupWeaponKeys'
|
||||
import organizeRaids from '~utils/organizeRaids'
|
||||
import setUserToken from '~utils/setUserToken'
|
||||
import api from '~utils/api'
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import type { GroupedWeaponKeys } from '~utils/groupWeaponKeys'
|
||||
|
||||
interface Props {
|
||||
jobs: Job[]
|
||||
jobSkills: JobSkill[]
|
||||
raids: Raid[]
|
||||
sortedRaids: Raid[][]
|
||||
weaponKeys: GroupedWeaponKeys
|
||||
}
|
||||
|
||||
const NewRoute: React.FC<Props> = (props: Props) => {
|
||||
|
|
@ -31,6 +34,7 @@ const NewRoute: React.FC<Props> = (props: Props) => {
|
|||
appState.raids = props.raids
|
||||
appState.jobs = props.jobs
|
||||
appState.jobSkills = props.jobSkills
|
||||
appState.weaponKeys = props.weaponKeys
|
||||
}
|
||||
|
||||
return <Party new={true} raids={props.sortedRaids} pushHistory={callback} />
|
||||
|
|
@ -61,9 +65,11 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex
|
|||
return response.data
|
||||
})
|
||||
|
||||
let jobSkills = await api.allJobSkills().then((response) => {
|
||||
return response.data
|
||||
})
|
||||
let jobSkills = await api.allJobSkills().then((response) => response.data)
|
||||
|
||||
let weaponKeys = await api.endpoints.weapon_keys
|
||||
.getAll()
|
||||
.then((response) => groupWeaponKeys(response.data))
|
||||
|
||||
return {
|
||||
props: {
|
||||
|
|
@ -71,6 +77,7 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex
|
|||
jobSkills: jobSkills,
|
||||
raids: raids,
|
||||
sortedRaids: sortedRaids,
|
||||
weaponKeys: weaponKeys,
|
||||
...(await serverSideTranslations(locale, ['common'])),
|
||||
// Will be passed to the page component as props
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
|||
import Party from '~components/Party'
|
||||
|
||||
import { appState } from '~utils/appState'
|
||||
import { groupWeaponKeys } from '~utils/groupWeaponKeys'
|
||||
import organizeRaids from '~utils/organizeRaids'
|
||||
import api from '~utils/api'
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import type { GroupedWeaponKeys } from '~utils/groupWeaponKeys'
|
||||
|
||||
interface Props {
|
||||
party: Party
|
||||
|
|
@ -16,6 +18,7 @@ interface Props {
|
|||
jobSkills: JobSkill[]
|
||||
raids: Raid[]
|
||||
sortedRaids: Raid[][]
|
||||
weaponKeys: GroupedWeaponKeys
|
||||
}
|
||||
|
||||
const PartyRoute: React.FC<Props> = (props: Props) => {
|
||||
|
|
@ -27,6 +30,7 @@ const PartyRoute: React.FC<Props> = (props: Props) => {
|
|||
appState.raids = props.raids
|
||||
appState.jobs = props.jobs
|
||||
appState.jobSkills = props.jobSkills
|
||||
appState.weaponKeys = props.weaponKeys
|
||||
}
|
||||
|
||||
return <Party team={props.party} raids={props.sortedRaids} />
|
||||
|
|
@ -65,6 +69,10 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex
|
|||
})
|
||||
|
||||
let jobSkills = await api.allJobSkills(headers).then((response) => response.data)
|
||||
|
||||
let weaponKeys = await api.endpoints.weapon_keys
|
||||
.getAll()
|
||||
.then((response) => groupWeaponKeys(response.data))
|
||||
|
||||
let party: Party | null = null
|
||||
if (query.party) {
|
||||
|
|
@ -81,6 +89,7 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex
|
|||
jobSkills: jobSkills,
|
||||
raids: raids,
|
||||
sortedRaids: sortedRaids,
|
||||
weaponKeys: weaponKeys,
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
// Will be passed to the page component as props
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 2.3 KiB |
|
|
@ -8,6 +8,15 @@
|
|||
"value_empty": "{{name}} must have a value"
|
||||
}
|
||||
},
|
||||
"awakening": {
|
||||
"no_type": "No awakening",
|
||||
"errors": {
|
||||
"value_too_low": "Awakening level must be at least {{minValue}}",
|
||||
"value_too_high": "Awakening level cannot be greater than {{maxValue}}",
|
||||
"value_not_whole": "Awakening level must be a whole number",
|
||||
"value_empty": "Awakening must have a level"
|
||||
}
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "Cancel",
|
||||
"copy": "Copy link",
|
||||
|
|
@ -192,6 +201,7 @@
|
|||
"subtitles": {
|
||||
"element": "Element",
|
||||
"ax_skills": "AX Skills",
|
||||
"awakening": "Awakening",
|
||||
"weapon_keys": "Weapon Keys"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,20 @@
|
|||
"no_skill": "EXスキルなし",
|
||||
"errors": {
|
||||
"value_too_low": "{{name}}は最低{{minValue}}{{suffix}}を入力してください",
|
||||
"value_too_high": "{{name}}は最大{{maxValue}}を入力してください",
|
||||
"value_too_high": "{{name}}は最大{{maxValue}}{{suffix}}を入力してください",
|
||||
"value_not_whole": "{{name}}は整数でなければなりません",
|
||||
"value_empty": "{{name}}を入力してください"
|
||||
}
|
||||
},
|
||||
"awakening": {
|
||||
"no_type": "覚醒タイプなし",
|
||||
"errors": {
|
||||
"value_too_low": "覚醒レベルは最低{{minValue}}を入力してください",
|
||||
"value_too_high": "覚醒レベルは最大{{maxValue}}を入力してください",
|
||||
"value_not_whole": "覚醒レベルは整数でなければなりません",
|
||||
"value_empty": "覚醒レベルを入力してください"
|
||||
}
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "キャンセルs",
|
||||
"copy": "リンクをコピー",
|
||||
|
|
@ -193,6 +202,7 @@
|
|||
"subtitles": {
|
||||
"element": "属性",
|
||||
"ax_skills": "EXスキル",
|
||||
"awakening": "覚醒",
|
||||
"weapon_keys": "武器スキル"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
--select-bg: #{$select--bg--light};
|
||||
--select-contained-bg: #{$select--contained--bg--light};
|
||||
--select-contained-bg-hover: #{$select--contained--bg--light--hover};
|
||||
--select-modal-bg: #{$select--modal--bg--light};
|
||||
--select-modal-bg-hover: #{$select--modal--bg--light--hover};
|
||||
--select-separator: #{$select--separator--light};
|
||||
--option-bg-hover: #{$option--bg--light--hover};
|
||||
|
||||
|
|
@ -72,19 +74,40 @@
|
|||
--subaura-orange-secondary: #{$subaura--orange--secondary--light};
|
||||
--subaura-orange-text: #{$subaura--orange--text--light};
|
||||
|
||||
// Light - Element Toggle
|
||||
--toggle-bg: #{$toggle--bg--light};
|
||||
--toggle-stroke: #{$toggle--stroke--light};
|
||||
|
||||
--grid-border-color: #{$grid--border--color--light};
|
||||
|
||||
--wind-bg: #{$wind-bg-10};
|
||||
--wind-hover-bg: #{$wind-bg-20};
|
||||
--wind-text: #{$wind-text-10};
|
||||
--wind-hover-text: #{$wind-text-20};
|
||||
|
||||
--fire-bg: #{$fire-bg-10};
|
||||
--fire-hover-bg: #{$fire-bg-20};
|
||||
--fire-text: #{$fire-text-10};
|
||||
--fire-hover-text: #{$fire-text-20};
|
||||
|
||||
--water-bg: #{$water-bg-10};
|
||||
--water-hover-bg: #{$water-bg-20};
|
||||
--water-text: #{$water-text-10};
|
||||
--water-hover-text: #{$water-text-20};
|
||||
|
||||
--earth-bg: #{$earth-bg-10};
|
||||
--earth-hover-bg: #{$earth-bg-20};
|
||||
--earth-text: #{$earth-text-10};
|
||||
--earth-hover-text: #{$earth-text-20};
|
||||
|
||||
--dark-bg: #{$dark-bg-10};
|
||||
--dark-hover-bg: #{$dark-bg-20};
|
||||
--dark-text: #{$dark-text-10};
|
||||
--dark-hover-text: #{$dark-text-20};
|
||||
|
||||
--light-bg: #{$light-bg-10};
|
||||
--light-hover-bg: #{$light-bg-20};
|
||||
--light-text: #{$light-text-10};
|
||||
--light-hover-text: #{$light-text-20};
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +151,8 @@
|
|||
--select-bg: #{$select--bg--dark};
|
||||
--select-contained-bg: #{$select--contained--bg--dark};
|
||||
--select-contained-bg-hover: #{$select--contained--bg--dark--hover};
|
||||
--select-modal-bg: #{$select--modal--bg--dark};
|
||||
--select-modal-bg-hover: #{$select--modal--bg--dark--hover};
|
||||
--select-separator: #{$select--separator--dark};
|
||||
--option-bg-hover: #{$option--bg--dark--hover};
|
||||
|
||||
|
|
@ -162,16 +187,40 @@
|
|||
--subaura-orange-secondary: #{$subaura--orange--secondary--dark};
|
||||
--subaura-orange-text: #{$subaura--orange--text--dark};
|
||||
|
||||
// Dark - Element Toggle
|
||||
--toggle-bg: #{$toggle--bg--dark};
|
||||
--toggle-stroke: #{$toggle--stroke--dark};
|
||||
|
||||
--grid-border-color: #{$grid--border--color--dark};
|
||||
|
||||
// Element theming
|
||||
--wind-bg: #{$wind-bg-10};
|
||||
--wind-hover-bg: #{$wind-bg-00};
|
||||
--wind-text: #{$wind-text-10};
|
||||
--wind-hover-text: #{$wind-text-00};
|
||||
|
||||
--fire-bg: #{$fire-bg-10};
|
||||
--fire-hover-bg: #{$fire-bg-00};
|
||||
--fire-text: #{$fire-text-10};
|
||||
--fire-hover-text: #{$fire-text-00};
|
||||
|
||||
--water-bg: #{$water-bg-10};
|
||||
--water-hover-bg: #{$water-bg-00};
|
||||
--water-text: #{$water-text-10};
|
||||
--water-hover-text: #{$water-text-00};
|
||||
|
||||
--earth-bg: #{$earth-bg-10};
|
||||
--earth-hover-bg: #{$earth-bg-00};
|
||||
--earth-text: #{$earth-text-10};
|
||||
--earth-hover-text: #{$earth-text-00};
|
||||
|
||||
--dark-bg: #{$dark-bg-10};
|
||||
--dark-hover-bg: #{$dark-bg-00};
|
||||
--dark-text: #{$dark-text-10};
|
||||
--dark-hover-text: #{$dark-text-00};
|
||||
|
||||
--light-bg: #{$light-bg-10};
|
||||
--light-hover-bg: #{$light-bg-00};
|
||||
--light-text: #{$light-text-10};
|
||||
--light-hover-text: #{$light-text-00};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ $unit-6x: $unit * 6;
|
|||
$unit-8x: $unit * 8;
|
||||
$unit-10x: $unit * 10;
|
||||
$unit-12x: $unit * 12;
|
||||
$unit-14x: $unit * 14;
|
||||
$unit-20x: $unit * 20;
|
||||
|
||||
// Colors
|
||||
|
|
@ -34,6 +35,7 @@ $grey-55: #888;
|
|||
$grey-60: #a9a9a9;
|
||||
$grey-70: #c6c6c6;
|
||||
$grey-80: #e9e9e9;
|
||||
$grey-85: #efefef;
|
||||
$grey-90: #f5f5f5;
|
||||
$grey-95: #fafafa;
|
||||
$grey-100: white;
|
||||
|
|
@ -132,8 +134,8 @@ $menu--text--dark--hover: $grey-15;
|
|||
// Color Definitions: Button
|
||||
$button--bg--light: $grey-80;
|
||||
$button--bg--light--hover: $grey-100;
|
||||
$button--bg--light--disabled: $grey-50;
|
||||
$button--contained--bg--light: $grey-90;
|
||||
$button--bg--light--disabled: $grey-80;
|
||||
$button--contained--bg--light: $grey-85;
|
||||
$button--contained--bg--light--hover: $grey-80;
|
||||
|
||||
$button--bg--dark: $grey-00;
|
||||
|
|
@ -144,10 +146,10 @@ $button--contained--bg--dark--hover: $grey-05;
|
|||
|
||||
$button--text--light: $grey-55;
|
||||
$button--text--light--hover: $grey-40;
|
||||
$button--text--light--disabled: $grey-40;
|
||||
$button--text--light--disabled: $grey-70;
|
||||
$button--text--dark: $grey-70;
|
||||
$button--text--dark--hover: $grey-100;
|
||||
$button--text--dark--disabled: $grey-50;
|
||||
$button--text--dark--disabled: $grey-40;
|
||||
|
||||
// Color Definitions: Input
|
||||
$input--bg--light: $grey-100;
|
||||
|
|
@ -155,7 +157,7 @@ $input--bg--light--hover: $grey-95;
|
|||
$input--bg--dark: $grey-40;
|
||||
$input--bg--dark--hover: $grey-30;
|
||||
|
||||
$input--bound--bg--light: $grey-90;
|
||||
$input--bound--bg--light: $grey-85;
|
||||
$input--bound--bg--light--hover: $grey-80;
|
||||
$input--bound--bg--dark: $grey-15;
|
||||
$input--bound--bg--dark--hover: $grey-25;
|
||||
|
|
@ -163,12 +165,20 @@ $input--bound--bg--dark--hover: $grey-25;
|
|||
// Color Definitions: Select
|
||||
$select--bg--light: $grey-100;
|
||||
$select--bg--dark: $grey-10;
|
||||
|
||||
$select--contained--bg--light: $grey-90;
|
||||
$select--contained--bg--dark: $grey-05;
|
||||
$select--contained--bg--light--hover: $grey-80;
|
||||
$select--contained--bg--dark: $grey-05;
|
||||
$select--contained--bg--dark--hover: $grey-00;
|
||||
|
||||
$select--modal--bg--light: $grey-85;
|
||||
$select--modal--bg--light--hover: $grey-80;
|
||||
$select--modal--bg--dark: $grey-40;
|
||||
$select--modal--bg--dark--hover: $grey-30;
|
||||
|
||||
$select--separator--light: $grey-90;
|
||||
$select--separator--dark: $grey-05;
|
||||
|
||||
$option--bg--light--hover: $grey-90;
|
||||
$option--bg--dark--hover: $grey-00;
|
||||
|
||||
|
|
@ -205,6 +215,13 @@ $subaura--orange--primary--dark: $orange-00;
|
|||
$subaura--orange--secondary--dark: $orange-10;
|
||||
$subaura--orange--text--dark: $orange-00;
|
||||
|
||||
// Color Definitions: Element Toggle
|
||||
$toggle--bg--light: $grey-90;
|
||||
$toggle--bg--dark: $grey-15;
|
||||
|
||||
$toggle--stroke--light: rgba(0, 0, 0, 0.14);
|
||||
$toggle--stroke--dark: rgba(0, 0, 0, 0.8);
|
||||
|
||||
// Color Definitions: Text
|
||||
$text--primary--color--light: $grey-40;
|
||||
$text--primary--color--dark: $grey-90;
|
||||
|
|
|
|||
1
types/AxSkill.d.ts
vendored
1
types/AxSkill.d.ts
vendored
|
|
@ -5,6 +5,7 @@ interface AxSkill {
|
|||
ja: string
|
||||
}
|
||||
id: number
|
||||
slug: string
|
||||
minValue: number
|
||||
maxValue: number
|
||||
suffix?: string
|
||||
|
|
|
|||
4
types/GridCharacter.d.ts
vendored
4
types/GridCharacter.d.ts
vendored
|
|
@ -3,4 +3,8 @@ interface GridCharacter {
|
|||
position: number
|
||||
object: Character
|
||||
uncap_level: number
|
||||
awakening: {
|
||||
type: number
|
||||
level: number
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
types/GridWeapon.d.ts
vendored
4
types/GridWeapon.d.ts
vendored
|
|
@ -7,4 +7,8 @@ interface GridWeapon {
|
|||
element: number
|
||||
weapon_keys?: Array<WeaponKey>
|
||||
ax?: Array<SimpleAxSkill>
|
||||
awakening?: {
|
||||
type: number
|
||||
level: number
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
types/Weapon.d.ts
vendored
1
types/Weapon.d.ts
vendored
|
|
@ -9,6 +9,7 @@ interface Weapon {
|
|||
max_skill_level: number
|
||||
series: number
|
||||
ax: number
|
||||
awakening: boolean
|
||||
name: {
|
||||
[key: string]: string
|
||||
en: string
|
||||
|
|
|
|||
1
types/WeaponKey.d.ts
vendored
1
types/WeaponKey.d.ts
vendored
|
|
@ -5,6 +5,7 @@ interface WeaponKey {
|
|||
en: string
|
||||
ja: string
|
||||
}
|
||||
slug: string
|
||||
series: integer
|
||||
slot: integer
|
||||
group: integer
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { proxy } from 'valtio'
|
||||
import { JobSkillObject } from '~types'
|
||||
import { GroupedWeaponKeys } from './groupWeaponKeys'
|
||||
|
||||
const emptyJob: Job = {
|
||||
id: '-1',
|
||||
|
|
@ -57,6 +58,7 @@ interface AppState {
|
|||
raids: Raid[]
|
||||
jobs: Job[]
|
||||
jobSkills: JobSkill[]
|
||||
weaponKeys: GroupedWeaponKeys
|
||||
}
|
||||
|
||||
export const initialAppState: AppState = {
|
||||
|
|
@ -103,6 +105,13 @@ export const initialAppState: AppState = {
|
|||
raids: [],
|
||||
jobs: [],
|
||||
jobSkills: [],
|
||||
weaponKeys: {
|
||||
pendulum: [],
|
||||
chain: [],
|
||||
teluma: [],
|
||||
gauph: [],
|
||||
emblem: [],
|
||||
},
|
||||
}
|
||||
|
||||
export const appState = proxy(initialAppState)
|
||||
|
|
|
|||
62
utils/awakening.tsx
Normal file
62
utils/awakening.tsx
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
export type Awakening = {
|
||||
id: number
|
||||
name: {
|
||||
[key: string]: string
|
||||
en: string
|
||||
ja: string
|
||||
}
|
||||
}
|
||||
export const characterAwakening: Awakening[] = [
|
||||
{
|
||||
id: 0,
|
||||
name: {
|
||||
en: 'Balanced',
|
||||
ja: 'バランス',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: {
|
||||
en: 'Attack',
|
||||
ja: '攻撃',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: {
|
||||
en: 'Defense',
|
||||
ja: '防御',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: {
|
||||
en: 'Multiattack',
|
||||
ja: '連続攻撃',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export const weaponAwakening: Awakening[] = [
|
||||
{
|
||||
id: 0,
|
||||
name: {
|
||||
en: 'Attack',
|
||||
ja: '攻撃',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: {
|
||||
en: 'Defense',
|
||||
ja: '防御',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: {
|
||||
en: 'Special',
|
||||
ja: '特殊',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -6,6 +6,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '攻撃',
|
||||
},
|
||||
id: 0,
|
||||
slug: 'atk',
|
||||
minValue: 1,
|
||||
maxValue: 3.5,
|
||||
suffix: '%',
|
||||
|
|
@ -16,6 +17,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -26,6 +28,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'DA確率',
|
||||
},
|
||||
id: 5,
|
||||
slug: 'da',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -36,6 +39,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'TA確率',
|
||||
},
|
||||
id: 6,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -46,6 +50,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'アビ上限',
|
||||
},
|
||||
id: 7,
|
||||
slug: 'skill-cap',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -58,6 +63,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '防御',
|
||||
},
|
||||
id: 1,
|
||||
slug: 'def',
|
||||
minValue: 1,
|
||||
maxValue: 8,
|
||||
suffix: '%',
|
||||
|
|
@ -68,6 +74,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'HP',
|
||||
},
|
||||
id: 2,
|
||||
slug: 'hp',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -78,6 +85,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '弱体耐性',
|
||||
},
|
||||
id: 9,
|
||||
slug: 'debuff',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -88,6 +96,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '回復性能',
|
||||
},
|
||||
id: 10,
|
||||
slug: 'healing',
|
||||
minValue: 2,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -98,6 +107,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '背水',
|
||||
},
|
||||
id: 11,
|
||||
slug: 'enmity',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -109,6 +119,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'HP',
|
||||
},
|
||||
id: 2,
|
||||
slug: 'hp',
|
||||
minValue: 1,
|
||||
maxValue: 11,
|
||||
suffix: '%',
|
||||
|
|
@ -119,6 +130,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '防御',
|
||||
},
|
||||
id: 1,
|
||||
slug: 'def',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -129,6 +141,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '弱体耐性',
|
||||
},
|
||||
id: 9,
|
||||
slug: 'debuff',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -139,6 +152,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '回復性能',
|
||||
},
|
||||
id: 10,
|
||||
slug: 'healing',
|
||||
minValue: 2,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -149,6 +163,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -160,6 +175,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 8.5,
|
||||
suffix: '%',
|
||||
|
|
@ -170,6 +186,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '攻撃',
|
||||
},
|
||||
id: 0,
|
||||
slug: 'atk',
|
||||
minValue: 1,
|
||||
maxValue: 1.5,
|
||||
suffix: '%',
|
||||
|
|
@ -180,6 +197,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '全属性攻撃力',
|
||||
},
|
||||
id: 13,
|
||||
slug: 'ele-atk',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -190,6 +208,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義上限',
|
||||
},
|
||||
id: 8,
|
||||
slug: 'ca-cap',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -200,6 +219,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -211,6 +231,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '連撃率',
|
||||
},
|
||||
id: 4,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -221,6 +242,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -231,6 +253,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '全属性攻撃力',
|
||||
},
|
||||
id: 13,
|
||||
slug: 'ele-atk',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -241,6 +264,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'DA確率',
|
||||
},
|
||||
id: 5,
|
||||
slug: 'da',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -251,6 +275,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'TA確率',
|
||||
},
|
||||
id: 6,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -265,6 +290,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '攻撃',
|
||||
},
|
||||
id: 0,
|
||||
slug: 'atk',
|
||||
minValue: 1,
|
||||
maxValue: 3.5,
|
||||
suffix: '%',
|
||||
|
|
@ -275,6 +301,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 8.5,
|
||||
suffix: '%',
|
||||
|
|
@ -285,6 +312,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '連撃確率',
|
||||
},
|
||||
id: 4,
|
||||
slug: 'ta',
|
||||
minValue: 1.5,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -295,6 +323,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '通常ダメ上限',
|
||||
},
|
||||
id: 14,
|
||||
slug: 'na-dmg',
|
||||
minValue: 0.5,
|
||||
maxValue: 1.5,
|
||||
suffix: '%',
|
||||
|
|
@ -305,6 +334,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'アビ与ダメ上昇',
|
||||
},
|
||||
id: 15,
|
||||
slug: 'skill-supp',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
},
|
||||
|
|
@ -316,6 +346,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '防御',
|
||||
},
|
||||
id: 1,
|
||||
slug: 'def',
|
||||
minValue: 1,
|
||||
maxValue: 8,
|
||||
suffix: '%',
|
||||
|
|
@ -326,6 +357,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '属性ダメ軽減',
|
||||
},
|
||||
id: 17,
|
||||
slug: 'ele-def',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -336,6 +368,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '弱体耐性',
|
||||
},
|
||||
id: 9,
|
||||
slug: 'debuff',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -346,6 +379,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '回復性能',
|
||||
},
|
||||
id: 10,
|
||||
slug: 'healing',
|
||||
minValue: 2,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -356,6 +390,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '背水',
|
||||
},
|
||||
id: 11,
|
||||
slug: 'enmity',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -367,6 +402,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'HP',
|
||||
},
|
||||
id: 2,
|
||||
slug: 'hp',
|
||||
minValue: 1,
|
||||
maxValue: 11,
|
||||
suffix: '%',
|
||||
|
|
@ -377,6 +413,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '属性ダメ軽減',
|
||||
},
|
||||
id: 17,
|
||||
slug: 'ele-def',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -387,6 +424,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '弱体耐性',
|
||||
},
|
||||
id: 9,
|
||||
slug: 'debuff',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -397,6 +435,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '回復性能',
|
||||
},
|
||||
id: 10,
|
||||
slug: 'healing',
|
||||
minValue: 2,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -407,6 +446,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -418,6 +458,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 8.5,
|
||||
suffix: '%',
|
||||
|
|
@ -428,6 +469,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '連撃率',
|
||||
},
|
||||
id: 4,
|
||||
slug: 'ta',
|
||||
minValue: 1.5,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -438,6 +480,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'アビ与ダメ上昇',
|
||||
},
|
||||
id: 15,
|
||||
slug: 'skill-supp',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
},
|
||||
|
|
@ -447,6 +490,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義与ダメ上昇',
|
||||
},
|
||||
id: 16,
|
||||
slug: 'ca-supp',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
},
|
||||
|
|
@ -456,6 +500,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -467,6 +512,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '連撃率',
|
||||
},
|
||||
id: 4,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -477,6 +523,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義与ダメ上昇',
|
||||
},
|
||||
id: 16,
|
||||
slug: 'ca-supp',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
},
|
||||
|
|
@ -486,6 +533,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '通常ダメ上限',
|
||||
},
|
||||
id: 14,
|
||||
slug: 'na-cap',
|
||||
minValue: 0.5,
|
||||
maxValue: 1.5,
|
||||
suffix: '%',
|
||||
|
|
@ -496,6 +544,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -505,6 +554,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '背水',
|
||||
},
|
||||
id: 11,
|
||||
slug: 'enmity',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -518,6 +568,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '攻撃',
|
||||
},
|
||||
id: 0,
|
||||
slug: 'atk',
|
||||
minValue: 1,
|
||||
maxValue: 3.5,
|
||||
suffix: '%',
|
||||
|
|
@ -528,6 +579,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -538,6 +590,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'DA確率',
|
||||
},
|
||||
id: 5,
|
||||
slug: 'da',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -548,6 +601,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'TA確率',
|
||||
},
|
||||
id: 6,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -558,6 +612,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'アビ上限',
|
||||
},
|
||||
id: 7,
|
||||
slug: 'skill-cap',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -570,6 +625,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '防御',
|
||||
},
|
||||
id: 1,
|
||||
slug: 'def',
|
||||
minValue: 1,
|
||||
maxValue: 8,
|
||||
suffix: '%',
|
||||
|
|
@ -580,6 +636,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'HP',
|
||||
},
|
||||
id: 2,
|
||||
slug: 'hp',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -590,6 +647,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '弱体耐性',
|
||||
},
|
||||
id: 9,
|
||||
slug: 'debuff',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -600,6 +658,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '回復性能',
|
||||
},
|
||||
id: 10,
|
||||
slug: 'healing',
|
||||
minValue: 2,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -610,6 +669,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '背水',
|
||||
},
|
||||
id: 11,
|
||||
slug: 'enmity',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -621,6 +681,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'HP',
|
||||
},
|
||||
id: 2,
|
||||
slug: 'hp',
|
||||
minValue: 1,
|
||||
maxValue: 11,
|
||||
suffix: '%',
|
||||
|
|
@ -631,6 +692,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '防御',
|
||||
},
|
||||
id: 1,
|
||||
slug: 'def',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -641,6 +703,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '弱体耐性',
|
||||
},
|
||||
id: 9,
|
||||
slug: 'debuff',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
suffix: '%',
|
||||
|
|
@ -651,6 +714,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '回復性能',
|
||||
},
|
||||
id: 10,
|
||||
slug: 'healing',
|
||||
minValue: 2,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -661,6 +725,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -672,6 +737,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 8.5,
|
||||
suffix: '%',
|
||||
|
|
@ -682,6 +748,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '攻撃',
|
||||
},
|
||||
id: 0,
|
||||
slug: 'atk',
|
||||
minValue: 1,
|
||||
maxValue: 1.5,
|
||||
suffix: '%',
|
||||
|
|
@ -692,6 +759,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '全属性攻撃力',
|
||||
},
|
||||
id: 13,
|
||||
slug: 'ele-atk',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -702,6 +770,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義上限',
|
||||
},
|
||||
id: 8,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -712,6 +781,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '渾身',
|
||||
},
|
||||
id: 12,
|
||||
slug: 'stamina',
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
},
|
||||
|
|
@ -723,6 +793,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '連撃率',
|
||||
},
|
||||
id: 4,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -733,6 +804,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '奥義ダメ',
|
||||
},
|
||||
id: 3,
|
||||
slug: 'ca-dmg',
|
||||
minValue: 2,
|
||||
maxValue: 4,
|
||||
suffix: '%',
|
||||
|
|
@ -743,6 +815,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '全属性攻撃力',
|
||||
},
|
||||
id: 13,
|
||||
slug: 'ele-atk',
|
||||
minValue: 1,
|
||||
maxValue: 5,
|
||||
suffix: '%',
|
||||
|
|
@ -753,6 +826,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'DA確率',
|
||||
},
|
||||
id: 5,
|
||||
slug: 'da',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -763,6 +837,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'TA確率',
|
||||
},
|
||||
id: 6,
|
||||
slug: 'ta',
|
||||
minValue: 1,
|
||||
maxValue: 2,
|
||||
suffix: '%',
|
||||
|
|
@ -775,6 +850,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: 'EXP UP',
|
||||
},
|
||||
id: 18,
|
||||
slug: 'exp',
|
||||
minValue: 5,
|
||||
maxValue: 10,
|
||||
suffix: '%',
|
||||
|
|
@ -785,6 +861,7 @@ export const axData: AxSkill[][] = [
|
|||
ja: '獲得ルピ',
|
||||
},
|
||||
id: 19,
|
||||
slug: 'rupie',
|
||||
minValue: 10,
|
||||
maxValue: 20,
|
||||
suffix: '%',
|
||||
|
|
|
|||
34
utils/groupWeaponKeys.tsx
Normal file
34
utils/groupWeaponKeys.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { weaponKeyGroups } from './weaponKeyGroups'
|
||||
|
||||
export type GroupedWeaponKeys = {
|
||||
[key: string]: WeaponKey[]
|
||||
pendulum: WeaponKey[]
|
||||
chain: WeaponKey[]
|
||||
teluma: WeaponKey[]
|
||||
gauph: WeaponKey[]
|
||||
emblem: WeaponKey[]
|
||||
}
|
||||
|
||||
export function groupWeaponKeys(keys: WeaponKey[]) {
|
||||
console.log(keys)
|
||||
const numGroups = Math.max.apply(
|
||||
Math,
|
||||
keys.map((key) => key.group)
|
||||
)
|
||||
|
||||
let groupedKeys: GroupedWeaponKeys = {
|
||||
pendulum: [],
|
||||
chain: [],
|
||||
teluma: [],
|
||||
gauph: [],
|
||||
emblem: [],
|
||||
}
|
||||
|
||||
for (let i = 0; i <= numGroups; i++) {
|
||||
groupedKeys[weaponKeyGroups[i].slug] = keys.filter((key) => key.group == i)
|
||||
}
|
||||
|
||||
console.log(groupedKeys)
|
||||
|
||||
return groupedKeys
|
||||
}
|
||||
52
utils/weaponKeyGroups.tsx
Normal file
52
utils/weaponKeyGroups.tsx
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
interface WeaponKeyGroup {
|
||||
id: number
|
||||
slug: string
|
||||
name: {
|
||||
[key: string]: string
|
||||
en: string
|
||||
ja: string
|
||||
}
|
||||
}
|
||||
|
||||
export const weaponKeyGroups: WeaponKeyGroup[] = [
|
||||
{
|
||||
id: 0,
|
||||
slug: 'pendulum',
|
||||
name: {
|
||||
en: 'Pendulum',
|
||||
ja: 'ペンデュラム',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
slug: 'chain',
|
||||
name: {
|
||||
en: 'Chain',
|
||||
ja: 'チェイン',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
slug: 'teluma',
|
||||
name: {
|
||||
en: 'Teluma',
|
||||
ja: 'テルマ',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
slug: 'gauph',
|
||||
name: {
|
||||
en: 'Gauph Key',
|
||||
ja: 'ガフスキー',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
slug: 'emblem',
|
||||
name: {
|
||||
en: 'Emblem',
|
||||
ja: 'エンブレム',
|
||||
},
|
||||
},
|
||||
]
|
||||
Loading…
Reference in a new issue