Merge pull request #74 from jedmund/fix-media-queries

Fix media queries
This commit is contained in:
Justin Edmund 2022-12-27 19:22:17 -08:00 committed by GitHub
commit b705bf7765
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 449 additions and 363 deletions

View file

@ -10,7 +10,8 @@
gap: 6px;
&:hover,
&.Blended:hover {
&.Blended:hover,
&.Blended.Active {
background: var(--button-bg-hover);
cursor: pointer;
color: var(--button-text-hover);

View file

@ -12,7 +12,7 @@
padding: 0;
max-width: 761px;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
justify-content: space-between;
width: 100%;
}
@ -20,7 +20,7 @@
& > * {
margin-right: $unit * 3;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
margin-right: inherit;
}
}

View file

@ -56,7 +56,7 @@
height: auto;
width: 131px;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
width: 17vw;
}

View file

@ -22,7 +22,7 @@
text-decoration: underline;
}
@media (max-width: $phone) {
@include breakpoint(phone) {
min-width: inherit;
min-height: inherit;
width: 100%;

View file

@ -10,7 +10,7 @@
position: relative;
left: 9px;
@media (max-width: $medium-screen) {
@include breakpoint(phone) {
left: auto;
max-width: auto;
width: 100%;

View file

@ -10,7 +10,7 @@
position: relative;
left: 8px;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
left: auto;
max-width: auto;
width: 100%;

View file

@ -15,7 +15,7 @@
width: 100%;
max-width: 996px;
@media (max-width: $tablet) {
@include breakpoint(tablet) {
position: static;
flex-direction: column;
width: 100%;
@ -29,7 +29,7 @@
gap: $unit;
width: auto;
@media (max-width: $tablet) {
@include breakpoint(tablet) {
flex-direction: column;
width: 100%;
}
@ -64,7 +64,7 @@
background-color: var(--select-contained-bg-hover);
}
@media (max-width: $tablet) {
@include breakpoint(tablet) {
width: 100%;
max-width: inherit;
text-align: center;

View file

@ -2,11 +2,12 @@
aspect-ratio: 3/2;
border-radius: $card-corner;
box-sizing: border-box;
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: 1fr 1fr;
gap: $unit;
padding: $unit-2x;
max-width: 320px;
min-width: 320px;
width: 100%;
&:hover {
background: var(--grid-rep-hover);
@ -20,48 +21,58 @@
cursor: pointer;
}
.Grid .weapon {
.Grid .Weapon {
box-shadow: inset 0 0 0 1px var(--grid-border-color);
}
@include breakpoint(phone) {
background: inherit;
.Grid .Weapon {
box-shadow: none;
}
}
}
.Grid {
display: flex;
flex-direction: row;
flex-shrink: 0;
gap: $unit;
& > .Grid {
aspect-ratio: 2/1;
display: grid;
grid-template-columns: 1fr 3fr; /* left column takes up 1 fraction, right column takes up 3 fractions */
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);
border-radius: 4px;
}
.grid_mainhand {
$d: 64px;
aspect-ratio: 200 / 418;
height: auto;
max-width: $d;
min-width: $d;
.Mainhand.Weapon {
grid-column: 1 / 2; /* spans one column */
}
.grid_weapons {
$p: 29.5%;
box-sizing: border-box;
display: grid;
grid-template-columns: fit-content($p) fit-content($p) fit-content($p);
grid-template-rows: fit-content($p) fit-content($p) fit-content($p);
.GridWeapons {
display: grid; /* make the right-images container a grid */
grid-template-columns: repeat(
3,
1fr
); /* create 3 columns, each taking up 1 fraction */
grid-template-rows: repeat(
3,
1fr
); /* create 3 rows, each taking up 1 fraction */
gap: $unit;
margin: 0;
padding: 0;
width: 100%;
}
.grid_weapon {
.Grid.Weapon {
aspect-ratio: 160 / 92;
display: grid;
}
.grid_mainhand img[src*='jpg'],
.grid_weapon img[src*='jpg'] {
.Mainhand.Weapon img[src*='jpg'],
.Grid.Weapon img[src*='jpg'] {
border-radius: 4px;
width: 100%;
height: 100%;

View file

@ -212,15 +212,12 @@ const GridRep = (props: Props) => {
<a className="GridRep">
{props.displayUser ? detailsWithUsername : details}
<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) => {
return (
<li
key={`${props.shortcode}-${i}`}
className="weapon grid_weapon"
>
<li key={`${props.shortcode}-${i}`} className="Grid Weapon">
{generateGridImage(i)}
</li>
)

View file

@ -1,21 +1,20 @@
.GridRepCollection {
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
margin: 0 auto;
padding: 0;
transition: opacity 0.14s ease-in-out;
justify-items: center;
// width: fit-content;
width: auto;
width: 100%;
max-width: 996px;
@media (max-width: $tablet) {
grid-template-columns: minmax(320px, 1fr);
@include breakpoint(tablet) {
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
max-width: inherit;
width: 100%;
}
@media (max-width: $phone) {
@include breakpoint(phone) {
grid-template-columns: 1fr;
max-width: inherit;
width: 100%;

View file

@ -1,23 +1,24 @@
.Header {
#Header {
display: flex;
flex-direction: row;
margin-bottom: $unit;
justify-content: space-between;
width: 100%;
&.bottom {
position: sticky;
bottom: $unit * 2;
}
#right > div {
#Right > div {
display: flex;
gap: 8px;
gap: $unit;
}
.dropdown {
#DropdownWrapper {
display: inline-block;
position: relative;
padding-bottom: $unit;
&:hover .Menu,
.Menu.open {
display: block;
}
&:hover {
padding-right: $unit-4x;
@ -25,18 +26,10 @@
background: var(--button-bg-hover);
color: var(--button-text-hover);
}
.Menu {
display: block;
}
}
}
.push {
margin-left: auto;
}
@media (max-width: $phone) {
@include breakpoint(phone) {
.Button .Text {
display: none;
}

View file

@ -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'
interface Props {
position: 'top' | 'bottom'
left: JSX.Element
right: JSX.Element
}
const Header = () => {
// Localization
const { t } = useTranslation('common')
// 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 (
<nav className={`Header ${props.position}`}>
<div id="left">{props.left}</div>
<div className="push" />
<div id="right">{props.right}</div>
<nav id="Header">
<div id="Left">{leftNav()}</div>
<div id="Right">{rightNav()}</div>
</nav>
)
}

View file

@ -1,12 +1,18 @@
.Menu {
background: var(--menu-bg);
border-radius: 6px;
box-sizing: border-box;
display: none;
min-width: 220px;
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
z-index: 10;
@include breakpoint(phone) {
left: $unit-2x;
right: $unit-2x;
}
}
.MenuItem {
@ -29,6 +35,16 @@
color: var(--text-primary);
}
}
@include breakpoint(phone) {
background: inherit;
color: inherit;
cursor: default;
a {
color: inherit;
}
}
}
&.profile > div {

View file

@ -1,7 +1,9 @@
import React, { useEffect, useState } from 'react'
import { getCookie, setCookie } from 'cookies-next'
import { useRouter } from 'next/router'
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 * as Switch from '@radix-ui/react-switch'
@ -14,36 +16,52 @@ import LoginModal from '~components/LoginModal'
import SignupModal from '~components/SignupModal'
import './index.scss'
import { accountState } from '~utils/accountState'
interface Props {
authenticated: boolean
open: boolean
username?: string
onClickOutside: () => void
logout?: () => void
}
const HeaderMenu = (props: Props) => {
// Setup
const router = useRouter()
const data: GranblueCookie | undefined = retrieveCookies()
const { t } = useTranslation('common')
const accountCookie = getCookie('account')
const accountData: AccountCookie = accountCookie
? JSON.parse(accountCookie as string)
: null
// Refs
const ref: React.RefObject<HTMLDivElement> = React.createRef()
const userCookie = getCookie('user')
const userData: UserCookie = userCookie
? JSON.parse(userCookie as string)
: null
useEffect(() => {
const handleClickOutside = (event: Event) => {
const target = event.target instanceof Element ? event.target : 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)
useEffect(() => {
const locale = localeCookie
const locale = data?.locale
setChecked(locale === 'ja' ? true : false)
}, [localeCookie])
}, [data?.locale])
function handleCheckedChange(value: boolean) {
const language = value ? 'ja' : 'en'
@ -51,66 +69,70 @@ const HeaderMenu = (props: Props) => {
router.push(router.asPath, undefined, { locale: language })
}
const menuClasses = classNames({
Menu: true,
auth: props.authenticated,
open: props.open,
})
function authItems() {
return (
<nav>
<ul className="Menu auth">
<div className="MenuGroup">
<li className="MenuItem profile">
<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">
<ul className={menuClasses}>
<div className="MenuGroup">
<li className="MenuItem profile">
<Link href={`/${data?.account.username}` || ''} passHref>
<div>
<span>{t('menu.guides')}</span>
<i className="tag">{t('coming_soon')}</i>
<span>{data?.account.username}</span>
<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>
</li>
</div>
<div className="MenuGroup">
<AboutModal />
<ChangelogModal />
<RoadmapModal />
</div>
<div className="MenuGroup">
<AccountModal
username={accountState.account.user?.username}
picture={accountState.account.user?.picture}
gender={accountState.account.user?.gender}
language={accountState.account.user?.language}
theme={accountState.account.user?.theme}
/>
<li className="MenuItem" onClick={props.logout}>
<span>{t('menu.logout')}</span>
</li>
</div>
</ul>
</nav>
</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>
<span>{t('menu.guides')}</span>
<i className="tag">{t('coming_soon')}</i>
</div>
</li>
</div>
<div className="MenuGroup">
<AboutModal />
<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() {
return (
<ul className="Menu unauth">
<ul className={menuClasses}>
<div className="MenuGroup">
<li className="MenuItem language">
<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

View file

@ -3,7 +3,7 @@
display: flex;
margin-bottom: $unit * 3;
@media (max-width: $phone) {
@include breakpoint(phone) {
flex-direction: column;
gap: $unit;
}
@ -56,7 +56,7 @@
width: $width;
transition: box-shadow 0.15s ease-in-out;
@media (max-width: $phone) {
@include breakpoint(phone) {
aspect-ratio: 16/9;
margin: 0;
width: inherit;

View file

@ -1,5 +1,5 @@
import type { ReactElement } from 'react'
import TopHeader from '~components/TopHeader'
import TopHeader from '~components/Header'
interface Props {
children: ReactElement

View file

@ -3,7 +3,7 @@
flex-direction: column;
margin-top: $unit-4x;
@media (max-width: $phone) {
@include breakpoint(phone) {
padding: 0 $unit;
}
@ -30,7 +30,7 @@
width: 100%;
textarea {
min-height: $unit * 20;
min-height: $unit * 22;
width: 100%;
}
}
@ -86,7 +86,7 @@
width: 60%;
height: 60%;
@media (max-width: $tablet) {
@include breakpoint(tablet) {
width: 100%;
height: 100%;
}

View file

@ -9,7 +9,7 @@
max-width: 760px;
position: relative;
@media (max-width: $phone) {
@include breakpoint(phone) {
gap: $unit;
margin-left: 0;
margin-right: 0;
@ -20,16 +20,16 @@
&.Editable {
justify-content: flex-start;
}
}
.SegmentedControl {
.SegmentedControl {
flex-grow: 1;
@include breakpoint(phone) {
flex-grow: 1;
@media (max-width: $phone) {
flex-grow: 1;
width: 100%;
display: grid;
grid-template-columns: auto auto auto;
}
width: 100%;
display: grid;
grid-template-columns: auto auto auto;
}
}
}
@ -44,7 +44,7 @@
position: absolute;
right: 0px;
@media (max-width: $phone) {
@include breakpoint(phone) {
position: static;
.Text {

View file

@ -8,7 +8,7 @@
gap: 0;
padding: 0;
@media (max-width: $phone) {
@include breakpoint(phone) {
min-width: inherit;
min-height: inherit;
width: 96%; // is this even right
@ -68,7 +68,7 @@
padding: 0 ($unit * 1.5);
overflow-y: scroll;
@media (max-width: $phone) {
@include breakpoint(phone) {
max-height: inherit;
}

View file

@ -34,7 +34,7 @@
}
}
@media (max-width: $phone) {
@include breakpoint(phone) {
min-width: initial;
width: 100%;
}

View file

@ -14,7 +14,7 @@
text-overflow: ellipsis;
overflow: hidden;
@media (max-width: $phone) {
@include breakpoint(phone) {
&.Friend {
max-width: 78px;
}

View file

@ -9,7 +9,7 @@
width: 182px;
height: auto;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
width: 20.3vw;
}
}
@ -19,7 +19,7 @@
// min-height: 141px;
min-height: 180px;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
min-height: 16.5vw;
}
@ -29,7 +29,7 @@
width: 148px;
height: auto;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
width: 20vw;
}
}

View file

@ -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

View file

@ -53,11 +53,8 @@
background-image: url('/icons/uncap/purple-hover@3x.png');
}
}
}
// Phone up to iPhone 14 Pro Max
@media only screen and (max-width: 430px) and (max-height: 850px) and (-webkit-device-pixel-ratio: 3) {
.UncapStar {
@include breakpoint(phone) {
background-size: cover;
height: 14px;
width: 14px;

View file

@ -2,7 +2,7 @@
display: flex;
justify-content: center;
@media (max-width: $phone) {
@include breakpoint(phone) {
display: grid;
grid-template-columns: 1fr auto;
}
@ -23,12 +23,12 @@
margin-bottom: $unit-3x;
margin-right: $unit-3x;
@media (max-width: $tablet) {
@include breakpoint(tablet) {
margin-bottom: $unit-2x;
margin-right: $unit-2x;
}
@media (max-width: $phone) {
@include breakpoint(tablet) {
margin-bottom: $unit;
margin-right: $unit;
}

View file

@ -5,7 +5,7 @@
min-height: 139px;
position: relative;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
min-height: auto;
}
@ -28,11 +28,12 @@
margin-right: $unit-3x;
max-width: 200px;
@media (max-width: $tablet) {
@include breakpoint(tablet) {
margin-right: $unit-2x;
}
@media (max-width: $phone) {
@include breakpoint(phone) {
margin-right: $unit-2x;
margin-right: $unit;
}
@ -62,7 +63,7 @@
}
}
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
width: 25vw;
}
}
@ -94,7 +95,7 @@
}
}
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
width: 20vw;
}
}

View file

@ -113,7 +113,7 @@ select {
margin-top: $unit * 3;
min-width: 752px;
@media (max-width: $medium-screen) {
@include breakpoint(tablet) {
min-width: auto;
width: 100%;
}
@ -291,7 +291,7 @@ i.tag {
gap: $unit;
padding: 0 ($unit * 3);
@media (max-width: $phone) {
@include breakpoint(phone) {
display: grid;
gap: 8px;
grid-template-columns: 1fr 1fr;

28
styles/mixins.scss Normal file
View 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;
}
}
}

View file

@ -1,4 +1,5 @@
// @import 'include-media/dist/_include-media';
@import 'mixins.scss';
// Breakpoints
$breakpoints: (

5
types/GranblueCookie.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
interface GranblueCookie {
account: AccountCookie
user: UserCookie
locale: string
}

23
utils/retrieveCookies.tsx Normal file
View 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 }
}