Refactored WeaponKeySelect and updated styles

This commit is contained in:
Justin Edmund 2022-12-20 23:06:27 -08:00
parent 9a9a0397e9
commit 85fd5df516
9 changed files with 120 additions and 68 deletions

View file

@ -311,7 +311,7 @@ const AXSelect = (props: Props) => {
if (ax) { if (ax) {
const rangeString = `${ax.minValue}~${ax.maxValue}${ax.suffix || ''}` const rangeString = `${ax.minValue}~${ax.maxValue}${ax.suffix || ''}`
element.className = 'Input Visible' element.className = 'Input Contained Visible'
element.disabled = false element.disabled = false
element.placeholder = rangeString element.placeholder = rangeString
element.min = `${ax.minValue}` element.min = `${ax.minValue}`
@ -320,12 +320,12 @@ const AXSelect = (props: Props) => {
} else { } else {
if (primaryAxValueInput.current && secondaryAxValueInput.current) { if (primaryAxValueInput.current && secondaryAxValueInput.current) {
if (primaryAxValueInput.current == element) { if (primaryAxValueInput.current == element) {
primaryAxValueInput.current.className = 'Input' primaryAxValueInput.current.className = 'Input Contained'
primaryAxValueInput.current.disabled = true primaryAxValueInput.current.disabled = true
primaryAxValueInput.current.placeholder = '' primaryAxValueInput.current.placeholder = ''
} }
secondaryAxValueInput.current.className = 'Input' secondaryAxValueInput.current.className = 'Input Contained'
secondaryAxValueInput.current.disabled = true secondaryAxValueInput.current.disabled = true
secondaryAxValueInput.current.placeholder = '' secondaryAxValueInput.current.placeholder = ''
} }
@ -356,6 +356,7 @@ const AXSelect = (props: Props) => {
open={openAX1} open={openAX1}
onChange={handleAX1SelectChange} onChange={handleAX1SelectChange}
onClick={() => openSelect(primaryAxModifierSelect)} onClick={() => openSelect(primaryAxModifierSelect)}
triggerClass="modal"
ref={primaryAxModifierSelect} ref={primaryAxModifierSelect}
> >
{generateOptions(0)} {generateOptions(0)}
@ -383,6 +384,7 @@ const AXSelect = (props: Props) => {
open={openAX2} open={openAX2}
onChange={handleAX2SelectChange} onChange={handleAX2SelectChange}
onClick={() => openSelect(secondaryAxModifierSelect)} onClick={() => openSelect(secondaryAxModifierSelect)}
triggerClass="modal"
ref={secondaryAxModifierSelect} ref={secondaryAxModifierSelect}
> >
{generateOptions(1)} {generateOptions(1)}

View file

@ -7,6 +7,14 @@
display: block; display: block;
padding: $unit-2x; padding: $unit-2x;
width: 100%; width: 100%;
&.Contained {
background-color: var(--input-bound-bg);
&:hover {
background-color: var(--input-bound-bg-hover);
}
}
} }
.InputError { .InputError {

View file

@ -7,15 +7,26 @@ interface Props
React.InputHTMLAttributes<HTMLInputElement>, React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement HTMLInputElement
> { > {
contained?: boolean
error?: string error?: string
label?: string label?: string
} }
const defaultProps = {
contained: false,
}
const Input = React.forwardRef<HTMLInputElement, Props>(function input( const Input = React.forwardRef<HTMLInputElement, Props>(function input(
props: Props, { contained, error, label, ...props },
forwardedRef forwardedRef
) { ) {
const classes = classNames({ Input: true }, props.className) const classes = classNames(
{
Input: true,
Contained: contained,
},
props.className
)
return ( return (
<label className="Label" htmlFor={props.name}> <label className="Label" htmlFor={props.name}>
@ -27,12 +38,12 @@ const Input = React.forwardRef<HTMLInputElement, Props>(function input(
ref={forwardedRef} ref={forwardedRef}
formNoValidate formNoValidate
/> />
{props.label} {label}
{props.error && props.error.length > 0 && ( {error && error.length > 0 && <p className="InputError">{error}</p>}
<p className="InputError">{props.error}</p>
)}
</label> </label>
) )
}) })
Input.defaultProps = defaultProps
export default Input export default Input

View file

@ -6,9 +6,22 @@
display: flex; display: flex;
padding: $unit-2x $unit-2x; padding: $unit-2x $unit-2x;
&.modal {
background-color: var(--select-modal-bg);
&:hover {
background-color: var(--select-modal-bg-hover);
}
}
&:hover { &:hover {
background-color: var(--input-bg-hover); background-color: var(--input-bg-hover);
color: var(--text-primary);
cursor: pointer; cursor: pointer;
&[data-placeholder] > span:not(.SelectIcon) {
color: var(--text-primary);
}
} }
&[data-placeholder] > span:not(.SelectIcon) { &[data-placeholder] > span:not(.SelectIcon) {

View file

@ -11,25 +11,27 @@ interface Props {
open: boolean open: boolean
defaultValue?: string | number defaultValue?: string | number
placeholder?: string placeholder?: string
trigger?: React.ReactNode name?: string
children?: React.ReactNode children?: React.ReactNode
onClick?: () => void onClick?: () => void
onChange?: (value: string) => void onChange?: (value: string) => void
triggerClass?: string triggerClass?: string
} }
const Select = React.forwardRef<HTMLSelectElement, Props>(function useFieldSet( const Select = React.forwardRef<HTMLButtonElement, Props>(function useFieldSet(
props, props,
ref ref
) { ) {
return ( return (
<RadixSelect.Root <RadixSelect.Root
defaultValue={props.defaultValue as string} defaultValue={props.defaultValue as string}
name={props.name}
onValueChange={props.onChange} onValueChange={props.onChange}
> >
<RadixSelect.Trigger <RadixSelect.Trigger
className={classNames('SelectTrigger', props.triggerClass)} className={classNames('SelectTrigger', props.triggerClass)}
placeholder={props.placeholder} placeholder={props.placeholder}
ref={ref}
> >
<RadixSelect.Value placeholder={props.placeholder} /> <RadixSelect.Value placeholder={props.placeholder} />
<RadixSelect.Icon className="SelectIcon"> <RadixSelect.Icon className="SelectIcon">

View file

@ -1,7 +1,7 @@
.SelectItem { .SelectItem {
border-radius: $item-corner; border-radius: $item-corner;
border: 2px solid transparent; border: 2px solid transparent;
color: var(--text-secondary); color: var(--text-tertiary);
font-size: $font-regular; font-size: $font-regular;
padding: ($unit * 1.5) $unit-2x; padding: ($unit * 1.5) $unit-2x;

View file

@ -1,5 +1,8 @@
import React, { useEffect, useState } from 'react' 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 api from '~utils/api'
import './index.scss' import './index.scss'
@ -9,14 +12,13 @@ interface Props {
currentValue?: WeaponKey currentValue?: WeaponKey
series: number series: number
slot: number slot: number
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void onChange?: (value: string, slot: number) => void
onBlur?: (event: React.ChangeEvent<HTMLSelectElement>) => void
} }
const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>( const WeaponKeySelect = React.forwardRef<HTMLButtonElement, Props>(
function useFieldSet(props, ref) { function useFieldSet(props, ref) {
const [open, setOpen] = useState(false)
const [keys, setKeys] = useState<WeaponKey[][]>([]) const [keys, setKeys] = useState<WeaponKey[][]>([])
const [currentKey, setCurrentKey] = useState('')
const pendulumNames = [ const pendulumNames = [
{ en: 'Pendulum', jp: '' }, { en: 'Pendulum', jp: '' },
@ -31,10 +33,6 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
{ en: 'Gate of Omnipotence', jp: '' }, { en: 'Gate of Omnipotence', jp: '' },
] ]
useEffect(() => {
if (props.currentValue) setCurrentKey(props.currentValue.id)
}, [props.currentValue])
useEffect(() => { useEffect(() => {
const filterParams = { const filterParams = {
params: { params: {
@ -66,6 +64,10 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
fetchWeaponKeys() fetchWeaponKeys()
}, [props.series, props.slot]) }, [props.series, props.slot])
function openSelect() {
setOpen(!open)
}
function weaponKeyGroup(index: number) { function weaponKeyGroup(index: number) {
;['α', 'β', 'γ', 'Δ'].sort((a, b) => a.localeCompare(b, 'el')) ;['α', 'β', 'γ', 'Δ'].sort((a, b) => a.localeCompare(b, 'el'))
@ -78,9 +80,9 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
keys[index].length > 0 && keys[index].length > 0 &&
keys[index].sort(sortByOrder).map((item, i) => { keys[index].sort(sortByOrder).map((item, i) => {
return ( return (
<option key={i} value={item.id}> <SelectItem key={i} value={item.id}>
{item.name.en} {item.name.en}
</option> </SelectItem>
) )
}) })
@ -93,21 +95,20 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
else if (props.series == 22) name = emblemNames[index] else if (props.series == 22) name = emblemNames[index]
return ( return (
<optgroup <SelectGroup
key={index} key={index}
label={ label={
props.series == 17 && props.slot == 2 ? name.en : `${name.en}s` props.series == 17 && props.slot == 2 ? name.en : `${name.en}s`
} }
separator={false}
> >
{options} {options}
</optgroup> </SelectGroup>
) )
} }
function handleChange(event: React.ChangeEvent<HTMLSelectElement>) { function handleChange(value: string) {
if (props.onChange) props.onChange(event) if (props.onChange) props.onChange(value, props.slot)
setCurrentKey(event.currentTarget.value)
} }
const emptyOption = () => { const emptyOption = () => {
@ -121,22 +122,24 @@ const WeaponKeyDropdown = React.forwardRef<HTMLSelectElement, Props>(
} }
return ( return (
<select <Select
key={`weapon-key-${props.slot}`} key={`weapon-key-${props.slot}`}
value={currentKey} defaultValue={props.currentValue ? props.currentValue.id : 'no-key'}
onBlur={props.onBlur} open={open}
onChange={handleChange} onChange={handleChange}
onClick={openSelect}
ref={ref} ref={ref}
triggerClass="modal"
> >
<option key="-1" value="-1"> <SelectItem key="no-key" value="no-key">
{emptyOption()} {emptyOption()}
</option> </SelectItem>
{Array.from(Array(keys?.length)).map((x, i) => { {Array.from(Array(keys?.length)).map((x, i) => {
return weaponKeyGroup(i) return weaponKeyGroup(i)
})} })}
</select> </Select>
) )
} }
) )
export default WeaponKeyDropdown export default WeaponKeySelect

View file

@ -1,4 +1,4 @@
import React, { useState } from 'react' import React, { useEffect, useState } from 'react'
import { getCookie } from 'cookies-next' import { getCookie } from 'cookies-next'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
@ -8,7 +8,7 @@ import * as Dialog from '@radix-ui/react-dialog'
import AXSelect from '~components/AxSelect' import AXSelect from '~components/AxSelect'
import ElementToggle from '~components/ElementToggle' import ElementToggle from '~components/ElementToggle'
import WeaponKeyDropdown from '~components/WeaponKeyDropdown' import WeaponKeySelect from '~components/WeaponKeySelect'
import Button from '~components/Button' import Button from '~components/Button'
import api from '~utils/api' import api from '~utils/api'
@ -50,21 +50,38 @@ const WeaponModal = (props: Props) => {
? { Authorization: `Bearer ${accountData.token}` } ? { Authorization: `Bearer ${accountData.token}` }
: {} : {}
// Refs
const weaponKey1Select = React.createRef<HTMLSelectElement>()
const weaponKey2Select = React.createRef<HTMLSelectElement>()
const weaponKey3Select = React.createRef<HTMLSelectElement>()
// State // State
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [formValid, setFormValid] = useState(false) const [formValid, setFormValid] = useState(false)
const [element, setElement] = useState(-1) const [element, setElement] = useState(-1)
const [primaryAxModifier, setPrimaryAxModifier] = useState(-1) const [primaryAxModifier, setPrimaryAxModifier] = useState(-1)
const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1) const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1)
const [primaryAxValue, setPrimaryAxValue] = useState(0.0) const [primaryAxValue, setPrimaryAxValue] = useState(0.0)
const [secondaryAxValue, setSecondaryAxValue] = 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) {
if (props.gridWeapon.weapon_keys[0]) {
setWeaponKey1(props.gridWeapon.weapon_keys[0])
}
if (props.gridWeapon.weapon_keys[1])
setWeaponKey2(props.gridWeapon.weapon_keys[1])
if (props.gridWeapon.weapon_keys[2])
setWeaponKey3(props.gridWeapon.weapon_keys[2])
}
}, [props])
function receiveAxValues( function receiveAxValues(
primaryAxModifier: number, primaryAxModifier: number,
primaryAxValue: number, primaryAxValue: number,
@ -91,14 +108,15 @@ const WeaponModal = (props: Props) => {
if (props.gridWeapon.object.element == 0) object.weapon.element = element if (props.gridWeapon.object.element == 0) object.weapon.element = element
if ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) if ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) {
object.weapon.weapon_key1_id = weaponKey1Select.current?.value object.weapon.weapon_key1_id = weaponKey1Id
}
if ([2, 3, 17].includes(props.gridWeapon.object.series)) if ([2, 3, 17].includes(props.gridWeapon.object.series))
object.weapon.weapon_key2_id = weaponKey2Select.current?.value object.weapon.weapon_key2_id = weaponKey2Id
if (props.gridWeapon.object.series == 17) if (props.gridWeapon.object.series == 17)
object.weapon.weapon_key3_id = weaponKey3Select.current?.value object.weapon.weapon_key3_id = weaponKey3Id
if (props.gridWeapon.object.ax > 0) { if (props.gridWeapon.object.ax > 0) {
object.weapon.ax_modifier1 = primaryAxModifier object.weapon.ax_modifier1 = primaryAxModifier
@ -131,12 +149,18 @@ const WeaponModal = (props: Props) => {
console.error(error) 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 = () => { const elementSelect = () => {
return ( return (
<section> <section>
<h3>{t('modals.weapon.subtitles.element')}</h3> <h3>{t('modals.weapon.subtitles.element')}</h3>
<ElementToggle <ElementToggle
currentElement={props.gridWeapon.element} currentElement={element}
sendValue={receiveElementValue} sendValue={receiveElementValue}
/> />
</section> </section>
@ -148,45 +172,33 @@ const WeaponModal = (props: Props) => {
<section> <section>
<h3>{t('modals.weapon.subtitles.weapon_keys')}</h3> <h3>{t('modals.weapon.subtitles.weapon_keys')}</h3>
{[2, 3, 17, 22].includes(props.gridWeapon.object.series) ? ( {[2, 3, 17, 22].includes(props.gridWeapon.object.series) ? (
<WeaponKeyDropdown <WeaponKeySelect
currentValue={ currentValue={weaponKey1 != null ? weaponKey1 : undefined}
props.gridWeapon.weapon_keys
? props.gridWeapon.weapon_keys[0]
: undefined
}
series={props.gridWeapon.object.series} series={props.gridWeapon.object.series}
slot={0} slot={0}
ref={weaponKey1Select} onChange={receiveWeaponKey}
/> />
) : ( ) : (
'' ''
)} )}
{[2, 3, 17].includes(props.gridWeapon.object.series) ? ( {[2, 3, 17].includes(props.gridWeapon.object.series) ? (
<WeaponKeyDropdown <WeaponKeySelect
currentValue={ currentValue={weaponKey2 != null ? weaponKey2 : undefined}
props.gridWeapon.weapon_keys
? props.gridWeapon.weapon_keys[1]
: undefined
}
series={props.gridWeapon.object.series} series={props.gridWeapon.object.series}
slot={1} slot={1}
ref={weaponKey2Select} onChange={receiveWeaponKey}
/> />
) : ( ) : (
'' ''
)} )}
{props.gridWeapon.object.series == 17 ? ( {props.gridWeapon.object.series == 17 ? (
<WeaponKeyDropdown <WeaponKeySelect
currentValue={ currentValue={weaponKey3 != null ? weaponKey3 : undefined}
props.gridWeapon.weapon_keys
? props.gridWeapon.weapon_keys[2]
: undefined
}
series={props.gridWeapon.object.series} series={props.gridWeapon.object.series}
slot={2} slot={2}
ref={weaponKey3Select} onChange={receiveWeaponKey}
/> />
) : ( ) : (
'' ''
@ -245,6 +257,7 @@ const WeaponModal = (props: Props) => {
: ''} : ''}
{props.gridWeapon.object.ax > 0 ? axSelect() : ''} {props.gridWeapon.object.ax > 0 ? axSelect() : ''}
<Button <Button
contained={true}
onClick={updateWeapon} onClick={updateWeapon}
disabled={props.gridWeapon.object.ax > 0 && !formValid} disabled={props.gridWeapon.object.ax > 0 && !formValid}
text={t('modals.weapon.buttons.confirm')} text={t('modals.weapon.buttons.confirm')}