diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..2cd2adde --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +utils/api.tsx diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..2a6e6ac0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "tabWidth": 2, + "singleQuote": true +} diff --git a/components/AboutModal/index.scss b/components/AboutModal/index.scss index 32f12aad..abab57b5 100644 --- a/components/AboutModal/index.scss +++ b/components/AboutModal/index.scss @@ -1,21 +1,21 @@ .About.Dialog { - width: $unit * 60; + width: $unit * 60; - section { - margin-bottom: $unit; + section { + margin-bottom: $unit; - h2 { - margin-bottom: $unit * 3; - } + h2 { + margin-bottom: $unit * 3; } + } - .DialogDescription { - font-size: $font-regular; - line-height: 1.24; - margin-bottom: $unit; + .DialogDescription { + font-size: $font-regular; + line-height: 1.24; + margin-bottom: $unit; - &:last-of-type { - margin-bottom: 0; - } + &:last-of-type { + margin-bottom: 0; } + } } diff --git a/components/AboutModal/index.tsx b/components/AboutModal/index.tsx index 501f0122..001b42d7 100644 --- a/components/AboutModal/index.tsx +++ b/components/AboutModal/index.tsx @@ -6,56 +6,68 @@ import CrossIcon from '~public/icons/Cross.svg' import './index.scss' const AboutModal = () => { - const { t } = useTranslation('common') + const { t } = useTranslation('common') - return ( - - -
  • - {t('modals.about.title')} -
  • -
    - - event.preventDefault() }> -
    - {t('menu.about')} - - - - - -
    + return ( + + +
  • + {t('modals.about.title')} +
  • +
    + + event.preventDefault()} + > +
    + + {t('menu.about')} + + + + + + +
    -
    - - Granblue.team is a tool to save and share team compositions for Granblue Fantasy. - - - Start adding things to a team and a URL will be created for you to share it wherever you like, no account needed. - - - You can make an account to save any teams you find for future reference, or to keep all of your teams together in one place. - -
    +
    + + Granblue.team is a tool to save and share team compositions for{' '} + Granblue Fantasy. + + + Start adding things to a team and a URL will be created for you to + share it wherever you like, no account needed. + + + You can make an account to save any teams you find for future + reference, or to keep all of your teams together in one place. + +
    -
    - Credits - - Granblue.team was built by @jedmund with a lot of help from @lalalalinna and @tarngerine. - -
    +
    + Credits + + Granblue.team was built by{' '} + @jedmund with a lot of + help from{' '} + @lalalalinna and{' '} + @tarngerine. + +
    -
    - Open Source - - This app is open source. You can contribute on Github. - -
    -
    - -
    -
    - ) +
    + Open Source + + This app is open source. You can contribute on Github. + +
    +
    + +
    +
    + ) } -export default AboutModal \ No newline at end of file +export default AboutModal diff --git a/components/AccountModal/index.scss b/components/AccountModal/index.scss index 497e316e..4c3f258b 100644 --- a/components/AccountModal/index.scss +++ b/components/AccountModal/index.scss @@ -1,164 +1,142 @@ .Account.Dialog { + display: flex; + flex-direction: column; + gap: $unit * 2; + width: $unit * 60; + + form { display: flex; flex-direction: column; gap: $unit * 2; - width: $unit * 60; - form { + .Switch { + $height: 34px; + background: $grey-70; + border-radius: calc($height / 2); + border: none; + position: relative; + width: 58px; + height: $height; + + &:focus { + box-shadow: 0 0 0 2px $grey-15; + } + + &[data-state='checked'] { + background: $grey-15; + } + } + + .Thumb { + background: $grey-100; + border-radius: 13px; + display: block; + height: 26px; + width: 26px; + transition: transform 100ms; + transform: translateX(-1px); + + &:hover { + cursor: pointer; + } + + &[data-state='checked'] { + background: $grey-100; + transform: translateX(21px); + } + } + + .field { + align-items: center; + display: flex; + flex-direction: row; + gap: $unit * 2; + + select { + background: no-repeat url('/icons/ArrowDark.svg'), $grey-90; + background-position-y: center; + background-position-x: 95%; + margin: 0; + width: 240px; + } + + .left { display: flex; flex-direction: column; - gap: $unit * 2; + flex-grow: 1; + gap: calc($unit / 2); - .Switch { - $height: 34px; - background: $grey-70; - border-radius: calc($height / 2); - border: none; - position: relative; - width: 58px; - height: $height; - - &:focus { - box-shadow: 0 0 0 2px $grey-00; - } - - &[data-state="checked"] { - background: $grey-00; - } + label { + color: var(--text-secondary); + font-size: $font-regular; } - .Thumb { - background: white; - border-radius: 13px; - display: block; - height: 26px; - width: 26px; - transition: transform 100ms; - transform: translateX(-1px); + p { + color: var(--text-secondary); + font-size: $font-small; + line-height: 1.1; + max-width: 300px; - &:hover { - cursor: pointer; - } + &.jp { + max-width: 270px; + } + } + } - &[data-state="checked"] { - background: white; - transform: translateX(21px); - } + .preview { + $diameter: 48px; + background-color: $grey-90; + border-radius: 999px; + height: $diameter; + width: $diameter; + + img { + height: $diameter; + width: $diameter; } - .Button { - font-size: $font-regular; - padding: ($unit * 1.5) ($unit * 2); - margin-top: $unit * 2; - width: 100%; - - &.btn-disabled { - background: $grey-90; - color: $grey-70; - cursor: not-allowed; - } - - &:not(.btn-disabled) { - background: $grey-90; - color: $grey-40; - - &:hover { - background: $grey-80; - } - } + &.fire { + background: $fire-bg-20; } - .field { - align-items: center; - display: flex; - flex-direction: row; - gap: $unit * 2; - - select { - background: no-repeat url('/icons/ArrowDark.svg'), $grey-90; - background-position-y: center; - background-position-x: 95%; - margin: 0; - width: 240px; - } - - .left { - display: flex; - flex-direction: column; - flex-grow: 1; - gap: calc($unit / 2); - - label { - color: $grey-00; - font-size: $font-regular; - } - - p { - color: $grey-60; - font-size: $font-small; - line-height: 1.1; - max-width: 300px; - - &.jp { - max-width: 270px; - } - } - } - - .preview { - $diameter: 48px; - background-color: $grey-90; - border-radius: 999px; - height: $diameter; - width: $diameter; - - img { - height: $diameter; - width: $diameter; - } - - &.fire { - background: $fire-bg-light; - } - - &.water { - background: $water-bg-light; - } - - &.wind { - background: $wind-bg-light; - } - - &.earth { - background: $earth-bg-light; - } - - &.dark { - background: $dark-bg-light; - } - - &.light { - background: $light-bg-light; - } - } + &.water { + background: $water-bg-20; } - section { - margin-bottom: $unit; - - h2 { - margin-bottom: $unit * 3; - } + &.wind { + background: $wind-bg-20; } + + &.earth { + background: $earth-bg-20; + } + + &.dark { + background: $dark-bg-10; + } + + &.light { + background: $light-bg-20; + } + } } - .DialogDescription { - font-size: $font-regular; - line-height: 1.24; - margin-bottom: $unit; + section { + margin-bottom: $unit; - &:last-of-type { - margin-bottom: 0; - } + h2 { + margin-bottom: $unit * 3; + } } + } + + .DialogDescription { + font-size: $font-regular; + line-height: 1.24; + margin-bottom: $unit; + + &:last-of-type { + margin-bottom: 0; + } + } } diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx index 6b081b20..13c18f17 100644 --- a/components/AccountModal/index.tsx +++ b/components/AccountModal/index.tsx @@ -1,31 +1,31 @@ -import React, { useEffect, useState } from "react" -import { getCookie } from "cookies-next" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" -import { useTranslation } from "next-i18next" +import React, { useEffect, useState } from 'react' +import { getCookie } from 'cookies-next' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' -import * as Dialog from "@radix-ui/react-dialog" -import * as Switch from "@radix-ui/react-switch" +import * as Dialog from '@radix-ui/react-dialog' +import * as Switch from '@radix-ui/react-switch' -import api from "~utils/api" -import { accountState } from "~utils/accountState" -import { pictureData } from "~utils/pictureData" +import api from '~utils/api' +import { accountState } from '~utils/accountState' +import { pictureData } from '~utils/pictureData' -import Button from "~components/Button" +import Button from '~components/Button' -import CrossIcon from "~public/icons/Cross.svg" -import "./index.scss" +import CrossIcon from '~public/icons/Cross.svg' +import './index.scss' const AccountModal = () => { const { account } = useSnapshot(accountState) const router = useRouter() - const { t } = useTranslation("common") + const { t } = useTranslation('common') const locale = - router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' // Cookies - const cookie = getCookie("account") + const cookie = getCookie('account') const headers = {} // cookies.account != null @@ -38,8 +38,8 @@ const AccountModal = () => { // State const [open, setOpen] = useState(false) - const [picture, setPicture] = useState("") - const [language, setLanguage] = useState("") + const [picture, setPicture] = useState('') + const [language, setLanguage] = useState('') const [gender, setGender] = useState(0) const [privateProfile, setPrivateProfile] = useState(false) @@ -136,7 +136,7 @@ const AccountModal = () => {
  • - {t("menu.settings")} + {t('menu.settings')}
  • @@ -147,7 +147,7 @@ const AccountModal = () => {
    - {t("modals.settings.title")} + {t('modals.settings.title')} @{account.user?.username} @@ -163,7 +163,7 @@ const AccountModal = () => {
    - +
    {
    - +
    - +
    - +

    - {t("modals.settings.descriptions.private")} + {t('modals.settings.descriptions.private')}

    @@ -243,7 +243,10 @@ const AccountModal = () => {
    - + - ) +const defaultProps = { + active: false, + blended: false, + contained: false, + size: 'medium', } -export default Button \ No newline at end of file +const Button = React.forwardRef(function button( + { accessoryIcon, active, blended, contained, size, text, ...props }, + forwardedRef +) { + const classes = classNames( + { + Button: true, + Active: active, + Blended: blended, + Contained: contained, + // 'btn-pressed': pressed, + // 'btn-disabled': disabled, + // save: props.icon === 'save', + // destructive: props.type == ButtonType.Destructive, + }, + size, + props.className + ) + + const hasAccessory = () => { + if (accessoryIcon) return {accessoryIcon} + } + + const hasText = () => { + if (text) return {text} + } + + return ( + + ) + + // useEffect(() => { + // if (props.type) setButtonType(props.type) + // }, [props.type]) + + // const addIcon = ( + // + // + // + // ) + + // const menuIcon = ( + // + // + // + // ) + + // const linkIcon = ( + // + // + // + // ) + + // const checkIcon = ( + // + // + // + // ) + + // const crossIcon = ( + // + // + // + // ) + + // const editIcon = ( + // + // + // + // ) + + // const saveIcon = ( + // + // + // + // ) + + // const settingsIcon = ( + // + // + // + // ) + + // function getIcon() { + // let icon: React.ReactNode + + // switch (props.icon) { + // 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 + // case 'settings': + // icon = settingsIcon + // break + // } + + // return icon + // } + + // function handleMouseDown() { + // setPressed(true) + // } + + // function handleMouseUp() { + // setPressed(false) + // } + // return ( + // + // ) +}) + +Button.defaultProps = defaultProps + +export default Button diff --git a/components/CharLimitedFieldset/index.scss b/components/CharLimitedFieldset/index.scss index 8f81bf3b..dc9eb4a5 100644 --- a/components/CharLimitedFieldset/index.scss +++ b/components/CharLimitedFieldset/index.scss @@ -1,29 +1,34 @@ .Limited { - background: white; - border-radius: 6px; - border: 2px solid transparent; - box-sizing: border-box; - display: flex; - gap: $unit; - padding-right: $unit * 2; + $offset: 2px; - &:focus-within { - border: 2px solid $blue; - box-shadow: 0 2px rgba(255, 255, 255, 1); + background: var(--input-bg); + border-radius: $input-corner; + border: $offset solid transparent; + box-sizing: border-box; + display: flex; + gap: $unit; + padding-top: 2px; + padding-bottom: 2px; + padding-right: calc($unit-2x - $offset); + + &:focus-within { + border: $offset solid $blue; + // box-shadow: 0 2px rgba(255, 255, 255, 1); + } + + .Counter { + color: $grey-55; + font-weight: $bold; + line-height: 42px; + } + + .Input { + background: transparent; + border-radius: 0; + padding-left: calc($unit-2x - $offset); + + &:focus { + outline: none; } - - .Counter { - color: $grey-50; - font-weight: $bold; - line-height: 42px; - } - - .Input { - background: transparent; - border-radius: 0; - - &:focus { - outline: none; - } - } -} \ No newline at end of file + } +} diff --git a/components/CharLimitedFieldset/index.tsx b/components/CharLimitedFieldset/index.tsx index ff741c59..cb822299 100644 --- a/components/CharLimitedFieldset/index.tsx +++ b/components/CharLimitedFieldset/index.tsx @@ -2,53 +2,56 @@ import React, { useEffect, useState } from 'react' import './index.scss' interface Props { - fieldName: string - placeholder: string - value?: string - limit: number - error: string - onBlur?: (event: React.ChangeEvent) => void - onChange?: (event: React.ChangeEvent) => void + fieldName: string + placeholder: string + value?: string + limit: number + error: string + onBlur?: (event: React.ChangeEvent) => void + onChange?: (event: React.ChangeEvent) => void } -const CharLimitedFieldset = React.forwardRef(function useFieldSet(props, ref) { - const fieldType = (['password', 'confirm_password'].includes(props.fieldName)) ? 'password' : 'text' +const CharLimitedFieldset = React.forwardRef( + function useFieldSet(props, ref) { + const fieldType = ['password', 'confirm_password'].includes(props.fieldName) + ? 'password' + : 'text' const [currentCount, setCurrentCount] = useState(0) useEffect(() => { - setCurrentCount((props.value) ? props.limit - props.value.length : props.limit) + setCurrentCount( + props.value ? props.limit - props.value.length : props.limit + ) }, [props.limit, props.value]) function onChange(event: React.ChangeEvent) { - setCurrentCount(props.limit - event.currentTarget.value.length) - if (props.onChange) props.onChange(event) + setCurrentCount(props.limit - event.currentTarget.value.length) + if (props.onChange) props.onChange(event) } return ( -
    -
    - - {currentCount} -
    - { - props.error.length > 0 && -

    {props.error}

    - } -
    +
    +
    + + {currentCount} +
    + {props.error.length > 0 &&

    {props.error}

    } +
    ) -}) + } +) -export default CharLimitedFieldset \ No newline at end of file +export default CharLimitedFieldset diff --git a/components/CharacterConflictModal/index.scss b/components/CharacterConflictModal/index.scss index 48176c81..866ec8f7 100644 --- a/components/CharacterConflictModal/index.scss +++ b/components/CharacterConflictModal/index.scss @@ -8,7 +8,7 @@ } .arrow { - color: $grey-50; + color: $grey-55; font-size: 4rem; text-align: center; } @@ -52,7 +52,7 @@ &:not(.btn-disabled) { background: $grey-90; - color: $grey-40; + color: $grey-50; &:hover { background: $grey-80; diff --git a/components/CharacterConflictModal/index.tsx b/components/CharacterConflictModal/index.tsx index 1f1ff6c0..3d54fb32 100644 --- a/components/CharacterConflictModal/index.tsx +++ b/components/CharacterConflictModal/index.tsx @@ -1,18 +1,18 @@ -import React, { useEffect, useState } from "react" -import { setCookie } from "cookies-next" -import Router, { useRouter } from "next/router" -import { useTranslation } from "react-i18next" -import { AxiosResponse } from "axios" +import React, { useEffect, useState } from 'react' +import { setCookie } from 'cookies-next' +import Router, { useRouter } from 'next/router' +import { useTranslation } from 'react-i18next' +import { AxiosResponse } from 'axios' -import * as Dialog from "@radix-ui/react-dialog" +import * as Dialog from '@radix-ui/react-dialog' -import api from "~utils/api" -import { appState } from "~utils/appState" -import { accountState } from "~utils/accountState" +import api from '~utils/api' +import { appState } from '~utils/appState' +import { accountState } from '~utils/accountState' -import Button from "~components/Button" +import Button from '~components/Button' -import "./index.scss" +import './index.scss' interface Props { open: boolean @@ -24,7 +24,7 @@ interface Props { } const CharacterConflictModal = (props: Props) => { - const { t } = useTranslation("common") + const { t } = useTranslation('common') // States const [open, setOpen] = useState(false) @@ -35,13 +35,13 @@ const CharacterConflictModal = (props: Props) => { function imageUrl(character?: Character, uncap: number = 0) { // Change the image based on the uncap level - let suffix = "01" - if (uncap == 6) suffix = "04" - else if (uncap == 5) suffix = "03" - else if (uncap > 2) suffix = "02" + let suffix = '01' + if (uncap == 6) suffix = '04' + else if (uncap == 5) suffix = '03' + else if (uncap > 2) suffix = '02' // Special casing for Lyria (and Young Cat eventually) - if (character?.granblue_id === "3030182000") { + if (character?.granblue_id === '3030182000') { let element = 1 if ( appState.grid.weapons.mainWeapon && diff --git a/components/CharacterGrid/index.scss b/components/CharacterGrid/index.scss index 01e6ada2..4a45134f 100644 --- a/components/CharacterGrid/index.scss +++ b/components/CharacterGrid/index.scss @@ -1,31 +1,31 @@ #CharacterGrid { - display: flex; - flex-direction: column; - justify-content: center; - margin: auto; - max-width: 761px; + display: flex; + flex-direction: column; + justify-content: center; + margin: auto; + max-width: 761px; } #grid_characters { - display: flex; - margin: 0; - padding: 0; - max-width: 761px; + display: flex; + margin: 0; + padding: 0; + max-width: 761px; + + @media (max-width: $medium-screen) { + justify-content: space-between; + width: 100%; + } + + & > * { + margin-right: $unit * 3; @media (max-width: $medium-screen) { - justify-content: space-between; - width: 100%; + margin-right: inherit; } + } - & > * { - margin-right: $unit * 3; - - @media (max-width: $medium-screen) { - margin-right: inherit; - } - } - - & > li:last-child { - margin: 0; - } -} \ No newline at end of file + & > li:last-child { + margin: 0; + } +} diff --git a/components/CharacterGrid/index.tsx b/components/CharacterGrid/index.tsx index 521c54c2..9660cfe6 100644 --- a/components/CharacterGrid/index.tsx +++ b/components/CharacterGrid/index.tsx @@ -1,22 +1,22 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import React, { useCallback, useEffect, useMemo, useState } from "react" -import { getCookie } from "cookies-next" -import { useSnapshot } from "valtio" +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { getCookie } from 'cookies-next' +import { useSnapshot } from 'valtio' -import { AxiosResponse } from "axios" -import debounce from "lodash.debounce" +import { AxiosResponse } from 'axios' +import debounce from 'lodash.debounce' -import Alert from "~components/Alert" -import JobSection from "~components/JobSection" -import CharacterUnit from "~components/CharacterUnit" -import CharacterConflictModal from "~components/CharacterConflictModal" +import Alert from '~components/Alert' +import JobSection from '~components/JobSection' +import CharacterUnit from '~components/CharacterUnit' +import CharacterConflictModal from '~components/CharacterConflictModal' -import type { JobSkillObject, SearchableObject } from "~types" +import type { JobSkillObject, SearchableObject } from '~types' -import api from "~utils/api" -import { appState } from "~utils/appState" +import api from '~utils/api' +import { appState } from '~utils/appState' -import "./index.scss" +import './index.scss' // Props interface Props { @@ -31,7 +31,7 @@ const CharacterGrid = (props: Props) => { const numCharacters: number = 5 // Cookies - const cookie = getCookie("account") + const cookie = getCookie('account') const accountData: AccountCookie = cookie ? JSON.parse(cookie as string) : null @@ -57,7 +57,7 @@ const CharacterGrid = (props: Props) => { 2: undefined, 3: undefined, }) - const [errorMessage, setErrorMessage] = useState("") + const [errorMessage, setErrorMessage] = useState('') // Create a temporary state to store previous character uncap values const [previousUncapValues, setPreviousUncapValues] = useState<{ @@ -116,7 +116,7 @@ const CharacterGrid = (props: Props) => { } async function handleCharacterResponse(data: any) { - if (data.hasOwnProperty("conflicts")) { + if (data.hasOwnProperty('conflicts')) { setIncoming(data.incoming) setConflicts(data.conflicts) setPosition(data.position) @@ -185,7 +185,7 @@ const CharacterGrid = (props: Props) => { const saveJob = function (job: Job) { const payload = { party: { - job_id: job ? job.id : "", + job_id: job ? job.id : '', }, ...headers, } @@ -231,9 +231,9 @@ const CharacterGrid = (props: Props) => { }) .catch((error) => { const data = error.response.data - if (data.code == "too_many_skills_of_type") { + if (data.code == 'too_many_skills_of_type') { const message = `You can only add up to 2 ${ - data.skill_type === "emp" + data.skill_type === 'emp' ? data.skill_type.toUpperCase() : data.skill_type } skills to your party at once.` @@ -268,7 +268,7 @@ const CharacterGrid = (props: Props) => { try { if (uncapLevel != previousUncapValues[position]) - await api.updateUncap("character", id, uncapLevel).then((response) => { + await api.updateUncap('character', id, uncapLevel).then((response) => { storeGridCharacter(response.data.grid_character) }) } catch (error) { @@ -332,7 +332,7 @@ const CharacterGrid = (props: Props) => { } function cancelAlert() { - setErrorMessage("") + setErrorMessage('') } // Render: JSX components @@ -342,7 +342,7 @@ const CharacterGrid = (props: Props) => { open={errorMessage.length > 0} message={errorMessage} cancelAction={cancelAlert} - cancelActionText={"Got it"} + cancelActionText={'Got it'} />
    { - const router = useRouter() - const { t } = useTranslation('common') - const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const router = useRouter() + const { t } = useTranslation('common') + const locale = + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' - const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] - const Proficiency = ['none', 'sword', 'dagger', 'axe', 'spear', 'bow', 'staff', 'fist', 'harp', 'gun', 'katana'] + const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] + const Proficiency = [ + 'none', + 'sword', + 'dagger', + 'axe', + 'spear', + 'bow', + 'staff', + 'fist', + 'harp', + 'gun', + 'katana', + ] - const tintElement = Element[props.gridCharacter.object.element] - const wikiUrl = `https://gbf.wiki/${props.gridCharacter.object.name.en.replaceAll(' ', '_')}` + const tintElement = Element[props.gridCharacter.object.element] + const wikiUrl = `https://gbf.wiki/${props.gridCharacter.object.name.en.replaceAll( + ' ', + '_' + )}` - function characterImage() { - let imgSrc = "" - - if (props.gridCharacter) { - const character = props.gridCharacter.object + function characterImage() { + let imgSrc = '' - // Change the image based on the uncap level - let suffix = '01' - if (props.gridCharacter.uncap_level == 6) - suffix = '04' - else if (props.gridCharacter.uncap_level == 5) - suffix = '03' - else if (props.gridCharacter.uncap_level > 2) - suffix = '02' + if (props.gridCharacter) { + const character = props.gridCharacter.object - imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_${suffix}.jpg` - } + // Change the image based on the uncap level + let suffix = '01' + if (props.gridCharacter.uncap_level == 6) suffix = '04' + else if (props.gridCharacter.uncap_level == 5) suffix = '03' + else if (props.gridCharacter.uncap_level > 2) suffix = '02' - return imgSrc + imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_${suffix}.jpg` } - return ( - - - { props.children } - - -
    -
    -

    { props.gridCharacter.object.name[locale] }

    - {props.gridCharacter.object.name[locale]} -
    -
    -
    - - - { (props.gridCharacter.object.proficiency.proficiency2) ? - - : ''} -
    - -
    -
    + return imgSrc + } - {t('buttons.wiki')} - -
    -
    - ) + return ( + + {props.children} + +
    +
    +

    {props.gridCharacter.object.name[locale]}

    + {props.gridCharacter.object.name[locale]} +
    +
    +
    + + + {props.gridCharacter.object.proficiency.proficiency2 ? ( + + ) : ( + '' + )} +
    + +
    +
    + + + {t('buttons.wiki')} + + +
    +
    + ) } export default CharacterHovercard - diff --git a/components/CharacterResult/index.scss b/components/CharacterResult/index.scss index 7c19ab70..3850d5e2 100644 --- a/components/CharacterResult/index.scss +++ b/components/CharacterResult/index.scss @@ -1,63 +1,67 @@ .CharacterResult { + border-radius: 6px; + display: flex; + gap: $unit; + padding: $unit * 1.5; + + &:hover { + background: var(--button-contained-bg); + cursor: pointer; + + .Info h5 { + color: var(--text-primary); + } + } + + img { + background: var(--card-bg); border-radius: 6px; + display: inline-block; + height: 72px; + width: 120px; + } + + .Info { display: flex; - gap: $unit; - padding: $unit * 1.5; + flex-direction: column; + flex-grow: 1; + gap: $unit-half; - &:hover { - background: $grey-90; - cursor: pointer; + h5 { + color: var(--text-secondary); + display: inline-block; + font-size: $font-medium; + font-weight: $medium; } - img { - background: $grey-80; - border-radius: 6px; - display: inline-block; - height: 72px; - width: 120px; + .UncapIndicator { + justify-content: left; + pointer-events: none; } - .Info { - display: flex; - flex-direction: column; - flex-grow: 1; - gap: calc($unit / 2); + .stars { + display: inline-block; + color: #ffa15e; + font-size: $font-xlarge; - h5 { - color: #555; - display: inline-block; - font-size: $font-medium; - font-weight: $medium; - } - - .UncapIndicator { - justify-content: left; - pointer-events: none; - } - - .stars { - display: inline-block; - color: #FFA15E; - font-size: $font-xlarge; - - & > span { - color: #65DAFF; - } - } - - .tags { - display: flex; - flex-direction: row; - gap: calc($unit / 2); - - .WeaponLabelIcon { - $aspect-ratio: calc(25 / 60); - $height: 22px; - background-size: calc($height / $aspect-ratio) $height; - background-repeat: no-repeat; - height: $height; - width: calc($height/ $aspect-ratio); - } - } + & > span { + color: #65daff; + } } -} \ No newline at end of file + + .tags { + display: flex; + flex-direction: row; + gap: calc($unit / 2); + + .WeaponLabelIcon { + $aspect-ratio: calc(25 / 60); + $height: 22px; + background-size: calc($height / $aspect-ratio) $height; + background-repeat: no-repeat; + height: $height; + width: calc($height/ $aspect-ratio); + } + } + } +} diff --git a/components/CharacterResult/index.tsx b/components/CharacterResult/index.tsx index cb6ad816..7b09409b 100644 --- a/components/CharacterResult/index.tsx +++ b/components/CharacterResult/index.tsx @@ -7,45 +7,46 @@ import WeaponLabelIcon from '~components/WeaponLabelIcon' import './index.scss' interface Props { - data: Character - onClick: () => void + data: Character + onClick: () => void } const Element = ['null', 'wind', 'fire', 'water', 'earth', 'dark', 'light'] const CharacterResult = (props: Props) => { - const router = useRouter() - const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const router = useRouter() + const locale = + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' - const character = props.data + const character = props.data - const characterUrl = () => { - let url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_01.jpg` + const characterUrl = () => { + let url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_01.jpg` - if (character.granblue_id === '3030182000') { - url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_01_01.jpg` - } - - return url + if (character.granblue_id === '3030182000') { + url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-grid/${character.granblue_id}_01_01.jpg` } - return ( -
  • - {character.name[locale]} -
    -
    {character.name[locale]}
    - -
    - -
    -
    -
  • - ) + return url + } + + return ( +
  • + {character.name[locale]} +
    +
    {character.name[locale]}
    + +
    + +
    +
    +
  • + ) } -export default CharacterResult \ No newline at end of file +export default CharacterResult diff --git a/components/CharacterSearchFilterBar/index.tsx b/components/CharacterSearchFilterBar/index.tsx index df451ec5..3ab0e1a4 100644 --- a/components/CharacterSearchFilterBar/index.tsx +++ b/components/CharacterSearchFilterBar/index.tsx @@ -9,197 +9,260 @@ import SearchFilter from '~components/SearchFilter' import SearchFilterCheckboxItem from '~components/SearchFilterCheckboxItem' import './index.scss' -import { emptyElementState, emptyProficiencyState, emptyRarityState } from '~utils/emptyStates' +import { + emptyElementState, + emptyProficiencyState, + emptyRarityState, +} from '~utils/emptyStates' import { elements, proficiencies, rarities } from '~utils/stateValues' interface Props { - sendFilters: (filters: { [key: string]: number[] }) => void + sendFilters: (filters: { [key: string]: number[] }) => void } const CharacterSearchFilterBar = (props: Props) => { - const { t } = useTranslation('common') + const { t } = useTranslation('common') - const [rarityMenu, setRarityMenu] = useState(false) - const [elementMenu, setElementMenu] = useState(false) - const [proficiency1Menu, setProficiency1Menu] = useState(false) - const [proficiency2Menu, setProficiency2Menu] = useState(false) + const [rarityMenu, setRarityMenu] = useState(false) + const [elementMenu, setElementMenu] = useState(false) + const [proficiency1Menu, setProficiency1Menu] = useState(false) + const [proficiency2Menu, setProficiency2Menu] = useState(false) - const [rarityState, setRarityState] = useState(emptyRarityState) - const [elementState, setElementState] = useState(emptyElementState) - const [proficiency1State, setProficiency1State] = useState(emptyProficiencyState) - const [proficiency2State, setProficiency2State] = useState(emptyProficiencyState) + const [rarityState, setRarityState] = useState(emptyRarityState) + const [elementState, setElementState] = + useState(emptyElementState) + const [proficiency1State, setProficiency1State] = useState( + emptyProficiencyState + ) + const [proficiency2State, setProficiency2State] = useState( + emptyProficiencyState + ) - function rarityMenuOpened(open: boolean) { - if (open) { - setRarityMenu(true) - setElementMenu(false) - setProficiency1Menu(false) - setProficiency2Menu(false) - } else setRarityMenu(false) + function rarityMenuOpened(open: boolean) { + if (open) { + setRarityMenu(true) + setElementMenu(false) + setProficiency1Menu(false) + setProficiency2Menu(false) + } else setRarityMenu(false) + } + + function elementMenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(true) + setProficiency1Menu(false) + setProficiency2Menu(false) + } else setElementMenu(false) + } + + function proficiency1MenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(false) + setProficiency1Menu(true) + setProficiency2Menu(false) + } else setProficiency1Menu(false) + } + + function proficiency2MenuOpened(open: boolean) { + if (open) { + setRarityMenu(false) + setElementMenu(false) + setProficiency1Menu(false) + setProficiency2Menu(true) + } else setProficiency2Menu(false) + } + + function handleRarityChange(checked: boolean, key: string) { + let newRarityState = cloneDeep(rarityState) + newRarityState[key].checked = checked + setRarityState(newRarityState) + } + + function handleElementChange(checked: boolean, key: string) { + let newElementState = cloneDeep(elementState) + newElementState[key].checked = checked + setElementState(newElementState) + } + + function handleProficiency1Change(checked: boolean, key: string) { + let newProficiencyState = cloneDeep(proficiency1State) + newProficiencyState[key].checked = checked + setProficiency1State(newProficiencyState) + } + + function handleProficiency2Change(checked: boolean, key: string) { + let newProficiencyState = cloneDeep(proficiency2State) + newProficiencyState[key].checked = checked + setProficiency2State(newProficiencyState) + } + + function sendFilters() { + const checkedRarityFilters = Object.values(rarityState) + .filter((x) => x.checked) + .map((x, i) => x.id) + const checkedElementFilters = Object.values(elementState) + .filter((x) => x.checked) + .map((x, i) => x.id) + const checkedProficiency1Filters = Object.values(proficiency1State) + .filter((x) => x.checked) + .map((x, i) => x.id) + const checkedProficiency2Filters = Object.values(proficiency2State) + .filter((x) => x.checked) + .map((x, i) => x.id) + + const filters = { + rarity: checkedRarityFilters, + element: checkedElementFilters, + proficiency1: checkedProficiency1Filters, + proficiency2: checkedProficiency2Filters, } - function elementMenuOpened(open: boolean) { - if (open) { - setRarityMenu(false) - setElementMenu(true) - setProficiency1Menu(false) - setProficiency2Menu(false) - } else setElementMenu(false) - } + props.sendFilters(filters) + } - function proficiency1MenuOpened(open: boolean) { - if (open) { - setRarityMenu(false) - setElementMenu(false) - setProficiency1Menu(true) - setProficiency2Menu(false) - } else setProficiency1Menu(false) - } + useEffect(() => { + sendFilters() + }, [rarityState, elementState, proficiency1State, proficiency2State]) - function proficiency2MenuOpened(open: boolean) { - if (open) { - setRarityMenu(false) - setElementMenu(false) - setProficiency1Menu(false) - setProficiency2Menu(true) - } else setProficiency2Menu(false) - } - - function handleRarityChange(checked: boolean, key: string) { - let newRarityState = cloneDeep(rarityState) - newRarityState[key].checked = checked - setRarityState(newRarityState) - } - - function handleElementChange(checked: boolean, key: string) { - let newElementState = cloneDeep(elementState) - newElementState[key].checked = checked - setElementState(newElementState) - } - - function handleProficiency1Change(checked: boolean, key: string) { - let newProficiencyState = cloneDeep(proficiency1State) - newProficiencyState[key].checked = checked - setProficiency1State(newProficiencyState) - } - - function handleProficiency2Change(checked: boolean, key: string) { - let newProficiencyState = cloneDeep(proficiency2State) - newProficiencyState[key].checked = checked - setProficiency2State(newProficiencyState) - } - - function sendFilters() { - const checkedRarityFilters = Object.values(rarityState).filter(x => x.checked).map((x, i) => x.id) - const checkedElementFilters = Object.values(elementState).filter(x => x.checked).map((x, i) => x.id) - const checkedProficiency1Filters = Object.values(proficiency1State).filter(x => x.checked).map((x, i) => x.id) - const checkedProficiency2Filters = Object.values(proficiency2State).filter(x => x.checked).map((x, i) => x.id) - - const filters = { - rarity: checkedRarityFilters, - element: checkedElementFilters, - proficiency1: checkedProficiency1Filters, - proficiency2: checkedProficiency2Filters - } - - props.sendFilters(filters) - } - - useEffect(() => { - sendFilters() - }, [rarityState, elementState, proficiency1State, proficiency2State]) - - function renderProficiencyFilter(proficiency: 1 | 2) { - const onCheckedChange = (proficiency == 1) ? handleProficiency1Change : handleProficiency2Change - const numSelected = (proficiency == 1) - ? Object.values(proficiency1State).map(x => x.checked).filter(Boolean).length - : Object.values(proficiency2State).map(x => x.checked).filter(Boolean).length - const open = (proficiency == 1) ? proficiency1Menu : proficiency2Menu - const onOpenChange = (proficiency == 1) ? proficiency1MenuOpened : proficiency2MenuOpened - - return ( - - {`${t('filters.labels.proficiency')} ${proficiency}`} -
    - - { Array.from(Array(proficiencies.length / 2)).map((x, i) => { - const checked = (proficiency == 1) - ? proficiency1State[proficiencies[i]].checked - : proficiency2State[proficiencies[i]].checked - - return ( - - {t(`proficiencies.${proficiencies[i]}`)} - - )} - ) } - - - { Array.from(Array(proficiencies.length / 2)).map((x, i) => { - const checked = (proficiency == 1) - ? proficiency1State[proficiencies[i + (proficiencies.length / 2)]].checked - : proficiency2State[proficiencies[i + (proficiencies.length / 2)]].checked - - return ( - - {t(`proficiencies.${proficiencies[i + (proficiencies.length / 2)]}`)} - - )} - ) } - -
    -
    - ) - } + function renderProficiencyFilter(proficiency: 1 | 2) { + const onCheckedChange = + proficiency == 1 ? handleProficiency1Change : handleProficiency2Change + const numSelected = + proficiency == 1 + ? Object.values(proficiency1State) + .map((x) => x.checked) + .filter(Boolean).length + : Object.values(proficiency2State) + .map((x) => x.checked) + .filter(Boolean).length + const open = proficiency == 1 ? proficiency1Menu : proficiency2Menu + const onOpenChange = + proficiency == 1 ? proficiency1MenuOpened : proficiency2MenuOpened return ( -
    - x.checked).filter(Boolean).length} open={rarityMenu} onOpenChange={rarityMenuOpened}> - {t('filters.labels.rarity')} - { Array.from(Array(rarities.length)).map((x, i) => { - return ( - - {t(`rarities.${rarities[i]}`)} - - )} - ) } - + + {`${t( + 'filters.labels.proficiency' + )} ${proficiency}`} +
    + + {Array.from(Array(proficiencies.length / 2)).map((x, i) => { + const checked = + proficiency == 1 + ? proficiency1State[proficiencies[i]].checked + : proficiency2State[proficiencies[i]].checked - x.checked).filter(Boolean).length} open={elementMenu} onOpenChange={elementMenuOpened}> - {t('filters.labels.element')} - { Array.from(Array(elements.length)).map((x, i) => { - return ( - - {t(`elements.${elements[i]}`)} - - )} - ) } - + return ( + + {t(`proficiencies.${proficiencies[i]}`)} + + ) + })} + + + {Array.from(Array(proficiencies.length / 2)).map((x, i) => { + const checked = + proficiency == 1 + ? proficiency1State[ + proficiencies[i + proficiencies.length / 2] + ].checked + : proficiency2State[ + proficiencies[i + proficiencies.length / 2] + ].checked - { renderProficiencyFilter(1) } - { renderProficiencyFilter(2) } -
    + return ( + + {t( + `proficiencies.${ + proficiencies[i + proficiencies.length / 2] + }` + )} + + ) + })} + + + ) + } + + return ( +
    + x.checked) + .filter(Boolean).length + } + open={rarityMenu} + onOpenChange={rarityMenuOpened} + > + + {t('filters.labels.rarity')} + + {Array.from(Array(rarities.length)).map((x, i) => { + return ( + + {t(`rarities.${rarities[i]}`)} + + ) + })} + + + x.checked) + .filter(Boolean).length + } + open={elementMenu} + onOpenChange={elementMenuOpened} + > + + {t('filters.labels.element')} + + {Array.from(Array(elements.length)).map((x, i) => { + return ( + + {t(`elements.${elements[i]}`)} + + ) + })} + + + {renderProficiencyFilter(1)} + {renderProficiencyFilter(2)} +
    + ) } export default CharacterSearchFilterBar diff --git a/components/CharacterUnit/index.scss b/components/CharacterUnit/index.scss index b51bd057..e2f2736d 100644 --- a/components/CharacterUnit/index.scss +++ b/components/CharacterUnit/index.scss @@ -1,79 +1,78 @@ .CharacterUnit { + 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; + box-shadow: $hover-shadow; + cursor: pointer; + transform: $scale-tall; + } + + &.filled h3 { + display: block; + } + + &.filled ul { 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; - box-shadow: $hover-shadow; - cursor: pointer; - transform: $scale-tall; + h3, + ul { + display: none; + } + + h3 { + color: var(--text-primary); + font-size: $font-regular; + font-weight: $normal; + line-height: 1.1; + margin: 0; + max-width: 131px; + text-align: center; + word-wrap: normal; + } + + img { + position: relative; + width: 100%; + z-index: 2; + } + + .CharacterImage { + aspect-ratio: 131 / 273; + background: var(--card-bg); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: $unit; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + transition: all 0.18s ease-in-out; + height: auto; + width: 131px; + + @media (max-width: $medium-screen) { + width: 17vw; } - &.filled h3 { - display: block; + &:hover .icon svg { + fill: var(--icon-secondary-hover); } - &.filled ul { - display: flex; - } - - h3, - ul { - display: none; - } - - h3 { - color: #333; - font-size: $font-regular; - font-weight: $normal; - line-height: 1.1; - margin: 0; - max-width: 131px; - text-align: center; - word-wrap: normal; - } - - img { - position: relative; - width: 100%; - z-index: 2; - } - - - .CharacterImage { - aspect-ratio: 131 / 273; - background: white; - border: 1px solid rgba(0, 0, 0, 0); - border-radius: $unit; - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - transition: all 0.18s ease-in-out; - height: auto; - width: 131px; - - @media (max-width: $medium-screen) { - width: 17vw; - } - - &:hover .icon svg { - color: $grey-40; - } - - .icon { - position: absolute; - height: $unit * 3; - width: $unit * 3; - z-index: 1; - - svg { - fill: $grey-70; - } - } + .icon { + position: absolute; + height: $unit * 3; + width: $unit * 3; + z-index: 1; + + svg { + fill: var(--icon-secondary); + } } + } } diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index 13e46635..7dbce073 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -1,19 +1,19 @@ -import React, { useEffect, useState } from "react" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" -import { useTranslation } from "next-i18next" -import classnames from "classnames" +import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' +import classnames from 'classnames' -import { appState } from "~utils/appState" +import { appState } from '~utils/appState' -import CharacterHovercard from "~components/CharacterHovercard" -import SearchModal from "~components/SearchModal" -import UncapIndicator from "~components/UncapIndicator" -import PlusIcon from "~public/icons/Add.svg" +import CharacterHovercard from '~components/CharacterHovercard' +import SearchModal from '~components/SearchModal' +import UncapIndicator from '~components/UncapIndicator' +import PlusIcon from '~public/icons/Add.svg' -import type { SearchableObject } from "~types" +import type { SearchableObject } from '~types' -import "./index.scss" +import './index.scss' interface Props { gridCharacter?: GridCharacter @@ -24,15 +24,15 @@ interface Props { } const CharacterUnit = (props: Props) => { - const { t } = useTranslation("common") + const { t } = useTranslation('common') const { party, grid } = useSnapshot(appState) const router = useRouter() const locale = - router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' - const [imageUrl, setImageUrl] = useState("") + const [imageUrl, setImageUrl] = useState('') const classes = classnames({ CharacterUnit: true, @@ -48,19 +48,19 @@ const CharacterUnit = (props: Props) => { }) function generateImageUrl() { - let imgSrc = "" + let imgSrc = '' if (props.gridCharacter) { const character = props.gridCharacter.object! // Change the image based on the uncap level - let suffix = "01" - if (props.gridCharacter.uncap_level == 6) suffix = "04" - else if (props.gridCharacter.uncap_level == 5) suffix = "03" - else if (props.gridCharacter.uncap_level > 2) suffix = "02" + let suffix = '01' + if (props.gridCharacter.uncap_level == 6) suffix = '04' + else if (props.gridCharacter.uncap_level == 5) suffix = '03' + else if (props.gridCharacter.uncap_level > 2) suffix = '02' // Special casing for Lyria (and Young Cat eventually) - if (props.gridCharacter.object.granblue_id === "3030182000") { + if (props.gridCharacter.object.granblue_id === '3030182000') { let element = 1 if (grid.weapons.mainWeapon && grid.weapons.mainWeapon.element) { element = grid.weapons.mainWeapon.element @@ -90,14 +90,14 @@ const CharacterUnit = (props: Props) => { ) : ( - "" + '' )}
    ) const editableImage = ( { special={character.special} /> ) : ( - "" + '' )}

    {character?.name[locale]}

    diff --git a/components/Dialog/index.scss b/components/Dialog/index.scss new file mode 100644 index 00000000..04c6e1c2 --- /dev/null +++ b/components/Dialog/index.scss @@ -0,0 +1,87 @@ +.Dialog { + $multiplier: 4; + + animation: 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal none running + openModal; + background: var(--dialog-bg); + border-radius: $card-corner; + display: flex; + flex-direction: column; + gap: $unit * $multiplier; + height: auto; + min-width: $unit * 48; + min-height: $unit-12x; + padding: $unit * $multiplier; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 21; + + .DialogHeader { + display: flex; + align-items: center; + gap: $unit; + + .left { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: $unit; + + p { + font-size: $font-small; + line-height: 1.25; + } + } + } + + .DialogClose { + background: transparent; + + &:hover { + cursor: pointer; + + svg { + fill: $error; + } + } + + svg { + fill: $grey-50; + float: right; + height: 24px; + width: 24px; + } + } + + .DialogTitle { + color: var(--text-primary); + font-size: $font-xlarge; + flex-grow: 1; + } + + .DialogTop { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: calc($unit / 2); + + .SubTitle { + color: var(--text-secondary); + font-size: $font-small; + font-weight: $medium; + } + } + + .DialogDescription { + color: var(--text-secondary); + flex-grow: 1; + } + + .actions { + display: flex; + justify-content: flex-end; + width: 100%; + } +} diff --git a/components/Dialog/index.tsx b/components/Dialog/index.tsx new file mode 100644 index 00000000..2438a2ed --- /dev/null +++ b/components/Dialog/index.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import * as DialogPrimitive from '@radix-ui/react-dialog' +import classNames from 'classnames' + +import './index.scss' + +interface Props + extends React.DetailedHTMLProps< + React.DialogHTMLAttributes, + HTMLDivElement + > {} + +export const DialogContent = React.forwardRef( + function dialog({ children, ...props }, forwardedRef) { + const classes = classNames( + { + Dialog: true, + }, + props.className + ) + + return ( + + + + {children} + + + ) + } +) + +export const Dialog = DialogPrimitive.Root +export const DialogTrigger = DialogPrimitive.Trigger +export const DialogClose = DialogPrimitive.Close diff --git a/components/ElementToggle/index.scss b/components/ElementToggle/index.scss index f675e16a..66b60813 100644 --- a/components/ElementToggle/index.scss +++ b/components/ElementToggle/index.scss @@ -1,64 +1,65 @@ .ToggleGroup { - $height: 36px; + $height: 36px; - border: 1px solid rgba(0, 0, 0, 0.14); - border-radius: $height; - display: flex; - height: $height; - gap: calc($unit / 4); - padding: calc($unit / 2); + border: 1px solid rgba(0, 0, 0, 0.14); + border-radius: $height; + display: flex; + height: $height; + gap: calc($unit / 4); + padding: calc($unit / 2); - .ToggleItem { - background: white; - border: none; - border-radius: 18px; - color: $grey-40; - flex-grow: 1; - font-size: $font-regular; - padding: ($unit) $unit * 2; + .ToggleItem { + background: $grey-100; + border: none; + border-radius: 18px; + color: $grey-50; + flex-grow: 1; + font-size: $font-regular; + padding: ($unit) $unit * 2; - &.ja { - padding-top: 6px; - padding-bottom: 10px; - } - - &:hover { - cursor: pointer; - } - - &:hover, &[data-state="on"] { - background:$grey-80; - color: $grey-00; - - &.fire { - background: $fire-bg-light; - color: $fire-text-dark; - } - - &.water { - background: $water-bg-light; - color: $water-text-dark; - } - - &.earth { - background: $earth-bg-light; - color: $earth-text-dark; - } - - &.wind { - background: $wind-bg-light; - color: $wind-text-dark; - } - - &.dark { - background: $dark-bg-light; - color: $dark-text-dark; - } - - &.light { - background: $light-bg-light; - color: $light-text-dark; - } - } + &.ja { + padding-top: 6px; + padding-bottom: 10px; } -} \ No newline at end of file + + &:hover { + cursor: pointer; + } + + &:hover, + &[data-state='on'] { + background: $grey-80; + color: $grey-15; + + &.fire { + background: $fire-bg-20; + color: $fire-text-10; + } + + &.water { + background: $water-bg-20; + color: $water-text-10; + } + + &.earth { + background: $earth-bg-20; + color: $earth-text-10; + } + + &.wind { + background: $wind-bg-20; + color: $wind-text-10; + } + + &.dark { + background: $dark-bg-10; + color: $dark-text-10; + } + + &.light { + background: $light-bg-20; + color: $light-text-10; + } + } + } +} diff --git a/components/ElementToggle/index.tsx b/components/ElementToggle/index.tsx index fe6a9e99..0748b66f 100644 --- a/components/ElementToggle/index.tsx +++ b/components/ElementToggle/index.tsx @@ -7,40 +7,75 @@ import * as ToggleGroup from '@radix-ui/react-toggle-group' import './index.scss' interface Props { - currentElement: number - sendValue: (value: string) => void + currentElement: number + sendValue: (value: string) => void } const ElementToggle = (props: Props) => { - const router = useRouter() - const { t } = useTranslation('common') - const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const router = useRouter() + const { t } = useTranslation('common') + const locale = + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' - return ( - - - {t('elements.null')} - - - {t('elements.wind')} - - - {t('elements.fire')} - - - {t('elements.water')} - - - {t('elements.earth')} - - - {t('elements.dark')} - - - {t('elements.light')} - - - ) + return ( + + + {t('elements.null')} + + + {t('elements.wind')} + + + {t('elements.fire')} + + + {t('elements.water')} + + + {t('elements.earth')} + + + {t('elements.dark')} + + + {t('elements.light')} + + + ) } -export default ElementToggle \ No newline at end of file +export default ElementToggle diff --git a/components/ExtraSummons/index.scss b/components/ExtraSummons/index.scss index ac570251..f8dad9c6 100644 --- a/components/ExtraSummons/index.scss +++ b/components/ExtraSummons/index.scss @@ -1,55 +1,55 @@ #ExtraSummons { - background: #FFEBD9; - border-radius: 8px; - box-sizing: border-box; + background: var(--subaura-orange-bg); + border-radius: 8px; + box-sizing: border-box; + display: flex; + justify-content: center; + margin: 20px auto; + max-width: 727px; + padding: 16px 16px 16px 0; + position: relative; + left: 9px; + + @media (max-width: $medium-screen) { + left: auto; + max-width: auto; + width: 100%; + } + + & > span { + color: var(--subaura-orange-text); display: flex; + align-items: center; justify-content: center; - margin: 20px auto; - max-width: 727px; - padding: 16px 16px 16px 0; - position: relative; - left: 9px; + line-height: 1.2; + font-weight: 500; + margin-right: 16px; + text-align: center; + width: 387px; + } - @media (max-width: $medium-screen) { - left: auto; - max-width: auto; - width: 100%; + #grid_summons { + display: grid; + grid-template-columns: auto auto; + grid-column-gap: $unit * 2; + grid-template-rows: 1fr; + grid-row-gap: $unit * 3; + + & > li { + list-style: none; + min-height: 0; + + .SummonUnit { + min-height: 0; + } } + } - & > span { - color: #825B39; - display: flex; - align-items: center; - justify-content: center; - line-height: 1.2; - font-weight: 500; - margin-right: 16px; - text-align: center; - width: 387px; - } + .SummonUnit .SummonImage { + background: var(--subaura-orange-card-bg); + } - #grid_summons { - display: grid; - grid-template-columns: auto auto; - grid-column-gap: $unit * 2; - grid-template-rows: 1fr; - grid-row-gap: $unit * 3; - - & > li { - list-style: none; - min-height: 0; - - .SummonUnit { - min-height: 0; - } - } - } - - .SummonUnit .SummonImage { - background: #facea7; - } - - .SummonUnit .SummonImage .icon svg { - fill: #a8703f; - } -} \ No newline at end of file + .SummonUnit .SummonImage .icon svg { + fill: var(--subaura-orange-secondary); + } +} diff --git a/components/ExtraSummons/index.tsx b/components/ExtraSummons/index.tsx index c064ba25..30a32352 100644 --- a/components/ExtraSummons/index.tsx +++ b/components/ExtraSummons/index.tsx @@ -1,8 +1,8 @@ -import React from "react" -import { useTranslation } from "next-i18next" -import SummonUnit from "~components/SummonUnit" -import { SearchableObject } from "~types" -import "./index.scss" +import React from 'react' +import { useTranslation } from 'next-i18next' +import SummonUnit from '~components/SummonUnit' +import { SearchableObject } from '~types' +import './index.scss' // Props interface Props { @@ -18,11 +18,11 @@ interface Props { const ExtraSummons = (props: Props) => { const numSummons: number = 2 - const { t } = useTranslation("common") + const { t } = useTranslation('common') return (
    - {t("summons.subaura")} + {t('summons.subaura')}
      {Array.from(Array(numSummons)).map((x, i) => { return ( diff --git a/components/ExtraWeapons/index.scss b/components/ExtraWeapons/index.scss index eac815e9..eedc2514 100644 --- a/components/ExtraWeapons/index.scss +++ b/components/ExtraWeapons/index.scss @@ -1,47 +1,47 @@ #ExtraGrid { - background: #ECEBFF; - border-radius: 8px; - box-sizing: border-box; + background: var(--extra-purple-bg); + border-radius: 8px; + box-sizing: border-box; + display: flex; + justify-content: center; + margin: 20px auto; + max-width: 766px; + padding: 16px 16px 16px 0; + position: relative; + left: 8px; + + @media (max-width: $medium-screen) { + left: auto; + max-width: auto; + width: 100%; + } + + & > span { + color: var(--extra-purple-text); display: flex; + align-items: center; + flex-grow: 1; justify-content: center; - margin: 20px auto; - max-width: 766px; - padding: 16px 16px 16px 0; - position: relative; - left: 8px; + line-height: 1.2; + font-weight: 500; + margin-right: 16px; + text-align: center; + } - @media (max-width: $medium-screen) { - left: auto; - max-width: auto; - width: 100%; - } + .grid_weapons { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0; + padding: 0; + max-width: 528px; + } - & > span { - color: #4F3C79; - display: flex; - align-items: center; - flex-grow: 1; - justify-content: center; - line-height: 1.2; - font-weight: 500; - margin-right: 16px; - text-align: center; - } + .WeaponUnit .WeaponImage { + background: var(--extra-purple-card-bg); + } - .grid_weapons { - display: flex; - flex-direction: row; - flex-wrap: wrap; - margin: 0; - padding: 0; - max-width: 528px; - } - - .WeaponUnit .WeaponImage { - background: #D5D3F6; - } - - .WeaponUnit .WeaponImage .icon svg { - fill: #8F8AC6; - } -} \ No newline at end of file + .WeaponUnit .WeaponImage .icon svg { + fill: var(--extra-purple-secondary); + } +} diff --git a/components/ExtraWeapons/index.tsx b/components/ExtraWeapons/index.tsx index f9ed14a0..0e3ae493 100644 --- a/components/ExtraWeapons/index.tsx +++ b/components/ExtraWeapons/index.tsx @@ -1,10 +1,10 @@ -import React from "react" -import { useTranslation } from "next-i18next" -import WeaponUnit from "~components/WeaponUnit" +import React from 'react' +import { useTranslation } from 'next-i18next' +import WeaponUnit from '~components/WeaponUnit' -import type { SearchableObject } from "~types" +import type { SearchableObject } from '~types' -import "./index.scss" +import './index.scss' // Props interface Props { @@ -18,17 +18,17 @@ interface Props { const ExtraWeapons = (props: Props) => { const numWeapons: number = 3 - const { t } = useTranslation("common") + const { t } = useTranslation('common') return (
      - {t("extra_weapons")} + {t('extra_weapons')}
        {Array.from(Array(numWeapons)).map((x, i) => { return (
      • ) => void - onChange?: (event: React.ChangeEvent) => void -} - -const Fieldset = React.forwardRef(function fieldSet(props, ref) { - const fieldType = (['password', 'confirm_password'].includes(props.fieldName)) ? 'password' : 'text' - - return ( -
        - - { - props.error.length > 0 && -

        {props.error}

        - } -
        - ) -}) - -export default Fieldset \ No newline at end of file diff --git a/components/FilterBar/index.scss b/components/FilterBar/index.scss index 994a3cf3..5787a887 100644 --- a/components/FilterBar/index.scss +++ b/components/FilterBar/index.scss @@ -1,63 +1,76 @@ .FilterBar { + align-items: center; + background: var(--bar-bg); + border-radius: 6px; + display: flex; + flex-direction: row; + gap: $unit * 2; + margin: 0 auto; + margin-top: 7px; // Line up with HeaderMenu + padding: $unit * 2; + position: sticky; + transition: box-shadow 0.24s ease-in-out; + top: $unit * 4; + width: 966px; + + &.shadow { + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.14); + } + + h1 { + color: var(--text-primary); + font-size: $font-regular; + font-weight: $normal; + flex-grow: 1; + text-align: left; + } + + select, + .SelectTrigger { + // background: url("/icons/Arrow.svg"), $grey-90; + // background-repeat: no-repeat; + // background-position-y: center; + // background-position-x: 95%; + // background-size: $unit * 1.5; + background-color: var(--select-contained-bg); + color: $grey-55; + font-size: $font-small; + margin: 0; + max-width: 200px; + + &:hover { + background-color: var(--select-contained-bg-hover); + } + } + + .SelectTrigger { + width: 100%; + + span { + font-size: $font-small; + } + } + + .UserInfo { align-items: center; - background: white; - border-radius: 6px; display: flex; flex-direction: row; - gap: $unit * 2; - margin: 0 auto; - margin-top: 7px; // Line up with HeaderMenu - padding: $unit * 2; - position: sticky; - transition: box-shadow 0.24s ease-in-out; - top: $unit * 4; - width: 966px; + flex-grow: 1; + gap: $unit * 1.5; - &.shadow { - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.14); + img { + $diameter: $unit * 6; + border-radius: $diameter / 2; + height: $diameter; + width: $diameter; + + &.gran { + background-color: #cee7fe; + } + + &.djeeta { + background-color: #ffe1fe; + } } - - h1 { - color: $grey-20; - font-size: $font-regular; - font-weight: $normal; - flex-grow: 1; - text-align: left; - } - - select { - background: url('/icons/Arrow.svg'), $grey-90; - background-repeat: no-repeat; - background-position-y: center; - background-position-x: 95%; - background-size: $unit * 1.5; - color: $grey-50; - font-size: $font-small; - margin: 0; - max-width: 200px; - } - - - .UserInfo { - align-items: center; - display: flex; - flex-direction: row; - flex-grow: 1; - gap: $unit * 1.5; - - img { - $diameter: $unit * 6; - border-radius: $diameter / 2; - height: $diameter; - width: $diameter; - - &.gran { - background-color: #CEE7FE; - } - - &.djeeta { - background-color: #FFE1FE; - } - } - } -} \ No newline at end of file + } +} diff --git a/components/FilterBar/index.tsx b/components/FilterBar/index.tsx index f3446142..d648af50 100644 --- a/components/FilterBar/index.tsx +++ b/components/FilterBar/index.tsx @@ -1,79 +1,145 @@ -import React from 'react' +import React, { useState } from 'react' import { useTranslation } from 'next-i18next' import classNames from 'classnames' import RaidDropdown from '~components/RaidDropdown' import './index.scss' +import Select from '~components/Select' +import SelectItem from '~components/SelectItem' interface Props { - children: React.ReactNode - scrolled: boolean + children: React.ReactNode + scrolled: boolean + element?: number + raidSlug?: string + recency?: number + onFilter: ({ + element, + raidSlug, + recency, + }: { element?: number raidSlug?: string recency?: number - onFilter: ({element, raidSlug, recency} : { element?: number, raidSlug?: string, recency?: number}) => void + }) => void } -const FilterBar = (props: Props) => { - // Set up translation - const { t } = useTranslation('common') +const FilterBar = (props: Props) => { + // Set up translation + const { t } = useTranslation('common') - // Set up refs for filter dropdowns - const elementSelect = React.createRef() - const raidSelect = React.createRef() - const recencySelect = React.createRef() + const [recencyOpen, setRecencyOpen] = useState(false) + const [elementOpen, setElementOpen] = useState(false) - // Set up classes object for showing shadow on scroll - const classes = classNames({ - 'FilterBar': true, - 'shadow': props.scrolled - }) + // Set up refs for filter dropdowns + const elementSelect = React.createRef() + const raidSelect = React.createRef() + const recencySelect = React.createRef() - function elementSelectChanged() { - const elementValue = (elementSelect.current) ? parseInt(elementSelect.current.value) : -1 - props.onFilter({ element: elementValue }) - } + // Set up classes object for showing shadow on scroll + const classes = classNames({ + FilterBar: true, + shadow: props.scrolled, + }) - function recencySelectChanged() { - const recencyValue = (recencySelect.current) ? parseInt(recencySelect.current.value) : -1 - props.onFilter({ recency: recencyValue }) - } + function openElementSelect() { + setElementOpen(!elementOpen) + } - function raidSelectChanged(slug?: string) { - props.onFilter({ raidSlug: slug }) - } + function openRecencySelect() { + setRecencyOpen(!recencyOpen) + } - return ( -
        - {props.children} - - - -
        - ) + function elementSelectChanged(value: string) { + const elementValue = parseInt(value) + props.onFilter({ element: elementValue }) + } + + function recencySelectChanged(value: string) { + const recencyValue = parseInt(value) + props.onFilter({ recency: recencyValue }) + } + + function raidSelectChanged(slug?: string) { + props.onFilter({ raidSlug: slug }) + } + + return ( +
        + {props.children} + + + + + +
        + ) } export default FilterBar diff --git a/components/GridRep/index.scss b/components/GridRep/index.scss index 37b5a10d..a47aa2fa 100644 --- a/components/GridRep/index.scss +++ b/components/GridRep/index.scss @@ -1,148 +1,147 @@ .GridRep { - border-radius: 6px; + border-radius: 6px; + display: flex; + flex-direction: column; + gap: $unit; + padding: $unit * 2; + + &:hover { + background: var(--grid-rep-hover); + + h2, + .Grid { + cursor: pointer; + } + + .Grid .weapon { + box-shadow: inset 0 0 0 1px var(--grid-border-color); + } + } + + .Grid { + display: flex; + flex-direction: row; + flex-shrink: 0; + + .weapon { + background: var(--card-bg); + border-radius: 4px; + } + + .grid_mainhand { + margin-right: $unit; + height: 139px; + width: 66px; + } + + .grid_weapons { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr 1fr; + gap: $unit; + margin: 0; + padding: 0; + width: fit-content; + } + + .grid_weapon { + float: left; + height: 40px; + width: 70px; + } + + .grid_mainhand img[src*='jpg'], + .grid_weapon img[src*='jpg'] { + border-radius: 4px; + width: 100%; + height: 100%; + } + } + + .Details { display: flex; flex-direction: column; - gap: $unit; - padding: $unit * 2; + gap: calc($unit / 2); - &:hover { - background: white; + h2 { + color: var(--text-primary); + font-size: $font-regular; + overflow: hidden; + padding-bottom: 1px; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 258px; // Can we not do this? - h2, .Grid { - cursor: pointer; - } - - .Grid .weapon { - box-shadow: inset 0 0 0 1px $grey-80; - } + &.empty { + color: var(--text-tertiary); + } } - .Grid { - display: flex; - flex-direction: row; - flex-shrink: 0; + .top { + display: flex; + flex-direction: row; + gap: calc($unit / 2); + align-items: center; - .weapon { - background: white; - border-radius: 4px; - } - - .grid_mainhand { - margin-right: $unit; - height: 139px; - width: 66px; - } - - .grid_weapons { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: 1fr 1fr 1fr; - gap: $unit; - margin: 0; - padding: 0; - width: fit-content; - } - - .grid_weapon { - float: left; - height: 40px; - width: 70px; - } - - .grid_mainhand img[src*="jpg"], - .grid_weapon img[src*="jpg"] { - border-radius: 4px; - width: 100%; - height: 100%; - } - } - - .Details { + .info { display: flex; flex-direction: column; + flex-grow: 1; gap: calc($unit / 2); + } - h2 { - color: $grey-00; - font-size: $font-regular; - overflow: hidden; - padding-bottom: 1px; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 258px; // Can we not do this? - - &.empty { - color: $grey-50; - } - } - - .top { - display: flex; - flex-direction: row; - gap: calc($unit / 2); - align-items: center; - - .info { - display: flex; - flex-direction: column; - flex-grow: 1; - gap: calc($unit / 2); - } - - button svg { - width: 14px; - height: 14px; - } - - button:hover, - button.Active { - background: $grey-90; - } - } - - .bottom { - display: flex; - flex-direction: row; - } - - .raid, .user, time { - color: $grey-50; - font-size: $font-small; - } - - .raid, .user { - flex-grow: 1; - } - - .raid { - margin-bottom: calc($unit / 2); - } - - .user { - display: flex; - gap: calc($unit / 2); - align-items: center; - - - img, .no-user { - $diameter: 18px; - - border-radius: calc($diameter / 2); - height: $diameter; - width: $diameter; - } - - img.gran { - background-color: #CEE7FE; - } - - img.djeeta { - background-color: #FFE1FE; - } - - .no-user { - background: $grey-80; - } - } + button svg { + width: 14px; + height: 14px; + } } + + .bottom { + display: flex; + flex-direction: row; + } + + .raid, + .user, + time { + color: $grey-55; + font-size: $font-small; + } + + .raid, + .user { + flex-grow: 1; + } + + .raid { + margin-bottom: calc($unit / 2); + } + + .user { + display: flex; + gap: calc($unit / 2); + align-items: center; + + img, + .no-user { + $diameter: 18px; + + border-radius: calc($diameter / 2); + height: $diameter; + width: $diameter; + } + + img.gran { + background-color: #cee7fe; + } + + img.djeeta { + background-color: #ffe1fe; + } + + .no-user { + background: $grey-80; + } + } + } } diff --git a/components/GridRep/index.tsx b/components/GridRep/index.tsx index ff9fe507..56b00f1a 100644 --- a/components/GridRep/index.tsx +++ b/components/GridRep/index.tsx @@ -1,16 +1,17 @@ -import React, { useEffect, useState } from "react" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" -import { useTranslation } from "next-i18next" -import classNames from "classnames" +import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' +import classNames from 'classnames' -import { accountState } from "~utils/accountState" -import { formatTimeAgo } from "~utils/timeAgo" +import { accountState } from '~utils/accountState' +import { formatTimeAgo } from '~utils/timeAgo' -import Button from "~components/Button" -import { ButtonType } from "~utils/enums" +import Button from '~components/Button' -import "./index.scss" +import SaveIcon from '~public/icons/Save.svg' + +import './index.scss' interface Props { shortcode: string @@ -32,9 +33,9 @@ const GridRep = (props: Props) => { const { account } = useSnapshot(accountState) const router = useRouter() - const { t } = useTranslation("common") + const { t } = useTranslation('common') const locale = - router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' const [mainhand, setMainhand] = useState() const [weapons, setWeapons] = useState>({}) @@ -75,7 +76,7 @@ const GridRep = (props: Props) => { } function generateMainhandImage() { - let url = "" + let url = '' if (mainhand) { if (mainhand.element == 0 && props.grid[0].element) { @@ -88,12 +89,12 @@ const GridRep = (props: Props) => { return mainhand && props.grid[0] ? ( {mainhand.name[locale]} ) : ( - "" + '' ) } function generateGridImage(position: number) { - let url = "" + let url = '' const weapon = weapons[position] const gridWeapon = grid[position] @@ -109,7 +110,7 @@ const GridRep = (props: Props) => { return weapons[position] ? ( {weapons[position]?.name[locale]} ) : ( - "" + '' ) } @@ -134,11 +135,11 @@ const GridRep = (props: Props) => { const details = (

        - {props.name ? props.name : t("no_title")} + {props.name ? props.name : t('no_title')}

        - {props.raid ? props.raid.name[locale] : t("no_raid")} + {props.raid ? props.raid.name[locale] : t('no_raid')}
      @@ -100,7 +100,7 @@ const HeaderMenu = (props: Props) => {
      • - {t("menu.language")} + {t('menu.language')} {
      • - {t("menu.teams")} + {t('menu.teams')}
      • - {t("menu.guides")} - {t("coming_soon")} + {t('menu.guides')} + {t('coming_soon')}
      • diff --git a/components/Input/index.scss b/components/Input/index.scss new file mode 100644 index 00000000..013f4a74 --- /dev/null +++ b/components/Input/index.scss @@ -0,0 +1,23 @@ +.Input { + -webkit-font-smoothing: antialiased; + background-color: var(--input-bg); + border: none; + border-radius: 6px; + box-sizing: border-box; + display: block; + padding: $unit-2x; + width: 100%; +} + +.InputError { + color: $error; + font-size: $font-tiny; + margin: $unit 0; + padding: calc($unit / 2) ($unit * 2); +} + +::placeholder { + /* Chrome, Firefox, Opera, Safari 10.1+ */ + color: var(--text-secondary) !important; + opacity: 1; /* Firefox */ +} diff --git a/components/Input/index.tsx b/components/Input/index.tsx new file mode 100644 index 00000000..27d21315 --- /dev/null +++ b/components/Input/index.tsx @@ -0,0 +1,38 @@ +import classNames from 'classnames' +import React from 'react' +import './index.scss' + +interface Props + extends React.DetailedHTMLProps< + React.InputHTMLAttributes, + HTMLInputElement + > { + error?: string + label?: string +} + +const Input = React.forwardRef(function input( + props: Props, + forwardedRef +) { + const classes = classNames({ Input: true }, props.className) + + return ( + + ) +}) + +export default Input diff --git a/components/JobDropdown/index.scss b/components/JobDropdown/index.scss index e69de29b..35cec4d9 100644 --- a/components/JobDropdown/index.scss +++ b/components/JobDropdown/index.scss @@ -0,0 +1,3 @@ +.Job.SelectTrigger { + margin-bottom: $unit; +} diff --git a/components/JobDropdown/index.tsx b/components/JobDropdown/index.tsx index 179034f4..3b1d468c 100644 --- a/components/JobDropdown/index.tsx +++ b/components/JobDropdown/index.tsx @@ -1,11 +1,15 @@ -import React, { useEffect, useState } from "react" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" +import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' -import { appState } from "~utils/appState" -import { jobGroups } from "~utils/jobGroups" +import Select from '~components/Select' +import SelectItem from '~components/SelectItem' +import SelectGroup from '~components/SelectGroup' -import "./index.scss" +import { appState } from '~utils/appState' +import { jobGroups } from '~utils/jobGroups' + +import './index.scss' // Props interface Props { @@ -20,12 +24,13 @@ const JobDropdown = React.forwardRef( function useFieldSet(props, ref) { // Set up router for locale const router = useRouter() - const locale = router.locale || "en" + const locale = router.locale || 'en' // Create snapshot of app state const { party } = useSnapshot(appState) // Set up local states for storing jobs + const [open, setOpen] = useState(false) const [currentJob, setCurrentJob] = useState() const [jobs, setJobs] = useState() const [sortedJobs, setSortedJobs] = useState() @@ -58,10 +63,14 @@ const JobDropdown = React.forwardRef( } }, [appState, props.currentJob]) + function openJobSelect() { + setOpen(!open) + } + // Enable changing select value - function handleChange(event: React.ChangeEvent) { + function handleChange(value: string) { if (jobs) { - const job = jobs.find((job) => job.id === event.target.value) + const job = jobs.find((job) => job.id === value) if (props.onChange) props.onChange(job) setCurrentJob(job) } @@ -76,36 +85,37 @@ const JobDropdown = React.forwardRef( .sort((a, b) => a.order - b.order) .map((item, i) => { return ( - + ) }) const groupName = jobGroups.find((g) => g.slug === group)?.name[locale] return ( - + {options} - + ) } return ( - + : ''} + ) } ) diff --git a/components/JobSection/index.scss b/components/JobSection/index.scss index f6e20d20..dfd34109 100644 --- a/components/JobSection/index.scss +++ b/components/JobSection/index.scss @@ -28,10 +28,10 @@ } .JobImage { - $height: 249px; + $height: 252px; $width: 447px; - background: url("/images/background_a.jpg"); + background: url('/images/background_a.jpg'); background-size: 500px 281px; border-radius: $unit; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); diff --git a/components/JobSection/index.tsx b/components/JobSection/index.tsx index 55ea8234..10f04f27 100644 --- a/components/JobSection/index.tsx +++ b/components/JobSection/index.tsx @@ -1,17 +1,17 @@ -import React, { ForwardedRef, useEffect, useState } from "react" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" -import { useTranslation } from "next-i18next" +import React, { ForwardedRef, useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' -import JobDropdown from "~components/JobDropdown" -import JobSkillItem from "~components/JobSkillItem" -import SearchModal from "~components/SearchModal" +import JobDropdown from '~components/JobDropdown' +import JobSkillItem from '~components/JobSkillItem' +import SearchModal from '~components/SearchModal' -import { appState } from "~utils/appState" +import { appState } from '~utils/appState' -import type { JobSkillObject, SearchableObject } from "~types" +import type { JobSkillObject, SearchableObject } from '~types' -import "./index.scss" +import './index.scss' // Props interface Props { @@ -24,14 +24,14 @@ interface Props { const JobSection = (props: Props) => { const { party } = useSnapshot(appState) - const { t } = useTranslation("common") + const { t } = useTranslation('common') const router = useRouter() const locale = - router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' const [job, setJob] = useState() - const [imageUrl, setImageUrl] = useState("") + const [imageUrl, setImageUrl] = useState('') const [numSkills, setNumSkills] = useState(4) const [skills, setSkills] = useState<{ [key: number]: JobSkill | undefined }>( [] @@ -62,7 +62,7 @@ const JobSection = (props: Props) => { if (job) { if ((party.job && job.id != party.job.id) || !party.job) appState.party.job = job - if (job.row === "1") setNumSkills(3) + if (job.row === '1') setNumSkills(3) else setNumSkills(4) } }, [job]) @@ -75,11 +75,11 @@ const JobSection = (props: Props) => { } function generateImageUrl() { - let imgSrc = "" + let imgSrc = '' if (job) { - const slug = job?.name.en.replaceAll(" ", "-").toLowerCase() - const gender = party.user && party.user.gender == 1 ? "b" : "a" + const slug = job?.name.en.replaceAll(' ', '-').toLowerCase() + const gender = party.user && party.user.gender == 1 ? 'b' : 'a' imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/jobs/${slug}_${gender}.png` } @@ -101,7 +101,7 @@ const JobSection = (props: Props) => { skill={skills[index]} editable={canEditSkill(skills[index])} key={`skill-${index}`} - hasJob={job != undefined && job.id != "-1"} + hasJob={job != undefined && job.id != '-1'} /> ) } @@ -109,7 +109,7 @@ const JobSection = (props: Props) => { const editableSkillItem = (index: number) => { return ( img, & > div.placeholder { - background: white; + background: var(--card-bg); border-radius: calc($unit / 2); border: 1px solid rgba(0, 0, 0, 0); width: $unit * 5; @@ -34,13 +38,17 @@ justify-content: center; & > svg { - fill: $grey-60; + fill: var(--icon-secondary); width: $unit * 2; height: $unit * 2; } } - p.placeholder { - color: $grey-50; + p { + color: var(--text-primary); + + &.placeholder { + color: var(--text-tertiary); + } } } diff --git a/components/JobSkillItem/index.tsx b/components/JobSkillItem/index.tsx index 52a1f191..bac8f729 100644 --- a/components/JobSkillItem/index.tsx +++ b/components/JobSkillItem/index.tsx @@ -1,14 +1,14 @@ -import React from "react" -import { useRouter } from "next/router" -import { useTranslation } from "next-i18next" +import React from 'react' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' -import classNames from "classnames" -import PlusIcon from "~public/icons/Add.svg" +import classNames from 'classnames' +import PlusIcon from '~public/icons/Add.svg' -import "./index.scss" +import './index.scss' // Props -interface Props extends React.ComponentPropsWithoutRef<"div"> { +interface Props extends React.ComponentPropsWithoutRef<'div'> { skill?: JobSkill editable: boolean hasJob: boolean @@ -17,11 +17,11 @@ interface Props extends React.ComponentPropsWithoutRef<"div"> { const JobSkillItem = React.forwardRef( function useJobSkillItem({ ...props }, forwardedRef) { const router = useRouter() - const { t } = useTranslation("common") + const { t } = useTranslation('common') const locale = - router.locale && ["en", "ja"].includes(router.locale) + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale - : "en" + : 'en' const classes = classNames({ JobSkill: true, @@ -47,7 +47,7 @@ const JobSkillItem = React.forwardRef( } else { jsx = (
        - {props.editable && props.hasJob ? : ""} + {props.editable && props.hasJob ? : ''}
        ) } @@ -61,9 +61,9 @@ const JobSkillItem = React.forwardRef( if (props.skill) { jsx =

        {props.skill.name[locale]}

        } else if (props.editable && props.hasJob) { - jsx =

        {t("job_skills.state.selectable")}

        + jsx =

        {t('job_skills.state.selectable')}

        } else { - jsx =

        {t("job_skills.state.no_skill")}

        + jsx =

        {t('job_skills.state.no_skill')}

        } return jsx diff --git a/components/JobSkillResult/index.scss b/components/JobSkillResult/index.scss index c8308b05..a2cc2cdf 100644 --- a/components/JobSkillResult/index.scss +++ b/components/JobSkillResult/index.scss @@ -6,57 +6,57 @@ align-items: center; &:hover { - background: $grey-90; + background: var(--button-contained-bg); cursor: pointer; - .Info .skill.pill { - background: $grey-80; + .Info h5 { + color: var(--text-primary); } } .Info { display: flex; flex-direction: row; - gap: calc($unit / 2); + gap: $unit-half; width: 100%; .skill.pill { background: $grey-90; border-radius: $unit * 2; - color: $grey-00; + color: $grey-15; display: inline; font-size: $font-tiny; font-weight: $medium; - padding: calc($unit / 2) $unit; + padding: $unit-half $unit; &.buffing { - background-color: $light-bg-dark; - color: $light-text-dark; + background-color: $light-bg-10; + color: $light-text-10; } &.debuffing { - background-color: $water-bg-dark; - color: $water-text-dark; + background-color: $water-bg-10; + color: $water-text-10; } &.healing { - background-color: $wind-bg-dark; - color: $wind-text-dark; + background-color: $wind-bg-10; + color: $wind-text-10; } &.damaging { - background-color: $fire-bg-dark; - color: $fire-text-dark; + background-color: $fire-bg-10; + color: $fire-text-10; } &.field { - background-color: $dark-bg-dark; - color: $dark-text-dark; + background-color: $dark-bg-20; + color: $dark-text-10; } } h5 { - color: #555; + color: var(--text-secondary); display: inline-block; font-size: $font-medium; font-weight: $medium; @@ -65,7 +65,7 @@ } img { - width: $unit * 6; - height: $unit * 6; + width: $unit-6x; + height: $unit-6x; } } diff --git a/components/JobSkillResult/index.tsx b/components/JobSkillResult/index.tsx index 09c08028..66d9333b 100644 --- a/components/JobSkillResult/index.tsx +++ b/components/JobSkillResult/index.tsx @@ -1,8 +1,8 @@ -import React, { useEffect, useState } from "react" -import { useRouter } from "next/router" -import { SkillGroup, skillClassification } from "~utils/skillGroups" +import React, { useEffect, useState } from 'react' +import { useRouter } from 'next/router' +import { SkillGroup, skillClassification } from '~utils/skillGroups' -import "./index.scss" +import './index.scss' interface Props { data: JobSkill @@ -12,7 +12,7 @@ interface Props { const JobSkillResult = (props: Props) => { const router = useRouter() const locale = - router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" + router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' const skill = props.data @@ -30,7 +30,7 @@ const JobSkillResult = (props: Props) => { {skill.name[locale]}
        {skill.name[locale]}
        -
        +
        {group?.name[locale]}
        diff --git a/components/JobSkillSearchFilterBar/index.scss b/components/JobSkillSearchFilterBar/index.scss index 6ccb5e2e..32ea1453 100644 --- a/components/JobSkillSearchFilterBar/index.scss +++ b/components/JobSkillSearchFilterBar/index.scss @@ -1,3 +1,3 @@ -.SearchFilterBar select { - background-color: $grey-90; +.SearchFilterBar .SelectTrigger { + width: 100%; } diff --git a/components/JobSkillSearchFilterBar/index.tsx b/components/JobSkillSearchFilterBar/index.tsx index 1de78add..6d442024 100644 --- a/components/JobSkillSearchFilterBar/index.tsx +++ b/components/JobSkillSearchFilterBar/index.tsx @@ -1,10 +1,10 @@ -import React, { useEffect, useState } from "react" -import { useRouter } from "next/router" -import { useTranslation } from "react-i18next" +import React, { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' -import { skillGroups } from "~utils/skillGroups" +import Select from '~components/Select' +import SelectItem from '~components/SelectItem' -import "./index.scss" +import './index.scss' interface Props { sendFilters: (filters: { [key: string]: number }) => void @@ -12,15 +12,18 @@ interface Props { const JobSkillSearchFilterBar = (props: Props) => { // Set up translation - const { t } = useTranslation("common") + const { t } = useTranslation('common') + const [open, setOpen] = useState(false) const [currentGroup, setCurrentGroup] = useState(-1) - function onChange(event: React.ChangeEvent) { - setCurrentGroup(parseInt(event.target.value)) + function openSelect() { + setOpen(!open) } - function onBlur(event: React.ChangeEvent) {} + function onChange(value: string) { + setCurrentGroup(parseInt(value)) + } function sendFilters() { const filters = { @@ -36,34 +39,35 @@ const JobSkillSearchFilterBar = (props: Props) => { return (
        - + +
        ) } diff --git a/components/Layout/index.tsx b/components/Layout/index.tsx index 5d03fb7c..ce3b6781 100644 --- a/components/Layout/index.tsx +++ b/components/Layout/index.tsx @@ -2,10 +2,10 @@ import type { ReactElement } from 'react' import TopHeader from '~components/TopHeader' interface Props { - children: ReactElement + children: ReactElement } -const Layout = ({children}: Props) => { +const Layout = ({ children }: Props) => { return ( <> @@ -14,4 +14,4 @@ const Layout = ({children}: Props) => { ) } -export default Layout \ No newline at end of file +export default Layout diff --git a/components/LoginModal/index.scss b/components/LoginModal/index.scss index f77633b8..e73b400d 100644 --- a/components/LoginModal/index.scss +++ b/components/LoginModal/index.scss @@ -1,31 +1,31 @@ .Login.Dialog form { - display: flex; - flex-direction: column; - gap: calc($unit / 2); - margin-bottom: $unit; + display: flex; + flex-direction: column; + gap: calc($unit / 2); + margin-bottom: $unit; - .Button { - font-size: $font-regular; - padding: ($unit * 1.5) ($unit * 2); - width: 100%; + .Button { + font-size: $font-regular; + padding: ($unit * 1.5) ($unit * 2); + width: 100%; - &.btn-disabled { - background: $grey-90; - color: $grey-70; - cursor: not-allowed; - } - - &:not(.btn-disabled) { - background: $grey-90; - color: $grey-40; - - &:hover { - background: $grey-80; - } - } + &.btn-disabled { + background: $grey-90; + color: $grey-70; + cursor: not-allowed; } - input { - background: $grey-90; + &:not(.btn-disabled) { + background: $grey-90; + color: $grey-50; + + &:hover { + background: $grey-80; + } } -} \ No newline at end of file + } + + input { + background: $grey-90; + } +} diff --git a/components/LoginModal/index.tsx b/components/LoginModal/index.tsx index de5f5443..2851d6db 100644 --- a/components/LoginModal/index.tsx +++ b/components/LoginModal/index.tsx @@ -1,19 +1,19 @@ -import React, { useState } from "react" -import { setCookie } from "cookies-next" -import Router, { useRouter } from "next/router" -import { useTranslation } from "react-i18next" -import { AxiosResponse } from "axios" +import React, { useState } from 'react' +import { setCookie } from 'cookies-next' +import Router, { useRouter } from 'next/router' +import { useTranslation } from 'react-i18next' +import { AxiosResponse } from 'axios' -import * as Dialog from "@radix-ui/react-dialog" +import * as Dialog from '@radix-ui/react-dialog' -import api from "~utils/api" -import { accountState } from "~utils/accountState" +import api from '~utils/api' +import { accountState } from '~utils/accountState' -import Button from "~components/Button" -import Fieldset from "~components/Fieldset" +import Button from '~components/Button' +import Fieldset from '~components/Input' -import CrossIcon from "~public/icons/Cross.svg" -import "./index.scss" +import CrossIcon from '~public/icons/Cross.svg' +import './index.scss' interface Props {} @@ -28,13 +28,13 @@ const emailRegex = const LoginModal = (props: Props) => { const router = useRouter() - const { t } = useTranslation("common") + const { t } = useTranslation('common') // Set up form states and error handling const [formValid, setFormValid] = useState(false) const [errors, setErrors] = useState({ - email: "", - password: "", + email: '', + password: '', }) // States @@ -50,17 +50,17 @@ const LoginModal = (props: Props) => { let newErrors = { ...errors } switch (name) { - case "email": + case 'email': if (value.length == 0) - newErrors.email = t("modals.login.errors.empty_email") + newErrors.email = t('modals.login.errors.empty_email') else if (!emailRegex.test(value)) - newErrors.email = t("modals.login.errors.invalid_email") - else newErrors.email = "" + newErrors.email = t('modals.login.errors.invalid_email') + else newErrors.email = '' break - case "password": + case 'password': newErrors.password = - value.length == 0 ? t("modals.login.errors.empty_password") : "" + value.length == 0 ? t('modals.login.errors.empty_password') : '' break default: @@ -91,7 +91,7 @@ const LoginModal = (props: Props) => { const body = { email: emailInput.current?.value, password: passwordInput.current?.value, - grant_type: "password", + grant_type: 'password', } if (formValid) { @@ -119,7 +119,7 @@ const LoginModal = (props: Props) => { token: response.data.access_token, } - setCookie("account", cookieObj, { path: "/" }) + setCookie('account', cookieObj, { path: '/' }) } function storeUserInfo(response: AxiosResponse) { @@ -132,7 +132,7 @@ const LoginModal = (props: Props) => { gender: user.gender, } - setCookie("user", cookieObj, { path: "/" }) + setCookie('user', cookieObj, { path: '/' }) accountState.account.user = { id: user.id, @@ -142,7 +142,7 @@ const LoginModal = (props: Props) => { gender: user.gender, } - console.log("Authorizing account...") + console.log('Authorizing account...') accountState.account.authorized = true setOpen(false) @@ -151,7 +151,7 @@ const LoginModal = (props: Props) => { function changeLanguage(newLanguage: string) { if (newLanguage !== router.locale) { - setCookie("NEXT_LOCALE", newLanguage, { path: "/" }) + setCookie('NEXT_LOCALE', newLanguage, { path: '/' }) router.push(router.asPath, undefined, { locale: newLanguage }) } } @@ -159,8 +159,8 @@ const LoginModal = (props: Props) => { function openChange(open: boolean) { setOpen(open) setErrors({ - email: "", - password: "", + email: '', + password: '', }) } @@ -168,7 +168,7 @@ const LoginModal = (props: Props) => {
      • - {t("menu.login")} + {t('menu.login')}
      • @@ -178,7 +178,7 @@ const LoginModal = (props: Props) => { >
        - {t("modals.login.title")} + {t('modals.login.title')} @@ -190,7 +190,7 @@ const LoginModal = (props: Props) => {
        {
        - + diff --git a/components/Party/index.scss b/components/Party/index.scss index 47c0c0f6..c6b14b47 100644 --- a/components/Party/index.scss +++ b/components/Party/index.scss @@ -1,7 +1,7 @@ #Party .Extra { - color: #888; - display: flex; - font-weight: 500; - gap: 8px; - line-height: 34px; -} \ No newline at end of file + color: #888; + display: flex; + font-weight: 500; + gap: 8px; + line-height: 34px; +} diff --git a/components/Party/index.tsx b/components/Party/index.tsx index 677a2ec8..6fcc15b9 100644 --- a/components/Party/index.tsx +++ b/components/Party/index.tsx @@ -1,20 +1,20 @@ -import React, { useCallback, useEffect, useMemo, useState } from "react" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" -import { getCookie } from "cookies-next" -import clonedeep from "lodash.clonedeep" +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' +import { getCookie } from 'cookies-next' +import clonedeep from 'lodash.clonedeep' -import PartySegmentedControl from "~components/PartySegmentedControl" -import PartyDetails from "~components/PartyDetails" -import WeaponGrid from "~components/WeaponGrid" -import SummonGrid from "~components/SummonGrid" -import CharacterGrid from "~components/CharacterGrid" +import PartySegmentedControl from '~components/PartySegmentedControl' +import PartyDetails from '~components/PartyDetails' +import WeaponGrid from '~components/WeaponGrid' +import SummonGrid from '~components/SummonGrid' +import CharacterGrid from '~components/CharacterGrid' -import api from "~utils/api" -import { appState, initialAppState } from "~utils/appState" -import { GridType, TeamElement } from "~utils/enums" +import api from '~utils/api' +import { appState, initialAppState } from '~utils/appState' +import { GridType, TeamElement } from '~utils/enums' -import "./index.scss" +import './index.scss' // Props interface Props { @@ -26,7 +26,7 @@ interface Props { const Party = (props: Props) => { // Cookies - const cookie = getCookie("account") + const cookie = getCookie('account') const accountData: AccountCookie = cookie ? JSON.parse(cookie as string) : null @@ -113,7 +113,7 @@ const Party = (props: Props) => { .destroy({ id: appState.party.id, params: headers }) .then(() => { // Push to route - router.push("/") + router.push('/') // Clean state const resetState = clonedeep(initialAppState) @@ -188,16 +188,16 @@ const Party = (props: Props) => { // Methods: Navigating with segmented control function segmentClicked(event: React.ChangeEvent) { switch (event.target.value) { - case "class": + case 'class': setCurrentTab(GridType.Class) break - case "characters": + case 'characters': setCurrentTab(GridType.Character) break - case "weapons": + case 'weapons': setCurrentTab(GridType.Weapon) break - case "summons": + case 'summons': setCurrentTab(GridType.Summon) break default: @@ -253,7 +253,7 @@ const Party = (props: Props) => { } return ( -
        + {navigation}
        {currentGrid()}
        { @@ -263,7 +263,7 @@ const Party = (props: Props) => { deleteCallback={deleteTeam} /> } -
        + ) } diff --git a/components/PartyDetails/index.scss b/components/PartyDetails/index.scss index 50f88ffb..f5297a37 100644 --- a/components/PartyDetails/index.scss +++ b/components/PartyDetails/index.scss @@ -1,153 +1,159 @@ .PartyDetails { - display: none; // This breaks transition, find a workaround - opacity: 0; - margin: 0 auto; - margin-bottom: 100px; - max-width: $unit * 95; - position: relative; + display: none; // This breaks transition, find a workaround + opacity: 0; + margin: $unit-4x auto 0; + max-width: $unit * 94; + position: relative; - &.Editable { - top: $unit; - height: 0; - z-index: 2; - transition: opacity 0.2s ease-in-out, - top 0.2s ease-in-out; + &.Editable { + top: $unit; + height: 0; + z-index: 2; + transition: opacity 0.2s ease-in-out, top 0.2s ease-in-out; - - &.Visible { - display: block; - height: auto; - margin-bottom: 40vh; - opacity: 1; - top: 0; - } - - fieldset { - display: block; - width: 100%; - - textarea { - min-height: $unit * 20; - width: 100%; - } - } - - .bottom { - display: flex; - flex-direction: row; - gap: $unit; - - .left { - flex-grow: 1; - } - - .right { - display: flex; - flex-direction: row; - gap: $unit; - } - } + &.Visible { + display: flex; + flex-direction: column; + gap: $unit; + height: auto; + opacity: 1; + top: 0; } - &.ReadOnly { - top: $unit * -1; - transition: opacity 0.2s ease-in-out, - top 0.2s ease-in-out; + fieldset { + display: block; + width: 100%; - &.Visible { - display: block; - height: auto; - opacity: 1; - top: 0; - } + textarea { + min-height: $unit * 20; + width: 100%; + } + } - a:hover { - text-decoration: underline; - } + .bottom { + display: flex; + flex-direction: row; + gap: $unit; + margin-bottom: $unit-12x; - p { - font-size: $font-regular; - line-height: $font-regular * 1.2; - white-space: pre-line; - } + .left { + flex-grow: 1; + } + .right { + display: flex; + flex-direction: row; + gap: $unit; + } + } + } + + &.ReadOnly { + top: $unit * -1; + transition: opacity 0.2s ease-in-out, top 0.2s ease-in-out; + + &.Visible { + display: block; + height: auto; + opacity: 1; + top: 0; + } + + a:hover { + text-decoration: underline; + } + + p { + font-size: $font-regular; + 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; 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; - } + color: var(--text-primary); + + &.empty { + color: var(--text-secondary); + } } + } } + + .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; + display: none; + justify-content: center; + margin: $unit-4x 0 $unit-10x; - &.Visible { - display: flex; - } -} \ No newline at end of file + &.Visible { + display: flex; + } +} diff --git a/components/PartyDetails/index.tsx b/components/PartyDetails/index.tsx index b432f127..59ff9714 100644 --- a/components/PartyDetails/index.tsx +++ b/components/PartyDetails/index.tsx @@ -1,34 +1,37 @@ -import React, { useState } from "react" -import Head from "next/head" -import { useRouter } from "next/router" -import { useSnapshot } from "valtio" -import { useTranslation } from "next-i18next" +import React, { useState } from 'react' +import Head from 'next/head' +import { useRouter } from 'next/router' +import { useSnapshot } from 'valtio' +import { useTranslation } from 'next-i18next' -import Linkify from "react-linkify" -import classNames from "classnames" +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 * as AlertDialog from '@radix-ui/react-alert-dialog' -import Button from "~components/Button" -import CharLimitedFieldset from "~components/CharLimitedFieldset" -import RaidDropdown from "~components/RaidDropdown" -import TextFieldset from "~components/TextFieldset" +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 { accountState } from '~utils/accountState' +import { appState } from '~utils/appState' -import "./index.scss" -import Link from "next/link" -import { formatTimeAgo } from "~utils/timeAgo" +import CheckIcon from '~public/icons/Check.svg' +import CrossIcon from '~public/icons/Cross.svg' +import EditIcon from '~public/icons/Edit.svg' + +import './index.scss' +import Link from 'next/link' +import { formatTimeAgo } from '~utils/timeAgo' const emptyRaid: Raid = { - id: "", + id: '', name: { - en: "", - ja: "", + en: '', + ja: '', }, - slug: "", + slug: '', level: 0, group: 0, element: 0, @@ -47,9 +50,9 @@ const PartyDetails = (props: Props) => { const { party, raids } = useSnapshot(appState) const { account } = useSnapshot(accountState) - const { t } = useTranslation("common") + const { t } = useTranslation('common') const router = useRouter() - const locale = router.locale || "en" + const locale = router.locale || 'en' const nameInput = React.createRef() const descriptionInput = React.createRef() @@ -87,8 +90,8 @@ const PartyDetails = (props: Props) => { }) const [errors, setErrors] = useState<{ [key: string]: string }>({ - name: "", - description: "", + name: '', + description: '', }) function handleInputChange(event: React.ChangeEvent) { @@ -140,7 +143,7 @@ const PartyDetails = (props: Props) => { return (
        {userImage()} - {party.user ? party.user.username : t("no_user")} + {party.user ? party.user.username : t('no_user')}
        ) } @@ -169,30 +172,30 @@ const PartyDetails = (props: Props) => { if (party.editable) { return ( - - + + - {t("buttons.delete")} + {t('buttons.delete')} - {t("modals.delete_team.title")} + {t('modals.delete_team.title')} - {t("modals.delete_team.description")} + {t('modals.delete_team.description')}
        - {t("modals.delete_team.buttons.cancel")} + {t('modals.delete_team.buttons.cancel')} props.deleteCallback(e)} > - {t("modals.delete_team.buttons.confirm")} + {t('modals.delete_team.buttons.confirm')}
        @@ -200,7 +203,7 @@ const PartyDetails = (props: Props) => {
        ) } else { - return "" + return '' } } @@ -217,13 +220,13 @@ const PartyDetails = (props: Props) => { /> {
        - {router.pathname !== "/new" ? deleteButton() : ""} + {router.pathname !== '/new' ? deleteButton() : ''}
        - - - +
        @@ -252,10 +254,12 @@ const PartyDetails = (props: Props) => {
        - {party.name ?

        {party.name}

        : ""} +

        + {party.name ? party.name : 'Untitled'} +

        {party.user ? linkedUserBlock(party.user) : userBlock()} - {party.raid ? linkedRaidBlock(party.raid) : ""} + {party.raid ? linkedRaidBlock(party.raid) : ''} {party.created_at != undefined ? ( ) : ( - "" + '' )}
        {party.editable ? ( - +
        ) @@ -291,59 +297,24 @@ const PartyDetails = (props: Props) => { const emptyDetails = (
        {party.editable ? ( - +
        + ) } export default PartySegmentedControl diff --git a/components/RaidDropdown/index.tsx b/components/RaidDropdown/index.tsx index a8202e81..636caf0c 100644 --- a/components/RaidDropdown/index.tsx +++ b/components/RaidDropdown/index.tsx @@ -1,6 +1,10 @@ import React, { useCallback, useEffect, useState } from 'react' import { useRouter } from 'next/router' +import Select from '~components/Select' +import SelectItem from '~components/SelectItem' +import SelectGroup from '~components/SelectGroup' + import api from '~utils/api' import { appState } from '~utils/appState' import { raidGroups } from '~utils/raidGroups' @@ -9,104 +13,136 @@ import './index.scss' // Props interface Props { - showAllRaidsOption: boolean - currentRaid?: string - onChange?: (slug?: string) => void - onBlur?: (event: React.ChangeEvent) => void + showAllRaidsOption: boolean + currentRaid?: string + defaultRaid?: string + onChange?: (slug?: string) => void + onBlur?: (event: React.ChangeEvent) => void } -const RaidDropdown = React.forwardRef(function useFieldSet(props, ref) { +const RaidDropdown = React.forwardRef( + function useFieldSet(props, ref) { // Set up router for locale const router = useRouter() const locale = router.locale || 'en' // Set up local states for storing raids + const [open, setOpen] = useState(false) const [currentRaid, setCurrentRaid] = useState() const [raids, setRaids] = useState() const [sortedRaids, setSortedRaids] = useState() + function openRaidSelect() { + setOpen(!open) + } + // Organize raids into groups on mount - const organizeRaids = useCallback((raids: Raid[]) => { + const organizeRaids = useCallback( + (raids: Raid[]) => { // Set up empty raid for "All raids" const all = { - id: '0', - name: { - en: 'All raids', - ja: '全て' - }, - slug: 'all', - level: 0, - group: 0, - element: 0 + id: '0', + name: { + en: 'All raids', + ja: '全て', + }, + slug: 'all', + level: 0, + group: 0, + element: 0, } - - const numGroups = Math.max.apply(Math, raids.map(raid => raid.group)) + + const numGroups = Math.max.apply( + Math, + raids.map((raid) => raid.group) + ) let groupedRaids = [] for (let i = 0; i <= numGroups; i++) { - groupedRaids[i] = raids.filter(raid => raid.group == i) + groupedRaids[i] = raids.filter((raid) => raid.group == i) } if (props.showAllRaidsOption) { - raids.unshift(all) - groupedRaids[0].unshift(all) + raids.unshift(all) + groupedRaids[0].unshift(all) } setRaids(raids) setSortedRaids(groupedRaids) appState.raids = raids - }, [props.showAllRaidsOption]) + }, + [props.showAllRaidsOption] + ) // Fetch all raids on mount useEffect(() => { - api.endpoints.raids.getAll() - .then(response => organizeRaids(response.data.map((r: any) => r.raid))) + api.endpoints.raids + .getAll() + .then((response) => + organizeRaids(response.data.map((r: any) => r.raid)) + ) }, [organizeRaids]) // Set current raid on mount useEffect(() => { - if (raids && props.currentRaid) { - const raid = raids.find(raid => raid.slug === props.currentRaid) - setCurrentRaid(raid) - } + if (raids && props.currentRaid) { + const raid = raids.find((raid) => raid.slug === props.currentRaid) + setCurrentRaid(raid) + } }, [raids, props.currentRaid]) // Enable changing select value - function handleChange(event: React.ChangeEvent) { - if (props.onChange) props.onChange(event.target.value) + function handleChange(value: string) { + console.log(value) + if (props.onChange) props.onChange(value) - if (raids) { - const raid = raids.find(raid => raid.slug === event.target.value) - setCurrentRaid(raid) - } + if (raids) { + const raid = raids.find((raid) => raid.slug === value) + setCurrentRaid(raid) + } } // Render JSX for each raid option, sorted into optgroups function renderRaidGroup(index: number) { - const options = sortedRaids && sortedRaids.length > 0 && sortedRaids[index].length > 0 && - sortedRaids[index].sort((a, b) => a.element - b.element).map((item, i) => { - return ( - - ) - }) - - return ( - - {options} - - ) + const options = + sortedRaids && + sortedRaids.length > 0 && + sortedRaids[index].length > 0 && + sortedRaids[index] + .sort((a, b) => a.element - b.element) + .map((item, i) => { + return ( + + {item.name[locale]} + + ) + }) + return ( + + {options} + + ) } - + return ( - + ) -}) + } +) export default RaidDropdown diff --git a/components/SearchFilter/index.scss b/components/SearchFilter/index.scss index 0c1bf29e..557ca3a8 100644 --- a/components/SearchFilter/index.scss +++ b/components/SearchFilter/index.scss @@ -1,74 +1,72 @@ -.DropdownLabel { - align-items: center; - background: $grey-90; - border: none; - border-radius: $unit * 2; - color: $grey-40; - display: flex; - gap: calc($unit / 2); - flex-direction: row; - padding: ($unit) ($unit * 2); +button.DropdownLabel { + align-items: center; + background: var(--button-contained-bg); + border: none; + border-radius: $unit-2x; + color: var(--text-secondary); + display: flex; + font-size: $font-small; + gap: $unit-half; + flex-direction: row; + padding: $unit ($unit * 1.5) $unit $unit-2x; - &:hover { - background: $grey-80; - color: $grey-00; - cursor: pointer; - } - - .count { - color: $grey-60; - font-weight: $medium; - } - - & > .icon { - $diameter: 12px; - height: $diameter; - width: $diameter; - - svg { - transform: scale(0.85); - - path { - fill: $grey-60; - } - } + &:hover { + background: var(--button-contained-bg-hover); + color: var(--text-primary); + cursor: pointer; + } + + .count { + color: var(--text-tertiary); + font-weight: $medium; + } + + & > .icon { + $diameter: 16px; + height: $diameter; + width: $diameter; + + svg { + path { + fill: $grey-60; + } } + } } .Dropdown { - background: white; - border-radius: $unit; - box-shadow: 0 0 2px rgba(0, 0, 0, 0.18); + background: var(--button-contained-bg); + border-radius: $unit; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.18); + display: flex; + flex-direction: column; + padding: $unit; + min-width: 120px; + + & > span { + overflow: hidden; + + svg { + fill: var(--button-contained-bg); + filter: drop-shadow(0px 0px 1px rgb(0 0 0 / 0.18)); + } + } + + section { display: flex; + flex-direction: row; + gap: $unit; + } + + .Group { + flex: 1 1 0px; flex-direction: column; - gap: calc($unit / 2); - padding: $unit; - min-width: 120px; + } - & > span { - overflow: hidden; - - svg { - fill: white; - filter: drop-shadow(0px 0px 1px rgb(0 0 0 / 0.18)); - } - } - - section { - display: flex; - flex-direction: row; - gap: $unit; - } - - .Group { - flex: 1 1 0px; - flex-direction: column; - } - - .Label { - color: $grey-60; - font-size: $font-small; - margin-bottom: calc($unit / 2); - padding-left: calc($unit / 2); - } -} \ No newline at end of file + .Label { + color: var(--text-tertiary); + font-size: $font-small; + margin-bottom: $unit-half; + padding: $unit-half 0 $unit $unit-half; + } +} diff --git a/components/SearchFilter/index.tsx b/components/SearchFilter/index.tsx index 8d6678fb..2cef27a9 100644 --- a/components/SearchFilter/index.tsx +++ b/components/SearchFilter/index.tsx @@ -6,29 +6,29 @@ import ArrowIcon from '~public/icons/Arrow.svg' import './index.scss' interface Props { - label: string - open: boolean - numSelected: number - onOpenChange: (open: boolean) => void - children: React.ReactNode + label: string + open: boolean + numSelected: number + onOpenChange: (open: boolean) => void + children: React.ReactNode } const SearchFilter = (props: Props) => { - return ( - - - {props.label} - {props.numSelected} - - - - - - {props.children} - - - - ) + return ( + + + {props.label} + {props.numSelected} + + + + + + {props.children} + + + + ) } export default SearchFilter diff --git a/components/SearchFilterCheckboxItem/index.scss b/components/SearchFilterCheckboxItem/index.scss index 7a951781..13488857 100644 --- a/components/SearchFilterCheckboxItem/index.scss +++ b/components/SearchFilterCheckboxItem/index.scss @@ -1,41 +1,42 @@ .Item { + align-items: center; + border-radius: calc($unit / 2); + color: var(--text-secondary); + font-size: $font-regular; + line-height: 1.2; + min-width: 100px; + position: relative; + padding: $unit; + padding-left: $unit * 3.5; + + &:hover { + background: var(--button-contained-bg-hover); + color: var(--text-primary); + cursor: pointer; + } + + &[data-state='checked'] { + background: var(--button-contained-bg-hover); + + svg { + fill: var(--text-secondary); + } + } + + .Indicator { + $diameter: 20px; + + display: flex; align-items: center; - border-radius: calc($unit / 2); - color: $grey-40; - font-size: $font-regular; - line-height: 1.2; - min-width: 100px; - position: relative; - padding: $unit; - padding-left: $unit * 3; + justify-content: center; + position: absolute; + left: calc($unit / 2); + height: $diameter; + width: $diameter; - &:hover { - background: $grey-90; - cursor: pointer; + svg { + height: $diameter; + width: $diameter; } - - &[data-state="checked"] { - background: $grey-90; - - svg { - fill: $grey-50; - } - } - - .Indicator { - $diameter: 18px; - - display: flex; - align-items: center; - justify-content: center; - position: absolute; - left: calc($unit / 2); - height: $diameter; - width: $diameter; - - svg { - height: $diameter; - width: $diameter; - } - } -} \ No newline at end of file + } +} diff --git a/components/SearchFilterCheckboxItem/index.tsx b/components/SearchFilterCheckboxItem/index.tsx index b6429fec..0c2111fd 100644 --- a/components/SearchFilterCheckboxItem/index.tsx +++ b/components/SearchFilterCheckboxItem/index.tsx @@ -6,29 +6,30 @@ import CheckIcon from '~public/icons/Check.svg' import './index.scss' interface Props { - checked?: boolean - valueKey: string - onCheckedChange: (open: boolean, key: string) => void - children: React.ReactNode + checked?: boolean + valueKey: string + onCheckedChange: (open: boolean, key: string) => void + children: React.ReactNode } const SearchFilterCheckboxItem = (props: Props) => { - function handleCheckedChange(checked: boolean) { - props.onCheckedChange(checked, props.valueKey) - } + function handleCheckedChange(checked: boolean) { + props.onCheckedChange(checked, props.valueKey) + } - return ( - event.preventDefault() }> - - - - {props.children} - - ) + return ( + event.preventDefault()} + > + + + + {props.children} + + ) } export default SearchFilterCheckboxItem diff --git a/components/SearchModal/index.scss b/components/SearchModal/index.scss index 35862d4f..fa823095 100644 --- a/components/SearchModal/index.scss +++ b/components/SearchModal/index.scss @@ -1,98 +1,99 @@ .Search.Dialog { + display: flex; + flex-direction: column; + min-height: 431px; + width: 600px; + height: 480px; + gap: 0; + padding: 0; + + #Header { + border-bottom: 1px solid transparent; display: flex; flex-direction: column; - min-height: 431px; - width: 600px; - height: 480px; - gap: 0; - padding: 0; + gap: $unit; + padding-bottom: $unit * 2; - #Header { - border-bottom: 1px solid transparent; - display: flex; - flex-direction: column; - gap: $unit; - padding-bottom: $unit * 2; - - &.scrolled { - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - box-shadow: 0 0 8px rgba(0, 0, 0, 0.12); - } - - #Bar { - border-top-left-radius: $unit; - border-top-right-radius: $unit; - display: flex; - gap: $unit * 2.5; - margin: 0; - padding: ($unit * 3) ($unit * 3) 0 ($unit * 3); - position: sticky; - top: 0; - - button { - background: transparent; - border: none; - height: 42px; - padding: 0; - } - - label { - width: 100%; - - .Input { - background: $grey-90; - border: none; - border-radius: calc($unit / 2); - box-sizing: border-box; - font-size: $font-regular; - padding: $unit * 1.5; - text-align: left; - width: 100%; - } - } - } + &.scrolled { + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 0 8px rgba(0, 0, 0, 0.12); } - #Results { - margin: 0; - max-height: 356px; - padding: 0 ($unit * 1.5); - overflow-y: scroll; + #Bar { + align-items: center; + border-top-left-radius: $unit; + border-top-right-radius: $unit; + display: flex; + gap: $unit * 2.5; + margin: 0; + padding: ($unit * 3) ($unit * 3) 0 ($unit * 3); + position: sticky; + top: 0; - h5.total { - font-size: $font-regular; - font-weight: $normal; - color: $grey-40; - padding: calc($unit / 2) ($unit * 1.5); - } + button { + background: transparent; + border: none; + height: 42px; + padding: 0; + } - .footer { - align-items: center; - display: flex; - color: $grey-60; - font-size: $font-regular; - font-weight: $normal; - height: $unit * 10; - justify-content: center; - } + label { + width: 100%; - .WeaponResult:last-child { - margin-bottom: $unit * 1.5; - } + // .Input { + // background: $grey-90; + // border: none; + // border-radius: calc($unit / 2); + // box-sizing: border-box; + // font-size: $font-regular; + // padding: $unit * 1.5; + // text-align: left; + // width: 100%; + // } + } } + } + + #Results { + margin: 0; + max-height: 356px; + padding: 0 ($unit * 1.5); + overflow-y: scroll; + + h5.total { + font-size: $font-regular; + font-weight: $normal; + color: var(--text-tertiary); + padding: $unit-half ($unit * 1.5); + } + + .footer { + align-items: center; + display: flex; + color: var(--text-tertiary); + font-size: $font-regular; + font-weight: $normal; + height: $unit-10x; + justify-content: center; + } + + .WeaponResult:last-child { + margin-bottom: $unit * 1.5; + } + } } .Search.Dialog #NoResults { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - flex-grow: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex-grow: 1; } .Search.Dialog #NoResults h2 { - color: #ccc; - font-size: $font-large; - font-weight: 500; - margin-top: -32px; -} \ No newline at end of file + color: var(--text-secondary); + font-size: $font-large; + font-weight: 500; + margin-top: $unit-4x * -1; +} diff --git a/components/SearchModal/index.tsx b/components/SearchModal/index.tsx index c9ecfaf0..61b0e24a 100644 --- a/components/SearchModal/index.tsx +++ b/components/SearchModal/index.tsx @@ -1,35 +1,41 @@ -import React, { useEffect, useState } from "react" -import { getCookie, setCookie } from "cookies-next" -import { useRouter } from "next/router" -import { useTranslation } from "react-i18next" -import InfiniteScroll from "react-infinite-scroll-component" +import React, { useEffect, useState } from 'react' +import { getCookie, setCookie } from 'cookies-next' +import { useRouter } from 'next/router' +import { useTranslation } from 'react-i18next' +import InfiniteScroll from 'react-infinite-scroll-component' -import api from "~utils/api" +import api from '~utils/api' -import * as Dialog from "@radix-ui/react-dialog" +import { + Dialog, + DialogTrigger, + DialogContent, + DialogClose, +} from '~components/Dialog' -import CharacterSearchFilterBar from "~components/CharacterSearchFilterBar" -import WeaponSearchFilterBar from "~components/WeaponSearchFilterBar" -import SummonSearchFilterBar from "~components/SummonSearchFilterBar" -import JobSkillSearchFilterBar from "~components/JobSkillSearchFilterBar" +import Input from '~components/Input' +import CharacterSearchFilterBar from '~components/CharacterSearchFilterBar' +import WeaponSearchFilterBar from '~components/WeaponSearchFilterBar' +import SummonSearchFilterBar from '~components/SummonSearchFilterBar' +import JobSkillSearchFilterBar from '~components/JobSkillSearchFilterBar' -import CharacterResult from "~components/CharacterResult" -import WeaponResult from "~components/WeaponResult" -import SummonResult from "~components/SummonResult" -import JobSkillResult from "~components/JobSkillResult" +import CharacterResult from '~components/CharacterResult' +import WeaponResult from '~components/WeaponResult' +import SummonResult from '~components/SummonResult' +import JobSkillResult from '~components/JobSkillResult' -import type { SearchableObject, SearchableObjectArray } from "~types" +import type { SearchableObject, SearchableObjectArray } from '~types' -import "./index.scss" -import CrossIcon from "~public/icons/Cross.svg" -import cloneDeep from "lodash.clonedeep" +import './index.scss' +import CrossIcon from '~public/icons/Cross.svg' +import cloneDeep from 'lodash.clonedeep' interface Props { send: (object: SearchableObject, position: number) => any placeholderText: string fromPosition: number job?: Job - object: "weapons" | "characters" | "summons" | "job_skills" + object: 'weapons' | 'characters' | 'summons' | 'job_skills' children: React.ReactNode } @@ -39,7 +45,7 @@ const SearchModal = (props: Props) => { const locale = router.locale // Set up translation - const { t } = useTranslation("common") + const { t } = useTranslation('common') let searchInput = React.createRef() let scrollContainer = React.createRef() @@ -47,7 +53,7 @@ const SearchModal = (props: Props) => { const [firstLoad, setFirstLoad] = useState(true) const [filters, setFilters] = useState<{ [key: string]: any }>() const [open, setOpen] = useState(false) - const [query, setQuery] = useState("") + const [query, setQuery] = useState('') const [results, setResults] = useState([]) // Pagination states @@ -64,7 +70,7 @@ const SearchModal = (props: Props) => { if (text.length) { setQuery(text) } else { - setQuery("") + setQuery('') } } @@ -113,7 +119,7 @@ const SearchModal = (props: Props) => { : [] let recents: SearchableObjectArray = [] - if (props.object === "weapons") { + if (props.object === 'weapons') { recents = cloneDeep(cookieObj as Weapon[]) || [] if ( !recents.find( @@ -123,7 +129,7 @@ const SearchModal = (props: Props) => { ) { recents.unshift(result as Weapon) } - } else if (props.object === "summons") { + } else if (props.object === 'summons') { recents = cloneDeep(cookieObj as Summon[]) || [] if ( !recents.find( @@ -136,7 +142,7 @@ const SearchModal = (props: Props) => { } if (recents && recents.length > 5) recents.pop() - setCookie(`recent_${props.object}`, recents, { path: "/" }) + setCookie(`recent_${props.object}`, recents, { path: '/' }) sendData(result) } @@ -192,16 +198,16 @@ const SearchModal = (props: Props) => { let jsx switch (props.object) { - case "weapons": + case 'weapons': jsx = renderWeaponSearchResults() break - case "summons": + case 'summons': jsx = renderSummonSearchResults(results) break - case "characters": + case 'characters': jsx = renderCharacterSearchResults(results) break - case "job_skills": + case 'job_skills': jsx = renderJobSkillSearchResults(results) break } @@ -305,7 +311,7 @@ const SearchModal = (props: Props) => { function openChange() { if (open) { - setQuery("") + setQuery('') setFirstLoad(true) setResults([]) setRecordCount(0) @@ -317,61 +323,54 @@ const SearchModal = (props: Props) => { } return ( - - {props.children} - - -