Fixes for reactivity and performance (#314)
* Remove editable styles * Use snapshot for segment reps Using snapshots lets that data be reactive. Also removed extra dependencies and fixed a bug in how SummonRep displayed sub-summons * Don't display QuickSummon on friends, subaura * Hotfix refreshing when switching tabs
This commit is contained in:
parent
45645aa352
commit
36804779e7
8 changed files with 123 additions and 268 deletions
|
|
@ -351,7 +351,8 @@ const Party = (props: Props) => {
|
||||||
// Methods: Navigating with segmented control
|
// Methods: Navigating with segmented control
|
||||||
function segmentClicked(event: React.ChangeEvent<HTMLInputElement>) {
|
function segmentClicked(event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const path = [
|
const path = [
|
||||||
router.asPath.split('/').filter((el) => el != '')[1],
|
// Enable when using Next.js Router
|
||||||
|
// router.asPath.split('/').filter((el) => el != '')[1],
|
||||||
event.target.value,
|
event.target.value,
|
||||||
].join('/')
|
].join('/')
|
||||||
|
|
||||||
|
|
@ -369,7 +370,10 @@ const Party = (props: Props) => {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
router.replace(path, undefined, { shallow: true })
|
// Ideally, we would use the Next.js Router to replace the URL,
|
||||||
|
// but something about shallow routing isn't working so the page is refreshing
|
||||||
|
// router.replace(path, undefined, { shallow: true })
|
||||||
|
history.pushState({}, '', path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render: JSX components
|
// Render: JSX components
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@
|
||||||
|
|
||||||
.PartyDetails {
|
.PartyDetails {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: none;
|
display: block;
|
||||||
|
line-height: 1.4;
|
||||||
|
white-space: pre-wrap;
|
||||||
margin: 0 auto $unit-2x;
|
margin: 0 auto $unit-2x;
|
||||||
max-width: $unit * 94;
|
max-width: $unit * 94;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -28,161 +30,6 @@
|
||||||
padding: 0 $unit;
|
padding: 0 $unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.Visible {
|
|
||||||
// margin-bottom: $unit-12x;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.Editable {
|
|
||||||
gap: $unit;
|
|
||||||
|
|
||||||
&.Visible {
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
min-height: $unit * 22;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.SelectTrigger {
|
|
||||||
padding: $unit-2x;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.DetailToggleGroup {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
|
||||||
gap: $unit;
|
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ToggleSection,
|
|
||||||
.InputSection {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
background: var(--card-bg);
|
|
||||||
border-radius: $input-corner;
|
|
||||||
|
|
||||||
& > label {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
font-size: $font-regular;
|
|
||||||
gap: $unit;
|
|
||||||
grid-template-columns: 2fr 1fr;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ToggleSection {
|
|
||||||
padding: ($unit * 1.5) $unit-2x;
|
|
||||||
}
|
|
||||||
|
|
||||||
.InputSection {
|
|
||||||
padding: $unit-half $unit-2x;
|
|
||||||
padding-right: $unit-half;
|
|
||||||
|
|
||||||
.Input {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.Input {
|
|
||||||
align-items: center;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
padding: $unit;
|
|
||||||
|
|
||||||
&:has(> input:focus) {
|
|
||||||
border: 2px solid $blue;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > input {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
padding: $unit 0;
|
|
||||||
text-align: right;
|
|
||||||
width: 2rem;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
span {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Input {
|
|
||||||
border-radius: 7px;
|
|
||||||
max-width: 10rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: $unit-half;
|
|
||||||
justify-content: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: $unit;
|
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: $unit;
|
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
|
||||||
.Button {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ReadOnly {
|
|
||||||
box-sizing: border-box;
|
|
||||||
line-height: 1.4;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
&.Visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +132,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.PartyInfo {
|
.PartyInfo {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ const PartyHeader = (props: Props) => {
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
PartyDetails: true,
|
PartyDetails: true,
|
||||||
ReadOnly: true,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const userClass = classNames({
|
const userClass = classNames({
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,25 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { appState } from '~utils/appState'
|
import { appState } from '~utils/appState'
|
||||||
|
import { accountState } from '~utils/accountState'
|
||||||
|
|
||||||
import SegmentedControl from '~components/common/SegmentedControl'
|
import SegmentedControl from '~components/common/SegmentedControl'
|
||||||
|
import RepSegment from '~components/reps/RepSegment'
|
||||||
|
import CharacterRep from '~components/reps/CharacterRep'
|
||||||
|
import WeaponRep from '~components/reps/WeaponRep'
|
||||||
|
import SummonRep from '~components/reps/SummonRep'
|
||||||
|
|
||||||
import { GridType } from '~utils/enums'
|
import { GridType } from '~utils/enums'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import classNames from 'classnames'
|
|
||||||
import RepSegment from '~components/reps/RepSegment'
|
// Fix for valtio readonly array
|
||||||
import CharacterRep from '~components/reps/CharacterRep'
|
declare module 'valtio' {
|
||||||
import { accountState } from '~utils/accountState'
|
function useSnapshot<T extends object>(p: T): T
|
||||||
import WeaponRep from '~components/reps/WeaponRep'
|
}
|
||||||
import SummonRep from '~components/reps/SummonRep'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
selectedTab: GridType
|
selectedTab: GridType
|
||||||
|
|
@ -27,7 +32,7 @@ const PartySegmentedControl = (props: Props) => {
|
||||||
|
|
||||||
const { party, grid } = useSnapshot(appState)
|
const { party, grid } = useSnapshot(appState)
|
||||||
|
|
||||||
function getElement() {
|
const getElement = () => {
|
||||||
let element: number = 0
|
let element: number = 0
|
||||||
if (party.element == 0 && grid.weapons.mainWeapon)
|
if (party.element == 0 && grid.weapons.mainWeapon)
|
||||||
element = grid.weapons.mainWeapon.element
|
element = grid.weapons.mainWeapon.element
|
||||||
|
|
@ -55,16 +60,16 @@ const PartySegmentedControl = (props: Props) => {
|
||||||
controlGroup="grid"
|
controlGroup="grid"
|
||||||
inputName="characters"
|
inputName="characters"
|
||||||
name={t('party.segmented_control.characters')}
|
name={t('party.segmented_control.characters')}
|
||||||
selected={props.selectedTab == GridType.Character}
|
selected={props.selectedTab === GridType.Character}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
>
|
>
|
||||||
<CharacterRep
|
<CharacterRep
|
||||||
job={appState.party?.job}
|
job={party.job}
|
||||||
element={appState.party?.element}
|
element={party.element}
|
||||||
gender={
|
gender={
|
||||||
accountState.account.user ? accountState.account.user.gender : 0
|
accountState.account.user ? accountState.account.user.gender : 0
|
||||||
}
|
}
|
||||||
grid={appState.grid.characters}
|
grid={grid.characters}
|
||||||
/>
|
/>
|
||||||
</RepSegment>
|
</RepSegment>
|
||||||
)
|
)
|
||||||
|
|
@ -77,10 +82,10 @@ const PartySegmentedControl = (props: Props) => {
|
||||||
controlGroup="grid"
|
controlGroup="grid"
|
||||||
inputName="weapons"
|
inputName="weapons"
|
||||||
name="Weapons"
|
name="Weapons"
|
||||||
selected={props.selectedTab == GridType.Weapon}
|
selected={props.selectedTab === GridType.Weapon}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
>
|
>
|
||||||
<WeaponRep grid={appState.grid.weapons} />
|
<WeaponRep grid={grid.weapons} />
|
||||||
</RepSegment>
|
</RepSegment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -92,10 +97,10 @@ const PartySegmentedControl = (props: Props) => {
|
||||||
controlGroup="grid"
|
controlGroup="grid"
|
||||||
inputName="summons"
|
inputName="summons"
|
||||||
name="Summons"
|
name="Summons"
|
||||||
selected={props.selectedTab == GridType.Summon}
|
selected={props.selectedTab === GridType.Summon}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
>
|
>
|
||||||
<SummonRep grid={appState.grid.summons} />
|
<SummonRep grid={grid.summons} />
|
||||||
</RepSegment>
|
</RepSegment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
|
||||||
import 'fix-date'
|
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
|
|
@ -18,7 +16,6 @@ const SUMMONS_COUNT = 4
|
||||||
const SummonRep = (props: Props) => {
|
const SummonRep = (props: Props) => {
|
||||||
// Localization for alt tags
|
// Localization for alt tags
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { t } = useTranslation('common')
|
|
||||||
const locale =
|
const locale =
|
||||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||||
|
|
||||||
|
|
@ -159,8 +156,8 @@ const SummonRep = (props: Props) => {
|
||||||
<ul className="GridSummons">
|
<ul className="GridSummons">
|
||||||
{Array.from(Array(SUMMONS_COUNT)).map((x, i) => {
|
{Array.from(Array(SUMMONS_COUNT)).map((x, i) => {
|
||||||
return (
|
return (
|
||||||
<li key={`summons-${i + 1}`} className="Grid Summon">
|
<li key={`summons-${i}`} className="Grid Summon">
|
||||||
{generateGridImage(i + 1)}
|
{generateGridImage(i)}
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
|
||||||
import 'fix-date'
|
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
|
|
@ -17,7 +15,6 @@ const WEAPONS_COUNT = 9
|
||||||
const WeaponRep = (props: Props) => {
|
const WeaponRep = (props: Props) => {
|
||||||
// Localization for alt tags
|
// Localization for alt tags
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { t } = useTranslation('common')
|
|
||||||
const locale =
|
const locale =
|
||||||
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,4 +70,8 @@
|
||||||
.SummonUnit .SummonImage .icon svg {
|
.SummonUnit .SummonImage .icon svg {
|
||||||
fill: var(--subaura-orange-secondary);
|
fill: var(--subaura-orange-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SummonUnit .QuickSummon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,7 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.main .QuickSummon,
|
&.main .QuickSummon {
|
||||||
&.friend .QuickSummon {
|
|
||||||
$diameter: $unit-6x;
|
$diameter: $unit-6x;
|
||||||
background-size: $diameter $diameter;
|
background-size: $diameter $diameter;
|
||||||
top: -2%;
|
top: -2%;
|
||||||
|
|
@ -127,6 +126,10 @@
|
||||||
height: $diameter;
|
height: $diameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.friend .QuickSummon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&.grid .QuickSummon {
|
&.grid .QuickSummon {
|
||||||
$diameter: $unit-5x;
|
$diameter: $unit-5x;
|
||||||
background-size: $diameter $diameter;
|
background-size: $diameter $diameter;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue