Merge pull request #74 from jedmund/fix-media-queries
Fix media queries
This commit is contained in:
commit
b705bf7765
32 changed files with 449 additions and 363 deletions
|
|
@ -10,7 +10,8 @@
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&.Blended:hover {
|
&.Blended:hover,
|
||||||
|
&.Blended.Active {
|
||||||
background: var(--button-bg-hover);
|
background: var(--button-bg-hover);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--button-text-hover);
|
color: var(--button-text-hover);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
max-width: 761px;
|
max-width: 761px;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
& > * {
|
& > * {
|
||||||
margin-right: $unit * 3;
|
margin-right: $unit * 3;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
margin-right: inherit;
|
margin-right: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
height: auto;
|
height: auto;
|
||||||
width: 131px;
|
width: 131px;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
width: 17vw;
|
width: 17vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
min-width: inherit;
|
min-width: inherit;
|
||||||
min-height: inherit;
|
min-height: inherit;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 9px;
|
left: 9px;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(phone) {
|
||||||
left: auto;
|
left: auto;
|
||||||
max-width: auto;
|
max-width: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
left: auto;
|
left: auto;
|
||||||
max-width: auto;
|
max-width: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 996px;
|
max-width: 996px;
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
position: static;
|
position: static;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
background-color: var(--select-contained-bg-hover);
|
background-color: var(--select-contained-bg-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: inherit;
|
max-width: inherit;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@
|
||||||
aspect-ratio: 3/2;
|
aspect-ratio: 3/2;
|
||||||
border-radius: $card-corner;
|
border-radius: $card-corner;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
grid-template-rows: 1fr 1fr;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
padding: $unit-2x;
|
padding: $unit-2x;
|
||||||
max-width: 320px;
|
min-width: 320px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--grid-rep-hover);
|
background: var(--grid-rep-hover);
|
||||||
|
|
@ -20,48 +21,58 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Grid .weapon {
|
.Grid .Weapon {
|
||||||
box-shadow: inset 0 0 0 1px var(--grid-border-color);
|
box-shadow: inset 0 0 0 1px var(--grid-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
background: inherit;
|
||||||
|
|
||||||
|
.Grid .Weapon {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Grid {
|
& > .Grid {
|
||||||
display: flex;
|
aspect-ratio: 2/1;
|
||||||
flex-direction: row;
|
display: grid;
|
||||||
flex-shrink: 0;
|
grid-template-columns: 1fr 3fr; /* left column takes up 1 fraction, right column takes up 3 fractions */
|
||||||
gap: $unit;
|
grid-template-rows: repeat(
|
||||||
|
3,
|
||||||
|
1fr
|
||||||
|
); /* create 3 rows, each taking up 1 fraction */
|
||||||
|
grid-gap: $unit; /* add a gap of 8px between grid items */
|
||||||
|
|
||||||
.weapon {
|
.Weapon {
|
||||||
background: var(--card-bg);
|
background: var(--card-bg);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid_mainhand {
|
.Mainhand.Weapon {
|
||||||
$d: 64px;
|
grid-column: 1 / 2; /* spans one column */
|
||||||
aspect-ratio: 200 / 418;
|
|
||||||
height: auto;
|
|
||||||
max-width: $d;
|
|
||||||
min-width: $d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid_weapons {
|
.GridWeapons {
|
||||||
$p: 29.5%;
|
display: grid; /* make the right-images container a grid */
|
||||||
box-sizing: border-box;
|
grid-template-columns: repeat(
|
||||||
display: grid;
|
3,
|
||||||
grid-template-columns: fit-content($p) fit-content($p) fit-content($p);
|
1fr
|
||||||
grid-template-rows: fit-content($p) fit-content($p) fit-content($p);
|
); /* create 3 columns, each taking up 1 fraction */
|
||||||
|
grid-template-rows: repeat(
|
||||||
|
3,
|
||||||
|
1fr
|
||||||
|
); /* create 3 rows, each taking up 1 fraction */
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid_weapon {
|
.Grid.Weapon {
|
||||||
aspect-ratio: 160 / 92;
|
aspect-ratio: 160 / 92;
|
||||||
|
display: grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid_mainhand img[src*='jpg'],
|
.Mainhand.Weapon img[src*='jpg'],
|
||||||
.grid_weapon img[src*='jpg'] {
|
.Grid.Weapon img[src*='jpg'] {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
||||||
|
|
@ -212,15 +212,12 @@ const GridRep = (props: Props) => {
|
||||||
<a className="GridRep">
|
<a className="GridRep">
|
||||||
{props.displayUser ? detailsWithUsername : details}
|
{props.displayUser ? detailsWithUsername : details}
|
||||||
<div className="Grid">
|
<div className="Grid">
|
||||||
<div className="weapon grid_mainhand">{generateMainhandImage()}</div>
|
<div className="Mainhand Weapon">{generateMainhandImage()}</div>
|
||||||
|
|
||||||
<ul className="grid_weapons">
|
<ul className="GridWeapons">
|
||||||
{Array.from(Array(numWeapons)).map((x, i) => {
|
{Array.from(Array(numWeapons)).map((x, i) => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li key={`${props.shortcode}-${i}`} className="Grid Weapon">
|
||||||
key={`${props.shortcode}-${i}`}
|
|
||||||
className="weapon grid_weapon"
|
|
||||||
>
|
|
||||||
{generateGridImage(i)}
|
{generateGridImage(i)}
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,20 @@
|
||||||
.GridRepCollection {
|
.GridRepCollection {
|
||||||
|
box-sizing: border-box;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
transition: opacity 0.14s ease-in-out;
|
transition: opacity 0.14s ease-in-out;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
// width: fit-content;
|
width: 100%;
|
||||||
width: auto;
|
|
||||||
max-width: 996px;
|
max-width: 996px;
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
grid-template-columns: minmax(320px, 1fr);
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
max-width: inherit;
|
max-width: inherit;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
max-width: inherit;
|
max-width: inherit;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,24 @@
|
||||||
.Header {
|
#Header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
margin-bottom: $unit;
|
margin-bottom: $unit;
|
||||||
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
&.bottom {
|
#Right > div {
|
||||||
position: sticky;
|
|
||||||
bottom: $unit * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#right > div {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: $unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown {
|
#DropdownWrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
|
||||||
padding-bottom: $unit;
|
padding-bottom: $unit;
|
||||||
|
|
||||||
|
&:hover .Menu,
|
||||||
|
.Menu.open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
padding-right: $unit-4x;
|
padding-right: $unit-4x;
|
||||||
|
|
||||||
|
|
@ -25,18 +26,10 @@
|
||||||
background: var(--button-bg-hover);
|
background: var(--button-bg-hover);
|
||||||
color: var(--button-text-hover);
|
color: var(--button-text-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.Menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.push {
|
@include breakpoint(phone) {
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
|
||||||
.Button .Text {
|
.Button .Text {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,189 @@
|
||||||
import React from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useSnapshot } from 'valtio'
|
||||||
|
import { deleteCookie } from 'cookies-next'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
|
import clonedeep from 'lodash.clonedeep'
|
||||||
|
|
||||||
|
import api from '~utils/api'
|
||||||
|
import { accountState, initialAccountState } from '~utils/accountState'
|
||||||
|
import { appState, initialAppState } from '~utils/appState'
|
||||||
|
|
||||||
|
import Button from '~components/Button'
|
||||||
|
import HeaderMenu from '~components/HeaderMenu'
|
||||||
|
|
||||||
|
import AddIcon from '~public/icons/Add.svg'
|
||||||
|
import LinkIcon from '~public/icons/Link.svg'
|
||||||
|
import MenuIcon from '~public/icons/Menu.svg'
|
||||||
|
import SaveIcon from '~public/icons/Save.svg'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
interface Props {
|
const Header = () => {
|
||||||
position: 'top' | 'bottom'
|
// Localization
|
||||||
left: JSX.Element
|
const { t } = useTranslation('common')
|
||||||
right: JSX.Element
|
|
||||||
}
|
// Router
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// State management
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
// Snapshots
|
||||||
|
const { account } = useSnapshot(accountState)
|
||||||
|
const { party } = useSnapshot(appState)
|
||||||
|
|
||||||
|
function menuButtonClicked() {
|
||||||
|
setOpen(!open)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClickOutsideMenu() {
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipboard() {
|
||||||
|
const el = document.createElement('input')
|
||||||
|
el.value = window.location.href
|
||||||
|
el.id = 'url-input'
|
||||||
|
document.body.appendChild(el)
|
||||||
|
|
||||||
|
el.select()
|
||||||
|
document.execCommand('copy')
|
||||||
|
el.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
function newParty() {
|
||||||
|
// Push the root URL
|
||||||
|
router.push('/')
|
||||||
|
|
||||||
|
// Clean state
|
||||||
|
const resetState = clonedeep(initialAppState)
|
||||||
|
Object.keys(resetState).forEach((key) => {
|
||||||
|
appState[key] = resetState[key]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set party to be editable
|
||||||
|
appState.party.editable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
deleteCookie('account')
|
||||||
|
deleteCookie('user')
|
||||||
|
|
||||||
|
// Clean state
|
||||||
|
const resetState = clonedeep(initialAccountState)
|
||||||
|
Object.keys(resetState).forEach((key) => {
|
||||||
|
if (key !== 'language') accountState[key] = resetState[key]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (router.route != '/new') appState.party.editable = false
|
||||||
|
|
||||||
|
router.push('/')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFavorite() {
|
||||||
|
if (party.favorited) unsaveFavorite()
|
||||||
|
else saveFavorite()
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveFavorite() {
|
||||||
|
if (party.id)
|
||||||
|
api.saveTeam({ id: party.id }).then((response) => {
|
||||||
|
if (response.status == 201) appState.party.favorited = true
|
||||||
|
})
|
||||||
|
else console.error('Failed to save team: No party ID')
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsaveFavorite() {
|
||||||
|
if (party.id)
|
||||||
|
api.unsaveTeam({ id: party.id }).then((response) => {
|
||||||
|
if (response.status == 200) appState.party.favorited = false
|
||||||
|
})
|
||||||
|
else console.error('Failed to unsave team: No party ID')
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyButton = () => {
|
||||||
|
if (router.route === '/p/[party]')
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
accessoryIcon={<LinkIcon className="stroke" />}
|
||||||
|
blended={true}
|
||||||
|
text={t('buttons.copy')}
|
||||||
|
onClick={copyToClipboard}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftNav = () => {
|
||||||
|
return (
|
||||||
|
<div id="DropdownWrapper">
|
||||||
|
<Button
|
||||||
|
accessoryIcon={<MenuIcon />}
|
||||||
|
className={classNames({ Active: open })}
|
||||||
|
blended={true}
|
||||||
|
text={t('buttons.menu')}
|
||||||
|
onClick={menuButtonClicked}
|
||||||
|
/>
|
||||||
|
<HeaderMenu
|
||||||
|
authenticated={account.authorized}
|
||||||
|
open={open}
|
||||||
|
username={account.user?.username}
|
||||||
|
onClickOutside={onClickOutsideMenu}
|
||||||
|
logout={logout}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveButton = () => {
|
||||||
|
if (party.favorited)
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
accessoryIcon={<SaveIcon />}
|
||||||
|
blended={true}
|
||||||
|
text="Saved"
|
||||||
|
onClick={toggleFavorite}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
else
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
accessoryIcon={<SaveIcon />}
|
||||||
|
blended={true}
|
||||||
|
text="Save"
|
||||||
|
onClick={toggleFavorite}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rightNav = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{router.route === '/p/[party]' &&
|
||||||
|
account.user &&
|
||||||
|
(!party.user || party.user.id !== account.user.id)
|
||||||
|
? saveButton()
|
||||||
|
: ''}
|
||||||
|
|
||||||
|
{copyButton()}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
accessoryIcon={<AddIcon className="Add" />}
|
||||||
|
blended={true}
|
||||||
|
text={t('buttons.new')}
|
||||||
|
onClick={newParty}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const Header = (props: Props) => {
|
|
||||||
return (
|
return (
|
||||||
<nav className={`Header ${props.position}`}>
|
<nav id="Header">
|
||||||
<div id="left">{props.left}</div>
|
<div id="Left">{leftNav()}</div>
|
||||||
<div className="push" />
|
<div id="Right">{rightNav()}</div>
|
||||||
<div id="right">{props.right}</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
.Menu {
|
.Menu {
|
||||||
background: var(--menu-bg);
|
background: var(--menu-bg);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
display: none;
|
display: none;
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: $unit * 5.75; // This shouldn't be hardcoded. How to calculate it?
|
top: $unit-8x; // This shouldn't be hardcoded. How to calculate it?
|
||||||
// Also, add space that doesn't make the menu disappear if you move your mouse slowly
|
// Also, add space that doesn't make the menu disappear if you move your mouse slowly
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
left: $unit-2x;
|
||||||
|
right: $unit-2x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.MenuItem {
|
.MenuItem {
|
||||||
|
|
@ -29,6 +35,16 @@
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
background: inherit;
|
||||||
|
color: inherit;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.profile > div {
|
&.profile > div {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { getCookie, setCookie } from 'cookies-next'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { setCookie } from 'cookies-next'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import retrieveCookies from '~utils/retrieveCookies'
|
||||||
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import * as Switch from '@radix-ui/react-switch'
|
import * as Switch from '@radix-ui/react-switch'
|
||||||
|
|
@ -14,36 +16,52 @@ import LoginModal from '~components/LoginModal'
|
||||||
import SignupModal from '~components/SignupModal'
|
import SignupModal from '~components/SignupModal'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import { accountState } from '~utils/accountState'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
authenticated: boolean
|
authenticated: boolean
|
||||||
|
open: boolean
|
||||||
username?: string
|
username?: string
|
||||||
|
onClickOutside: () => void
|
||||||
logout?: () => void
|
logout?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderMenu = (props: Props) => {
|
const HeaderMenu = (props: Props) => {
|
||||||
|
// Setup
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const data: GranblueCookie | undefined = retrieveCookies()
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
|
|
||||||
const accountCookie = getCookie('account')
|
// Refs
|
||||||
const accountData: AccountCookie = accountCookie
|
const ref: React.RefObject<HTMLDivElement> = React.createRef()
|
||||||
? JSON.parse(accountCookie as string)
|
|
||||||
: null
|
|
||||||
|
|
||||||
const userCookie = getCookie('user')
|
useEffect(() => {
|
||||||
const userData: UserCookie = userCookie
|
const handleClickOutside = (event: Event) => {
|
||||||
? JSON.parse(userCookie as string)
|
const target = event.target instanceof Element ? event.target : null
|
||||||
: null
|
const isButton = target && target.closest('.Button.Active')
|
||||||
|
|
||||||
const localeCookie = getCookie('NEXT_LOCALE')
|
if (
|
||||||
|
ref.current &&
|
||||||
|
target &&
|
||||||
|
!ref.current.contains(target) &&
|
||||||
|
!isButton &&
|
||||||
|
props.open
|
||||||
|
) {
|
||||||
|
props.onClickOutside()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('click', handleClickOutside, true)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', handleClickOutside, true)
|
||||||
|
}
|
||||||
|
}, [props.onClickOutside])
|
||||||
|
|
||||||
const [checked, setChecked] = useState(false)
|
const [checked, setChecked] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const locale = localeCookie
|
const locale = data?.locale
|
||||||
setChecked(locale === 'ja' ? true : false)
|
setChecked(locale === 'ja' ? true : false)
|
||||||
}, [localeCookie])
|
}, [data?.locale])
|
||||||
|
|
||||||
function handleCheckedChange(value: boolean) {
|
function handleCheckedChange(value: boolean) {
|
||||||
const language = value ? 'ja' : 'en'
|
const language = value ? 'ja' : 'en'
|
||||||
|
|
@ -51,66 +69,70 @@ const HeaderMenu = (props: Props) => {
|
||||||
router.push(router.asPath, undefined, { locale: language })
|
router.push(router.asPath, undefined, { locale: language })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const menuClasses = classNames({
|
||||||
|
Menu: true,
|
||||||
|
auth: props.authenticated,
|
||||||
|
open: props.open,
|
||||||
|
})
|
||||||
|
|
||||||
function authItems() {
|
function authItems() {
|
||||||
return (
|
return (
|
||||||
<nav>
|
<ul className={menuClasses}>
|
||||||
<ul className="Menu auth">
|
<div className="MenuGroup">
|
||||||
<div className="MenuGroup">
|
<li className="MenuItem profile">
|
||||||
<li className="MenuItem profile">
|
<Link href={`/${data?.account.username}` || ''} passHref>
|
||||||
<Link href={`/${accountData.username}` || ''} passHref>
|
|
||||||
<div>
|
|
||||||
<span>{accountData.username}</span>
|
|
||||||
<img
|
|
||||||
alt={userData.picture}
|
|
||||||
className={`profile ${accountState.account.user?.element}`}
|
|
||||||
srcSet={`/profile/${accountState.account.user?.picture}.png,
|
|
||||||
/profile/${userData.picture}@2x.png 2x`}
|
|
||||||
src={`/profile/${userData.picture}.png`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li className="MenuItem">
|
|
||||||
<Link href={`/saved` || ''}>{t('menu.saved')}</Link>
|
|
||||||
</li>
|
|
||||||
</div>
|
|
||||||
<div className="MenuGroup">
|
|
||||||
<li className="MenuItem">
|
|
||||||
<Link href="/teams">{t('menu.teams')}</Link>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className="MenuItem disabled">
|
|
||||||
<div>
|
<div>
|
||||||
<span>{t('menu.guides')}</span>
|
<span>{data?.account.username}</span>
|
||||||
<i className="tag">{t('coming_soon')}</i>
|
<img
|
||||||
|
alt={data?.user.picture}
|
||||||
|
className={`profile ${data?.user.element}`}
|
||||||
|
srcSet={`/profile/${data?.user.picture}.png,
|
||||||
|
/profile/${data?.user.picture}@2x.png 2x`}
|
||||||
|
src={`/profile/${data?.user.picture}.png`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</Link>
|
||||||
</div>
|
</li>
|
||||||
<div className="MenuGroup">
|
<li className="MenuItem">
|
||||||
<AboutModal />
|
<Link href={`/saved` || ''}>{t('menu.saved')}</Link>
|
||||||
<ChangelogModal />
|
</li>
|
||||||
<RoadmapModal />
|
</div>
|
||||||
</div>
|
<div className="MenuGroup">
|
||||||
<div className="MenuGroup">
|
<li className="MenuItem">
|
||||||
<AccountModal
|
<Link href="/teams">{t('menu.teams')}</Link>
|
||||||
username={accountState.account.user?.username}
|
</li>
|
||||||
picture={accountState.account.user?.picture}
|
|
||||||
gender={accountState.account.user?.gender}
|
<li className="MenuItem disabled">
|
||||||
language={accountState.account.user?.language}
|
<div>
|
||||||
theme={accountState.account.user?.theme}
|
<span>{t('menu.guides')}</span>
|
||||||
/>
|
<i className="tag">{t('coming_soon')}</i>
|
||||||
<li className="MenuItem" onClick={props.logout}>
|
</div>
|
||||||
<span>{t('menu.logout')}</span>
|
</li>
|
||||||
</li>
|
</div>
|
||||||
</div>
|
<div className="MenuGroup">
|
||||||
</ul>
|
<AboutModal />
|
||||||
</nav>
|
<ChangelogModal />
|
||||||
|
<RoadmapModal />
|
||||||
|
</div>
|
||||||
|
<div className="MenuGroup">
|
||||||
|
<AccountModal
|
||||||
|
username={data?.account.username}
|
||||||
|
picture={data?.user.picture}
|
||||||
|
gender={data?.user.gender}
|
||||||
|
language={data?.user.language}
|
||||||
|
theme={data?.user.theme}
|
||||||
|
/>
|
||||||
|
<li className="MenuItem" onClick={props.logout}>
|
||||||
|
<span>{t('menu.logout')}</span>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function unauthItems() {
|
function unauthItems() {
|
||||||
return (
|
return (
|
||||||
<ul className="Menu unauth">
|
<ul className={menuClasses}>
|
||||||
<div className="MenuGroup">
|
<div className="MenuGroup">
|
||||||
<li className="MenuItem language">
|
<li className="MenuItem language">
|
||||||
<span>{t('menu.language')}</span>
|
<span>{t('menu.language')}</span>
|
||||||
|
|
@ -150,7 +172,9 @@ const HeaderMenu = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return props.authenticated ? authItems() : unauthItems()
|
return (
|
||||||
|
<nav ref={ref}>{props.authenticated ? authItems() : unauthItems()}</nav>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HeaderMenu
|
export default HeaderMenu
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: $unit * 3;
|
margin-bottom: $unit * 3;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
width: $width;
|
width: $width;
|
||||||
transition: box-shadow 0.15s ease-in-out;
|
transition: box-shadow 0.15s ease-in-out;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
aspect-ratio: 16/9;
|
aspect-ratio: 16/9;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { ReactElement } from 'react'
|
import type { ReactElement } from 'react'
|
||||||
import TopHeader from '~components/TopHeader'
|
import TopHeader from '~components/Header'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactElement
|
children: ReactElement
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-top: $unit-4x;
|
margin-top: $unit-4x;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
padding: 0 $unit;
|
padding: 0 $unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
min-height: $unit * 20;
|
min-height: $unit * 22;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@
|
||||||
width: 60%;
|
width: 60%;
|
||||||
height: 60%;
|
height: 60%;
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
max-width: 760px;
|
max-width: 760px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
|
|
@ -20,16 +20,16 @@
|
||||||
&.Editable {
|
&.Editable {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.SegmentedControl {
|
.SegmentedControl {
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
@media (max-width: $phone) {
|
display: grid;
|
||||||
flex-grow: 1;
|
grid-template-columns: auto auto auto;
|
||||||
width: 100%;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto auto auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
position: static;
|
position: static;
|
||||||
|
|
||||||
.Text {
|
.Text {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
gap: 0;
|
gap: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
min-width: inherit;
|
min-width: inherit;
|
||||||
min-height: inherit;
|
min-height: inherit;
|
||||||
width: 96%; // is this even right
|
width: 96%; // is this even right
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
padding: 0 ($unit * 1.5);
|
padding: 0 ($unit * 1.5);
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
max-height: inherit;
|
max-height: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
min-width: initial;
|
min-width: initial;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
&.Friend {
|
&.Friend {
|
||||||
max-width: 78px;
|
max-width: 78px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
width: 182px;
|
width: 182px;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
width: 20.3vw;
|
width: 20.3vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
// min-height: 141px;
|
// min-height: 141px;
|
||||||
min-height: 180px;
|
min-height: 180px;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
min-height: 16.5vw;
|
min-height: 16.5vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
width: 148px;
|
width: 148px;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
width: 20vw;
|
width: 20vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { useSnapshot } from 'valtio'
|
|
||||||
import { getCookie, deleteCookie } from 'cookies-next'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
|
||||||
|
|
||||||
import clonedeep from 'lodash.clonedeep'
|
|
||||||
|
|
||||||
import api from '~utils/api'
|
|
||||||
import { accountState, initialAccountState } from '~utils/accountState'
|
|
||||||
import { appState, initialAppState } from '~utils/appState'
|
|
||||||
|
|
||||||
import Header from '~components/Header'
|
|
||||||
import Button from '~components/Button'
|
|
||||||
import HeaderMenu from '~components/HeaderMenu'
|
|
||||||
|
|
||||||
import AddIcon from '~public/icons/Add.svg'
|
|
||||||
import LinkIcon from '~public/icons/Link.svg'
|
|
||||||
import MenuIcon from '~public/icons/Menu.svg'
|
|
||||||
import SaveIcon from '~public/icons/Save.svg'
|
|
||||||
|
|
||||||
const TopHeader = () => {
|
|
||||||
const { t } = useTranslation('common')
|
|
||||||
|
|
||||||
// Cookies
|
|
||||||
const accountCookie = getCookie('account')
|
|
||||||
const userCookie = getCookie('user')
|
|
||||||
|
|
||||||
const headers = {}
|
|
||||||
// accountCookies.account != null
|
|
||||||
// ? {
|
|
||||||
// Authorization: `Bearer ${accountCookies.account.access_token}`,
|
|
||||||
// }
|
|
||||||
// : {}
|
|
||||||
|
|
||||||
const { account } = useSnapshot(accountState)
|
|
||||||
const { party } = useSnapshot(appState)
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
function copyToClipboard() {
|
|
||||||
const el = document.createElement('input')
|
|
||||||
el.value = window.location.href
|
|
||||||
el.id = 'url-input'
|
|
||||||
document.body.appendChild(el)
|
|
||||||
|
|
||||||
el.select()
|
|
||||||
document.execCommand('copy')
|
|
||||||
el.remove()
|
|
||||||
}
|
|
||||||
|
|
||||||
function newParty() {
|
|
||||||
// Push the root URL
|
|
||||||
router.push('/')
|
|
||||||
|
|
||||||
// Clean state
|
|
||||||
const resetState = clonedeep(initialAppState)
|
|
||||||
Object.keys(resetState).forEach((key) => {
|
|
||||||
appState[key] = resetState[key]
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set party to be editable
|
|
||||||
appState.party.editable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function logout() {
|
|
||||||
deleteCookie('account')
|
|
||||||
deleteCookie('user')
|
|
||||||
|
|
||||||
// Clean state
|
|
||||||
const resetState = clonedeep(initialAccountState)
|
|
||||||
Object.keys(resetState).forEach((key) => {
|
|
||||||
if (key !== 'language') accountState[key] = resetState[key]
|
|
||||||
})
|
|
||||||
|
|
||||||
if (router.route != '/new') appState.party.editable = false
|
|
||||||
|
|
||||||
router.push('/')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleFavorite() {
|
|
||||||
if (party.favorited) unsaveFavorite()
|
|
||||||
else saveFavorite()
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveFavorite() {
|
|
||||||
if (party.id)
|
|
||||||
api.saveTeam({ id: party.id, params: headers }).then((response) => {
|
|
||||||
if (response.status == 201) appState.party.favorited = true
|
|
||||||
})
|
|
||||||
else console.error('Failed to save team: No party ID')
|
|
||||||
}
|
|
||||||
|
|
||||||
function unsaveFavorite() {
|
|
||||||
if (party.id)
|
|
||||||
api.unsaveTeam({ id: party.id, params: headers }).then((response) => {
|
|
||||||
if (response.status == 200) appState.party.favorited = false
|
|
||||||
})
|
|
||||||
else console.error('Failed to unsave team: No party ID')
|
|
||||||
}
|
|
||||||
|
|
||||||
const copyButton = () => {
|
|
||||||
if (router.route === '/p/[party]')
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
accessoryIcon={<LinkIcon className="stroke" />}
|
|
||||||
blended={true}
|
|
||||||
text={t('buttons.copy')}
|
|
||||||
onClick={copyToClipboard}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const leftNav = () => {
|
|
||||||
return (
|
|
||||||
<div className="dropdown">
|
|
||||||
<Button
|
|
||||||
accessoryIcon={<MenuIcon />}
|
|
||||||
blended={true}
|
|
||||||
text={t('buttons.menu')}
|
|
||||||
/>
|
|
||||||
{account.user ? (
|
|
||||||
<HeaderMenu
|
|
||||||
authenticated={account.authorized}
|
|
||||||
username={account.user.username}
|
|
||||||
logout={logout}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<HeaderMenu authenticated={account.authorized} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveButton = () => {
|
|
||||||
if (party.favorited)
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
accessoryIcon={<SaveIcon />}
|
|
||||||
blended={true}
|
|
||||||
text="Saved"
|
|
||||||
onClick={toggleFavorite}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
else
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
accessoryIcon={<SaveIcon />}
|
|
||||||
blended={true}
|
|
||||||
text="Save"
|
|
||||||
onClick={toggleFavorite}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const rightNav = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{router.route === '/p/[party]' &&
|
|
||||||
account.user &&
|
|
||||||
(!party.user || party.user.id !== account.user.id)
|
|
||||||
? saveButton()
|
|
||||||
: ''}
|
|
||||||
|
|
||||||
{copyButton()}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
accessoryIcon={<AddIcon className="Add" />}
|
|
||||||
blended={true}
|
|
||||||
text={t('buttons.new')}
|
|
||||||
onClick={newParty}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Header position="top" left={leftNav()} right={rightNav()} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TopHeader
|
|
||||||
|
|
@ -53,11 +53,8 @@
|
||||||
background-image: url('/icons/uncap/purple-hover@3x.png');
|
background-image: url('/icons/uncap/purple-hover@3x.png');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Phone up to iPhone 14 Pro Max
|
@include breakpoint(phone) {
|
||||||
@media only screen and (max-width: 430px) and (max-height: 850px) and (-webkit-device-pixel-ratio: 3) {
|
|
||||||
.UncapStar {
|
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
}
|
}
|
||||||
|
|
@ -23,12 +23,12 @@
|
||||||
margin-bottom: $unit-3x;
|
margin-bottom: $unit-3x;
|
||||||
margin-right: $unit-3x;
|
margin-right: $unit-3x;
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
margin-bottom: $unit-2x;
|
margin-bottom: $unit-2x;
|
||||||
margin-right: $unit-2x;
|
margin-right: $unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(tablet) {
|
||||||
margin-bottom: $unit;
|
margin-bottom: $unit;
|
||||||
margin-right: $unit;
|
margin-right: $unit;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
min-height: 139px;
|
min-height: 139px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,11 +28,12 @@
|
||||||
margin-right: $unit-3x;
|
margin-right: $unit-3x;
|
||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
|
|
||||||
@media (max-width: $tablet) {
|
@include breakpoint(tablet) {
|
||||||
margin-right: $unit-2x;
|
margin-right: $unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
|
margin-right: $unit-2x;
|
||||||
margin-right: $unit;
|
margin-right: $unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
width: 25vw;
|
width: 25vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +95,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
width: 20vw;
|
width: 20vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ select {
|
||||||
margin-top: $unit * 3;
|
margin-top: $unit * 3;
|
||||||
min-width: 752px;
|
min-width: 752px;
|
||||||
|
|
||||||
@media (max-width: $medium-screen) {
|
@include breakpoint(tablet) {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +291,7 @@ i.tag {
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
padding: 0 ($unit * 3);
|
padding: 0 ($unit * 3);
|
||||||
|
|
||||||
@media (max-width: $phone) {
|
@include breakpoint(phone) {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
|
|
|
||||||
28
styles/mixins.scss
Normal file
28
styles/mixins.scss
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// use with @include
|
||||||
|
@mixin breakpoint($breakpoint) {
|
||||||
|
$phone-width: 430px;
|
||||||
|
$phone-height: 850px;
|
||||||
|
|
||||||
|
$tablet-width: 1024px;
|
||||||
|
$tablet-height: 1024px;
|
||||||
|
|
||||||
|
@if $breakpoint == tablet {
|
||||||
|
// prettier-ignore
|
||||||
|
@media only screen
|
||||||
|
and (max-width: $tablet-width)
|
||||||
|
and (max-height: $tablet-height)
|
||||||
|
and (-webkit-min-device-pixel-ratio: 2) {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $breakpoint == phone {
|
||||||
|
// prettier-ignore
|
||||||
|
@media only screen
|
||||||
|
and (max-width: $phone-width)
|
||||||
|
and (max-height: $phone-height)
|
||||||
|
and (-webkit-min-device-pixel-ratio: 2) {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// @import 'include-media/dist/_include-media';
|
// @import 'include-media/dist/_include-media';
|
||||||
|
@import 'mixins.scss';
|
||||||
|
|
||||||
// Breakpoints
|
// Breakpoints
|
||||||
$breakpoints: (
|
$breakpoints: (
|
||||||
|
|
|
||||||
5
types/GranblueCookie.d.ts
vendored
Normal file
5
types/GranblueCookie.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface GranblueCookie {
|
||||||
|
account: AccountCookie
|
||||||
|
user: UserCookie
|
||||||
|
locale: string
|
||||||
|
}
|
||||||
23
utils/retrieveCookies.tsx
Normal file
23
utils/retrieveCookies.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { getCookies } from 'cookies-next'
|
||||||
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
|
|
||||||
|
export default function retrieveCookies(
|
||||||
|
req?: NextApiRequest,
|
||||||
|
res?: NextApiResponse
|
||||||
|
): GranblueCookie | undefined {
|
||||||
|
const cookies = getCookies({ req, res })
|
||||||
|
if (!cookies) return undefined
|
||||||
|
|
||||||
|
const {
|
||||||
|
account: accountData,
|
||||||
|
user: userData,
|
||||||
|
NEXT_LOCALE: localeData,
|
||||||
|
} = cookies
|
||||||
|
if (!accountData || !userData) return undefined
|
||||||
|
|
||||||
|
const account = JSON.parse(decodeURIComponent(accountData)) ?? undefined
|
||||||
|
const user = JSON.parse(decodeURIComponent(userData)) ?? undefined
|
||||||
|
const locale = localeData as string
|
||||||
|
|
||||||
|
return { account, user, locale }
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue