Quality pass (#326)
* Move min-width to RaidCombobox, not Popover This fixes #318 * Use snapshots to make tokens reactive This fixes #319 * Revert ChatGPT refactor of this method Oops. This code was nice, but it didn't actually assign `false` to keys to be sent to the server. We will revisit this, but it needs to be fixed right now. This fixes #325 * Ignore gacha directory We will probably scrape these images soon. * Add translation for Auto Summon token * Add auto summon token to app state * Set battle settings in state on update Also renames PartyDetails to PartyFooter and makes description reactive * Stop 1password icon from appearing in name field * Use snapshot for reactive Edit party modal * Fix Edit modal placeholder colors * Fix bug with RaidCombobox and Farming Selecting farming then opening the raid combobox *twice* consecutively would put you in no segment, so no raids appeared Fixes #323 * Fix values staying in Edit team even if not saved The values a user entered in the Edit team modal would persist even if the user hit cancel to close the modal. They wouldn't save to the server, but very confusing nonetheless. Now fixed. * Fix unreadable colors in ElementToggle * Fix button alignment in weapon modal * Add text to filters button on small screens The FilterBar showed a left aligned filter icon on mobile for months and it was driving me insane * Remove extraneous code from Header Including the party name, since it's at the top now * Fix Alert at small sizes * Make copy link toast work again * Remove stylesheet links * Fix remix toasts and alerts from both locations The remix toast and alert was barely hooked up and not showing up when invoked from PartyHeader. It now shows up whether you remix your own team (from PartyDropdown) or if you remix another person's team (from PartyHeader).
This commit is contained in:
parent
73b98db85e
commit
103ef7e1a2
26 changed files with 384 additions and 369 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -58,6 +58,7 @@ public/images/mastery*
|
|||
public/images/updates*
|
||||
public/images/guidebooks*
|
||||
public/images/raids*
|
||||
public/images/gacha*
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
|
|
|||
|
|
@ -47,32 +47,32 @@
|
|||
|
||||
&.fire {
|
||||
background: var(--fire-bg);
|
||||
color: var(--fire-text);
|
||||
color: var(--fire-hover-text);
|
||||
}
|
||||
|
||||
&.water {
|
||||
background: var(--water-bg);
|
||||
color: var(--water-text);
|
||||
color: var(--water-hover-text);
|
||||
}
|
||||
|
||||
&.earth {
|
||||
background: var(--earth-bg);
|
||||
color: var(--earth-text);
|
||||
color: var(--earth-hover-text);
|
||||
}
|
||||
|
||||
&.wind {
|
||||
background: var(--wind-bg);
|
||||
color: var(--wind-text);
|
||||
color: var(--wind-hover-text);
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background: var(--dark-bg);
|
||||
color: var(--dark-text);
|
||||
color: var(--dark-hover-text);
|
||||
}
|
||||
|
||||
&.light {
|
||||
background: var(--light-bg);
|
||||
color: var(--light-text);
|
||||
color: var(--light-hover-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
.Filter.Button {
|
||||
justify-content: center;
|
||||
|
||||
.Text {
|
||||
display: none;
|
||||
width: auto;
|
||||
|
||||
@include breakpoint(tablet) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@include breakpoint(phone) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.UserInfo {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ const FilterBar = (props: Props) => {
|
|||
className={filterButtonClasses}
|
||||
blended={true}
|
||||
leftAccessoryIcon={<FilterIcon />}
|
||||
text={t('filters.name')}
|
||||
onClick={() => setFilterModalOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import classNames from 'classnames'
|
|||
import clonedeep from 'lodash.clonedeep'
|
||||
import Link from 'next/link'
|
||||
|
||||
import api from '~utils/api'
|
||||
import { accountState, initialAccountState } from '~utils/accountState'
|
||||
import { appState, initialAppState } from '~utils/appState'
|
||||
import { getLocalId } from '~utils/localId'
|
||||
|
|
@ -32,11 +31,8 @@ import Tooltip from '~components/common/Tooltip'
|
|||
import * as Switch from '@radix-ui/react-switch'
|
||||
|
||||
import ChevronIcon from '~public/icons/Chevron.svg'
|
||||
import LinkIcon from '~public/icons/Link.svg'
|
||||
import MenuIcon from '~public/icons/Menu.svg'
|
||||
import RemixIcon from '~public/icons/Remix.svg'
|
||||
import PlusIcon from '~public/icons/Add.svg'
|
||||
import SaveIcon from '~public/icons/Save.svg'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
|
|
@ -51,7 +47,6 @@ const Header = () => {
|
|||
const localeData = retrieveLocaleCookies()
|
||||
|
||||
// State management
|
||||
const [copyToastOpen, setCopyToastOpen] = useState(false)
|
||||
const [remixToastOpen, setRemixToastOpen] = useState(false)
|
||||
const [loginModalOpen, setLoginModalOpen] = useState(false)
|
||||
const [signupModalOpen, setSignupModalOpen] = useState(false)
|
||||
|
|
@ -64,7 +59,6 @@ const Header = () => {
|
|||
const [originalName, setOriginalName] = useState('')
|
||||
|
||||
// Snapshots
|
||||
const { account } = useSnapshot(accountState)
|
||||
const { party: partySnapshot } = useSnapshot(appState)
|
||||
|
||||
// Subscribe to app state to listen for party name and
|
||||
|
|
@ -108,15 +102,6 @@ const Header = () => {
|
|||
setRightMenuOpen(false)
|
||||
}
|
||||
|
||||
// Methods: Event handlers (Copy toast)
|
||||
function handleCopyToastOpenChanged(open: boolean) {
|
||||
setCopyToastOpen(open)
|
||||
}
|
||||
|
||||
function handleCopyToastCloseClicked() {
|
||||
setCopyToastOpen(false)
|
||||
}
|
||||
|
||||
// Methods: Event handlers (Remix toasts)
|
||||
function handleRemixToastOpenChanged(open: boolean) {
|
||||
setRemixToastOpen(open)
|
||||
|
|
@ -142,23 +127,6 @@ const Header = () => {
|
|||
router.push(router.asPath, undefined, { locale: language })
|
||||
}
|
||||
|
||||
function copyToClipboard() {
|
||||
const path = router.asPath.split('/')[1]
|
||||
|
||||
if (path === 'p') {
|
||||
const el = document.createElement('input')
|
||||
el.value = window.location.href
|
||||
el.id = 'url-input'
|
||||
document.body.appendChild(el)
|
||||
|
||||
el.select()
|
||||
document.execCommand('copy')
|
||||
el.remove()
|
||||
|
||||
setCopyToastOpen(true)
|
||||
}
|
||||
}
|
||||
|
||||
function logout() {
|
||||
// Close menu
|
||||
closeRightMenu()
|
||||
|
|
@ -188,84 +156,6 @@ const Header = () => {
|
|||
router.push('/new')
|
||||
}
|
||||
|
||||
function remixTeam() {
|
||||
setOriginalName(partySnapshot.name ? partySnapshot.name : t('no_title'))
|
||||
|
||||
if (partySnapshot.shortcode) {
|
||||
const body = getLocalId()
|
||||
api
|
||||
.remix({ shortcode: partySnapshot.shortcode, body: body })
|
||||
.then((response) => {
|
||||
const remix = response.data.party
|
||||
|
||||
// Store the edit key in local storage
|
||||
if (remix.edit_key) {
|
||||
storeEditKey(remix.id, remix.edit_key)
|
||||
setEditKey(remix.id, remix.user)
|
||||
}
|
||||
|
||||
router.push(`/p/${remix.shortcode}`)
|
||||
setRemixToastOpen(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFavorite() {
|
||||
if (partySnapshot.favorited) unsaveFavorite()
|
||||
else saveFavorite()
|
||||
}
|
||||
|
||||
function saveFavorite() {
|
||||
if (partySnapshot.id)
|
||||
api.saveTeam({ id: partySnapshot.id }).then((response) => {
|
||||
if (response.status == 201) appState.party.favorited = true
|
||||
})
|
||||
else console.error('Failed to save team: No party ID')
|
||||
}
|
||||
|
||||
function unsaveFavorite() {
|
||||
if (partySnapshot.id)
|
||||
api.unsaveTeam({ id: partySnapshot.id }).then((response) => {
|
||||
if (response.status == 200) appState.party.favorited = false
|
||||
})
|
||||
else console.error('Failed to unsave team: No party ID')
|
||||
}
|
||||
|
||||
// Rendering: Elements
|
||||
const pageTitle = () => {
|
||||
let title = ''
|
||||
let hasAccessory = false
|
||||
|
||||
const path = router.asPath.split('/')[1]
|
||||
if (path === 'p') {
|
||||
hasAccessory = true
|
||||
if (appState.party && appState.party.name) {
|
||||
title = appState.party.name
|
||||
} else {
|
||||
title = t('no_title')
|
||||
}
|
||||
} else {
|
||||
title = ''
|
||||
}
|
||||
|
||||
return title !== '' ? (
|
||||
<Tooltip content={t('tooltips.copy_url')}>
|
||||
<Button
|
||||
blended={true}
|
||||
rightAccessoryIcon={
|
||||
path === 'p' && hasAccessory ? (
|
||||
<LinkIcon className="stroke" />
|
||||
) : undefined
|
||||
}
|
||||
text={title}
|
||||
onClick={copyToClipboard}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
const profileImage = () => {
|
||||
let image
|
||||
|
||||
|
|
@ -310,21 +200,6 @@ const Header = () => {
|
|||
)
|
||||
}
|
||||
|
||||
// Rendering: Toasts
|
||||
const urlCopyToast = () => {
|
||||
return (
|
||||
<Toast
|
||||
altText={t('toasts.copied')}
|
||||
open={copyToastOpen}
|
||||
duration={2400}
|
||||
type="foreground"
|
||||
content={t('toasts.copied')}
|
||||
onOpenChange={handleCopyToastOpenChanged}
|
||||
onCloseClick={handleCopyToastCloseClicked}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const remixToast = () => {
|
||||
return (
|
||||
<Toast
|
||||
|
|
@ -394,7 +269,6 @@ const Header = () => {
|
|||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
{!appState.errorCode ? pageTitle() : ''}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -564,8 +438,6 @@ const Header = () => {
|
|||
<nav id="Header">
|
||||
{left()}
|
||||
{right()}
|
||||
{urlCopyToast()}
|
||||
{remixToast()}
|
||||
{settingsModal()}
|
||||
{loginModal()}
|
||||
{signupModal()}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,14 @@
|
|||
max-width: 30vw;
|
||||
padding: $unit * 4;
|
||||
|
||||
@include breakpoint(tablet) {
|
||||
max-width: inherit;
|
||||
max-width: 60vw;
|
||||
}
|
||||
|
||||
@include breakpoint(phone) {
|
||||
max-width: inherit;
|
||||
width: 60vw;
|
||||
width: 70vw;
|
||||
}
|
||||
|
||||
.description {
|
||||
|
|
@ -41,5 +46,15 @@
|
|||
display: flex;
|
||||
align-self: flex-end;
|
||||
gap: $unit;
|
||||
|
||||
@include breakpoint(phone) {
|
||||
flex-direction: column-reverse;
|
||||
align-self: center;
|
||||
width: 100%;
|
||||
|
||||
.Button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
.Joined .Input::placeholder {
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ const CharLimitedFieldset: ForwardRefRenderFunction<HTMLInputElement, Props> = (
|
|||
<div className={classNames({ Joined: true }, props.className)}>
|
||||
<input
|
||||
{...props}
|
||||
data-1p-ignore
|
||||
autoComplete="off"
|
||||
className="Input"
|
||||
type={props.type}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,6 @@
|
|||
|
||||
.Input::placeholder {
|
||||
/* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||
color: var(--text-secondary) !important;
|
||||
color: var(--text-secondary);
|
||||
opacity: 1; /* Firefox */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
padding: $unit;
|
||||
transform-origin: var(--radix-popover-content-transform-origin);
|
||||
width: var(--radix-popover-trigger-width);
|
||||
min-width: 440px;
|
||||
z-index: 5;
|
||||
|
||||
@include breakpoint(phone) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
color: var(--full-auto-text);
|
||||
}
|
||||
|
||||
&.AutoGuard.On {
|
||||
&.AutoGuard.On,
|
||||
&.AutoSummon.On {
|
||||
background: var(--auto-guard-bg);
|
||||
color: var(--auto-guard-text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const RemixTeamAlert = ({
|
|||
<Trans i18nKey="modals.remix_team.description.viewer">
|
||||
Remixing a team makes a copy of it in your account so you can make
|
||||
your own changes.\n\nWould you like to remix{' '}
|
||||
<strong>{{ name: 'HEY' }}</strong>?
|
||||
<strong>{{ name: name }}</strong>?
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import {
|
||||
|
|
@ -22,6 +23,8 @@ import TableField from '~components/common/TableField'
|
|||
import type { DetailsObject } from 'types'
|
||||
import type { DialogProps } from '@radix-ui/react-dialog'
|
||||
|
||||
import { appState } from '~utils/appState'
|
||||
|
||||
import CheckIcon from '~public/icons/Check.svg'
|
||||
import CrossIcon from '~public/icons/Cross.svg'
|
||||
import './index.scss'
|
||||
|
|
@ -31,14 +34,16 @@ interface Props extends DialogProps {
|
|||
updateCallback: (details: DetailsObject) => void
|
||||
}
|
||||
|
||||
const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
||||
const EditPartyModal = ({ updateCallback, ...props }: Props) => {
|
||||
// Set up router
|
||||
const router = useRouter()
|
||||
const locale = router.locale
|
||||
|
||||
// Set up translation
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
// Set up reactive state
|
||||
const { party } = useSnapshot(appState)
|
||||
|
||||
// Refs
|
||||
const headerRef = React.createRef<HTMLDivElement>()
|
||||
const footerRef = React.createRef<HTMLDivElement>()
|
||||
|
|
@ -54,6 +59,7 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
|||
|
||||
// States: Data
|
||||
const [name, setName] = useState('')
|
||||
const [description, setDescription] = useState('')
|
||||
const [raid, setRaid] = useState<Raid>()
|
||||
const [extra, setExtra] = useState(false)
|
||||
const [chargeAttack, setChargeAttack] = useState(true)
|
||||
|
|
@ -68,24 +74,15 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
|||
|
||||
// Hooks
|
||||
useEffect(() => {
|
||||
if (!party) return
|
||||
|
||||
setName(party.name)
|
||||
setRaid(party.raid)
|
||||
setAutoGuard(party.auto_guard)
|
||||
setAutoSummon(party.auto_summon)
|
||||
setFullAuto(party.full_auto)
|
||||
setChargeAttack(party.charge_attack)
|
||||
setClearTime(party.clear_time)
|
||||
if (party.turn_count) setTurnCount(party.turn_count)
|
||||
if (party.button_count) setButtonCount(party.button_count)
|
||||
if (party.chain_count) setChainCount(party.chain_count)
|
||||
persistFromState()
|
||||
}, [party])
|
||||
|
||||
// Methods: Event handlers (Dialog)
|
||||
function openChange() {
|
||||
if (open) {
|
||||
setOpen(false)
|
||||
setCurrentSegment(0)
|
||||
persistFromState()
|
||||
if (props.onOpenChange) props.onOpenChange(false)
|
||||
} else {
|
||||
setOpen(true)
|
||||
|
|
@ -176,6 +173,21 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
|||
}
|
||||
|
||||
// Methods: Data methods
|
||||
function persistFromState() {
|
||||
if (!party) return
|
||||
setName(party.name ? party.name : '')
|
||||
setDescription(party.description ? party.description : '')
|
||||
setRaid(party.raid)
|
||||
setAutoGuard(party.autoGuard)
|
||||
setAutoSummon(party.autoSummon)
|
||||
setFullAuto(party.fullAuto)
|
||||
setChargeAttack(party.chargeAttack)
|
||||
setClearTime(party.clearTime)
|
||||
if (party.turnCount) setTurnCount(party.turnCount)
|
||||
if (party.buttonCount) setButtonCount(party.buttonCount)
|
||||
if (party.chainCount) setChainCount(party.chainCount)
|
||||
}
|
||||
|
||||
function updateDetails(event: React.MouseEvent) {
|
||||
const descriptionValue = descriptionInput.current?.value
|
||||
const details: DetailsObject = {
|
||||
|
|
@ -272,9 +284,8 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
|||
}
|
||||
onChange={handleTextAreaChanged}
|
||||
ref={descriptionInput}
|
||||
>
|
||||
{party ? party.description : ''}
|
||||
</textarea>
|
||||
defaultValue={description}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import clonedeep from 'lodash.clonedeep'
|
|||
|
||||
import Alert from '~components/common/Alert'
|
||||
import PartySegmentedControl from '~components/party/PartySegmentedControl'
|
||||
import PartyDetails from '~components/party/PartyDetails'
|
||||
import PartyFooter from '~components/party/PartyFooter'
|
||||
import PartyHeader from '~components/party/PartyHeader'
|
||||
import WeaponGrid from '~components/weapon/WeaponGrid'
|
||||
import SummonGrid from '~components/summon/SummonGrid'
|
||||
|
|
@ -145,37 +145,27 @@ const Party = (props: Props) => {
|
|||
function formatDetailsObject(details: DetailsObject) {
|
||||
const payload: { [key: string]: any } = {}
|
||||
|
||||
const mappings: { [key: string]: string } = {
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
chargeAttack: 'charge_attack',
|
||||
fullAuto: 'full_auto',
|
||||
autoGuard: 'auto_guard',
|
||||
autoSummon: 'auto_summon',
|
||||
clearTime: 'clear_time',
|
||||
buttonCount: 'button_count',
|
||||
chainCount: 'chain_count',
|
||||
turnCount: 'turn_count',
|
||||
extra: 'extra',
|
||||
job: 'job_id',
|
||||
guidebook1_id: 'guidebook1_id',
|
||||
guidebook2_id: 'guidebook2_id',
|
||||
guidebook3_id: 'guidebook3_id',
|
||||
}
|
||||
|
||||
Object.entries(mappings).forEach(([key, value]) => {
|
||||
if (details[key]) {
|
||||
payload[value] = details[key]
|
||||
}
|
||||
})
|
||||
|
||||
if (details.name) payload.name = details.name
|
||||
if (details.description) payload.description = details.description
|
||||
if (details.raid) payload.raid_id = details.raid.id
|
||||
if (details.chargeAttack != undefined)
|
||||
payload.charge_attack = details.chargeAttack
|
||||
if (details.fullAuto != undefined) payload.full_auto = details.fullAuto
|
||||
if (details.autoGuard != undefined) payload.auto_guard = details.autoGuard
|
||||
if (details.autoSummon != undefined)
|
||||
payload.auto_summon = details.autoSummon
|
||||
if (details.clearTime) payload.clear_time = details.clearTime
|
||||
if (details.buttonCount) payload.button_count = details.buttonCount
|
||||
if (details.chainCount) payload.chain_count = details.chainCount
|
||||
if (details.turnCount) payload.turn_count = details.turnCount
|
||||
if (details.extra != undefined) payload.extra = details.extra
|
||||
if (details.job) payload.job_id = details.job.id
|
||||
if (details.guidebook1_id) payload.guidebook1_id = details.guidebook1_id
|
||||
if (details.guidebook2_id) payload.guidebook2_id = details.guidebook2_id
|
||||
if (details.guidebook3_id) payload.guidebook3_id = details.guidebook3_id
|
||||
|
||||
if (Object.keys(payload).length >= 1) {
|
||||
return { party: payload }
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
if (Object.keys(payload).length >= 1) return { party: payload }
|
||||
else return {}
|
||||
}
|
||||
|
||||
function cancelAlert() {
|
||||
|
|
@ -275,6 +265,15 @@ const Party = (props: Props) => {
|
|||
appState.party.jobSkills = team.job_skills
|
||||
appState.party.accessory = team.accessory
|
||||
|
||||
appState.party.chargeAttack = team.charge_attack
|
||||
appState.party.fullAuto = team.full_auto
|
||||
appState.party.autoGuard = team.auto_guard
|
||||
appState.party.autoSummon = team.auto_summon
|
||||
appState.party.clearTime = team.clear_time
|
||||
appState.party.buttonCount = team.button_count
|
||||
appState.party.chainCount = team.chain_count
|
||||
appState.party.turnCount = team.turn_count
|
||||
|
||||
appState.party.id = team.id
|
||||
appState.party.shortcode = team.shortcode
|
||||
appState.party.extra = team.extra
|
||||
|
|
@ -455,7 +454,7 @@ const Party = (props: Props) => {
|
|||
|
||||
<section id="Party">{currentGrid()}</section>
|
||||
|
||||
<PartyDetails
|
||||
<PartyFooter
|
||||
party={props.team}
|
||||
new={props.new || false}
|
||||
editable={party.editable}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { subscribe, useSnapshot } from 'valtio'
|
||||
import { Trans, useTranslation } from 'next-i18next'
|
||||
import Link from 'next/link'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import classNames from 'classnames'
|
||||
|
||||
// Dependencies: Common
|
||||
|
|
@ -125,22 +124,27 @@ const PartyDropdown = ({
|
|||
|
||||
// Toasts / Copy URL
|
||||
function handleCopyToastOpenChanged(open: boolean) {
|
||||
setCopyToastOpen(open)
|
||||
setCopyToastOpen(!open)
|
||||
}
|
||||
|
||||
function handleCopyToastCloseClicked() {
|
||||
setCopyToastOpen(false)
|
||||
}
|
||||
|
||||
// Toasts / Remix team
|
||||
// Toasts: Remix team
|
||||
function handleRemixToastOpenChanged(open: boolean) {
|
||||
setRemixToastOpen(open)
|
||||
setRemixToastOpen(!open)
|
||||
}
|
||||
|
||||
function handleRemixToastCloseClicked() {
|
||||
setRemixToastOpen(false)
|
||||
}
|
||||
|
||||
function remixCallback() {
|
||||
setRemixToastOpen(true)
|
||||
remixTeamCallback()
|
||||
}
|
||||
|
||||
const editableItems = () => {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -185,10 +189,23 @@ const PartyDropdown = ({
|
|||
|
||||
<RemixTeamAlert
|
||||
creator={editable}
|
||||
name={partySnapshot.name ? partySnapshot.name : t('no_title')}
|
||||
name={partySnapshot.name || t('no_title')}
|
||||
open={remixAlertOpen}
|
||||
onOpenChange={handleRemixTeamAlertChange}
|
||||
remixCallback={remixTeamCallback}
|
||||
remixCallback={remixCallback}
|
||||
/>
|
||||
|
||||
<RemixedToast
|
||||
open={remixToastOpen}
|
||||
partyName={partySnapshot.name || t('no_title')}
|
||||
onOpenChange={handleRemixToastOpenChanged}
|
||||
onCloseClick={handleRemixToastCloseClicked}
|
||||
/>
|
||||
|
||||
<UrlCopiedToast
|
||||
open={copyToastOpen}
|
||||
onOpenChange={handleCopyToastOpenChanged}
|
||||
onCloseClick={handleCopyToastCloseClicked}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.DetailsWrapper {
|
||||
.FooterWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $unit-2x;
|
||||
|
|
@ -16,10 +16,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.PartyDetails {
|
||||
.PartyFooter {
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
line-height: 1.4;
|
||||
white-space: pre-wrap;
|
||||
margin: 0 auto $unit-2x;
|
||||
margin-bottom: $unit-12x;
|
||||
min-height: 10vh;
|
||||
max-width: $unit * 94;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
|
@ -27,11 +30,6 @@
|
|||
@include breakpoint(phone) {
|
||||
padding: 0 $unit;
|
||||
}
|
||||
|
||||
&.Visible {
|
||||
// margin-bottom: $unit-12x;
|
||||
}
|
||||
|
||||
&.Editable {
|
||||
gap: $unit;
|
||||
|
||||
|
|
@ -174,115 +172,109 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.ReadOnly {
|
||||
box-sizing: border-box;
|
||||
line-height: 1.4;
|
||||
white-space: pre-wrap;
|
||||
&.Visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.Visible {
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $font-regular;
|
||||
line-height: $font-regular * 1.2;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.Details {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: $unit;
|
||||
margin-bottom: $unit-2x;
|
||||
}
|
||||
|
||||
.YoutubeWrapper {
|
||||
background-color: var(--card-bg);
|
||||
border-radius: $card-corner;
|
||||
margin: $unit 0;
|
||||
position: relative;
|
||||
display: block;
|
||||
contain: content;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
|
||||
@include breakpoint(tablet) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* gradient */
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==);
|
||||
background-position: top;
|
||||
background-repeat: repeat-x;
|
||||
height: 60px;
|
||||
padding-bottom: 50px;
|
||||
width: 100%;
|
||||
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $font-regular;
|
||||
line-height: $font-regular * 1.2;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.Details {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: $unit;
|
||||
margin-bottom: $unit-2x;
|
||||
}
|
||||
|
||||
.YoutubeWrapper {
|
||||
background-color: var(--card-bg);
|
||||
border-radius: $card-corner;
|
||||
margin: $unit 0;
|
||||
position: relative;
|
||||
display: block;
|
||||
contain: content;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
|
||||
@include breakpoint(tablet) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* gradient */
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==);
|
||||
background-position: top;
|
||||
background-repeat: repeat-x;
|
||||
height: 60px;
|
||||
padding-bottom: 50px;
|
||||
width: 100%;
|
||||
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* responsive iframe with a 16:9 aspect ratio
|
||||
/* responsive iframe with a 16:9 aspect ratio
|
||||
thanks https://css-tricks.com/responsive-iframes/
|
||||
*/
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
padding-bottom: calc(100% / (16 / 9));
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
padding-bottom: calc(100% / (16 / 9));
|
||||
}
|
||||
|
||||
&:hover > .PlayerButton {
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover > .PlayerButton {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
& > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
& > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Play button */
|
||||
& > .PlayerButton {
|
||||
background: none;
|
||||
border: none;
|
||||
background-image: url('/icons/youtube.svg');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
opacity: 0.8;
|
||||
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
/* Play button */
|
||||
& > .PlayerButton {
|
||||
background: none;
|
||||
border: none;
|
||||
background-image: url('/icons/youtube.svg');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
opacity: 0.8;
|
||||
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
& > .PlayerButton,
|
||||
& > .PlayerButton:before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
& > .PlayerButton,
|
||||
& > .PlayerButton:before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
|
||||
/* Post-click styles */
|
||||
&.lyt-activated {
|
||||
cursor: unset;
|
||||
}
|
||||
&.lyt-activated::before,
|
||||
&.lyt-activated > .PlayerButton {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* Post-click styles */
|
||||
&.lyt-activated {
|
||||
cursor: unset;
|
||||
}
|
||||
&.lyt-activated::before,
|
||||
&.lyt-activated > .PlayerButton {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import clonedeep from 'lodash.clonedeep'
|
||||
|
||||
|
|
@ -27,10 +28,12 @@ interface Props {
|
|||
updateCallback: (details: DetailsObject) => void
|
||||
}
|
||||
|
||||
const PartyDetails = (props: Props) => {
|
||||
const PartyFooter = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
const router = useRouter()
|
||||
|
||||
const { party } = useSnapshot(appState)
|
||||
|
||||
const youtubeUrlRegex =
|
||||
/(?:https:\/\/www\.youtube\.com\/watch\?v=|https:\/\/youtu\.be\/)([\w-]+)/g
|
||||
|
||||
|
|
@ -40,16 +43,10 @@ const PartyDetails = (props: Props) => {
|
|||
const [embeddedDescription, setEmbeddedDescription] =
|
||||
useState<React.ReactNode>()
|
||||
|
||||
const readOnlyClasses = classNames({
|
||||
PartyDetails: true,
|
||||
ReadOnly: true,
|
||||
Visible: !open,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
// Extract the video IDs from the description
|
||||
if (appState.party.description) {
|
||||
const videoIds = extractYoutubeVideoIds(appState.party.description)
|
||||
if (party.description) {
|
||||
const videoIds = extractYoutubeVideoIds(party.description)
|
||||
|
||||
// Fetch the video titles for each ID
|
||||
const fetchPromises = videoIds.map(({ id }) => fetchYoutubeData(id))
|
||||
|
|
@ -58,7 +55,7 @@ const PartyDetails = (props: Props) => {
|
|||
Promise.all(fetchPromises).then((videoTitles) => {
|
||||
// Replace the video URLs in the description with LiteYoutubeEmbed elements
|
||||
const newDescription = reactStringReplace(
|
||||
appState.party.description,
|
||||
party.description,
|
||||
youtubeUrlRegex,
|
||||
(match, i) => (
|
||||
<LiteYouTubeEmbed
|
||||
|
|
@ -77,7 +74,7 @@ const PartyDetails = (props: Props) => {
|
|||
} else {
|
||||
setEmbeddedDescription('')
|
||||
}
|
||||
}, [appState.party.description])
|
||||
}, [party.description])
|
||||
|
||||
async function fetchYoutubeData(videoId: string) {
|
||||
return await youtube
|
||||
|
|
@ -173,14 +170,6 @@ const PartyDetails = (props: Props) => {
|
|||
})
|
||||
}
|
||||
|
||||
const readOnly = () => {
|
||||
return (
|
||||
<section className={readOnlyClasses}>
|
||||
<Linkify>{embeddedDescription}</Linkify>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const remixSection = () => {
|
||||
return (
|
||||
<section className="Remixes">
|
||||
|
|
@ -192,10 +181,14 @@ const PartyDetails = (props: Props) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<section className="DetailsWrapper">{readOnly()}</section>
|
||||
<section className="FooterWrapper">
|
||||
<section className="PartyFooter">
|
||||
<Linkify>{embeddedDescription}</Linkify>
|
||||
</section>
|
||||
</section>
|
||||
{remixes && remixes.length > 0 ? remixSection() : ''}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PartyDetails
|
||||
export default PartyFooter
|
||||
|
|
@ -12,6 +12,7 @@ import Token from '~components/common/Token'
|
|||
import EditPartyModal from '~components/party/EditPartyModal'
|
||||
import PartyDropdown from '~components/party/PartyDropdown'
|
||||
|
||||
import api from '~utils/api'
|
||||
import { accountState } from '~utils/accountState'
|
||||
import { appState, initialAppState } from '~utils/appState'
|
||||
import { formatTimeAgo } from '~utils/timeAgo'
|
||||
|
|
@ -23,7 +24,9 @@ import SaveIcon from '~public/icons/Save.svg'
|
|||
import type { DetailsObject } from 'types'
|
||||
|
||||
import './index.scss'
|
||||
import api from '~utils/api'
|
||||
import RemixTeamAlert from '~components/dialogs/RemixTeamAlert'
|
||||
import RemixedToast from '~components/toasts/RemixedToast'
|
||||
import { set } from 'local-storage'
|
||||
|
||||
// Props
|
||||
interface Props {
|
||||
|
|
@ -44,12 +47,16 @@ const PartyHeader = (props: Props) => {
|
|||
|
||||
const { party: partySnapshot } = useSnapshot(appState)
|
||||
|
||||
const [name, setName] = useState('')
|
||||
// State: Component
|
||||
const [remixAlertOpen, setRemixAlertOpen] = useState(false)
|
||||
const [remixToastOpen, setRemixToastOpen] = useState(false)
|
||||
|
||||
// State: Data
|
||||
const [name, setName] = useState('')
|
||||
const [chargeAttack, setChargeAttack] = useState(true)
|
||||
const [fullAuto, setFullAuto] = useState(false)
|
||||
const [autoGuard, setAutoGuard] = useState(false)
|
||||
|
||||
const [autoSummon, setAutoSummon] = useState(false)
|
||||
const [buttonCount, setButtonCount] = useState<number | undefined>(undefined)
|
||||
const [chainCount, setChainCount] = useState<number | undefined>(undefined)
|
||||
const [turnCount, setTurnCount] = useState<number | undefined>(undefined)
|
||||
|
|
@ -78,6 +85,7 @@ const PartyHeader = (props: Props) => {
|
|||
setName(props.party.name)
|
||||
setAutoGuard(props.party.auto_guard)
|
||||
setFullAuto(props.party.full_auto)
|
||||
setAutoSummon(props.party.auto_summon)
|
||||
setChargeAttack(props.party.charge_attack)
|
||||
setClearTime(props.party.clear_time)
|
||||
if (props.party.turn_count) setTurnCount(props.party.turn_count)
|
||||
|
|
@ -155,6 +163,32 @@ const PartyHeader = (props: Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
// Actions: Remix team
|
||||
function remixTeamCallback() {
|
||||
setRemixToastOpen(true)
|
||||
props.remixCallback()
|
||||
}
|
||||
|
||||
// Alerts: Remix team
|
||||
function openRemixTeamAlert() {
|
||||
setRemixAlertOpen(true)
|
||||
}
|
||||
|
||||
function handleRemixTeamAlertChange(open: boolean) {
|
||||
setRemixAlertOpen(open)
|
||||
}
|
||||
|
||||
// Toasts: Remix team
|
||||
function handleRemixToastOpenChanged(open: boolean) {
|
||||
setRemixToastOpen(!open)
|
||||
}
|
||||
|
||||
function handleRemixToastCloseClicked() {
|
||||
setRemixToastOpen(false)
|
||||
}
|
||||
|
||||
// Rendering
|
||||
|
||||
const userBlock = (username?: string, picture?: string, element?: string) => {
|
||||
return (
|
||||
<div className={userClass}>
|
||||
|
|
@ -212,12 +246,12 @@ const PartyHeader = (props: Props) => {
|
|||
<Token
|
||||
className={classNames({
|
||||
ChargeAttack: true,
|
||||
On: chargeAttack,
|
||||
Off: !chargeAttack,
|
||||
On: party.chargeAttack,
|
||||
Off: !party.chargeAttack,
|
||||
})}
|
||||
>
|
||||
{`${t('party.details.labels.charge_attack')} ${
|
||||
chargeAttack ? 'On' : 'Off'
|
||||
party.chargeAttack ? 'On' : 'Off'
|
||||
}`}
|
||||
</Token>
|
||||
)
|
||||
|
|
@ -226,11 +260,13 @@ const PartyHeader = (props: Props) => {
|
|||
<Token
|
||||
className={classNames({
|
||||
FullAuto: true,
|
||||
On: fullAuto,
|
||||
Off: !fullAuto,
|
||||
On: party.fullAuto,
|
||||
Off: !party.fullAuto,
|
||||
})}
|
||||
>
|
||||
{`${t('party.details.labels.full_auto')} ${fullAuto ? 'On' : 'Off'}`}
|
||||
{`${t('party.details.labels.full_auto')} ${
|
||||
party.fullAuto ? 'On' : 'Off'
|
||||
}`}
|
||||
</Token>
|
||||
)
|
||||
|
||||
|
|
@ -238,37 +274,57 @@ const PartyHeader = (props: Props) => {
|
|||
<Token
|
||||
className={classNames({
|
||||
AutoGuard: true,
|
||||
On: autoGuard,
|
||||
Off: !autoGuard,
|
||||
On: party.autoGuard,
|
||||
Off: !party.autoGuard,
|
||||
})}
|
||||
>
|
||||
{`${t('party.details.labels.auto_guard')} ${autoGuard ? 'On' : 'Off'}`}
|
||||
{`${t('party.details.labels.auto_guard')} ${
|
||||
party.autoGuard ? 'On' : 'Off'
|
||||
}`}
|
||||
</Token>
|
||||
)
|
||||
|
||||
const autoSummonToken = (
|
||||
<Token
|
||||
className={classNames({
|
||||
AutoSummon: true,
|
||||
On: party.autoSummon,
|
||||
Off: !party.autoSummon,
|
||||
})}
|
||||
>
|
||||
{`${t('party.details.labels.auto_summon')} ${
|
||||
party.autoSummon ? 'On' : 'Off'
|
||||
}`}
|
||||
</Token>
|
||||
)
|
||||
|
||||
const turnCountToken = (
|
||||
<Token>
|
||||
{t('party.details.turns.with_count', {
|
||||
count: turnCount,
|
||||
count: party.turnCount,
|
||||
})}
|
||||
</Token>
|
||||
)
|
||||
|
||||
const buttonChainToken = () => {
|
||||
if (buttonCount || chainCount) {
|
||||
if (party.buttonCount || party.chainCount) {
|
||||
let string = ''
|
||||
|
||||
if (buttonCount && buttonCount > 0) {
|
||||
string += `${buttonCount}b`
|
||||
if (party.buttonCount && party.buttonCount > 0) {
|
||||
string += `${party.buttonCount}b`
|
||||
}
|
||||
|
||||
if (!buttonCount && chainCount && chainCount > 0) {
|
||||
string += `0${t('party.details.suffix.buttons')}${chainCount}${t(
|
||||
if (!party.buttonCount && party.chainCount && party.chainCount > 0) {
|
||||
string += `0${t('party.details.suffix.buttons')}${party.chainCount}${t(
|
||||
'party.details.suffix.chains'
|
||||
)}`
|
||||
} else if (buttonCount && chainCount && chainCount > 0) {
|
||||
string += `${chainCount}${t('party.details.suffix.chains')}`
|
||||
} else if (buttonCount && !chainCount) {
|
||||
} else if (
|
||||
party.buttonCount &&
|
||||
party.chainCount &&
|
||||
party.chainCount > 0
|
||||
) {
|
||||
string += `${party.chainCount}${t('party.details.suffix.chains')}`
|
||||
} else if (party.buttonCount && !party.chainCount) {
|
||||
string += `0${t('party.details.suffix.chains')}`
|
||||
}
|
||||
|
||||
|
|
@ -277,8 +333,8 @@ const PartyHeader = (props: Props) => {
|
|||
}
|
||||
|
||||
const clearTimeToken = () => {
|
||||
const minutes = Math.floor(clearTime / 60)
|
||||
const seconds = clearTime - minutes * 60
|
||||
const minutes = Math.floor(party.clearTime / 60)
|
||||
const seconds = party.clearTime - minutes * 60
|
||||
|
||||
let string = ''
|
||||
if (minutes > 0)
|
||||
|
|
@ -296,8 +352,9 @@ const PartyHeader = (props: Props) => {
|
|||
{chargeAttackToken}
|
||||
{fullAutoToken}
|
||||
{autoGuardToken}
|
||||
{turnCount ? turnCountToken : ''}
|
||||
{clearTime > 0 ? clearTimeToken() : ''}
|
||||
{autoSummonToken}
|
||||
{party.turnCount ? turnCountToken : ''}
|
||||
{party.clearTime > 0 ? clearTimeToken() : ''}
|
||||
{buttonChainToken()}
|
||||
</section>
|
||||
)
|
||||
|
|
@ -329,7 +386,7 @@ const PartyHeader = (props: Props) => {
|
|||
leftAccessoryIcon={<RemixIcon />}
|
||||
className="Remix"
|
||||
text={t('buttons.remix')}
|
||||
onClick={props.remixCallback}
|
||||
onClick={openRemixTeamAlert}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
|
|
@ -341,8 +398,8 @@ const PartyHeader = (props: Props) => {
|
|||
<div className="PartyInfo">
|
||||
<div className="Left">
|
||||
<div className="Header">
|
||||
<h1 className={name ? '' : 'empty'}>
|
||||
{name ? name : t('no_title')}
|
||||
<h1 className={party.name ? '' : 'empty'}>
|
||||
{party.name ? party.name : t('no_title')}
|
||||
</h1>
|
||||
{party.remix && party.sourceParty ? (
|
||||
<Tooltip content={t('tooltips.source')}>
|
||||
|
|
@ -398,6 +455,21 @@ const PartyHeader = (props: Props) => {
|
|||
</div>
|
||||
<section className={classes}>{renderTokens()}</section>
|
||||
</section>
|
||||
|
||||
<RemixTeamAlert
|
||||
creator={props.editable}
|
||||
name={partySnapshot.name ? partySnapshot.name : t('no_title')}
|
||||
open={remixAlertOpen}
|
||||
onOpenChange={handleRemixTeamAlertChange}
|
||||
remixCallback={remixTeamCallback}
|
||||
/>
|
||||
|
||||
<RemixedToast
|
||||
open={remixToastOpen}
|
||||
partyName={props.party?.name || t('no_title')}
|
||||
onOpenChange={handleRemixToastOpenChanged}
|
||||
onCloseClick={handleRemixToastCloseClicked}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
.Combobox.Raid {
|
||||
box-sizing: border-box;
|
||||
min-width: 440px;
|
||||
|
||||
.Header {
|
||||
background: var(--dialog-bg);
|
||||
|
|
@ -184,6 +185,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.SelectTrigger.Raid .Value.Empty {
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.Filters .SelectTrigger.Raid {
|
||||
& > span {
|
||||
overflow: hidden;
|
||||
|
|
|
|||
|
|
@ -105,19 +105,25 @@ const RaidCombobox = (props: Props) => {
|
|||
|
||||
// Set current raid and section when the component mounts
|
||||
useEffect(() => {
|
||||
if (appState.party.raid) {
|
||||
setCurrentRaid(appState.party.raid)
|
||||
setCurrentSection(appState.party.raid.group.section)
|
||||
} else if (props.showAllRaidsOption && !currentRaid) {
|
||||
setCurrentRaid(allRaidsOption)
|
||||
}
|
||||
// if (appState.party.raid) {
|
||||
// setCurrentRaid(appState.party.raid)
|
||||
// if (appState.party.raid.group.section > 0) {
|
||||
// setCurrentSection(appState.party.raid.group.section)
|
||||
// } else {
|
||||
// setCurrentSection(1)
|
||||
// }
|
||||
// } else if (props.showAllRaidsOption && !currentRaid) {
|
||||
// setCurrentRaid(allRaidsOption)
|
||||
// }
|
||||
}, [])
|
||||
|
||||
// Set current raid and section when the current raid changes
|
||||
useEffect(() => {
|
||||
if (props.currentRaid) {
|
||||
setCurrentRaid(props.currentRaid)
|
||||
setCurrentSection(props.currentRaid.group.section)
|
||||
if (appState.party.raid && appState.party.raid.group.section > 0)
|
||||
setCurrentSection(props.currentRaid.group.section)
|
||||
else setCurrentSection(1)
|
||||
}
|
||||
}, [props.currentRaid])
|
||||
|
||||
|
|
@ -260,7 +266,11 @@ const RaidCombobox = (props: Props) => {
|
|||
// Toggle the open state of the combobox
|
||||
function toggleOpen() {
|
||||
if (open) {
|
||||
if (currentRaid && currentRaid.slug !== 'all') {
|
||||
if (
|
||||
currentRaid &&
|
||||
currentRaid.slug !== 'all' &&
|
||||
currentRaid.group.section > 0
|
||||
) {
|
||||
setCurrentSection(currentRaid.group.section)
|
||||
}
|
||||
setScrolled(false)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import Toast from '~components/common/Toast'
|
||||
import { Trans, useTranslation } from 'next-i18next'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props {
|
||||
partyName: string
|
||||
open: boolean
|
||||
|
|
@ -19,7 +17,9 @@ const RemixedToast = ({
|
|||
onCloseClick,
|
||||
}: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
useEffect(() => {
|
||||
console.log(partyName)
|
||||
}, [])
|
||||
// Methods: Event handlers
|
||||
function handleOpenChange() {
|
||||
onOpenChange(open)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import React from 'react'
|
||||
import Toast from '~components/common/Toast'
|
||||
|
||||
import './index.scss'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
interface Props {
|
||||
|
|
|
|||
|
|
@ -394,12 +394,14 @@ const WeaponModal = ({
|
|||
{gridWeapon.object.awakenings ? awakeningSelect() : ''}
|
||||
</div>
|
||||
<div className="DialogFooter" ref={footerRef}>
|
||||
<Button
|
||||
contained={true}
|
||||
onClick={updateWeapon}
|
||||
disabled={!formValid}
|
||||
text={t('modals.weapon.buttons.confirm')}
|
||||
/>
|
||||
<div className="actions">
|
||||
<Button
|
||||
contained={true}
|
||||
onClick={updateWeapon}
|
||||
disabled={!formValid}
|
||||
text={t('modals.weapon.buttons.confirm')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
"unauthorized": "You don't have permission to perform that action"
|
||||
},
|
||||
"filters": {
|
||||
"name": "Filter",
|
||||
"labels": {
|
||||
"element": "Element",
|
||||
"series": "Series",
|
||||
|
|
@ -383,6 +384,7 @@
|
|||
"charge_attack": "Charge Attack",
|
||||
"full_auto": "Full Auto",
|
||||
"auto_guard": "Auto Guard",
|
||||
"auto_summon": "Auto Summon",
|
||||
"turn_count": "Turn count",
|
||||
"button_chain": "Buttons/Chains",
|
||||
"clear_time": "Clear time"
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
"unauthorized": "行ったアクションを実行する権限がありません"
|
||||
},
|
||||
"filters": {
|
||||
"name": "フィルター",
|
||||
"labels": {
|
||||
"element": "属性",
|
||||
"series": "シリーズ",
|
||||
|
|
@ -380,6 +381,7 @@
|
|||
"charge_attack": "奥義",
|
||||
"full_auto": "フルオート",
|
||||
"auto_guard": "オートガード",
|
||||
"auto_summon": "オート召喚",
|
||||
"turn_count": "経過ターン",
|
||||
"button_chain": "ポチチェイン",
|
||||
"clear_time": "討伐時間"
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ interface AppState {
|
|||
element: number
|
||||
fullAuto: boolean
|
||||
autoGuard: boolean
|
||||
autoSummon: boolean
|
||||
chargeAttack: boolean
|
||||
clearTime: number
|
||||
buttonCount?: number
|
||||
|
|
@ -110,6 +111,7 @@ export const initialAppState: AppState = {
|
|||
raid: undefined,
|
||||
fullAuto: false,
|
||||
autoGuard: false,
|
||||
autoSummon: false,
|
||||
chargeAttack: true,
|
||||
clearTime: 0,
|
||||
buttonCount: undefined,
|
||||
|
|
|
|||
Loading…
Reference in a new issue