commit
f5dd8372e2
18 changed files with 372 additions and 164 deletions
|
|
@ -1,121 +0,0 @@
|
|||
import React from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import clonedeep from 'lodash.clonedeep'
|
||||
import * as Scroll from 'react-scroll'
|
||||
|
||||
import * as AlertDialog from '@radix-ui/react-alert-dialog'
|
||||
|
||||
import Header from '~components/Header'
|
||||
import Button from '~components/Button'
|
||||
|
||||
import api from '~utils/api'
|
||||
import { appState, initialAppState } from '~utils/appState'
|
||||
|
||||
import CrossIcon from '~public/icons/Cross.svg'
|
||||
|
||||
const BottomHeader = () => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
const app = useSnapshot(appState)
|
||||
|
||||
const router = useRouter()
|
||||
const scroll = Scroll.animateScroll;
|
||||
|
||||
// Cookies
|
||||
const [cookies] = useCookies(['account'])
|
||||
const headers = (cookies.account != null) ? {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
}
|
||||
} : {}
|
||||
|
||||
function toggleDetails() {
|
||||
appState.party.detailsVisible = !appState.party.detailsVisible
|
||||
|
||||
if (appState.party.detailsVisible)
|
||||
scroll.scrollToBottom()
|
||||
else
|
||||
scroll.scrollToTop()
|
||||
}
|
||||
|
||||
function deleteTeam(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
|
||||
if (appState.party.editable && appState.party.id) {
|
||||
api.endpoints.parties.destroy({ id: appState.party.id, params: headers })
|
||||
.then(() => {
|
||||
// Push to route
|
||||
router.push('/')
|
||||
|
||||
// Clean state
|
||||
const resetState = clonedeep(initialAppState)
|
||||
Object.keys(resetState).forEach((key) => {
|
||||
appState[key] = resetState[key]
|
||||
})
|
||||
|
||||
// Set party to be editable
|
||||
appState.party.editable = true
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const leftNav = () => {
|
||||
if (router.pathname === '/p/[party]' || router.pathname === '/new') {
|
||||
if (app.party.detailsVisible) {
|
||||
return (<Button icon="edit" active={true} onClick={toggleDetails}>{t('buttons.hide_info')}</Button>)
|
||||
} else {
|
||||
return (<Button icon="edit" onClick={toggleDetails}>{t('buttons.show_info')}</Button>)
|
||||
}
|
||||
} else {
|
||||
return (<div />)
|
||||
}
|
||||
}
|
||||
|
||||
const rightNav = () => {
|
||||
if (app.party.editable && router.route === '/p/[party]') {
|
||||
return (
|
||||
<AlertDialog.Root>
|
||||
<AlertDialog.Trigger className="Button destructive">
|
||||
<span className='icon'>
|
||||
<CrossIcon />
|
||||
</span>
|
||||
<span className="text">{t('buttons.delete')}</span>
|
||||
</AlertDialog.Trigger>
|
||||
<AlertDialog.Portal>
|
||||
<AlertDialog.Overlay className="Overlay" />
|
||||
<AlertDialog.Content className="Dialog">
|
||||
<AlertDialog.Title className="DialogTitle">
|
||||
{t('modals.delete_team.title')}
|
||||
</AlertDialog.Title>
|
||||
<AlertDialog.Description className="DialogDescription">
|
||||
{t('modals.delete_team.description')}
|
||||
</AlertDialog.Description>
|
||||
<div className="actions">
|
||||
<AlertDialog.Cancel className="Button modal">{t('modals.delete_team.buttons.cancel')}</AlertDialog.Cancel>
|
||||
<AlertDialog.Action className="Button modal destructive" onClick={(e) => deleteTeam(e)}>{t('modals.delete_team.buttons.confirm')}</AlertDialog.Action>
|
||||
</div>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Portal>
|
||||
</AlertDialog.Root>
|
||||
)
|
||||
} else {
|
||||
return (<div />)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Header
|
||||
position="bottom"
|
||||
left={ leftNav() }
|
||||
right={ rightNav() }
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default BottomHeader
|
||||
|
|
@ -82,6 +82,12 @@
|
|||
width: 12px;
|
||||
}
|
||||
|
||||
&.check svg {
|
||||
margin-top: 1px;
|
||||
height: 14px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&.stroke svg {
|
||||
fill: none;
|
||||
stroke: $grey-50;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import classNames from 'classnames'
|
|||
import Link from 'next/link'
|
||||
|
||||
import AddIcon from '~public/icons/Add.svg'
|
||||
import CheckIcon from '~public/icons/LargeCheck.svg'
|
||||
import CrossIcon from '~public/icons/Cross.svg'
|
||||
import EditIcon from '~public/icons/Edit.svg'
|
||||
import LinkIcon from '~public/icons/Link.svg'
|
||||
|
|
@ -65,6 +66,12 @@ const Button = (props: Props) => {
|
|||
</span>
|
||||
)
|
||||
|
||||
const checkIcon = (
|
||||
<span className='icon check'>
|
||||
<CheckIcon />
|
||||
</span>
|
||||
)
|
||||
|
||||
const crossIcon = (
|
||||
<span className='icon'>
|
||||
<CrossIcon />
|
||||
|
|
@ -96,6 +103,7 @@ const Button = (props: Props) => {
|
|||
case 'new': icon = addIcon; break
|
||||
case 'menu': icon = menuIcon; break
|
||||
case 'link': icon = linkIcon; break
|
||||
case 'check': icon = checkIcon; break
|
||||
case 'cross': icon = crossIcon; break
|
||||
case 'edit': icon = editIcon; break
|
||||
case 'save': icon = saveIcon; break
|
||||
|
|
|
|||
|
|
@ -86,7 +86,9 @@ const CharacterGrid = (props: Props) => {
|
|||
appState.party.id = party.id
|
||||
appState.party.user = party.user
|
||||
appState.party.favorited = party.favorited
|
||||
|
||||
appState.party.created_at = party.created_at
|
||||
appState.party.updated_at = party.updated_at
|
||||
|
||||
setFound(true)
|
||||
setLoading(false)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc($unit / 2);
|
||||
min-height: 320px;
|
||||
max-width: 200px;
|
||||
margin-bottom: $unit * 4;
|
||||
|
||||
&.editable .CharacterImage:hover {
|
||||
border: $hover-stroke;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import type { ReactElement } from 'react'
|
||||
import TopHeader from '~components/TopHeader'
|
||||
import BottomHeader from '~components/BottomHeader'
|
||||
|
||||
interface Props {
|
||||
children: ReactElement
|
||||
|
|
@ -11,7 +10,6 @@ const Layout = ({children}: Props) => {
|
|||
<>
|
||||
<TopHeader />
|
||||
<main>{children}</main>
|
||||
<BottomHeader />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#Party {
|
||||
margin-bottom: $unit * 4;
|
||||
}
|
||||
#Party .Extra {
|
||||
color: #888;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import clonedeep from 'lodash.clonedeep'
|
||||
|
|
@ -32,6 +33,9 @@ const Party = (props: Props) => {
|
|||
} : {}
|
||||
}, [cookies.account])
|
||||
|
||||
// Set up router
|
||||
const router = useRouter()
|
||||
|
||||
// Set up states
|
||||
const { party } = useSnapshot(appState)
|
||||
const [currentTab, setCurrentTab] = useState<GridType>(GridType.Weapon)
|
||||
|
|
@ -81,10 +85,34 @@ const Party = (props: Props) => {
|
|||
appState.party.name = name
|
||||
appState.party.description = description
|
||||
appState.party.raid = raid
|
||||
appState.party.updated_at = party.updated_at
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Deleting the party
|
||||
function deleteTeam(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
|
||||
if (appState.party.editable && appState.party.id) {
|
||||
api.endpoints.parties.destroy({ id: appState.party.id, params: headers })
|
||||
.then(() => {
|
||||
// Push to route
|
||||
router.push('/')
|
||||
|
||||
// Clean state
|
||||
const resetState = clonedeep(initialAppState)
|
||||
Object.keys(resetState).forEach((key) => {
|
||||
appState[key] = resetState[key]
|
||||
})
|
||||
|
||||
// Set party to be editable
|
||||
appState.party.editable = true
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Methods: Navigating with segmented control
|
||||
function segmentClicked(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
switch(event.target.value) {
|
||||
|
|
@ -110,6 +138,8 @@ const Party = (props: Props) => {
|
|||
appState.party.id = response.data.party.id
|
||||
appState.party.user = response.data.party.user
|
||||
appState.party.favorited = response.data.party.favorited
|
||||
appState.party.created_at = response.data.party.created_at
|
||||
appState.party.updated_at = response.data.party.updated_at
|
||||
|
||||
// Store the party's user-generated details
|
||||
appState.party.name = response.data.party.name
|
||||
|
|
@ -194,6 +224,7 @@ const Party = (props: Props) => {
|
|||
{ <PartyDetails
|
||||
editable={party.editable}
|
||||
updateCallback={updateDetails}
|
||||
deleteCallback={deleteTeam}
|
||||
/>}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,22 @@
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $unit;
|
||||
|
||||
.left {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ReadOnly {
|
||||
|
|
@ -45,26 +61,8 @@
|
|||
top: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $font-xlarge;
|
||||
font-weight: $normal;
|
||||
text-align: left;
|
||||
margin-bottom: $unit;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $blue;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.Raid {
|
||||
color: $grey-50;
|
||||
font-size: $font-regular;
|
||||
font-weight: $medium;
|
||||
margin-bottom: $unit * 2;
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p {
|
||||
|
|
@ -72,5 +70,84 @@
|
|||
line-height: $font-regular * 1.2;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
font-size: $font-xlarge;
|
||||
font-weight: $normal;
|
||||
text-align: left;
|
||||
margin-bottom: $unit;
|
||||
}
|
||||
|
||||
.info {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $unit;
|
||||
margin-bottom: $unit * 2;
|
||||
|
||||
.left {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.attribution {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
& > div {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
font-size: $font-small;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
time {
|
||||
font-size: $font-small;
|
||||
}
|
||||
|
||||
& > *:not(:last-child):after {
|
||||
content: " · ";
|
||||
margin: 0 calc($unit / 2);
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
gap: calc($unit / 2);
|
||||
margin-top: 1px;
|
||||
|
||||
img, .no-user {
|
||||
$diameter: 24px;
|
||||
|
||||
border-radius: calc($diameter / 2);
|
||||
height: $diameter;
|
||||
width: $diameter;
|
||||
}
|
||||
|
||||
img.gran {
|
||||
background-color: #CEE7FE;
|
||||
}
|
||||
|
||||
img.djeeta {
|
||||
background-color: #FFE1FE;
|
||||
}
|
||||
|
||||
.no-user {
|
||||
background: $grey-80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.EmptyDetails {
|
||||
display: none;
|
||||
justify-content: center;
|
||||
margin-bottom: $unit * 10;
|
||||
|
||||
&.Visible {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,53 @@
|
|||
import React, { useState } from 'react'
|
||||
import Head from 'next/head'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import Linkify from 'react-linkify'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import * as AlertDialog from '@radix-ui/react-alert-dialog'
|
||||
import CrossIcon from '~public/icons/Cross.svg'
|
||||
|
||||
import Button from '~components/Button'
|
||||
import CharLimitedFieldset from '~components/CharLimitedFieldset'
|
||||
import RaidDropdown from '~components/RaidDropdown'
|
||||
import TextFieldset from '~components/TextFieldset'
|
||||
|
||||
import { accountState } from '~utils/accountState'
|
||||
import { appState } from '~utils/appState'
|
||||
|
||||
import './index.scss'
|
||||
import Link from 'next/link'
|
||||
import { formatTimeAgo } from '~utils/timeAgo'
|
||||
|
||||
const emptyRaid: Raid = {
|
||||
id: '',
|
||||
name: {
|
||||
en: '',
|
||||
ja: ''
|
||||
},
|
||||
slug: '',
|
||||
level: 0,
|
||||
group: 0,
|
||||
element: 0
|
||||
}
|
||||
|
||||
// Props
|
||||
interface Props {
|
||||
editable: boolean
|
||||
updateCallback: (name?: string, description?: string, raid?: Raid) => void
|
||||
deleteCallback: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
|
||||
}
|
||||
|
||||
const PartyDetails = (props: Props) => {
|
||||
const { party, raids } = useSnapshot(appState)
|
||||
const { account } = useSnapshot(accountState)
|
||||
|
||||
const { t } = useTranslation('common')
|
||||
const router = useRouter()
|
||||
const locale = router.locale || 'en'
|
||||
|
||||
const nameInput = React.createRef<HTMLInputElement>()
|
||||
const descriptionInput = React.createRef<HTMLTextAreaElement>()
|
||||
|
|
@ -39,6 +65,25 @@ const PartyDetails = (props: Props) => {
|
|||
'Visible': party.detailsVisible
|
||||
})
|
||||
|
||||
const emptyClasses = classNames({
|
||||
'EmptyDetails': true,
|
||||
'Visible': !party.detailsVisible
|
||||
})
|
||||
|
||||
const userClass = classNames({
|
||||
'user': true,
|
||||
'empty': !party.user
|
||||
})
|
||||
|
||||
const linkClass = classNames({
|
||||
'wind': party && party.element == 1,
|
||||
'fire': party && party.element == 2,
|
||||
'water': party && party.element == 3,
|
||||
'earth': party && party.element == 4,
|
||||
'dark': party && party.element == 5,
|
||||
'light': party && party.element == 6
|
||||
})
|
||||
|
||||
const [errors, setErrors] = useState<{ [key: string]: string }>({
|
||||
name: '',
|
||||
description: ''
|
||||
|
|
@ -62,12 +107,100 @@ const PartyDetails = (props: Props) => {
|
|||
setErrors(newErrors)
|
||||
}
|
||||
|
||||
function updateDetails(event: React.ChangeEvent) {
|
||||
function toggleDetails() {
|
||||
appState.party.detailsVisible = !appState.party.detailsVisible
|
||||
|
||||
// if (appState.party.detailsVisible)
|
||||
// scroll.scrollToBottom()
|
||||
// else
|
||||
// scroll.scrollToTop()
|
||||
}
|
||||
|
||||
function updateDetails(event: React.MouseEvent) {
|
||||
const nameValue = nameInput.current?.value
|
||||
const descriptionValue = descriptionInput.current?.value
|
||||
const raid = raids.find(raid => raid.slug === raidSelect.current?.value)
|
||||
|
||||
props.updateCallback(nameValue, descriptionValue, raid)
|
||||
toggleDetails()
|
||||
}
|
||||
|
||||
const userImage = () => {
|
||||
if (party.user)
|
||||
return (
|
||||
<img
|
||||
alt={party.user.picture.picture}
|
||||
className={`profile ${party.user.picture.element}`}
|
||||
srcSet={`/profile/${party.user.picture.picture}.png,
|
||||
/profile/${party.user.picture.picture}@2x.png 2x`}
|
||||
src={`/profile/${party.user.picture.picture}.png`}
|
||||
/>
|
||||
)
|
||||
else
|
||||
return (<div className="no-user" />)
|
||||
}
|
||||
|
||||
const userBlock = () => {
|
||||
return (
|
||||
<div className={userClass}>
|
||||
{ userImage() }
|
||||
{ (party.user) ? party.user.username : t('no_user') }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const linkedUserBlock = (user: User) => {
|
||||
return (
|
||||
<div>
|
||||
<Link href={`/${user.username}`} passHref>
|
||||
<a className={linkClass}>{userBlock()}</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const linkedRaidBlock = (raid: Raid) => {
|
||||
return (
|
||||
<div>
|
||||
<Link href={`/teams?raid=${raid.slug}`} passHref>
|
||||
<a className={`Raid ${linkClass}`}>
|
||||
{raid.name[locale]}
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const deleteButton = () => {
|
||||
if (party.editable) {
|
||||
return (
|
||||
<AlertDialog.Root>
|
||||
<AlertDialog.Trigger className="Button destructive">
|
||||
<span className='icon'>
|
||||
<CrossIcon />
|
||||
</span>
|
||||
<span className="text">{t('buttons.delete')}</span>
|
||||
</AlertDialog.Trigger>
|
||||
<AlertDialog.Portal>
|
||||
<AlertDialog.Overlay className="Overlay" />
|
||||
<AlertDialog.Content className="Dialog">
|
||||
<AlertDialog.Title className="DialogTitle">
|
||||
{t('modals.delete_team.title')}
|
||||
</AlertDialog.Title>
|
||||
<AlertDialog.Description className="DialogDescription">
|
||||
{t('modals.delete_team.description')}
|
||||
</AlertDialog.Description>
|
||||
<div className="actions">
|
||||
<AlertDialog.Cancel className="Button modal">{t('modals.delete_team.buttons.cancel')}</AlertDialog.Cancel>
|
||||
<AlertDialog.Action className="Button modal destructive" onClick={(e) => props.deleteCallback(e)}>{t('modals.delete_team.buttons.confirm')}</AlertDialog.Action>
|
||||
</div>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Portal>
|
||||
</AlertDialog.Root>
|
||||
)
|
||||
} else {
|
||||
return ('')
|
||||
}
|
||||
}
|
||||
|
||||
const editable = (
|
||||
|
|
@ -77,7 +210,6 @@ const PartyDetails = (props: Props) => {
|
|||
placeholder="Name your team"
|
||||
value={party.name}
|
||||
limit={50}
|
||||
onBlur={updateDetails}
|
||||
onChange={handleInputChange}
|
||||
error={errors.name}
|
||||
ref={nameInput}
|
||||
|
|
@ -85,29 +217,72 @@ const PartyDetails = (props: Props) => {
|
|||
<RaidDropdown
|
||||
showAllRaidsOption={false}
|
||||
currentRaid={party.raid?.slug || ''}
|
||||
onBlur={updateDetails}
|
||||
ref={raidSelect}
|
||||
/>
|
||||
<TextFieldset
|
||||
fieldName="name"
|
||||
placeholder={"Write your notes here\n\n\nWatch out for the 50% trigger!\nMake sure to click Fediel’s 1 first\nGood luck with RNG!"}
|
||||
value={party.description}
|
||||
onBlur={updateDetails}
|
||||
onChange={handleTextAreaChange}
|
||||
error={errors.description}
|
||||
ref={descriptionInput}
|
||||
/>
|
||||
|
||||
<div className="bottom">
|
||||
<div className="left">
|
||||
{ (router.pathname !== '/new') ? deleteButton() : '' }
|
||||
</div>
|
||||
<div className="right">
|
||||
<Button
|
||||
active={true}
|
||||
onClick={toggleDetails}>
|
||||
{t('buttons.cancel')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
active={true}
|
||||
icon="check"
|
||||
onClick={updateDetails}>
|
||||
{t('buttons.save_info')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
|
||||
const readOnly = (
|
||||
<section className={readOnlyClasses}>
|
||||
{ (party.name) ? <h1>{party.name}</h1> : '' }
|
||||
{ (party.raid) ? <div className="Raid">{party.raid.name.en}</div> : '' }
|
||||
<div className="info">
|
||||
<div className="left">
|
||||
{ (party.name) ? <h1>{party.name}</h1> : '' }
|
||||
<div className="attribution">
|
||||
{ (party.user) ? linkedUserBlock(party.user) : userBlock() }
|
||||
{ (party.raid) ? linkedRaidBlock(party.raid) : '' }
|
||||
{ (party.created_at != undefined)
|
||||
? <time
|
||||
className="last-updated"
|
||||
dateTime={new Date(party.created_at).toString()}>
|
||||
{formatTimeAgo(new Date(party.created_at), locale)}
|
||||
</time>
|
||||
: '' }
|
||||
</div>
|
||||
</div>
|
||||
<div className="right">
|
||||
{ (party.editable)
|
||||
? <Button active={true} icon="edit" onClick={toggleDetails}>{t('buttons.show_info')}</Button>
|
||||
: <div /> }
|
||||
</div>
|
||||
</div>
|
||||
{ (party.description) ? <p><Linkify>{party.description}</Linkify></p> : '' }
|
||||
</section>
|
||||
)
|
||||
|
||||
const emptyDetails = (
|
||||
<div className={emptyClasses}>
|
||||
<Button active={true} icon="edit" onClick={toggleDetails}>{t('buttons.show_info')}</Button>
|
||||
</div>
|
||||
)
|
||||
|
||||
const generateTitle = () => {
|
||||
let title = ''
|
||||
|
||||
|
|
@ -138,7 +313,7 @@ const PartyDetails = (props: Props) => {
|
|||
<meta name="twitter:title" content={generateTitle()} />
|
||||
<meta name="twitter:description" content={ (party.description) ? party.description : '' } />
|
||||
</Head>
|
||||
{readOnly}
|
||||
{ (editable && (party.name || party.description || party.raid)) ? readOnly : emptyDetails}
|
||||
{editable}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ const SummonGrid = (props: Props) => {
|
|||
appState.party.id = party.id
|
||||
appState.party.user = party.user
|
||||
appState.party.favorited = party.favorited
|
||||
|
||||
appState.party.created_at = party.created_at
|
||||
appState.party.updated_at = party.updated_at
|
||||
|
||||
setFound(true)
|
||||
setLoading(false)
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ const WeaponGrid = (props: Props) => {
|
|||
appState.party.extra = party.extra
|
||||
appState.party.user = party.user
|
||||
appState.party.favorited = party.favorited
|
||||
appState.party.created_at = party.created_at
|
||||
appState.party.updated_at = party.updated_at
|
||||
|
||||
setFound(true)
|
||||
setLoading(false)
|
||||
|
|
|
|||
3
public/icons/LargeCheck.svg
Normal file
3
public/icons/LargeCheck.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8858 5.35355C12.0811 5.15829 12.0811 4.84171 11.8858 4.64645C11.6906 4.45118 11.374 4.45118 11.1787 4.64645L5.08066 10.7445L2.85355 8.51741C2.65829 8.32215 2.34171 8.32215 2.14645 8.51741C1.95118 8.71268 1.95118 9.02926 2.14645 9.22452L4.72709 11.8052C4.82473 11.9028 4.9527 11.9516 5.08066 11.9516C5.1119 11.9516 5.14314 11.9487 5.17394 11.9429C5.2693 11.9249 5.36042 11.879 5.43422 11.8052L11.8858 5.35355Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 569 B |
|
|
@ -9,10 +9,12 @@
|
|||
}
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "Cancel",
|
||||
"copy": "Copy link",
|
||||
"delete": "Delete team",
|
||||
"show_info": "Edit info",
|
||||
"hide_info": "Hide info",
|
||||
"save_info": "Save info",
|
||||
"menu": "Menu",
|
||||
"new": "New",
|
||||
"wiki": "View more on gbf.wiki"
|
||||
|
|
|
|||
|
|
@ -9,9 +9,11 @@
|
|||
}
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "キャンセルs",
|
||||
"copy": "リンクをコピー",
|
||||
"delete": "編成を削除",
|
||||
"show_info": "詳細を編集",
|
||||
"save_info": "詳細を保存",
|
||||
"hide_info": "詳細を非表示",
|
||||
"menu": "メニュー",
|
||||
"new": "作成",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,30 @@ main {
|
|||
|
||||
a {
|
||||
text-decoration: none;
|
||||
|
||||
&.wind {
|
||||
color: $wind-text-dark;
|
||||
}
|
||||
|
||||
&.fire {
|
||||
color: $fire-text-dark;
|
||||
}
|
||||
|
||||
&.water {
|
||||
color: $water-text-dark;
|
||||
}
|
||||
|
||||
&.earth {
|
||||
color: $earth-text-dark;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
color: $dark-text-dark;
|
||||
}
|
||||
|
||||
&.light {
|
||||
color: $light-text-dark;
|
||||
}
|
||||
}
|
||||
|
||||
button, input {
|
||||
|
|
|
|||
6
types/WeaponGridProps.d.ts
vendored
6
types/WeaponGridProps.d.ts
vendored
|
|
@ -1,6 +0,0 @@
|
|||
interface WeaponGridProps {
|
||||
onReceiveData: (Weapon, number) => void
|
||||
weapon: Weapon | undefined
|
||||
position: number
|
||||
editable: boolean
|
||||
}
|
||||
|
|
@ -13,7 +13,9 @@ interface AppState {
|
|||
element: number,
|
||||
extra: boolean,
|
||||
user: User | undefined,
|
||||
favorited: boolean
|
||||
favorited: boolean,
|
||||
created_at: string
|
||||
updated_at: string
|
||||
},
|
||||
grid: {
|
||||
weapons: {
|
||||
|
|
@ -48,7 +50,9 @@ export const initialAppState: AppState = {
|
|||
element: 0,
|
||||
extra: false,
|
||||
user: undefined,
|
||||
favorited: false
|
||||
favorited: false,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
},
|
||||
grid: {
|
||||
weapons: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue