Merge pull request #20 from jedmund/weapon-mods
Add the ability to add modifications to grid weapons
This commit is contained in:
commit
25bf58da2b
30 changed files with 1903 additions and 42 deletions
48
components/AxSelect/index.scss
Normal file
48
components/AxSelect/index.scss
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
.AXSelect {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $unit;
|
||||||
|
|
||||||
|
.AXSet {
|
||||||
|
&.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.errors {
|
||||||
|
color: $error;
|
||||||
|
display: none;
|
||||||
|
padding: $unit 0;
|
||||||
|
|
||||||
|
&.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: $unit;
|
||||||
|
|
||||||
|
select {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Input {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
border: none;
|
||||||
|
background-color: $grey-90;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: $grey-00;
|
||||||
|
height: $unit * 6;
|
||||||
|
display: block;
|
||||||
|
font-size: $font-regular;
|
||||||
|
padding: $unit;
|
||||||
|
text-align: right;
|
||||||
|
min-width: 100px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
243
components/AxSelect/index.tsx
Normal file
243
components/AxSelect/index.tsx
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
import { axData } from '~utils/axData'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
interface ErrorMap {
|
||||||
|
[index: string]: string
|
||||||
|
axValue1: string
|
||||||
|
axValue2: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
axType: number
|
||||||
|
currentSkills?: SimpleAxSkill[],
|
||||||
|
sendValidity: (isValid: boolean) => void
|
||||||
|
sendValues: (primaryAxModifier: number, primaryAxValue: number, secondaryAxModifier: number, secondaryAxValue: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const AXSelect = (props: Props) => {
|
||||||
|
// Set up form states and error handling
|
||||||
|
const [errors, setErrors] = useState<ErrorMap>({
|
||||||
|
axValue1: '',
|
||||||
|
axValue2: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const primaryErrorClasses = classNames({
|
||||||
|
'errors': true,
|
||||||
|
'visible': errors.axValue1.length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const secondaryErrorClasses = classNames({
|
||||||
|
'errors': true,
|
||||||
|
'visible': errors.axValue2.length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// Refs
|
||||||
|
const primaryAxModifierSelect = React.createRef<HTMLSelectElement>()
|
||||||
|
const primaryAxValueInput = React.createRef<HTMLInputElement>()
|
||||||
|
const secondaryAxModifierSelect = React.createRef<HTMLSelectElement>()
|
||||||
|
const secondaryAxValueInput = React.createRef<HTMLInputElement>()
|
||||||
|
|
||||||
|
// States
|
||||||
|
const [primaryAxModifier, setPrimaryAxModifier] = useState(-1)
|
||||||
|
const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1)
|
||||||
|
const [primaryAxValue, setPrimaryAxValue] = useState(0.0)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}, [props.currentSkills])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
props.sendValues(primaryAxModifier, primaryAxValue, secondaryAxModifier, secondaryAxValue)
|
||||||
|
}, [props, primaryAxModifier, primaryAxValue, secondaryAxModifier, secondaryAxValue])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
props.sendValidity(primaryAxValue > 0 && errors.axValue1 === '' && errors.axValue2 === '')
|
||||||
|
}, [props, primaryAxValue, errors])
|
||||||
|
|
||||||
|
// Classes
|
||||||
|
const secondarySetClasses = classNames({
|
||||||
|
'AXSet': true,
|
||||||
|
'hidden': primaryAxModifier < 0
|
||||||
|
})
|
||||||
|
|
||||||
|
function generateOptions(modifierSet: number) {
|
||||||
|
const axOptions = axData[props.axType - 1]
|
||||||
|
|
||||||
|
let axOptionElements: React.ReactNode[] = []
|
||||||
|
if (modifierSet == 0) {
|
||||||
|
axOptionElements = axOptions.map((ax, i) => {
|
||||||
|
return (
|
||||||
|
<option key={i} value={ax.id}>{ax.name.en}</option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// If we are loading data from the server, state doesn't set before render,
|
||||||
|
// so our defaultValue is undefined.
|
||||||
|
let modifier = -1;
|
||||||
|
if (primaryAxModifier >= 0)
|
||||||
|
modifier = primaryAxModifier
|
||||||
|
else if (props.currentSkills)
|
||||||
|
modifier = props.currentSkills[0].modifier
|
||||||
|
|
||||||
|
if (modifier >= 0 && axOptions[modifier]) {
|
||||||
|
const primarySkill = axOptions[modifier]
|
||||||
|
|
||||||
|
if (primarySkill.secondary) {
|
||||||
|
const secondaryAxOptions = primarySkill.secondary
|
||||||
|
axOptionElements = secondaryAxOptions.map((ax, i) => {
|
||||||
|
return (
|
||||||
|
<option key={i} value={ax.id}>{ax.name.en}</option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
axOptionElements?.unshift(<option key={-1} value={-1}>No AX Skill</option>)
|
||||||
|
return axOptionElements
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
|
const value = parseInt(event.target.value)
|
||||||
|
|
||||||
|
if (primaryAxModifierSelect.current == event.target) {
|
||||||
|
setPrimaryAxModifier(value)
|
||||||
|
|
||||||
|
if (primaryAxValueInput.current && secondaryAxModifierSelect.current && secondaryAxValueInput.current) {
|
||||||
|
setupInput(axData[props.axType - 1][value], primaryAxValueInput.current)
|
||||||
|
|
||||||
|
secondaryAxModifierSelect.current.value = "-1"
|
||||||
|
secondaryAxValueInput.current.value = ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setSecondaryAxModifier(value)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
|
const value = parseFloat(event.target.value)
|
||||||
|
let newErrors = {...errors}
|
||||||
|
|
||||||
|
if (primaryAxValueInput.current == event.target) {
|
||||||
|
if (handlePrimaryErrors(value))
|
||||||
|
setPrimaryAxValue(value)
|
||||||
|
} else {
|
||||||
|
if (handleSecondaryErrors(value))
|
||||||
|
setSecondaryAxValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePrimaryErrors(value: number) {
|
||||||
|
const primaryAxSkill = axData[props.axType - 1][primaryAxModifier]
|
||||||
|
let newErrors = {...errors}
|
||||||
|
|
||||||
|
if (value < primaryAxSkill.minValue) {
|
||||||
|
newErrors.axValue1 = `${primaryAxSkill.name.en} must be at least ${primaryAxSkill.minValue}${ (primaryAxSkill.suffix) ? primaryAxSkill.suffix : ''}`
|
||||||
|
} else if (value > primaryAxSkill.maxValue) {
|
||||||
|
newErrors.axValue1 = `${primaryAxSkill.name.en} cannot be greater than ${primaryAxSkill.maxValue}${ (primaryAxSkill.suffix) ? primaryAxSkill.suffix : ''}`
|
||||||
|
} else if (!value || value <= 0) {
|
||||||
|
newErrors.axValue1 = `${primaryAxSkill.name.en} must have a value`
|
||||||
|
} else {
|
||||||
|
newErrors.axValue1 = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(newErrors)
|
||||||
|
|
||||||
|
return newErrors.axValue1.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSecondaryErrors(value: number) {
|
||||||
|
const primaryAxSkill = axData[props.axType - 1][primaryAxModifier]
|
||||||
|
let newErrors = {...errors}
|
||||||
|
|
||||||
|
if (primaryAxSkill.secondary) {
|
||||||
|
const secondaryAxSkill = primaryAxSkill.secondary.find(skill => skill.id == secondaryAxModifier)
|
||||||
|
|
||||||
|
if (secondaryAxSkill) {
|
||||||
|
if (value < secondaryAxSkill.minValue) {
|
||||||
|
newErrors.axValue2 = `${secondaryAxSkill.name.en} must be at least ${secondaryAxSkill.minValue}${ (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : ''}`
|
||||||
|
} else if (value > secondaryAxSkill.maxValue) {
|
||||||
|
newErrors.axValue2 = `${secondaryAxSkill.name.en} cannot be greater than ${secondaryAxSkill.maxValue}${ (secondaryAxSkill.suffix) ? secondaryAxSkill.suffix : ''}`
|
||||||
|
} else if (!secondaryAxSkill.suffix && value % 1 !== 0) {
|
||||||
|
newErrors.axValue2 = `${secondaryAxSkill.name.en} must be a whole number`
|
||||||
|
} else if (primaryAxValue <= 0) {
|
||||||
|
newErrors.axValue1 = `${primaryAxSkill.name.en} must have a value`
|
||||||
|
} else {
|
||||||
|
newErrors.axValue2 = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(newErrors)
|
||||||
|
|
||||||
|
return newErrors.axValue2.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupInput(ax: AxSkill | undefined, element: HTMLInputElement) {
|
||||||
|
if (ax) {
|
||||||
|
const rangeString = `${ax.minValue}~${ax.maxValue}${ax.suffix || ''}`
|
||||||
|
|
||||||
|
element.disabled = false
|
||||||
|
element.placeholder = rangeString
|
||||||
|
element.min = `${ax.minValue}`
|
||||||
|
element.max = `${ax.maxValue}`
|
||||||
|
element.step = (ax.suffix) ? "0.5" : "1"
|
||||||
|
} else {
|
||||||
|
if (primaryAxValueInput.current && secondaryAxValueInput.current) {
|
||||||
|
if (primaryAxValueInput.current == element) {
|
||||||
|
primaryAxValueInput.current.disabled = true
|
||||||
|
primaryAxValueInput.current.placeholder = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
secondaryAxValueInput.current.disabled = true
|
||||||
|
secondaryAxValueInput.current.placeholder = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="AXSelect">
|
||||||
|
<div className="AXSet">
|
||||||
|
<div className="fields">
|
||||||
|
<select key="ax1" defaultValue={ (props.currentSkills && props.currentSkills[0]) ? props.currentSkills[0].modifier : -1 } onChange={handleSelectChange} ref={primaryAxModifierSelect}>{ generateOptions(0) }</select>
|
||||||
|
<input defaultValue={ (props.currentSkills && props.currentSkills[0]) ? props.currentSkills[0].strength : 0 } className="Input" type="number" onChange={handleInputChange} ref={primaryAxValueInput} disabled />
|
||||||
|
</div>
|
||||||
|
<p className={primaryErrorClasses}>{errors.axValue1}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={secondarySetClasses}>
|
||||||
|
<div className="fields">
|
||||||
|
<select key="ax2" defaultValue={ (props.currentSkills && props.currentSkills[1]) ? props.currentSkills[1].modifier : -1 } onChange={handleSelectChange} ref={secondaryAxModifierSelect}>{ generateOptions(1) }</select>
|
||||||
|
<input defaultValue={ (props.currentSkills && props.currentSkills[1]) ? props.currentSkills[1].strength : 0 } className="Input" type="number" onChange={handleInputChange} ref={secondaryAxValueInput} disabled />
|
||||||
|
</div>
|
||||||
|
<p className={secondaryErrorClasses}>{errors.axValue2}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AXSelect
|
||||||
|
|
@ -86,6 +86,11 @@
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: $grey-50;
|
stroke: $grey-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.settings svg {
|
||||||
|
height: 13px;
|
||||||
|
width: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.Active {
|
&.Active {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import EditIcon from '~public/icons/Edit.svg'
|
||||||
import LinkIcon from '~public/icons/Link.svg'
|
import LinkIcon from '~public/icons/Link.svg'
|
||||||
import MenuIcon from '~public/icons/Menu.svg'
|
import MenuIcon from '~public/icons/Menu.svg'
|
||||||
import SaveIcon from '~public/icons/Save.svg'
|
import SaveIcon from '~public/icons/Save.svg'
|
||||||
|
import SettingsIcon from '~public/icons/Settings.svg'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
|
|
@ -68,6 +69,10 @@ class Button extends React.Component<Props, State> {
|
||||||
icon = <span className='icon stroke'>
|
icon = <span className='icon stroke'>
|
||||||
<SaveIcon />
|
<SaveIcon />
|
||||||
</span>
|
</span>
|
||||||
|
} else if (this.props.icon === 'settings') {
|
||||||
|
icon = <span className='icon settings'>
|
||||||
|
<SettingsIcon />
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
|
|
|
||||||
59
components/ElementToggle/index.scss
Normal file
59
components/ElementToggle/index.scss
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
.ToggleGroup {
|
||||||
|
$height: 36px;
|
||||||
|
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.14);
|
||||||
|
border-radius: $height;
|
||||||
|
display: flex;
|
||||||
|
height: $height;
|
||||||
|
gap: $unit / 4;
|
||||||
|
padding: $unit / 2;
|
||||||
|
|
||||||
|
.ToggleItem {
|
||||||
|
background: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 18px;
|
||||||
|
color: $grey-40;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: $font-regular;
|
||||||
|
padding: ($unit) $unit * 2;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover, &[data-state="on"] {
|
||||||
|
background:$grey-80;
|
||||||
|
color: $grey-00;
|
||||||
|
|
||||||
|
&.fire {
|
||||||
|
background: $fire-bg-light;
|
||||||
|
color: $fire-text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.water {
|
||||||
|
background: $water-bg-light;
|
||||||
|
color: $water-text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.earth {
|
||||||
|
background: $earth-bg-light;
|
||||||
|
color: $earth-text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.wind {
|
||||||
|
background: $wind-bg-light;
|
||||||
|
color: $wind-text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
background: $dark-bg-light;
|
||||||
|
color: $dark-text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
background: $light-bg-light;
|
||||||
|
color: $light-text-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
components/ElementToggle/index.tsx
Normal file
39
components/ElementToggle/index.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import React from 'react'
|
||||||
|
import * as ToggleGroup from '@radix-ui/react-toggle-group'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
currentElement: number
|
||||||
|
sendValue: (value: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElementToggle = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<ToggleGroup.Root className="ToggleGroup" type="single" defaultValue={`${props.currentElement}`} aria-label="Element" onValueChange={props.sendValue}>
|
||||||
|
<ToggleGroup.Item className="ToggleItem" value="0" aria-label="null">
|
||||||
|
Null
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
<ToggleGroup.Item className="ToggleItem wind" value="1" aria-label="wind">
|
||||||
|
Wind
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
<ToggleGroup.Item className="ToggleItem fire" value="2" aria-label="fire">
|
||||||
|
Fire
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
<ToggleGroup.Item className="ToggleItem water" value="3" aria-label="water">
|
||||||
|
Water
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
<ToggleGroup.Item className="ToggleItem earth" value="4" aria-label="earth">
|
||||||
|
Earth
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
<ToggleGroup.Item className="ToggleItem dark" value="5" aria-label="dark">
|
||||||
|
Dark
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
<ToggleGroup.Item className="ToggleItem light" value="6" aria-label="light">
|
||||||
|
Light
|
||||||
|
</ToggleGroup.Item>
|
||||||
|
</ToggleGroup.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ElementToggle
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
background: url('/icons/Arrow.svg'), $grey-90;
|
background: url('/icons/Arrow.svg'), $grey-90;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position-y: center;
|
background-position-y: center;
|
||||||
background-position-x: 98%;
|
background-position-x: 95%;
|
||||||
background-size: $unit * 1.5;
|
background-size: $unit * 1.5;
|
||||||
color: $grey-50;
|
color: $grey-50;
|
||||||
font-size: $font-small;
|
font-size: $font-small;
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,16 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartySegmentedControl = (props: Props) => {
|
const PartySegmentedControl = (props: Props) => {
|
||||||
const { party } = useSnapshot(appState)
|
const { party, grid } = useSnapshot(appState)
|
||||||
|
|
||||||
function getElement() {
|
function getElement() {
|
||||||
switch(party.element) {
|
let element: number = 0
|
||||||
|
if (party.element == 0 && grid.weapons.mainWeapon)
|
||||||
|
element = grid.weapons.mainWeapon.element
|
||||||
|
else
|
||||||
|
element = party.element
|
||||||
|
|
||||||
|
switch(element) {
|
||||||
case 1: return "wind"; break
|
case 1: return "wind"; break
|
||||||
case 2: return "fire"; break
|
case 2: return "fire"; break
|
||||||
case 3: return "water"; break
|
case 3: return "water"; break
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
import { useCookies } from 'react-cookie'
|
|
||||||
|
|
||||||
import { appState } from '~utils/appState'
|
import { appState } from '~utils/appState'
|
||||||
import api from '~utils/api'
|
import api from '~utils/api'
|
||||||
|
|
@ -15,7 +14,6 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const RaidDropdown = React.forwardRef<HTMLSelectElement, Props>(function useFieldSet(props, ref) {
|
const RaidDropdown = React.forwardRef<HTMLSelectElement, Props>(function useFieldSet(props, ref) {
|
||||||
const [cookies] = useCookies(['user'])
|
|
||||||
const [raids, setRaids] = useState<Raid[][]>()
|
const [raids, setRaids] = useState<Raid[][]>()
|
||||||
|
|
||||||
const raidGroups = [
|
const raidGroups = [
|
||||||
|
|
@ -50,12 +48,8 @@ const RaidDropdown = React.forwardRef<HTMLSelectElement, Props>(function useFiel
|
||||||
}, [props.allOption])
|
}, [props.allOption])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const headers = (cookies.user != null) ? {
|
|
||||||
headers: { 'Authorization': `Bearer ${cookies.user.access_token}` }
|
|
||||||
} : {}
|
|
||||||
|
|
||||||
function fetchRaids() {
|
function fetchRaids() {
|
||||||
api.endpoints.raids.getAll(headers)
|
api.endpoints.raids.getAll()
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const raids = response.data.map((r: any) => r.raid)
|
const raids = response.data.map((r: any) => r.raid)
|
||||||
|
|
||||||
|
|
@ -65,7 +59,7 @@ const RaidDropdown = React.forwardRef<HTMLSelectElement, Props>(function useFiel
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchRaids()
|
fetchRaids()
|
||||||
}, [cookies.user, organizeRaids])
|
}, [organizeRaids])
|
||||||
|
|
||||||
function raidGroup(index: number) {
|
function raidGroup(index: number) {
|
||||||
const options = raids && raids.length > 0 && raids[index].length > 0 &&
|
const options = raids && raids.length > 0 && raids[index].length > 0 &&
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ const WeaponGrid = (props: Props) => {
|
||||||
// Render: JSX components
|
// Render: JSX components
|
||||||
const mainhandElement = (
|
const mainhandElement = (
|
||||||
<WeaponUnit
|
<WeaponUnit
|
||||||
gridWeapon={grid.weapons.mainWeapon}
|
gridWeapon={appState.grid.weapons.mainWeapon}
|
||||||
editable={party.editable}
|
editable={party.editable}
|
||||||
key="grid_mainhand"
|
key="grid_mainhand"
|
||||||
position={-1}
|
position={-1}
|
||||||
|
|
@ -247,7 +247,7 @@ const WeaponGrid = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<li key={`grid_unit_${i}`} >
|
<li key={`grid_unit_${i}`} >
|
||||||
<WeaponUnit
|
<WeaponUnit
|
||||||
gridWeapon={grid.weapons.allWeapons[i]}
|
gridWeapon={appState.grid.weapons.allWeapons[i]}
|
||||||
editable={party.editable}
|
editable={party.editable}
|
||||||
position={i}
|
position={i}
|
||||||
unitType={1}
|
unitType={1}
|
||||||
|
|
@ -261,7 +261,7 @@ const WeaponGrid = (props: Props) => {
|
||||||
|
|
||||||
const extraGridElement = (
|
const extraGridElement = (
|
||||||
<ExtraWeapons
|
<ExtraWeapons
|
||||||
grid={grid.weapons.allWeapons}
|
grid={appState.grid.weapons.allWeapons}
|
||||||
editable={party.editable}
|
editable={party.editable}
|
||||||
offset={numWeapons}
|
offset={numWeapons}
|
||||||
updateObject={receiveWeaponFromSearch}
|
updateObject={receiveWeaponFromSearch}
|
||||||
|
|
|
||||||
0
components/WeaponKeyDropdown/index.scss
Normal file
0
components/WeaponKeyDropdown/index.scss
Normal file
140
components/WeaponKeyDropdown/index.tsx
Normal file
140
components/WeaponKeyDropdown/index.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import api from '~utils/api'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
interface Props {
|
||||||
|
currentValue?: WeaponKey
|
||||||
|
series: number
|
||||||
|
slot: number
|
||||||
|
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void
|
||||||
|
onBlur?: (event: React.ChangeEvent<HTMLSelectElement>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(function useFieldSet(props, ref) {
|
||||||
|
const [keys, setKeys] = useState<WeaponKey[][]>([])
|
||||||
|
|
||||||
|
const pendulumNames = [
|
||||||
|
{ en: 'Pendulum', jp: '' },
|
||||||
|
{ en: 'Chain', 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: '' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const keyName = () => {
|
||||||
|
return {
|
||||||
|
en: '',
|
||||||
|
jp: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyKey: WeaponKey = {
|
||||||
|
id: '0',
|
||||||
|
name: {
|
||||||
|
en: `No ${keyName().en}`,
|
||||||
|
jp: `${keyName().jp}なし`
|
||||||
|
},
|
||||||
|
series: props.series,
|
||||||
|
slot: props.slot,
|
||||||
|
group: -1,
|
||||||
|
order: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const organizeWeaponKeys = useCallback((weaponKeys: WeaponKey[]) => {
|
||||||
|
const numGroups = Math.max.apply(Math, weaponKeys.map(key => key.group))
|
||||||
|
let groupedKeys = []
|
||||||
|
for (let i = 0; i <= numGroups; i++) {
|
||||||
|
groupedKeys[i] = weaponKeys.filter(key => key.group == i)
|
||||||
|
}
|
||||||
|
|
||||||
|
setKeys(groupedKeys)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const filterParams = {
|
||||||
|
params: {
|
||||||
|
series: props.series,
|
||||||
|
slot: props.slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchWeaponKeys() {
|
||||||
|
api.endpoints.weapon_keys.getAll(filterParams)
|
||||||
|
.then((response) => {
|
||||||
|
const keys = response.data.map((k: any) => k.weapon_key)
|
||||||
|
organizeWeaponKeys(keys)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchWeaponKeys()
|
||||||
|
}, [props.series, props.slot, organizeWeaponKeys])
|
||||||
|
|
||||||
|
function weaponKeyGroup(index: number) {
|
||||||
|
['α','β','γ','Δ'].sort((a, b) => a.localeCompare(b, 'el'))
|
||||||
|
|
||||||
|
const sortByOrder = (a: WeaponKey, b: WeaponKey) => a.order > b.order ? 1 : -1
|
||||||
|
|
||||||
|
const options = keys && keys.length > 0 && keys[index].length > 0 &&
|
||||||
|
keys[index].sort(sortByOrder).map((item, i) => {
|
||||||
|
return (
|
||||||
|
<option key={i} value={item.id}>{item.name.en}</option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
let name: { [key: string]: string } = {}
|
||||||
|
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 == 17)
|
||||||
|
name = gauphNames[props.slot]
|
||||||
|
else if (props.series == 22)
|
||||||
|
name = emblemNames[index]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<optgroup key={index} label={ (props.series == 17 && props.slot == 2) ? name.en : `${name.en}s`}>
|
||||||
|
{options}
|
||||||
|
</optgroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyOption = () => {
|
||||||
|
let name = ''
|
||||||
|
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
|
||||||
|
|
||||||
|
return `No ${name}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
key={ (props.currentValue) ? props.currentValue.id : ''}
|
||||||
|
defaultValue={ (props.currentValue) ? props.currentValue.id : '' }
|
||||||
|
onBlur={props.onBlur}
|
||||||
|
onChange={props.onChange}
|
||||||
|
ref={ref}>
|
||||||
|
<option key="-1" value="-1">{emptyOption()}</option>
|
||||||
|
{ Array.from(Array(keys?.length)).map((x, i) => {
|
||||||
|
return weaponKeyGroup(i)
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default WeaponKeyDropdown
|
||||||
44
components/WeaponModal/index.scss
Normal file
44
components/WeaponModal/index.scss
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
.Weapon.Dialog {
|
||||||
|
.mods {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $unit * 4;
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $unit / 2;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: $grey-50;
|
||||||
|
font-size: $font-small;
|
||||||
|
margin-bottom: $unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
background-color: $grey-90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.Button {
|
||||||
|
font-size: $font-regular;
|
||||||
|
padding: ($unit * 1.5) ($unit * 2);
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.btn-disabled {
|
||||||
|
background: $grey-90;
|
||||||
|
color: $grey-70;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.btn-disabled) {
|
||||||
|
background: $grey-90;
|
||||||
|
color: $grey-40;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $grey-80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
216
components/WeaponModal/index.tsx
Normal file
216
components/WeaponModal/index.tsx
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useCookies } from 'react-cookie'
|
||||||
|
import { AxiosResponse } from 'axios'
|
||||||
|
import * as Dialog from '@radix-ui/react-dialog'
|
||||||
|
|
||||||
|
import AXSelect from '~components/AxSelect'
|
||||||
|
import ElementToggle from '~components/ElementToggle'
|
||||||
|
import WeaponKeyDropdown from '~components/WeaponKeyDropdown'
|
||||||
|
import Button from '~components/Button'
|
||||||
|
|
||||||
|
import api from '~utils/api'
|
||||||
|
import { appState } from '~utils/appState'
|
||||||
|
|
||||||
|
import CrossIcon from '~public/icons/Cross.svg'
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
|
||||||
|
interface GridWeaponObject {
|
||||||
|
weapon: {
|
||||||
|
element?: number
|
||||||
|
weapon_key1_id?: string
|
||||||
|
weapon_key2_id?: string
|
||||||
|
weapon_key3_id?: string
|
||||||
|
ax_modifier1?: number
|
||||||
|
ax_modifier2?: number
|
||||||
|
ax_strength1?: number
|
||||||
|
ax_strength2?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
gridWeapon: GridWeapon
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const WeaponModal = (props: Props) => {
|
||||||
|
// Cookies
|
||||||
|
const [cookies, _] = useCookies(['user'])
|
||||||
|
const headers = (cookies.user != null) ? {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${cookies.user.access_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 [primaryAxModifier, setPrimaryAxModifier] = useState(-1)
|
||||||
|
const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1)
|
||||||
|
const [primaryAxValue, setPrimaryAxValue] = useState(0.0)
|
||||||
|
const [secondaryAxValue, setSecondaryAxValue] = useState(0.0)
|
||||||
|
|
||||||
|
function receiveAxValues(primaryAxModifier: number, primaryAxValue: number, secondaryAxModifier: number, secondaryAxValue: number) {
|
||||||
|
setPrimaryAxModifier(primaryAxModifier)
|
||||||
|
setSecondaryAxModifier(secondaryAxModifier)
|
||||||
|
|
||||||
|
setPrimaryAxValue(primaryAxValue)
|
||||||
|
setSecondaryAxValue(secondaryAxValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
function receiveAxValidity(isValid: boolean) {
|
||||||
|
setFormValid(isValid)
|
||||||
|
}
|
||||||
|
|
||||||
|
function receiveElementValue(element: string) {
|
||||||
|
setElement(parseInt(element))
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareObject() {
|
||||||
|
let object: GridWeaponObject = { weapon: {} }
|
||||||
|
|
||||||
|
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].includes(props.gridWeapon.object.series))
|
||||||
|
object.weapon.weapon_key2_id = weaponKey2Select.current?.value
|
||||||
|
|
||||||
|
if (props.gridWeapon.object.series == 17)
|
||||||
|
object.weapon.weapon_key3_id = weaponKey3Select.current?.value
|
||||||
|
|
||||||
|
if (props.gridWeapon.object.ax > 0) {
|
||||||
|
object.weapon.ax_modifier1 = primaryAxModifier
|
||||||
|
object.weapon.ax_modifier2 = secondaryAxModifier
|
||||||
|
object.weapon.ax_strength1 = primaryAxValue
|
||||||
|
object.weapon.ax_strength2 = secondaryAxValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateWeapon() {
|
||||||
|
const updateObject = prepareObject()
|
||||||
|
return await api.endpoints.grid_weapons.update(props.gridWeapon.id, updateObject, headers)
|
||||||
|
.then(response => processResult(response))
|
||||||
|
.catch(error => processError(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
function processResult(response: AxiosResponse) {
|
||||||
|
const gridWeapon: GridWeapon = response.data.grid_weapon
|
||||||
|
|
||||||
|
if (gridWeapon.mainhand)
|
||||||
|
appState.grid.weapons.mainWeapon = gridWeapon
|
||||||
|
else
|
||||||
|
appState.grid.weapons.allWeapons[gridWeapon.position] = gridWeapon
|
||||||
|
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function processError(error: any) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementSelect = () => {
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<h3>Element</h3>
|
||||||
|
<ElementToggle
|
||||||
|
currentElement={props.gridWeapon.element}
|
||||||
|
sendValue={receiveElementValue}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const keySelect = () => {
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<h3>Weapon Keys</h3>
|
||||||
|
{ ([2, 3, 17, 22].includes(props.gridWeapon.object.series)) ?
|
||||||
|
<WeaponKeyDropdown
|
||||||
|
currentValue={ (props.gridWeapon.weapon_keys) ? props.gridWeapon.weapon_keys[0] : undefined }
|
||||||
|
series={props.gridWeapon.object.series}
|
||||||
|
slot={0}
|
||||||
|
ref={weaponKey1Select} />
|
||||||
|
: ''}
|
||||||
|
|
||||||
|
{ ([2, 3, 17].includes(props.gridWeapon.object.series)) ?
|
||||||
|
<WeaponKeyDropdown
|
||||||
|
currentValue={ (props.gridWeapon.weapon_keys) ? props.gridWeapon.weapon_keys[1] : undefined }
|
||||||
|
series={props.gridWeapon.object.series}
|
||||||
|
slot={1}
|
||||||
|
ref={weaponKey2Select} />
|
||||||
|
: ''}
|
||||||
|
|
||||||
|
{ (props.gridWeapon.object.series == 17) ?
|
||||||
|
<WeaponKeyDropdown
|
||||||
|
currentValue={ (props.gridWeapon.weapon_keys) ? props.gridWeapon.weapon_keys[2] : undefined }
|
||||||
|
series={props.gridWeapon.object.series}
|
||||||
|
slot={2}
|
||||||
|
ref={weaponKey3Select} />
|
||||||
|
: ''}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const axSelect = () => {
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<AXSelect
|
||||||
|
axType={props.gridWeapon.object.ax}
|
||||||
|
currentSkills={props.gridWeapon.ax}
|
||||||
|
sendValidity={receiveAxValidity}
|
||||||
|
sendValues={receiveAxValues}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function openChange(open: boolean) {
|
||||||
|
setFormValid(false)
|
||||||
|
setOpen(open)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog.Root open={open} onOpenChange={openChange}>
|
||||||
|
<Dialog.Trigger asChild>
|
||||||
|
{ props.children }
|
||||||
|
</Dialog.Trigger>
|
||||||
|
<Dialog.Portal>
|
||||||
|
<Dialog.Content className="Weapon Dialog" onOpenAutoFocus={ (event) => event.preventDefault() }>
|
||||||
|
<div className="DialogHeader">
|
||||||
|
<div className="DialogTop">
|
||||||
|
<Dialog.Title className="SubTitle">Modify Weapon</Dialog.Title>
|
||||||
|
<Dialog.Title className="DialogTitle">{props.gridWeapon.object.name.en}</Dialog.Title>
|
||||||
|
</div>
|
||||||
|
<Dialog.Close className="DialogClose" asChild>
|
||||||
|
<span>
|
||||||
|
<CrossIcon />
|
||||||
|
</span>
|
||||||
|
</Dialog.Close>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mods">
|
||||||
|
{ (props.gridWeapon.object.element == 0) ? elementSelect() : '' }
|
||||||
|
{ ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) ? keySelect() : '' }
|
||||||
|
{ (props.gridWeapon.object.ax > 0) ? axSelect() : '' }
|
||||||
|
<Button click={updateWeapon} disabled={!formValid}>Save Weapon</Button>
|
||||||
|
</div>
|
||||||
|
</Dialog.Content>
|
||||||
|
<Dialog.Overlay className="Overlay" />
|
||||||
|
</Dialog.Portal>
|
||||||
|
</Dialog.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WeaponModal
|
||||||
|
|
@ -3,11 +3,16 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
min-height: 139px;
|
min-height: 139px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@media (max-width: $medium-screen) {
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover .Button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
&.editable .WeaponImage:hover {
|
&.editable .WeaponImage:hover {
|
||||||
border: $hover-stroke;
|
border: $hover-stroke;
|
||||||
box-shadow: $hover-shadow;
|
box-shadow: $hover-shadow;
|
||||||
|
|
@ -66,6 +71,16 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Button {
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.14);
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
left: $unit;
|
||||||
|
top: $unit;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
color: $grey-00;
|
color: $grey-00;
|
||||||
font-size: $font-button;
|
font-size: $font-button;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@ import React, { useEffect, useState } from 'react'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import SearchModal from '~components/SearchModal'
|
import SearchModal from '~components/SearchModal'
|
||||||
|
import WeaponModal from '~components/WeaponModal'
|
||||||
import UncapIndicator from '~components/UncapIndicator'
|
import UncapIndicator from '~components/UncapIndicator'
|
||||||
import PlusIcon from '~public/icons/Add.svg'
|
import Button from '~components/Button'
|
||||||
|
|
||||||
|
import { ButtonType } from '~utils/enums'
|
||||||
|
|
||||||
|
import PlusIcon from '~public/icons/Add.svg'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -39,10 +43,17 @@ const WeaponUnit = (props: Props) => {
|
||||||
if (props.gridWeapon) {
|
if (props.gridWeapon) {
|
||||||
const weapon = props.gridWeapon.object!
|
const weapon = props.gridWeapon.object!
|
||||||
|
|
||||||
if (props.unitType == 0)
|
if (props.unitType == 0) {
|
||||||
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${weapon.granblue_id}.jpg`
|
if (props.gridWeapon.object.element == 0 && props.gridWeapon.element)
|
||||||
else
|
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${weapon.granblue_id}_${props.gridWeapon.element}.jpg`
|
||||||
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}.jpg`
|
else
|
||||||
|
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${weapon.granblue_id}.jpg`
|
||||||
|
} else {
|
||||||
|
if (props.gridWeapon.object.element == 0 && props.gridWeapon.element)
|
||||||
|
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}_${props.gridWeapon.element}.jpg`
|
||||||
|
else
|
||||||
|
imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}.jpg`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setImageUrl(imgSrc)
|
setImageUrl(imgSrc)
|
||||||
|
|
@ -53,6 +64,13 @@ const WeaponUnit = (props: Props) => {
|
||||||
props.updateUncap(props.gridWeapon.id, props.position, uncap)
|
props.updateUncap(props.gridWeapon.id, props.position, uncap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canBeModified(gridWeapon: GridWeapon) {
|
||||||
|
const weapon = gridWeapon.object
|
||||||
|
|
||||||
|
return weapon.ax > 0 ||
|
||||||
|
(weapon.series) && [2, 3, 17, 22].includes(weapon.series)
|
||||||
|
}
|
||||||
|
|
||||||
const image = (
|
const image = (
|
||||||
<div className="WeaponImage">
|
<div className="WeaponImage">
|
||||||
<img alt={weapon?.name.en} className="grid_image" src={imageUrl} />
|
<img alt={weapon?.name.en} className="grid_image" src={imageUrl} />
|
||||||
|
|
@ -61,18 +79,26 @@ const WeaponUnit = (props: Props) => {
|
||||||
)
|
)
|
||||||
|
|
||||||
const editableImage = (
|
const editableImage = (
|
||||||
<SearchModal
|
<div className="WeaponImage">
|
||||||
placeholderText="Search for a weapon..."
|
<SearchModal
|
||||||
fromPosition={props.position}
|
placeholderText="Search for a weapon..."
|
||||||
object="weapons"
|
fromPosition={props.position}
|
||||||
send={props.updateObject}>
|
object="weapons"
|
||||||
{image}
|
send={props.updateObject}>
|
||||||
</SearchModal>
|
{image}
|
||||||
|
</SearchModal>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
|
{ (props.editable && gridWeapon && canBeModified(gridWeapon)) ?
|
||||||
|
<WeaponModal gridWeapon={gridWeapon}>
|
||||||
|
<div>
|
||||||
|
<Button icon="settings" type={ButtonType.IconOnly}/>
|
||||||
|
</div>
|
||||||
|
</WeaponModal>: '' }
|
||||||
{ (props.editable) ? editableImage : image }
|
{ (props.editable) ? editableImage : image }
|
||||||
{ (gridWeapon) ?
|
{ (gridWeapon) ?
|
||||||
<UncapIndicator
|
<UncapIndicator
|
||||||
|
|
|
||||||
186
package-lock.json
generated
186
package-lock.json
generated
|
|
@ -12,6 +12,7 @@
|
||||||
"@radix-ui/react-hover-card": "^0.1.3",
|
"@radix-ui/react-hover-card": "^0.1.3",
|
||||||
"@radix-ui/react-label": "^0.1.4",
|
"@radix-ui/react-label": "^0.1.4",
|
||||||
"@radix-ui/react-switch": "^0.1.4",
|
"@radix-ui/react-switch": "^0.1.4",
|
||||||
|
"@radix-ui/react-toggle-group": "^0.1.5",
|
||||||
"@svgr/webpack": "^6.2.0",
|
"@svgr/webpack": "^6.2.0",
|
||||||
"@types/axios": "^0.14.0",
|
"@types/axios": "^0.14.0",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.25.0",
|
||||||
|
|
@ -2630,6 +2631,107 @@
|
||||||
"react": "^16.8 || ^17.0"
|
"react": "^16.8 || ^17.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-gxUq6NgMc4ChV8VJnwdYqueeoblspwXHAexYo+jM9N2hFLbI1C587jLjdTHzIcUa9q68Xaw4jtiImWDOokEhRw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "0.1.0",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-use-controllable-state": "0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle-group": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-Yp14wFiqe00azF+sG5CCJz4JGOP/f5Jj+CxLlZCmMpG5qhVTWeaeG4YH6pvX4KL41fS8x9FAaLb8wW9y01o67g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "0.1.0",
|
||||||
|
"@radix-ui/react-context": "0.1.1",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-roving-focus": "0.1.5",
|
||||||
|
"@radix-ui/react-toggle": "0.1.4",
|
||||||
|
"@radix-ui/react-use-controllable-state": "0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-collection": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-compose-refs": "0.1.0",
|
||||||
|
"@radix-ui/react-context": "0.1.1",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-slot": "0.1.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-id": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-use-layout-effect": "0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-slot": "0.1.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-roving-focus": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "0.1.0",
|
||||||
|
"@radix-ui/react-collection": "0.1.4",
|
||||||
|
"@radix-ui/react-compose-refs": "0.1.0",
|
||||||
|
"@radix-ui/react-context": "0.1.1",
|
||||||
|
"@radix-ui/react-id": "0.1.5",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-use-callback-ref": "0.1.0",
|
||||||
|
"@radix-ui/react-use-controllable-state": "0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-slot": "0.1.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-use-body-pointer-events": {
|
"node_modules/@radix-ui/react-use-body-pointer-events": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.0.tgz",
|
||||||
|
|
@ -8660,6 +8762,90 @@
|
||||||
"@radix-ui/react-use-size": "0.1.0"
|
"@radix-ui/react-use-size": "0.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@radix-ui/react-toggle": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-gxUq6NgMc4ChV8VJnwdYqueeoblspwXHAexYo+jM9N2hFLbI1C587jLjdTHzIcUa9q68Xaw4jtiImWDOokEhRw==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "0.1.0",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-use-controllable-state": "0.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-primitive": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-slot": "0.1.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-toggle-group": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-Yp14wFiqe00azF+sG5CCJz4JGOP/f5Jj+CxLlZCmMpG5qhVTWeaeG4YH6pvX4KL41fS8x9FAaLb8wW9y01o67g==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "0.1.0",
|
||||||
|
"@radix-ui/react-context": "0.1.1",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-roving-focus": "0.1.5",
|
||||||
|
"@radix-ui/react-toggle": "0.1.4",
|
||||||
|
"@radix-ui/react-use-controllable-state": "0.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-collection": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-compose-refs": "0.1.0",
|
||||||
|
"@radix-ui/react-context": "0.1.1",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-slot": "0.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-id": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-use-layout-effect": "0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-primitive": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/react-slot": "0.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@radix-ui/react-roving-focus": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "0.1.0",
|
||||||
|
"@radix-ui/react-collection": "0.1.4",
|
||||||
|
"@radix-ui/react-compose-refs": "0.1.0",
|
||||||
|
"@radix-ui/react-context": "0.1.1",
|
||||||
|
"@radix-ui/react-id": "0.1.5",
|
||||||
|
"@radix-ui/react-primitive": "0.1.4",
|
||||||
|
"@radix-ui/react-use-callback-ref": "0.1.0",
|
||||||
|
"@radix-ui/react-use-controllable-state": "0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@radix-ui/react-use-body-pointer-events": {
|
"@radix-ui/react-use-body-pointer-events": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"@radix-ui/react-hover-card": "^0.1.3",
|
"@radix-ui/react-hover-card": "^0.1.3",
|
||||||
"@radix-ui/react-label": "^0.1.4",
|
"@radix-ui/react-label": "^0.1.4",
|
||||||
"@radix-ui/react-switch": "^0.1.4",
|
"@radix-ui/react-switch": "^0.1.4",
|
||||||
|
"@radix-ui/react-toggle-group": "^0.1.5",
|
||||||
"@svgr/webpack": "^6.2.0",
|
"@svgr/webpack": "^6.2.0",
|
||||||
"@types/axios": "^0.14.0",
|
"@types/axios": "^0.14.0",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.25.0",
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
|
|
||||||
type Data = {
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function handler(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
res.status(200).json({ name: 'John Doe' })
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<svg viewBox="0 0 14 14" fill="#444" xmlns="http://www.w3.org/2000/svg">
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.3121 4.60937C2.09636 4.43701 1.78173 4.47219 1.60937 4.68793C1.43701 4.90368 1.47219 5.2183 1.68793 5.39066L6.68107 9.37966C6.75234 9.4366 6.8344 9.47089 6.91856 9.48351C7.05774 9.51055 7.20746 9.47854 7.32678 9.38296L12.311 5.39025C12.5265 5.21761 12.5613 4.90294 12.3886 4.68742C12.216 4.4719 11.9013 4.43714 11.6858 4.60979L7.00557 8.35897L2.3121 4.60937Z" />
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.93618 4.62991C2.73179 4.44423 2.41557 4.4594 2.22989 4.6638C2.04421 4.8682 2.05938 5.18441 2.26378 5.37009L6.65743 9.36145C6.72962 9.42702 6.81576 9.46755 6.90516 9.48353C7.05808 9.51688 7.2243 9.47812 7.34882 9.3647L11.7346 5.36964C11.9388 5.18368 11.9535 4.86745 11.7676 4.6633C11.5816 4.45916 11.2654 4.44441 11.0612 4.63037L7.00447 8.32569L2.93618 4.62991Z" fill="black"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 495 B After Width: | Height: | Size: 532 B |
3
public/icons/ArrowDark.svg
Normal file
3
public/icons/ArrowDark.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.9363 5.12991C2.73191 4.94423 2.41569 4.9594 2.23001 5.1638C2.04433 5.3682 2.0595 5.68441 2.2639 5.87009L6.65755 9.86145C6.72974 9.92702 6.81588 9.96755 6.90529 9.98353C7.05821 10.0169 7.22443 9.97812 7.34894 9.8647L11.7348 5.86964C11.9389 5.68368 11.9537 5.36745 11.7677 5.1633C11.5817 4.95916 11.2655 4.94441 11.0614 5.13037L7.00459 8.82569L2.9363 5.12991Z" fill="#888888"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 531 B |
6
public/icons/Settings.svg
Normal file
6
public/icons/Settings.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -49,7 +49,7 @@ select {
|
||||||
background-image: url('/icons/Arrow.svg');
|
background-image: url('/icons/Arrow.svg');
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position-y: center;
|
background-position-y: center;
|
||||||
background-position-x: 98%;
|
background-position-x: 97%;
|
||||||
background-size: $unit * 1.5;
|
background-size: $unit * 1.5;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|
@ -110,6 +110,7 @@ select {
|
||||||
|
|
||||||
.DialogHeader {
|
.DialogHeader {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
|
|
@ -150,6 +151,19 @@ select {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.DialogTop {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
gap: $unit / 2;
|
||||||
|
|
||||||
|
.SubTitle {
|
||||||
|
color: $grey-50;
|
||||||
|
font-size: $font-small;
|
||||||
|
font-weight: $medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.DialogDescription {
|
.DialogDescription {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
types/AxSkill.d.ts
vendored
Normal file
11
types/AxSkill.d.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
interface AxSkill {
|
||||||
|
name: {
|
||||||
|
en: string,
|
||||||
|
jp: string
|
||||||
|
},
|
||||||
|
id: number,
|
||||||
|
minValue: number,
|
||||||
|
maxValue: number,
|
||||||
|
suffix?: string,
|
||||||
|
secondary?: AxSkill[]
|
||||||
|
}
|
||||||
3
types/GridWeapon.d.ts
vendored
3
types/GridWeapon.d.ts
vendored
|
|
@ -4,4 +4,7 @@ interface GridWeapon {
|
||||||
position: number
|
position: number
|
||||||
object: Weapon
|
object: Weapon
|
||||||
uncap_level: number
|
uncap_level: number
|
||||||
|
element: number
|
||||||
|
weapon_keys?: Array<WeaponKey>
|
||||||
|
ax?: Array<SimpleAxSkill>
|
||||||
}
|
}
|
||||||
4
types/SimpleAxSkill.d.ts
vendored
Normal file
4
types/SimpleAxSkill.d.ts
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
interface SimpleAxSkill {
|
||||||
|
modifier: number
|
||||||
|
strength: number
|
||||||
|
}
|
||||||
2
types/Weapon.d.ts
vendored
2
types/Weapon.d.ts
vendored
|
|
@ -7,6 +7,8 @@ interface Weapon {
|
||||||
proficiency: number
|
proficiency: number
|
||||||
max_level: number
|
max_level: number
|
||||||
max_skill_level: number
|
max_skill_level: number
|
||||||
|
series: number
|
||||||
|
ax: number
|
||||||
name: {
|
name: {
|
||||||
en: string
|
en: string
|
||||||
jp: string
|
jp: string
|
||||||
|
|
|
||||||
11
types/WeaponKey.d.ts
vendored
Normal file
11
types/WeaponKey.d.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
interface WeaponKey {
|
||||||
|
id: string
|
||||||
|
name: {
|
||||||
|
en: string,
|
||||||
|
jp: string
|
||||||
|
}
|
||||||
|
series: integer
|
||||||
|
slot: integer
|
||||||
|
group: integer
|
||||||
|
order: integer
|
||||||
|
}
|
||||||
|
|
@ -103,10 +103,12 @@ class Api {
|
||||||
const api: Api = new Api({ url: process.env.NEXT_PUBLIC_SIERO_API_URL || 'https://localhost:3000/api/v1'})
|
const api: Api = new Api({ url: process.env.NEXT_PUBLIC_SIERO_API_URL || 'https://localhost:3000/api/v1'})
|
||||||
api.createEntity( { name: 'users' })
|
api.createEntity( { name: 'users' })
|
||||||
api.createEntity( { name: 'parties' })
|
api.createEntity( { name: 'parties' })
|
||||||
|
api.createEntity( { name: 'grid_weapons' })
|
||||||
api.createEntity( { name: 'characters' })
|
api.createEntity( { name: 'characters' })
|
||||||
api.createEntity( { name: 'weapons' })
|
api.createEntity( { name: 'weapons' })
|
||||||
api.createEntity( { name: 'summons' })
|
api.createEntity( { name: 'summons' })
|
||||||
api.createEntity( { name: 'raids' })
|
api.createEntity( { name: 'raids' })
|
||||||
|
api.createEntity( { name: 'weapon_keys' })
|
||||||
api.createEntity( { name: 'favorites' })
|
api.createEntity( { name: 'favorites' })
|
||||||
|
|
||||||
export default api
|
export default api
|
||||||
791
utils/axData.tsx
Normal file
791
utils/axData.tsx
Normal file
|
|
@ -0,0 +1,791 @@
|
||||||
|
export const axData: AxSkill[][] = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "ATK",
|
||||||
|
"jp": "攻撃"
|
||||||
|
},
|
||||||
|
id: 0,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3.5,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Double Attack Rate",
|
||||||
|
"jp": "DA確率"
|
||||||
|
},
|
||||||
|
id: 5,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Triple Attack Rate",
|
||||||
|
"jp": "TA確率"
|
||||||
|
},
|
||||||
|
id: 6,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Skill DMG Cap",
|
||||||
|
"jp": "アビ上限"
|
||||||
|
},
|
||||||
|
id: 7,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "DEF",
|
||||||
|
"jp": "防御"
|
||||||
|
},
|
||||||
|
id: 1,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 8,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "HP",
|
||||||
|
"jp": "HP"
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Debuff Resistance",
|
||||||
|
"jp": "弱体耐性"
|
||||||
|
},
|
||||||
|
id: 9,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Healing",
|
||||||
|
"jp": "回復性能"
|
||||||
|
},
|
||||||
|
id: 10,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Enmity",
|
||||||
|
"jp": "背水"
|
||||||
|
},
|
||||||
|
id: 11,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "HP",
|
||||||
|
"jp": "HP"
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 11,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "DEF",
|
||||||
|
"jp": "防御"
|
||||||
|
},
|
||||||
|
id: 1,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Debuff Resistance",
|
||||||
|
"jp": "弱体耐性"
|
||||||
|
},
|
||||||
|
id: 9,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Healing",
|
||||||
|
"jp": "回復性能"
|
||||||
|
},
|
||||||
|
id: 10,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 8.5,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "ATK",
|
||||||
|
"jp": "攻撃"
|
||||||
|
},
|
||||||
|
id: 0,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 1.5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Elemental ATK",
|
||||||
|
"jp": "全属性攻撃力"
|
||||||
|
},
|
||||||
|
id: 13,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG Cap",
|
||||||
|
"jp": "奥義上限"
|
||||||
|
},
|
||||||
|
id: 8,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Multiattack Rate",
|
||||||
|
"jp": "連撃率"
|
||||||
|
},
|
||||||
|
id: 4,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Elemental ATK",
|
||||||
|
"jp": "全属性攻撃力"
|
||||||
|
},
|
||||||
|
id: 13,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Double Attack Rate",
|
||||||
|
"jp": "DA確率"
|
||||||
|
},
|
||||||
|
id: 5,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Triple Attack Rate",
|
||||||
|
"jp": "TA確率"
|
||||||
|
},
|
||||||
|
id: 6,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
], [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "ATK",
|
||||||
|
"jp": "攻撃"
|
||||||
|
},
|
||||||
|
id: 0,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3.5,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 8.5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Multiattack Rate",
|
||||||
|
"jp": "連撃確率"
|
||||||
|
},
|
||||||
|
id: 4,
|
||||||
|
minValue: 1.5,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Normal ATK DMG Cap",
|
||||||
|
"jp": "通常ダメ上限"
|
||||||
|
},
|
||||||
|
id: 14,
|
||||||
|
minValue: 0.5,
|
||||||
|
maxValue: 1.5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Supplemental Skill DMG",
|
||||||
|
"jp": "アビ与ダメ上昇"
|
||||||
|
},
|
||||||
|
id: 15,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "DEF",
|
||||||
|
"jp": "防御"
|
||||||
|
},
|
||||||
|
id: 1,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 8,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Elemental DMG Reduction",
|
||||||
|
"jp": "属性ダメ軽減"
|
||||||
|
},
|
||||||
|
id: 17,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Debuff Resistance",
|
||||||
|
"jp": "弱体耐性"
|
||||||
|
},
|
||||||
|
id: 9,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Healing",
|
||||||
|
"jp": "回復性能"
|
||||||
|
},
|
||||||
|
id: 10,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Enmity",
|
||||||
|
"jp": "背水"
|
||||||
|
},
|
||||||
|
id: 11,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "HP",
|
||||||
|
"jp": "HP"
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 11,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Elemental DMG Reduction",
|
||||||
|
"jp": "属性ダメ軽減"
|
||||||
|
},
|
||||||
|
id: 17,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Debuff Resistance",
|
||||||
|
"jp": "弱体耐性"
|
||||||
|
},
|
||||||
|
id: 9,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Healing",
|
||||||
|
"jp": "回復性能"
|
||||||
|
},
|
||||||
|
id: 10,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 8.5,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Multiattack Rate",
|
||||||
|
"jp": "連撃率"
|
||||||
|
},
|
||||||
|
id: 4,
|
||||||
|
minValue: 1.5,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Supplemental Skill DMG",
|
||||||
|
"jp": "アビ与ダメ上昇"
|
||||||
|
},
|
||||||
|
id: 15,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Supplemental C.A. DMG",
|
||||||
|
"jp": "奥義与ダメ上昇"
|
||||||
|
},
|
||||||
|
id: 16,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Multiattack Rate",
|
||||||
|
"jp": "連撃率"
|
||||||
|
},
|
||||||
|
id: 4,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Supplemental C.A. DMG",
|
||||||
|
"jp": "奥義与ダメ上昇"
|
||||||
|
},
|
||||||
|
id: 16,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Normal ATK DMG Cap",
|
||||||
|
"jp": "通常ダメ上限"
|
||||||
|
},
|
||||||
|
id: 14,
|
||||||
|
minValue: 0.5,
|
||||||
|
maxValue: 1.5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Enmity",
|
||||||
|
"jp": "背水"
|
||||||
|
},
|
||||||
|
id: 11,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
], [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "ATK",
|
||||||
|
"jp": "攻撃"
|
||||||
|
},
|
||||||
|
id: 0,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3.5,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Double Attack Rate",
|
||||||
|
"jp": "DA確率"
|
||||||
|
},
|
||||||
|
id: 5,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Triple Attack Rate",
|
||||||
|
"jp": "TA確率"
|
||||||
|
},
|
||||||
|
id: 6,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Skill DMG Cap",
|
||||||
|
"jp": "アビ上限"
|
||||||
|
},
|
||||||
|
id: 7,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "DEF",
|
||||||
|
"jp": "防御"
|
||||||
|
},
|
||||||
|
id: 1,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 8,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "HP",
|
||||||
|
"jp": "HP"
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Debuff Resistance",
|
||||||
|
"jp": "弱体耐性"
|
||||||
|
},
|
||||||
|
id: 9,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Healing",
|
||||||
|
"jp": "回復性能"
|
||||||
|
},
|
||||||
|
id: 10,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Enmity",
|
||||||
|
"jp": "背水"
|
||||||
|
},
|
||||||
|
id: 11,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "HP",
|
||||||
|
"jp": "HP"
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 11,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "DEF",
|
||||||
|
"jp": "防御"
|
||||||
|
},
|
||||||
|
id: 1,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Debuff Resistance",
|
||||||
|
"jp": "弱体耐性"
|
||||||
|
},
|
||||||
|
id: 9,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Healing",
|
||||||
|
"jp": "回復性能"
|
||||||
|
},
|
||||||
|
id: 10,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 8.5,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "ATK",
|
||||||
|
"jp": "攻撃"
|
||||||
|
},
|
||||||
|
id: 0,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 1.5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Elemental ATK",
|
||||||
|
"jp": "全属性攻撃力"
|
||||||
|
},
|
||||||
|
id: 13,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG Cap",
|
||||||
|
"jp": "奥義上限"
|
||||||
|
},
|
||||||
|
id: 8,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Stamina",
|
||||||
|
"jp": "渾身"
|
||||||
|
},
|
||||||
|
id: 12,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Multiattack Rate",
|
||||||
|
"jp": "連撃率"
|
||||||
|
},
|
||||||
|
id: 4,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%',
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "C.A. DMG",
|
||||||
|
"jp": "奥義ダメ"
|
||||||
|
},
|
||||||
|
id: 3,
|
||||||
|
minValue: 2,
|
||||||
|
maxValue: 4,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Elemental ATK",
|
||||||
|
"jp": "全属性攻撃力"
|
||||||
|
},
|
||||||
|
id: 13,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 5,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Double Attack Rate",
|
||||||
|
"jp": "DA確率"
|
||||||
|
},
|
||||||
|
id: 5,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Triple Attack Rate",
|
||||||
|
"jp": "TA確率"
|
||||||
|
},
|
||||||
|
id: 6,
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 2,
|
||||||
|
suffix: '%'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "EXP Up",
|
||||||
|
"jp": "EXP UP"
|
||||||
|
},
|
||||||
|
id: 18,
|
||||||
|
minValue: 5,
|
||||||
|
maxValue: 10,
|
||||||
|
suffix: '%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
"en": "Rupies",
|
||||||
|
"jp": "獲得ルピ"
|
||||||
|
},
|
||||||
|
id: 19,
|
||||||
|
minValue: 10,
|
||||||
|
maxValue: 20,
|
||||||
|
suffix: '%'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
Loading…
Reference in a new issue