diff --git a/components/ElementToggle/index.scss b/components/ElementToggle/index.module.scss similarity index 82% rename from components/ElementToggle/index.scss rename to components/ElementToggle/index.module.scss index d1910810..45e7d2c1 100644 --- a/components/ElementToggle/index.scss +++ b/components/ElementToggle/index.module.scss @@ -1,4 +1,4 @@ -.ToggleGroup { +.group { $height: 36px; background-color: var(--toggle-bg); @@ -15,7 +15,7 @@ height: auto; } - .ToggleItem { + .item { background: var(--toggle-bg); border: none; border-radius: 18px; @@ -47,32 +47,32 @@ &.fire { background: var(--fire-bg); - color: var(--fire-hover-text); + color: var(--fire-text-bg); } &.water { background: var(--water-bg); - color: var(--water-hover-text); + color: var(--water-text-bg); } &.earth { background: var(--earth-bg); - color: var(--earth-hover-text); + color: var(--earth-text-bg); } &.wind { background: var(--wind-bg); - color: var(--wind-hover-text); + color: var(--wind-text-bg); } &.dark { background: var(--dark-bg); - color: var(--dark-hover-text); + color: var(--dark-text-bg); } &.light { background: var(--light-bg); - color: var(--light-hover-text); + color: var(--light-text-bg); } } } diff --git a/components/ElementToggle/index.tsx b/components/ElementToggle/index.tsx index 0748b66f..b87e85fb 100644 --- a/components/ElementToggle/index.tsx +++ b/components/ElementToggle/index.tsx @@ -1,74 +1,114 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import { useRouter } from 'next/router' import { useTranslation } from 'next-i18next' +import classNames from 'classnames' import * as ToggleGroup from '@radix-ui/react-toggle-group' - -import './index.scss' +import styles from './index.module.scss' interface Props { currentElement: number - sendValue: (value: string) => void + sendValue: (value: number) => void } -const ElementToggle = (props: Props) => { +const ElementToggle = ({ currentElement, sendValue, ...props }: Props) => { + // Router and localization const router = useRouter() - const { t } = useTranslation('common') const locale = router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' + const { t } = useTranslation('common') + + // State: Component + const [element, setElement] = useState(currentElement) + + // Methods: Handlers + const handleElementChange = (value: string) => { + const newElement = parseInt(value) + setElement(newElement) + sendValue(newElement) + } + + // Methods: Rendering return ( {t('elements.null')} {t('elements.wind')} {t('elements.fire')} {t('elements.water')} {t('elements.earth')} {t('elements.dark')} diff --git a/components/ErrorSection/index.scss b/components/ErrorSection/index.module.scss similarity index 76% rename from components/ErrorSection/index.scss rename to components/ErrorSection/index.module.scss index be07a46c..78e41e59 100644 --- a/components/ErrorSection/index.scss +++ b/components/ErrorSection/index.module.scss @@ -1,4 +1,4 @@ -section.Error { +.error { align-items: center; display: flex; flex-direction: column; @@ -9,14 +9,13 @@ section.Error { height: 60vh; text-align: center; - .Code { + .code { color: var(--text-secondary); font-size: $font-tiny; font-weight: $bold; } - .Button { - margin-top: $unit-2x; - width: fit-content; + p { + margin-bottom: $unit-4x; } } diff --git a/components/ErrorSection/index.tsx b/components/ErrorSection/index.tsx index b606c798..0970d00e 100644 --- a/components/ErrorSection/index.tsx +++ b/components/ErrorSection/index.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next' import Button from '~components/common/Button' import { ResponseStatus } from '~types' -import './index.scss' +import styles from './index.module.scss' interface Props { status: ResponseStatus @@ -24,7 +24,7 @@ const ErrorSection = ({ status }: Props) => { const errorBody = () => { return ( <> -
{status.code}
+
{status.code}

{t(`errors.${statusText}.title`)}

{t(`errors.${statusText}.description`)}

@@ -32,7 +32,7 @@ const ErrorSection = ({ status }: Props) => { } return ( -
+
{errorBody()} {[401, 404].includes(status.code) ? ( diff --git a/components/FilterBar/index.scss b/components/FilterBar/index.scss deleted file mode 100644 index 148094e9..00000000 --- a/components/FilterBar/index.scss +++ /dev/null @@ -1,143 +0,0 @@ -.FilterBar { - align-items: center; - background: var(--bar-bg); - border-radius: $card-corner; - box-sizing: border-box; - display: flex; - flex-direction: row; - gap: $unit-2x; - 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: 100%; - max-width: 996px; - min-height: 80px; - - @include breakpoint(tablet) { - position: static; - flex-direction: column; - width: 100%; - } - - @include breakpoint(phone) { - min-height: auto; - } - - .Filters { - display: flex; - box-sizing: border-box; - flex-direction: row; - flex-grow: 1; - gap: $unit; - width: auto; - - @include breakpoint(tablet) { - flex-direction: column; - width: 100%; - } - - .Button.Filter.Blended { - &.FiltersActive .Accessory svg { - fill: var(--accent-blue); - stroke: none; - } - - &:hover { - background: var(--button-bg); - } - - .Accessory svg { - fill: none; - stroke: var(--button-text); - width: 18px; - height: 18px; - } - } - } - - &.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/Chevron.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); - font-size: $font-small; - margin: 0; - max-width: 200px; - - &:hover { - background-color: var(--select-contained-bg-hover); - } - - @include breakpoint(tablet) { - width: 100%; - max-width: inherit; - text-align: center; - } - } - - .SelectTrigger { - width: 100%; - - span { - font-size: $font-small; - } - } - - .Filter.Button { - justify-content: center; - - .Text { - display: none; - width: auto; - - @include breakpoint(tablet) { - display: block; - } - - @include breakpoint(phone) { - display: block; - } - } - } - - .UserInfo { - align-items: center; - display: flex; - flex-direction: row; - flex-grow: 1; - gap: $unit * 1.5; - - img { - $diameter: $unit * 6; - border-radius: calc($diameter / 2); - height: $diameter; - width: $diameter; - - &.gran { - background-color: #cee7fe; - } - - &.djeeta { - background-color: #ffe1fe; - } - } - } -} diff --git a/components/FilterModal/index.scss b/components/FilterModal/index.scss deleted file mode 100644 index 6be72ddf..00000000 --- a/components/FilterModal/index.scss +++ /dev/null @@ -1,15 +0,0 @@ -.Dialog { - .Filter.DialogContent { - overflow: hidden; - - .TableField .Right .SelectTrigger.Table { - width: $unit-20x; - min-width: auto; - } - } - - .DialogFooter .Buttons .Button.Blended { - padding-left: 0; - padding-right: 0; - } -} diff --git a/components/GridRep/index.scss b/components/GridRep/index.module.scss similarity index 73% rename from components/GridRep/index.scss rename to components/GridRep/index.module.scss index 4d5bd3df..e208225d 100644 --- a/components/GridRep/index.scss +++ b/components/GridRep/index.module.scss @@ -1,5 +1,6 @@ -.GridRep { +.gridRep { aspect-ratio: 3/2; + border: 1px solid transparent; border-radius: $card-corner; box-sizing: border-box; display: grid; @@ -11,18 +12,18 @@ &:hover { background: var(--grid-rep-hover); + border: 1px solid rgba(0, 0, 0, 0.1); a { text-decoration: none; } - h2, - .Grid { + .weaponGrid { cursor: pointer; - } - .Grid .Weapon { - box-shadow: inset 0 0 0 1px var(--grid-border-color); + .weapon { + background: var(--unit-bg-hover); + } } @include breakpoint(phone) { @@ -34,25 +35,25 @@ } } - & > .Grid { + & > .weaponGrid { aspect-ratio: 2/0.95; display: grid; grid-template-columns: 1fr 3.36fr; /* left column takes up 1 fraction, right column takes up 3 fractions */ grid-gap: $unit; /* add a gap of 8px between grid items */ - .Weapon { - background: var(--card-bg); + .weapon { + background: var(--unit-bg); border-radius: 4px; } - .Mainhand.Weapon { + .mainhand.weapon { aspect-ratio: 73/153; display: grid; grid-column: 1 / 2; /* spans one column */ - max-height: 140px; + height: calc(100% - $unit-fourth); } - .GridWeapons { + .weapons { display: grid; /* make the right-images container a grid */ grid-template-columns: repeat( 3, @@ -67,26 +68,27 @@ // row-gap: $unit-2x; } - .Grid.Weapon { + .grid.weapon { aspect-ratio: 280 / 160; display: grid; } - .Mainhand.Weapon img[src*='jpg'], - .Grid.Weapon img[src*='jpg'] { + .mainhand.weapon img[src*='jpg'], + .grid.weapon img[src*='jpg'] { border-radius: 4px; width: 100%; } } - .Details { + .details { display: flex; flex-direction: column; - gap: calc($unit / 2); + gap: $unit; h2 { color: var(--text-primary); font-size: $font-regular; + font-weight: $bold; overflow: hidden; padding-bottom: 1px; text-overflow: ellipsis; @@ -117,16 +119,21 @@ } } + .attributed, .bottom { display: flex; - flex-direction: row; + gap: $unit-half; + justify-content: space-between; a.user:hover { color: var(--link-text-hover); } } - .Properties, + .bottom { + flex-direction: column; + } + .user { flex-grow: 1; } @@ -134,23 +141,44 @@ .user, .raid, time { - color: $grey-55; + color: var(--text-tertiary); font-size: $font-small; } - .Properties { + time { + white-space: nowrap; + } + + .properties { + display: flex; + font-size: $font-small; + gap: $unit-half; + + .raid { + white-space: nowrap; + text-overflow: ellipsis; + } + .auto { + flex: 1; display: inline-flex; gap: $unit-half; flex-direction: row; - margin-left: $unit-half; + flex-wrap: nowrap; } - .full_auto { + .fullAuto { color: var(--full-auto-label-text); + white-space: nowrap; } - .auto_guard { + .extra { + color: var(--extra-purple-light-text); + white-space: nowrap; + } + + .autoGuard { + display: inline-block; width: 12px; height: 12px; @@ -162,7 +190,6 @@ .raid { color: var(--text-primary); - margin-bottom: calc($unit / 2); &.empty { color: var(--text-tertiary); diff --git a/components/GridRep/index.tsx b/components/GridRep/index.tsx index 6c3bc029..11220f95 100644 --- a/components/GridRep/index.tsx +++ b/components/GridRep/index.tsx @@ -13,7 +13,7 @@ import Button from '~components/common/Button' import SaveIcon from '~public/icons/Save.svg' import ShieldIcon from '~public/icons/Shield.svg' -import './index.scss' +import styles from './index.module.scss' interface Props { shortcode: string @@ -26,7 +26,6 @@ interface Props { autoGuard: boolean favorited: boolean createdAt: Date - displayUser?: boolean | false onClick: (shortcode: string) => void onSave?: (partyId: string, favorited: boolean) => void } @@ -50,13 +49,23 @@ const GridRep = (props: Props) => { }) const raidClass = classNames({ - raid: true, - empty: !props.raid, + [styles.raid]: true, + [styles.empty]: !props.raid, }) const userClass = classNames({ - user: true, - empty: !props.user, + [styles.user]: true, + [styles.empty]: !props.user, + }) + + const mainhandClasses = classNames({ + [styles.weapon]: true, + [styles.mainhand]: true, + }) + + const weaponClasses = classNames({ + [styles.weapon]: true, + [styles.grid]: true, }) useEffect(() => { @@ -156,76 +165,52 @@ const GridRep = (props: Props) => { ) } - const linkedAttribution = () => ( - - - {userImage()} - {props.user ? props.user.username : t('no_user')} - - - ) - - const unlinkedAttribution = () => ( -
+ const attribution = () => ( + {userImage()} {props.user ? props.user.username : t('no_user')} -
+ ) function fullAutoString() { const fullAutoElement = ( - + {` · ${t('party.details.labels.full_auto')}`} ) const autoGuardElement = ( - + ) return ( -
+
{fullAutoElement} {props.autoGuard ? autoGuardElement : ''}
) } - const details = ( -
-

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

-
-
- - {props.raid ? props.raid.name[locale] : t('no_raid')} - - {props.fullAuto ? fullAutoString() : ''} -
- -
-
- ) const detailsWithUsername = ( -
-
-
+
+
+

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

-
+
{props.raid ? props.raid.name[locale] : t('no_raid')} - {props.fullAuto ? ( - + {props.fullAuto && ( + {` · ${t('party.details.labels.full_auto')}`} - ) : ( - '' + )} + {props.raid && props.raid.group.extra && ( + {` · EX`} )}
@@ -234,11 +219,14 @@ const GridRep = (props: Props) => { !props.user) ? (
-
- {props.user ? linkedAttribution() : unlinkedAttribution()} +
+ {attribution()} -
@@ -258,15 +249,15 @@ const GridRep = (props: Props) => { return ( - - {props.displayUser ? detailsWithUsername : details} -
-
{generateMainhandImage()}
+
+ {detailsWithUsername} +
+
{generateMainhandImage()}
-
    +
      {Array.from(Array(numWeapons)).map((x, i) => { return ( -
    • +
    • {generateGridImage(i)}
    • ) diff --git a/components/GridRepCollection/index.scss b/components/GridRepCollection/index.module.scss similarity index 96% rename from components/GridRepCollection/index.scss rename to components/GridRepCollection/index.module.scss index 9044fe6c..686b6de0 100644 --- a/components/GridRepCollection/index.scss +++ b/components/GridRepCollection/index.module.scss @@ -1,4 +1,4 @@ -.GridRepCollection { +.collection { box-sizing: border-box; display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); diff --git a/components/GridRepCollection/index.tsx b/components/GridRepCollection/index.tsx index 6780cb79..82fd0bf0 100644 --- a/components/GridRepCollection/index.tsx +++ b/components/GridRepCollection/index.tsx @@ -1,18 +1,12 @@ -import classNames from 'classnames' import React from 'react' - -import './index.scss' +import styles from './index.module.scss' interface Props { children: React.ReactNode } const GridRepCollection = (props: Props) => { - const classes = classNames({ - GridRepCollection: true, - }) - - return
      {props.children}
      + return
      {props.children}
      } export default GridRepCollection diff --git a/components/Header/index.scss b/components/Header/index.module.scss similarity index 91% rename from components/Header/index.scss rename to components/Header/index.module.scss index bfa358ea..309ba5e0 100644 --- a/components/Header/index.scss +++ b/components/Header/index.module.scss @@ -1,4 +1,4 @@ -#Header { +.header { display: flex; flex-direction: row; margin-bottom: $unit; @@ -22,7 +22,7 @@ background: var(--placeholder-bg); } - #DropdownWrapper { + .dropdownWrapper { display: inline-block; padding-bottom: $unit; @@ -32,8 +32,6 @@ } &:hover { - // padding-right: $unit-4x; - .Button { background: var(--button-bg-hover); color: var(--button-text-hover); diff --git a/components/Header/index.tsx b/components/Header/index.tsx index 5bd6d940..cf714466 100644 --- a/components/Header/index.tsx +++ b/components/Header/index.tsx @@ -1,40 +1,36 @@ -import React, { useEffect, useState } from 'react' -import { subscribe, useSnapshot } from 'valtio' -import { setCookie, deleteCookie } from 'cookies-next' +import React, { useState } from 'react' +import { deleteCookie } from 'cookies-next' import { useRouter } from 'next/router' -import { Trans, useTranslation } from 'next-i18next' +import { useTranslation } from 'next-i18next' import classNames from 'classnames' import clonedeep from 'lodash.clonedeep' import Link from 'next/link' import { accountState, initialAccountState } from '~utils/accountState' import { appState, initialAppState } from '~utils/appState' -import { getLocalId } from '~utils/localId' -import { retrieveLocaleCookies } from '~utils/retrieveCookies' -import { setEditKey, storeEditKey } from '~utils/userToken' +import Alert from '~components/common/Alert' import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, DropdownMenuSeparator, - DropdownMenuLabel, } from '~components/common/DropdownMenuContent' +import DropdownMenuGroup from '~components/common/DropdownMenuGroup' +import DropdownMenuLabel from '~components/common/DropdownMenuLabel' +import DropdownMenuItem from '~components/common/DropdownMenuItem' +import LanguageSwitch from '~components/LanguageSwitch' import LoginModal from '~components/auth/LoginModal' import SignupModal from '~components/auth/SignupModal' import AccountModal from '~components/auth/AccountModal' -import Toast from '~components/common/Toast' import Button from '~components/common/Button' import Tooltip from '~components/common/Tooltip' -import * as Switch from '@radix-ui/react-switch' import ChevronIcon from '~public/icons/Chevron.svg' import MenuIcon from '~public/icons/Menu.svg' import PlusIcon from '~public/icons/Add.svg' -import './index.scss' +import styles from './index.module.scss' const Header = () => { // Localization @@ -44,37 +40,14 @@ const Header = () => { const router = useRouter() const locale = router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' - const localeData = retrieveLocaleCookies() // State management - const [remixToastOpen, setRemixToastOpen] = useState(false) + const [alertOpen, setAlertOpen] = useState(false) const [loginModalOpen, setLoginModalOpen] = useState(false) const [signupModalOpen, setSignupModalOpen] = useState(false) const [settingsModalOpen, setSettingsModalOpen] = useState(false) const [leftMenuOpen, setLeftMenuOpen] = useState(false) const [rightMenuOpen, setRightMenuOpen] = useState(false) - const [languageChecked, setLanguageChecked] = useState(false) - - const [name, setName] = useState('') - const [originalName, setOriginalName] = useState('') - - // Snapshots - const { party: partySnapshot } = useSnapshot(appState) - - // Subscribe to app state to listen for party name and - // unsubscribe when component is unmounted - const unsubscribe = subscribe(appState, () => { - const newName = - appState.party && appState.party.name ? appState.party.name : '' - setName(newName) - }) - - useEffect(() => () => unsubscribe(), []) - - // Hooks - useEffect(() => { - setLanguageChecked(localeData === 'ja' ? true : false) - }, [localeData]) // Methods: Event handlers (Buttons) function handleLeftMenuButtonClicked() { @@ -102,15 +75,6 @@ const Header = () => { setRightMenuOpen(false) } - // Methods: Event handlers (Remix toasts) - function handleRemixToastOpenChanged(open: boolean) { - setRemixToastOpen(open) - } - - function handleRemixToastCloseClicked() { - setRemixToastOpen(false) - } - // Methods: Actions function handleNewTeam(event: React.MouseEvent) { event.preventDefault() @@ -118,15 +82,6 @@ const Header = () => { closeRightMenu() } - function changeLanguage(value: boolean) { - const language = value ? 'ja' : 'en' - const expiresAt = new Date() - expiresAt.setDate(expiresAt.getDate() + 120) - - setCookie('NEXT_LOCALE', language, { path: '/', expires: expiresAt }) - router.push(router.asPath, undefined, { locale: language }) - } - function logout() { // Close menu closeRightMenu() @@ -153,15 +108,14 @@ const Header = () => { }) // Push the root URL - router.push('/new') + router.push('/new', undefined, { shallow: true }) } + // Methods: Rendering const profileImage = () => { - let image - const user = accountState.account.user if (accountState.account.authorized && user) { - image = ( + return ( {user.username} { /> ) } else { - image = ( + return ( {t('no_user')} { /> ) } - - return image } // Rendering: Buttons - const newButton = () => { - return ( - -
-
- ) - } + const authorizedLeftItems = ( + <> + {accountState.account.user && ( + <> + + + + {t('menu.profile')} + + + + {t('menu.saved')} + + + + )} + + ) + const leftMenuItems = ( + <> + {accountState.account.authorized && + accountState.account.user && + authorizedLeftItems} - const right = () => { - return ( -
- {newButton()} + + + {t('menu.teams')} + + +
+ {t('menu.guides')} + {t('coming_soon')} +
+
+
+ + +
+ {t('about.segmented_control.about')} + + + + + {t('about.segmented_control.updates')} + + + + + {t('about.segmented_control.roadmap')} + + + + + ) + + const left = ( +
+
- ) - } + +
+ ) - const leftMenuItems = () => { - return ( - <> - {accountState.account.authorized && accountState.account.user ? ( - <> - - - - {t('menu.profile')} - - - - {t('menu.saved')} - - - - ) : ( - '' - )} - - - {t('menu.teams')} - - -
- {t('menu.guides')} - {t('coming_soon')} -
-
-
- - - - {t('about.segmented_control.about')} - - - - - {t('about.segmented_control.updates')} - - - - - {t('about.segmented_control.roadmap')} - - - - - ) - } - - const rightMenuItems = () => { - let items - - const account = accountState.account - if (account.authorized && account.user) { - items = ( + const authorizedRightItems = ( + <> + {accountState.account.user && ( <> - - - {account.user ? `@${account.user.username}` : t('no_user')} + + + {`@${accountState.account.user.username}`} - - + + {t('menu.profile')} - + setSettingsModalOpen(true)} > {t('menu.settings')} - + setAlertOpen(true)} + destructive={true} + > {t('menu.logout')} - ) - } else { - items = ( - <> - - - {t('menu.language')} - - - JP - EN - - - - - setLoginModalOpen(true)} - > - {t('menu.login')} - - setSignupModalOpen(true)} - > - {t('menu.signup')} - - - - ) - } + )} + + ) - return items - } + const unauthorizedRightItems = ( + <> + + + {t('menu.language')} + + + + + setLoginModalOpen(true)} + > + {t('menu.login')} + + setSignupModalOpen(true)} + > + {t('menu.signup')} + + + + ) + + const rightMenuItems = ( + <> + {accountState.account.authorized && accountState.account.user + ? authorizedRightItems + : unauthorizedRightItems} + + ) + + const right = ( +
+ {newButton} + + +
+ ) return ( -