(Hotfix) Popover and hovercard fixes (#379)
* Fix job accessory popover, so shields and manatura can be selected again * Don't show AX skill section in weapon hovercard if no AX skill is set * Center uncap indicator under item image and fix hovercard header layout * Fix a bug that prevented all ring bonuses from displaying in hovercard * Fix transcendence_step being set to 0 when updating a character's masteries * Fix weapon modal so you can set AX skills on weapons with rupee or exp gain * Ensure job accessory and transcendence popovers open/close properly
This commit is contained in:
parent
14ad468737
commit
b50ea1fa31
28 changed files with 430 additions and 252 deletions
|
|
@ -41,17 +41,19 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: $unit * 2;
|
justify-content: space-between;
|
||||||
|
gap: $unit-2x;
|
||||||
|
|
||||||
.icons {
|
.icons {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-grow: 1;
|
flex-grow: 0;
|
||||||
|
gap: $unit-half;
|
||||||
|
|
||||||
|
.proficiencies {
|
||||||
|
display: flex;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.UncapIndicator {
|
|
||||||
min-width: 100px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import UncapIndicator from '~components/uncap/UncapIndicator'
|
||||||
import WeaponLabelIcon from '~components/weapon/WeaponLabelIcon'
|
import WeaponLabelIcon from '~components/weapon/WeaponLabelIcon'
|
||||||
|
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
gridObject: GridCharacter | GridSummon | GridWeapon
|
gridObject: GridCharacter | GridSummon | GridWeapon
|
||||||
|
|
@ -107,6 +108,61 @@ const HovercardHeader = ({ gridObject, object, type, ...props }: Props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const summonProficiency = (
|
||||||
|
<div className={styles.icons}>
|
||||||
|
<WeaponLabelIcon labelType={Element[object.element]} size="small" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const weaponProficiency = (
|
||||||
|
<div className={styles.icons}>
|
||||||
|
<WeaponLabelIcon labelType={Element[object.element]} size="small" />
|
||||||
|
{'proficiency' in object && !Array.isArray(object.proficiency) && (
|
||||||
|
<WeaponLabelIcon
|
||||||
|
labelType={Proficiency[object.proficiency]}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const characterProficiency = (
|
||||||
|
<div
|
||||||
|
className={classNames({
|
||||||
|
[styles.icons]: true,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<WeaponLabelIcon labelType={Element[object.element]} size="small" />
|
||||||
|
|
||||||
|
{'proficiency' in object && Array.isArray(object.proficiency) && (
|
||||||
|
<WeaponLabelIcon
|
||||||
|
labelType={Proficiency[object.proficiency[0]]}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{'proficiency' in object &&
|
||||||
|
Array.isArray(object.proficiency) &&
|
||||||
|
object.proficiency.length > 1 && (
|
||||||
|
<WeaponLabelIcon
|
||||||
|
labelType={Proficiency[object.proficiency[1]]}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
function proficiency() {
|
||||||
|
switch (type) {
|
||||||
|
case 'character':
|
||||||
|
return characterProficiency
|
||||||
|
case 'summon':
|
||||||
|
return summonProficiency
|
||||||
|
case 'weapon':
|
||||||
|
return weaponProficiency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={styles.root}>
|
<header className={styles.root}>
|
||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
|
|
@ -117,21 +173,9 @@ const HovercardHeader = ({ gridObject, object, type, ...props }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.subInfo}>
|
<div className={styles.subInfo}>
|
||||||
<div className={styles.icons}>
|
{proficiency()}
|
||||||
<WeaponLabelIcon labelType={Element[object.element]} />
|
|
||||||
{'proficiency' in object && Array.isArray(object.proficiency) && (
|
|
||||||
<WeaponLabelIcon labelType={Proficiency[object.proficiency[0]]} />
|
|
||||||
)}
|
|
||||||
{'proficiency' in object && !Array.isArray(object.proficiency) && (
|
|
||||||
<WeaponLabelIcon labelType={Proficiency[object.proficiency]} />
|
|
||||||
)}
|
|
||||||
{'proficiency' in object &&
|
|
||||||
Array.isArray(object.proficiency) &&
|
|
||||||
object.proficiency.length > 1 && (
|
|
||||||
<WeaponLabelIcon labelType={Proficiency[object.proficiency[1]]} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<UncapIndicator
|
<UncapIndicator
|
||||||
|
className="hovercard"
|
||||||
type={type}
|
type={type}
|
||||||
ulb={object.uncap.ulb || false}
|
ulb={object.uncap.ulb || false}
|
||||||
flb={object.uncap.flb || false}
|
flb={object.uncap.flb || false}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
.version {
|
.version {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-2x;
|
|
||||||
|
|
||||||
&.content {
|
&.content {
|
||||||
.header h3 {
|
.header h3 {
|
||||||
|
|
@ -12,6 +11,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bugs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
list-style-type: disc;
|
||||||
|
gap: $unit-half;
|
||||||
|
padding-left: $unit-2x;
|
||||||
|
}
|
||||||
|
|
||||||
.contents {
|
.contents {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -121,14 +128,6 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Bugs {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
list-style-type: disc;
|
|
||||||
gap: $unit-half;
|
|
||||||
padding-left: $unit-2x;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ const UpdatesPage = () => {
|
||||||
'202302U2': {
|
'202302U2': {
|
||||||
updates: 1,
|
updates: 1,
|
||||||
},
|
},
|
||||||
|
'1.2.1': {
|
||||||
|
bugs: 5,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function image(
|
function image(
|
||||||
|
|
@ -75,6 +78,20 @@ const UpdatesPage = () => {
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
<h1>{common('about.segmented_control.updates')}</h1>
|
<h1>{common('about.segmented_control.updates')}</h1>
|
||||||
|
<section className={styles.version} data-version="1.2.1">
|
||||||
|
<div className={styles.header}>
|
||||||
|
<h3>1.2.1</h3>
|
||||||
|
<time>2023/09/01</time>
|
||||||
|
</div>
|
||||||
|
<h2>Bug fixes</h2>
|
||||||
|
<ul className={styles.bugs}>
|
||||||
|
{[...Array(versionUpdates['1.2.1'].bugs)].map((e, i) => (
|
||||||
|
<li key={`1.2.1-bugfix-${i}`}>
|
||||||
|
{updates(`versions.1.2.1.bugs.${i}`)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
<ContentUpdate
|
<ContentUpdate
|
||||||
version="2023-08L"
|
version="2023-08L"
|
||||||
dateString="2023/08/31"
|
dateString="2023/08/31"
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,8 @@ const CharacterHovercard = (props: Props) => {
|
||||||
{[...Array(4)].map((e, i) => {
|
{[...Array(4)].map((e, i) => {
|
||||||
const ringIndex = i + 1
|
const ringIndex = i + 1
|
||||||
const ringStat: ExtendedMastery =
|
const ringStat: ExtendedMastery =
|
||||||
props.gridCharacter.over_mastery[i]
|
props.gridCharacter.over_mastery[ringIndex]
|
||||||
|
|
||||||
if (ringStat && ringStat.modifier && ringStat.modifier > 0) {
|
if (ringStat && ringStat.modifier && ringStat.modifier > 0) {
|
||||||
if (ringIndex === 1 || ringIndex === 2) {
|
if (ringIndex === 1 || ringIndex === 2) {
|
||||||
return masteryElement(overMastery.a, ringStat)
|
return masteryElement(overMastery.a, ringStat)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,9 @@ const CharacterModal = ({
|
||||||
const [earring, setEarring] = useState<ExtendedMastery>(emptyExtendedMastery)
|
const [earring, setEarring] = useState<ExtendedMastery>(emptyExtendedMastery)
|
||||||
const [awakening, setAwakening] = useState<Awakening>()
|
const [awakening, setAwakening] = useState<Awakening>()
|
||||||
const [awakeningLevel, setAwakeningLevel] = useState(1)
|
const [awakeningLevel, setAwakeningLevel] = useState(1)
|
||||||
const [transcendenceStep, setTranscendenceStep] = useState(0)
|
const [transcendenceStep, setTranscendenceStep] = useState(
|
||||||
|
gridCharacter.transcendence_step
|
||||||
|
)
|
||||||
|
|
||||||
// Refs
|
// Refs
|
||||||
const headerRef = React.createRef<HTMLDivElement>()
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-2x;
|
gap: $unit-2x;
|
||||||
min-width: 20vw;
|
min-width: 20vw;
|
||||||
max-width: 32vw;
|
max-width: 40vw;
|
||||||
padding: $unit * 4;
|
padding: $unit * 4;
|
||||||
|
|
||||||
@include breakpoint(tablet) {
|
@include breakpoint(tablet) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,93 @@
|
||||||
|
.popover {
|
||||||
|
animation: scaleIn $duration-zoom ease-out;
|
||||||
|
background: var(--dialog-bg);
|
||||||
|
border-radius: $card-corner;
|
||||||
|
border: 0.5px solid rgba(0, 0, 0, 0.18);
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.24);
|
||||||
|
outline: none;
|
||||||
|
padding: $unit;
|
||||||
|
transform-origin: var(--radix-popover-content-transform-origin);
|
||||||
|
width: var(--radix-popover-trigger-width);
|
||||||
|
z-index: 5;
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.raid {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.flush {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.jobAccessory {
|
||||||
|
padding: $unit-2x;
|
||||||
|
min-width: 40vw;
|
||||||
|
max-width: 40vw;
|
||||||
|
max-height: 40vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: none;
|
||||||
|
margin-left: $unit-2x;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: $font-regular;
|
||||||
|
font-weight: $medium;
|
||||||
|
margin: 0 0 $unit $unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.readOnly {
|
||||||
|
min-width: inherit;
|
||||||
|
max-width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include breakpoint(tablet) {
|
||||||
|
width: initial;
|
||||||
|
max-width: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
width: initial;
|
||||||
|
max-width: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.transcendence {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $unit-half;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: $unit-10x;
|
||||||
|
height: $unit-10x;
|
||||||
|
|
||||||
|
animation: scaleIn $duration-zoom ease-out;
|
||||||
|
background: var(--dialog-bg);
|
||||||
|
border-radius: $card-corner;
|
||||||
|
border: 0.5px solid rgba(0, 0, 0, 0.18);
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.24);
|
||||||
|
outline: none;
|
||||||
|
padding: $unit;
|
||||||
|
transform-origin: var(--radix-popover-content-transform-origin);
|
||||||
|
z-index: 32;
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
opacity: 1;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: $font-small;
|
||||||
|
font-weight: $medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending {
|
||||||
|
color: $yellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
fill: var(--dialog-bg);
|
fill: var(--dialog-bg);
|
||||||
filter: drop-shadow(0px 1px 1px rgb(0 0 0 / 0.18));
|
filter: drop-shadow(0px 1px 1px rgb(0 0 0 / 0.18));
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,13 @@ export const PopoverContent = React.forwardRef<HTMLDivElement, Props>(
|
||||||
{ children, ...props }: PropsWithChildren<Props>,
|
{ children, ...props }: PropsWithChildren<Props>,
|
||||||
forwardedRef
|
forwardedRef
|
||||||
) {
|
) {
|
||||||
const classes = classnames(props.className, {
|
const classes = classnames(
|
||||||
Popover: true,
|
{
|
||||||
})
|
[styles.popover]: true,
|
||||||
|
},
|
||||||
|
props.className?.split(' ').map((a) => styles[a])
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopoverPrimitive.Portal>
|
<PopoverPrimitive.Portal>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.JobAccessoryItem {
|
.item {
|
||||||
background: none;
|
background: none;
|
||||||
border-radius: $input-corner;
|
border-radius: $input-corner;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const JobAccessoryItem = ({ accessory, selected }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadioGroup.Item
|
<RadioGroup.Item
|
||||||
className="JobAccessoryItem"
|
className={styles.item}
|
||||||
data-state={selected ? 'checked' : 'unchecked'}
|
data-state={selected ? 'checked' : 'unchecked'}
|
||||||
value={accessory.id}
|
value={accessory.id}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,4 @@
|
||||||
.JobAccessory.Popover {
|
.accessories {
|
||||||
padding: $unit-2x;
|
|
||||||
min-width: 40vw;
|
|
||||||
max-width: 40vw;
|
|
||||||
max-height: 40vh;
|
|
||||||
overflow-y: scroll;
|
|
||||||
margin-left: $unit-2x;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: $font-regular;
|
|
||||||
font-weight: $medium;
|
|
||||||
margin: 0 0 $unit $unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ReadOnly {
|
|
||||||
min-width: inherit;
|
|
||||||
max-width: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include breakpoint(tablet) {
|
|
||||||
width: initial;
|
|
||||||
max-width: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
|
||||||
width: initial;
|
|
||||||
max-width: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Accessories {
|
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||||
|
|
@ -36,9 +7,9 @@
|
||||||
grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
|
||||||
gap: 0;
|
gap: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.EquippedAccessory {
|
.equippedAccessory {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-2x;
|
gap: $unit-2x;
|
||||||
|
|
@ -47,7 +18,7 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Accessory {
|
.accessory {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
|
|
@ -63,5 +34,4 @@
|
||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ const JobAccessoryPopover = ({
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
JobAccessory: true,
|
jobAccessory: true,
|
||||||
ReadOnly: !editable,
|
readOnly: !editable,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
|
|
@ -91,7 +91,7 @@ const JobAccessoryPopover = ({
|
||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
<RadioGroup.Root
|
<RadioGroup.Root
|
||||||
className="Accessories"
|
className={styles.accessories}
|
||||||
onValueChange={handleAccessorySelected}
|
onValueChange={handleAccessorySelected}
|
||||||
>
|
>
|
||||||
{accessories.map((accessory) => (
|
{accessories.map((accessory) => (
|
||||||
|
|
@ -110,14 +110,14 @@ const JobAccessoryPopover = ({
|
||||||
)
|
)
|
||||||
|
|
||||||
const readOnly = currentAccessory ? (
|
const readOnly = currentAccessory ? (
|
||||||
<div className="EquippedAccessory">
|
<div className={styles.equippedAccessory}>
|
||||||
<h3>
|
<h3>
|
||||||
{t('equipped')}{' '}
|
{t('equipped')}{' '}
|
||||||
{job.accessory_type === 1
|
{job.accessory_type === 1
|
||||||
? `${t('accessories.paladin')}s`
|
? `${t('accessories.paladin')}s`
|
||||||
: t('accessories.manadiver')}
|
: t('accessories.manadiver')}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="Accessory">
|
<div className={styles.accessory}>
|
||||||
<img
|
<img
|
||||||
alt={currentAccessory.name[locale]}
|
alt={currentAccessory.name[locale]}
|
||||||
src={`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/accessory-grid/${currentAccessory.granblue_id}.jpg`}
|
src={`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/accessory-grid/${currentAccessory.granblue_id}.jpg`}
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ const JobImage = ({
|
||||||
editable={editable}
|
editable={editable}
|
||||||
open={open}
|
open={open}
|
||||||
job={job}
|
job={job}
|
||||||
|
key={`accessory-${open}`}
|
||||||
onAccessorySelected={onAccessorySelected}
|
onAccessorySelected={onAccessorySelected}
|
||||||
onOpenChange={handlePopoverOpenChanged}
|
onOpenChange={handlePopoverOpenChanged}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,12 @@ const AXSelect = (props: Props) => {
|
||||||
// States
|
// States
|
||||||
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(
|
||||||
const [secondaryAxValue, setSecondaryAxValue] = useState(0.0)
|
props.currentSkills ? props.currentSkills[0].strength : 0.0
|
||||||
|
)
|
||||||
|
const [secondaryAxValue, setSecondaryAxValue] = useState(
|
||||||
|
props.currentSkills ? props.currentSkills[1].strength : 0.0
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setupAx1()
|
setupAx1()
|
||||||
|
|
@ -146,7 +150,10 @@ const AXSelect = (props: Props) => {
|
||||||
// Classes
|
// Classes
|
||||||
const secondarySetClasses = classNames({
|
const secondarySetClasses = classNames({
|
||||||
[styles.set]: true,
|
[styles.set]: true,
|
||||||
[styles.hidden]: primaryAxModifier < 0,
|
[styles.hidden]:
|
||||||
|
primaryAxModifier < 0 ||
|
||||||
|
primaryAxModifier === 18 ||
|
||||||
|
primaryAxModifier === 19,
|
||||||
})
|
})
|
||||||
|
|
||||||
function setupAx1() {
|
function setupAx1() {
|
||||||
|
|
@ -270,9 +277,12 @@ const AXSelect = (props: Props) => {
|
||||||
secondaryAxModifierSelect.current &&
|
secondaryAxModifierSelect.current &&
|
||||||
secondaryAxValueInput.current
|
secondaryAxValueInput.current
|
||||||
) {
|
) {
|
||||||
setupInput(ax[props.axType - 1][value], primaryAxValueInput.current)
|
setupInput(
|
||||||
|
ax[props.axType - 1].find((ax) => ax.id === value),
|
||||||
|
primaryAxValueInput.current
|
||||||
|
)
|
||||||
|
|
||||||
setPrimaryAxValue(0)
|
setPrimaryAxValue(0)
|
||||||
primaryAxValueInput.current.value = ''
|
|
||||||
|
|
||||||
// Reset the secondary AX modifier, reset the AX value and hide the input
|
// Reset the secondary AX modifier, reset the AX value and hide the input
|
||||||
setSecondaryAxModifier(-1)
|
setSecondaryAxModifier(-1)
|
||||||
|
|
@ -302,7 +312,7 @@ const AXSelect = (props: Props) => {
|
||||||
const value = parseFloat(event.target.value)
|
const value = parseFloat(event.target.value)
|
||||||
let newErrors = { ...errors }
|
let newErrors = { ...errors }
|
||||||
|
|
||||||
if (primaryAxValueInput.current == event.target) {
|
if (primaryAxValueInput.current === event.target) {
|
||||||
if (handlePrimaryErrors(value)) setPrimaryAxValue(value)
|
if (handlePrimaryErrors(value)) setPrimaryAxValue(value)
|
||||||
} else {
|
} else {
|
||||||
if (handleSecondaryErrors(value)) setSecondaryAxValue(value)
|
if (handleSecondaryErrors(value)) setSecondaryAxValue(value)
|
||||||
|
|
@ -310,16 +320,18 @@ const AXSelect = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePrimaryErrors(value: number) {
|
function handlePrimaryErrors(value: number) {
|
||||||
const primaryAxSkill = ax[props.axType - 1][primaryAxModifier]
|
const primaryAxSkill = ax[props.axType - 1].find(
|
||||||
|
(ax) => ax.id === primaryAxModifier
|
||||||
|
)
|
||||||
let newErrors = { ...errors }
|
let newErrors = { ...errors }
|
||||||
|
|
||||||
if (value < primaryAxSkill.minValue) {
|
if (primaryAxSkill && value < primaryAxSkill.minValue) {
|
||||||
newErrors.axValue1 = t('ax.errors.value_too_low', {
|
newErrors.axValue1 = t('ax.errors.value_too_low', {
|
||||||
name: primaryAxSkill.name[locale],
|
name: primaryAxSkill.name[locale],
|
||||||
minValue: primaryAxSkill.minValue,
|
minValue: primaryAxSkill.minValue,
|
||||||
suffix: primaryAxSkill.suffix ? primaryAxSkill.suffix : '',
|
suffix: primaryAxSkill.suffix ? primaryAxSkill.suffix : '',
|
||||||
})
|
})
|
||||||
} else if (value > primaryAxSkill.maxValue) {
|
} else if (primaryAxSkill && value > primaryAxSkill.maxValue) {
|
||||||
newErrors.axValue1 = t('ax.errors.value_too_high', {
|
newErrors.axValue1 = t('ax.errors.value_too_high', {
|
||||||
name: primaryAxSkill.name[locale],
|
name: primaryAxSkill.name[locale],
|
||||||
maxValue: primaryAxSkill.maxValue,
|
maxValue: primaryAxSkill.maxValue,
|
||||||
|
|
@ -327,7 +339,7 @@ const AXSelect = (props: Props) => {
|
||||||
})
|
})
|
||||||
} else if (!value || value <= 0) {
|
} else if (!value || value <= 0) {
|
||||||
newErrors.axValue1 = t('ax.errors.value_empty', {
|
newErrors.axValue1 = t('ax.errors.value_empty', {
|
||||||
name: primaryAxSkill.name[locale],
|
name: primaryAxSkill?.name[locale],
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
newErrors.axValue1 = ''
|
newErrors.axValue1 = ''
|
||||||
|
|
@ -380,6 +392,7 @@ const AXSelect = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupInput(ax: ItemSkill | undefined, element: HTMLInputElement) {
|
function setupInput(ax: ItemSkill | undefined, element: HTMLInputElement) {
|
||||||
|
console.log(ax)
|
||||||
if (ax) {
|
if (ax) {
|
||||||
const rangeString = `${ax.minValue}~${ax.maxValue}${ax.suffix || ''}`
|
const rangeString = `${ax.minValue}~${ax.maxValue}${ax.suffix || ''}`
|
||||||
|
|
||||||
|
|
@ -431,11 +444,7 @@ const AXSelect = (props: Props) => {
|
||||||
hidden: primaryAxModifier < 0,
|
hidden: primaryAxModifier < 0,
|
||||||
})}
|
})}
|
||||||
bound={true}
|
bound={true}
|
||||||
value={
|
value={primaryAxValue}
|
||||||
props.currentSkills && props.currentSkills[0]
|
|
||||||
? props.currentSkills[0].strength
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
type="number"
|
type="number"
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
ref={primaryAxValueInput}
|
ref={primaryAxValueInput}
|
||||||
|
|
@ -469,11 +478,7 @@ const AXSelect = (props: Props) => {
|
||||||
hidden: secondaryAxModifier < 0,
|
hidden: secondaryAxModifier < 0,
|
||||||
})}
|
})}
|
||||||
bound={true}
|
bound={true}
|
||||||
value={
|
value={secondaryAxValue}
|
||||||
props.currentSkills && props.currentSkills[1]
|
|
||||||
? props.currentSkills[1].strength
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
type="number"
|
type="number"
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
ref={secondaryAxValueInput}
|
ref={secondaryAxValueInput}
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,3 @@
|
||||||
.transcendence {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $unit-half;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: $unit-10x;
|
|
||||||
height: $unit-10x;
|
|
||||||
|
|
||||||
animation: scaleIn $duration-zoom ease-out;
|
|
||||||
background: var(--dialog-bg);
|
|
||||||
border-radius: $card-corner;
|
|
||||||
border: 0.5px solid rgba(0, 0, 0, 0.18);
|
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.24);
|
|
||||||
outline: none;
|
|
||||||
padding: $unit;
|
|
||||||
transform-origin: var(--radix-popover-content-transform-origin);
|
|
||||||
z-index: 32;
|
|
||||||
|
|
||||||
&.open {
|
|
||||||
opacity: 1;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: $font-small;
|
|
||||||
font-weight: $medium;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pending {
|
|
||||||
color: $yellow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes scaleIn {
|
@keyframes scaleIn {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ interface Props
|
||||||
HTMLDivElement
|
HTMLDivElement
|
||||||
> {
|
> {
|
||||||
type: 'character' | 'summon'
|
type: 'character' | 'summon'
|
||||||
|
starRef: React.RefObject<HTMLDivElement>
|
||||||
open: boolean
|
open: boolean
|
||||||
stage: number
|
stage: number
|
||||||
onOpenChange?: (open: boolean) => void
|
onOpenChange?: (open: boolean) => void
|
||||||
|
|
@ -24,8 +25,9 @@ interface Props
|
||||||
}
|
}
|
||||||
|
|
||||||
const TranscendencePopover = ({
|
const TranscendencePopover = ({
|
||||||
children,
|
|
||||||
open: popoverOpen,
|
open: popoverOpen,
|
||||||
|
starRef,
|
||||||
|
children,
|
||||||
type,
|
type,
|
||||||
stage,
|
stage,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
|
|
@ -45,8 +47,8 @@ const TranscendencePopover = ({
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) popoverRef.current?.focus()
|
setOpen(popoverOpen)
|
||||||
}, [])
|
}, [popoverOpen])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (stage) setCurrentStage(stage)
|
if (stage) setCurrentStage(stage)
|
||||||
|
|
@ -57,10 +59,6 @@ const TranscendencePopover = ({
|
||||||
else if (type === 'summon') setBaseLevel(200)
|
else if (type === 'summon') setBaseLevel(200)
|
||||||
}, [type])
|
}, [type])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOpen(popoverOpen)
|
|
||||||
}, [popoverOpen])
|
|
||||||
|
|
||||||
function handleFragmentClicked(newStage: number) {
|
function handleFragmentClicked(newStage: number) {
|
||||||
setCurrentStage(newStage)
|
setCurrentStage(newStage)
|
||||||
if (sendValue) sendValue(newStage)
|
if (sendValue) sendValue(newStage)
|
||||||
|
|
@ -70,13 +68,33 @@ const TranscendencePopover = ({
|
||||||
setCurrentStage(newStage)
|
setCurrentStage(newStage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closePopover() {
|
||||||
|
setOpen(false)
|
||||||
|
if (onOpenChange) onOpenChange(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePointerDownOutside(
|
||||||
|
event: CustomEvent<{ originalEvent: PointerEvent }>
|
||||||
|
) {
|
||||||
|
const target = event.detail.originalEvent.target as Element
|
||||||
|
if (
|
||||||
|
target &&
|
||||||
|
starRef.current &&
|
||||||
|
target.closest('.TranscendenceStar') !== starRef.current
|
||||||
|
) {
|
||||||
|
closePopover()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover open={open} onOpenChange={onOpenChange}>
|
<Popover open={open}>
|
||||||
<PopoverAnchor>{children}</PopoverAnchor>
|
<PopoverAnchor>{children}</PopoverAnchor>
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
className={styles.transcendence}
|
className="transcendence"
|
||||||
ref={popoverRef}
|
ref={popoverRef}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
|
onEscapeKeyDown={closePopover}
|
||||||
|
onPointerDownOutside={handlePointerDownOutside}
|
||||||
>
|
>
|
||||||
<TranscendenceStar
|
<TranscendenceStar
|
||||||
className="interactive base"
|
className="interactive base"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ interface Props
|
||||||
|
|
||||||
const NUM_FRAGMENTS = 5
|
const NUM_FRAGMENTS = 5
|
||||||
|
|
||||||
const TranscendenceStar = ({
|
const TranscendenceStar = React.forwardRef<HTMLDivElement, Props>(
|
||||||
|
function TranscendenceStar(
|
||||||
|
{
|
||||||
className,
|
className,
|
||||||
interactive,
|
interactive,
|
||||||
stage,
|
stage,
|
||||||
|
|
@ -29,13 +31,16 @@ const TranscendenceStar = ({
|
||||||
onStarClick,
|
onStarClick,
|
||||||
onFragmentClick,
|
onFragmentClick,
|
||||||
onFragmentHover,
|
onFragmentHover,
|
||||||
}: Props) => {
|
}: Props,
|
||||||
|
forwardedRef
|
||||||
|
) {
|
||||||
const [visibleStage, setVisibleStage] = useState(0)
|
const [visibleStage, setVisibleStage] = useState(0)
|
||||||
const [currentStage, setCurrentStage] = useState(0)
|
const [currentStage, setCurrentStage] = useState(0)
|
||||||
const [immutable, setImmutable] = useState(false)
|
const [immutable, setImmutable] = useState(false)
|
||||||
|
|
||||||
// Classes
|
// Classes
|
||||||
const starClasses = classnames({
|
const starClasses = classnames({
|
||||||
|
TranscendenceStar: true,
|
||||||
[styles.star]: true,
|
[styles.star]: true,
|
||||||
[styles.immutable]: immutable,
|
[styles.immutable]: immutable,
|
||||||
[styles.empty]: stage === 0,
|
[styles.empty]: stage === 0,
|
||||||
|
|
@ -59,9 +64,7 @@ const TranscendenceStar = ({
|
||||||
}, [stage])
|
}, [stage])
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
if (onStarClick) {
|
if (onStarClick) onStarClick()
|
||||||
onStarClick()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFragmentClick(index: number) {
|
function handleFragmentClick(index: number) {
|
||||||
|
|
@ -88,6 +91,7 @@ const TranscendenceStar = ({
|
||||||
className={starClasses}
|
className={starClasses}
|
||||||
onClick={editable ? handleClick : () => {}}
|
onClick={editable ? handleClick : () => {}}
|
||||||
onMouseLeave={interactive ? handleMouseLeave : () => {}}
|
onMouseLeave={interactive ? handleMouseLeave : () => {}}
|
||||||
|
ref={forwardedRef}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
>
|
>
|
||||||
<div className={styles.fragments}>
|
<div className={styles.fragments}>
|
||||||
|
|
@ -110,7 +114,8 @@ const TranscendenceStar = ({
|
||||||
<i className={baseImageClasses} />
|
<i className={baseImageClasses} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
TranscendenceStar.defaultProps = {
|
TranscendenceStar.defaultProps = {
|
||||||
stage: 0,
|
stage: 0,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
.wrapper {
|
.wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
&.hovercard {
|
||||||
|
min-width: 100px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.indicator {
|
.indicator {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ import TranscendencePopover from '~components/uncap/TranscendencePopover'
|
||||||
import TranscendenceStar from '~components/uncap/TranscendenceStar'
|
import TranscendenceStar from '~components/uncap/TranscendenceStar'
|
||||||
|
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
interface Props {
|
interface Props extends React.ComponentProps<'div'> {
|
||||||
type: 'character' | 'weapon' | 'summon'
|
type: 'character' | 'weapon' | 'summon'
|
||||||
rarity?: number
|
rarity?: number
|
||||||
uncapLevel?: number
|
uncapLevel?: number
|
||||||
|
|
@ -25,6 +26,15 @@ const UncapIndicator = (props: Props) => {
|
||||||
|
|
||||||
const [popoverOpen, setPopoverOpen] = useState(false)
|
const [popoverOpen, setPopoverOpen] = useState(false)
|
||||||
|
|
||||||
|
const transcendenceStarRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
||||||
|
const classes = classNames(
|
||||||
|
{
|
||||||
|
[styles.wrapper]: true,
|
||||||
|
},
|
||||||
|
props.className?.split(' ').map((className) => styles[className])
|
||||||
|
)
|
||||||
|
|
||||||
function setNumStars() {
|
function setNumStars() {
|
||||||
let numStars
|
let numStars
|
||||||
|
|
||||||
|
|
@ -74,7 +84,11 @@ const UncapIndicator = (props: Props) => {
|
||||||
|
|
||||||
function sendTranscendenceStage(stage: number) {
|
function sendTranscendenceStage(stage: number) {
|
||||||
if (props.updateTranscendence) props.updateTranscendence(stage)
|
if (props.updateTranscendence) props.updateTranscendence(stage)
|
||||||
togglePopover(false)
|
setPopoverOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStarClicked() {
|
||||||
|
if (props.editable) togglePopover(!popoverOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
const transcendence = (i: number) => {
|
const transcendence = (i: number) => {
|
||||||
|
|
@ -82,25 +96,27 @@ const UncapIndicator = (props: Props) => {
|
||||||
return props.type === 'character' || props.type === 'summon' ? (
|
return props.type === 'character' || props.type === 'summon' ? (
|
||||||
<TranscendencePopover
|
<TranscendencePopover
|
||||||
open={popoverOpen}
|
open={popoverOpen}
|
||||||
stage={props.transcendenceStage ? props.transcendenceStage : 0}
|
stage={props.transcendenceStage || 0}
|
||||||
type={props.type}
|
type={props.type}
|
||||||
onOpenChange={togglePopover}
|
onOpenChange={togglePopover}
|
||||||
sendValue={sendTranscendenceStage}
|
sendValue={sendTranscendenceStage}
|
||||||
key={`star_${i}`}
|
key={`popover_${i}_${popoverOpen}`}
|
||||||
|
starRef={transcendenceStarRef}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
>
|
>
|
||||||
<TranscendenceStar
|
<TranscendenceStar
|
||||||
key={`star_${i}`}
|
key={`star_${i}`}
|
||||||
stage={props.transcendenceStage}
|
stage={props.transcendenceStage || 0}
|
||||||
editable={props.editable}
|
editable={props.editable}
|
||||||
interactive={false}
|
interactive={false}
|
||||||
onStarClick={() => togglePopover(true)}
|
ref={transcendenceStarRef}
|
||||||
|
onStarClick={handleStarClicked}
|
||||||
/>
|
/>
|
||||||
</TranscendencePopover>
|
</TranscendencePopover>
|
||||||
) : (
|
) : (
|
||||||
<TranscendenceStar
|
<TranscendenceStar
|
||||||
key={`star_${i}`}
|
key={`star_${i}`}
|
||||||
stage={props.transcendenceStage}
|
stage={props.transcendenceStage || 0}
|
||||||
editable={props.editable}
|
editable={props.editable}
|
||||||
interactive={false}
|
interactive={false}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
|
|
@ -150,7 +166,7 @@ const UncapIndicator = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={classes}>
|
||||||
<ul className={styles.indicator}>
|
<ul className={styles.indicator}>
|
||||||
{Array.from(Array(numStars)).map((x, i) => {
|
{Array.from(Array(numStars)).map((x, i) => {
|
||||||
if (props.type === 'character' && i > 4) {
|
if (props.type === 'character' && i > 4) {
|
||||||
|
|
|
||||||
|
|
@ -229,8 +229,8 @@ const WeaponHovercard = (props: Props) => {
|
||||||
/>
|
/>
|
||||||
{props.gridWeapon.object.ax &&
|
{props.gridWeapon.object.ax &&
|
||||||
props.gridWeapon.ax &&
|
props.gridWeapon.ax &&
|
||||||
props.gridWeapon.ax[0].modifier !== undefined &&
|
props.gridWeapon.ax[0].modifier !== null &&
|
||||||
props.gridWeapon.ax[0].strength !== undefined &&
|
props.gridWeapon.ax[0].strength !== null &&
|
||||||
axSection}
|
axSection}
|
||||||
{props.gridWeapon.awakening && awakeningSection}
|
{props.gridWeapon.awakening && awakeningSection}
|
||||||
{props.gridWeapon.weapon_keys &&
|
{props.gridWeapon.weapon_keys &&
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,12 @@
|
||||||
height: 25px;
|
height: 25px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
background-size: 50px 20px;
|
||||||
|
height: 20px;
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Elements */
|
/* Elements */
|
||||||
|
|
||||||
&.fire.en {
|
&.fire.en {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import styles from './index.module.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
labelType: string
|
labelType: string
|
||||||
|
size: 'small' | 'normal'
|
||||||
}
|
}
|
||||||
|
|
||||||
const WeaponLabelIcon = (props: Props) => {
|
const WeaponLabelIcon = (props: Props) => {
|
||||||
|
|
@ -13,6 +14,7 @@ const WeaponLabelIcon = (props: Props) => {
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
[styles.icon]: true,
|
[styles.icon]: true,
|
||||||
|
[styles.small]: props.size === 'small',
|
||||||
[styles[props.labelType]]: true,
|
[styles[props.labelType]]: true,
|
||||||
[styles.en]: router.locale === 'en',
|
[styles.en]: router.locale === 'en',
|
||||||
[styles.ja]: router.locale === 'ja',
|
[styles.ja]: router.locale === 'ja',
|
||||||
|
|
@ -21,4 +23,8 @@ const WeaponLabelIcon = (props: Props) => {
|
||||||
return <i className={classes} />
|
return <i className={classes} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WeaponLabelIcon.defaultProps = {
|
||||||
|
size: 'normal',
|
||||||
|
}
|
||||||
|
|
||||||
export default WeaponLabelIcon
|
export default WeaponLabelIcon
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,8 @@ const WeaponUnit = ({
|
||||||
gridWeapon.ax &&
|
gridWeapon.ax &&
|
||||||
gridWeapon.ax.length > 0
|
gridWeapon.ax.length > 0
|
||||||
) {
|
) {
|
||||||
for (let i = 0; i < gridWeapon.ax.length; i++) {
|
const numSkills = gridWeapon.ax[1].modifier ? 2 : 1
|
||||||
|
for (let i = 0; i < numSkills; i++) {
|
||||||
const image = axImage(i)
|
const image = axImage(i)
|
||||||
if (image) images.push(image)
|
if (image) images.push(image)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
|
@ -19,6 +19,16 @@
|
||||||
"uncap": "Uncap"
|
"uncap": "Uncap"
|
||||||
},
|
},
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"1.2.1": {
|
||||||
|
"bugs": [
|
||||||
|
"Job accessory popover has been fixed, so Paladin shields and Manadiver manatura can be selected again",
|
||||||
|
"The AX skill section no longer shows up in the weapon hovercard if no AX skills are set",
|
||||||
|
"The top of the character hovercard has been slightly refined",
|
||||||
|
"Fixed a bug that prevented all character over mastery (ring) bonuses from being displayed",
|
||||||
|
"Fixed a bug that reset a character's transcendence level if their mastery values are set",
|
||||||
|
"Fixed a bug that prevented setting the value for Rupee Gain or EXP Gain AX skills on weapons"
|
||||||
|
]
|
||||||
|
},
|
||||||
"1.2.0": {
|
"1.2.0": {
|
||||||
"notes": "I'm very bad at writing actual release notes, so this is a consolidation of the bigger features released in the last six months. Don't worry: there's some new stuff here too!\nThe next features (in no particular order) will be: a way to define roles and substitutions for characters, a collection tracker and hopefully making progress on guides. That's a lot, but I'll chip away at it bit by bit.\nAs always, if you have any feedback, feel free to reach out in the granblue-tools Discord. Thanks for using granblue.team!",
|
"notes": "I'm very bad at writing actual release notes, so this is a consolidation of the bigger features released in the last six months. Don't worry: there's some new stuff here too!\nThe next features (in no particular order) will be: a way to define roles and substitutions for characters, a collection tracker and hopefully making progress on guides. That's a lot, but I'll chip away at it bit by bit.\nAs always, if you have any feedback, feel free to reach out in the granblue-tools Discord. Thanks for using granblue.team!",
|
||||||
"features": [
|
"features": [
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,16 @@
|
||||||
"uncap": "上限解放"
|
"uncap": "上限解放"
|
||||||
},
|
},
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"1.2.1": {
|
||||||
|
"bugs": [
|
||||||
|
"ジョブアクセサリーのメニューが修正され、パラディンの盾やマナダイバーのマナベリーが再び選択できるようになりました",
|
||||||
|
"EXスキルが設定されていない場合、武器ホバーカードにEXスキルの項目が表示されなくなりました",
|
||||||
|
"キャラクターホバーカードのトップが少し洗練されました",
|
||||||
|
"キャラクターホバーカードにリミットボーナスを全部表示しないバグを修正しました",
|
||||||
|
"キャラクターのボーナス値が設定されている場合、キャラクターの超越レベルがリセットされるバグを修正しました",
|
||||||
|
"武器にルピーUPまたはEXP UPのEXスキルの値を設定できないバグを修正しました"
|
||||||
|
]
|
||||||
|
},
|
||||||
"1.2.0": {
|
"1.2.0": {
|
||||||
"notes": "I'm very bad at writing actual release notes, so this is a consolidation of the bigger features released in the last six months. Don't worry: there's some new stuff here too!\nThe next features (in no particular order) will be: a way to define roles and substitutions for characters, a collection tracker and hopefully making progress on guides. That's a lot, but I'll chip away at it bit by bit.\nAs always, if you have any feedback, feel free to reach out in the granblue-tools Discord. Thanks for using granblue.team!",
|
"notes": "I'm very bad at writing actual release notes, so this is a consolidation of the bigger features released in the last six months. Don't worry: there's some new stuff here too!\nThe next features (in no particular order) will be: a way to define roles and substitutions for characters, a collection tracker and hopefully making progress on guides. That's a lot, but I'll chip away at it bit by bit.\nAs always, if you have any feedback, feel free to reach out in the granblue-tools Discord. Thanks for using granblue.team!",
|
||||||
"features": [
|
"features": [
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue