Merge pull request #85 from jedmund/dialog-mobile

Mobile updates - Dialog, Characters, Selects
This commit is contained in:
Justin Edmund 2022-12-28 22:47:59 -08:00 committed by GitHub
commit ae456c0ba6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 158 additions and 80 deletions

View file

@ -3,6 +3,7 @@
background: none; background: none;
border: 0; border: 0;
inset: 0; inset: 0;
top: 0;
display: grid; display: grid;
place-items: center; place-items: center;
min-height: 100vh; min-height: 100vh;
@ -12,12 +13,19 @@
} }
.About.Dialog { .About.Dialog {
width: $unit * 60;
top: 0; top: 0;
animation: none;
transform: translate(-50%, 0); transform: translate(-50%, 0);
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
margin-top: $unit-10x; margin-top: $unit-10x;
@include breakpoint(phone) {
border-radius: 0;
transform: none;
margin: 0;
}
section { section {
margin-bottom: $unit; margin-bottom: $unit;
@ -102,4 +110,5 @@
place-items: center; place-items: center;
overflow-y: auto; overflow-y: auto;
z-index: 40; z-index: 40;
padding-top: 10%;
} }

View file

@ -7,24 +7,19 @@
} }
#grid_characters { #grid_characters {
display: flex; display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: $unit;
margin: 0; margin: 0;
padding: 0; padding: 0;
max-width: 761px; max-width: 761px;
isolation: isolate;
@include breakpoint(tablet) { @include breakpoint(tablet) {
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
} }
& > * {
margin-right: $unit * 3;
@include breakpoint(tablet) {
margin-right: inherit;
}
}
& > li:last-child { & > li:last-child {
margin: 0; margin: 0;
} }

View file

@ -1,9 +1,10 @@
.CharacterUnit { .CharacterUnit {
align-items: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: calc($unit / 2); gap: calc($unit / 2);
min-height: 320px; // min-height: 320px;
max-width: 200px; // max-width: 200px;
margin-bottom: $unit * 4; margin-bottom: $unit * 4;
&.editable .CharacterImage:hover { &.editable .CharacterImage:hover {
@ -35,6 +36,10 @@
max-width: 131px; max-width: 131px;
text-align: center; text-align: center;
word-wrap: normal; word-wrap: normal;
@include breakpoint(phone) {
font-size: $font-small;
}
} }
img { img {
@ -54,11 +59,7 @@
overflow: hidden; overflow: hidden;
transition: all 0.18s ease-in-out; transition: all 0.18s ease-in-out;
height: auto; height: auto;
width: 131px; width: 100%;
@include breakpoint(tablet) {
width: 17vw;
}
&:hover .icon svg { &:hover .icon svg {
fill: var(--icon-secondary-hover); fill: var(--icon-secondary-hover);

View file

@ -2,9 +2,10 @@
$multiplier: 4; $multiplier: 4;
animation: 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal none running animation: 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal none running
openModal; openModalDesktop;
background: var(--dialog-bg); background: var(--dialog-bg);
border-radius: $card-corner; border-radius: $card-corner;
box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: $unit * $multiplier; gap: $unit * $multiplier;
@ -16,15 +17,22 @@
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 21; z-index: 40;
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
} }
@include breakpoint(phone) { @include breakpoint(phone) {
animation: 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0s 1 normal forwards running
openModalMobile;
min-width: inherit; min-width: inherit;
min-height: inherit; min-height: 80vh;
transform: initial;
left: 0;
right: 0;
top: 0;
height: auto;
width: 100%; width: 100%;
} }

View file

@ -3,6 +3,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'
import classNames from 'classnames' import classNames from 'classnames'
import './index.scss' import './index.scss'
import Overlay from '~components/Overlay'
interface Props interface Props
extends React.DetailedHTMLProps< extends React.DetailedHTMLProps<
@ -24,7 +25,6 @@ export const DialogContent = React.forwardRef<HTMLDivElement, Props>(
return ( return (
<DialogPrimitive.Portal> <DialogPrimitive.Portal>
<DialogPrimitive.Overlay className="Overlay" />
<DialogPrimitive.Content <DialogPrimitive.Content
className={classes} className={classes}
{...props} {...props}
@ -34,6 +34,7 @@ export const DialogContent = React.forwardRef<HTMLDivElement, Props>(
> >
{children} {children}
</DialogPrimitive.Content> </DialogPrimitive.Content>
<Overlay visible={true} open={true} />
</DialogPrimitive.Portal> </DialogPrimitive.Portal>
) )
} }

View file

@ -19,6 +19,10 @@
color: var(--text-tertiary); color: var(--text-tertiary);
font-weight: $normal; font-weight: $normal;
@include breakpoint(phone) {
cursor: pointer;
}
&:hover:not(.disabled) { &:hover:not(.disabled) {
background: var(--menu-bg-item-hover); background: var(--menu-bg-item-hover);
color: var(--text-primary); color: var(--text-primary);

View file

@ -1,9 +1,10 @@
#Job { #Job {
align-items: center;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
margin-bottom: $unit * 3; margin-bottom: $unit * 3;
@include breakpoint(phone) { @include breakpoint(tablet) {
flex-direction: column; flex-direction: column;
gap: $unit; gap: $unit;
} }
@ -45,6 +46,7 @@
box-sizing: border-box; box-sizing: border-box;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
display: block; display: block;
isolation: isolate;
flex-grow: 2; flex-grow: 2;
flex-shrink: 0; flex-shrink: 0;
height: $height; height: $height;
@ -59,7 +61,7 @@
@include breakpoint(phone) { @include breakpoint(phone) {
aspect-ratio: 16/9; aspect-ratio: 16/9;
margin: 0; margin: 0;
width: inherit; width: 100%;
height: inherit; height: inherit;
} }

View file

@ -7,7 +7,6 @@ import axios, { AxiosError, AxiosResponse } from 'axios'
import api from '~utils/api' import api from '~utils/api'
import { accountState } from '~utils/accountState' import { accountState } from '~utils/accountState'
import Alert from '~components/Alert'
import Button from '~components/Button' import Button from '~components/Button'
import Input from '~components/Input' import Input from '~components/Input'
import { import {
@ -28,12 +27,6 @@ interface ErrorMap {
password: string password: string
} }
interface GranblueAxiosError {
response: AxiosResponse<any, any>
request: any
code: number
}
const emailRegex = const emailRegex =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

View file

@ -0,0 +1,13 @@
.Overlay {
isolation: isolate;
position: fixed;
z-index: 30;
top: 0;
right: 0;
bottom: 0;
left: 0;
&.Visible {
background: rgba(0, 0, 0, 0.6);
}
}

View file

@ -0,0 +1,50 @@
import React, { useEffect, useState } from 'react'
import classNames from 'classnames'
import './index.scss'
interface Props {
visible: boolean
open: boolean
}
const defaultProps = {
visible: true,
}
const Overlay = ({
visible: displayed,
open,
}: {
visible: boolean
open: boolean
}) => {
const [visible, setVisible] = useState(open)
const classes = classNames({
Overlay: true,
Visible: displayed,
})
useEffect(() => {
if (!open) {
const timer = setTimeout(() => {
setVisible(false)
}, 200)
return () => {
clearTimeout(timer)
}
}
setVisible(true)
return () => {}
}, [open])
function handleClick(event: React.MouseEvent<HTMLDivElement, MouseEvent>) {
event.stopPropagation()
}
return visible ? <div className={classes} onClick={handleClick} /> : null
}
Overlay.defaultProps = defaultProps
export default Overlay

View file

@ -16,10 +16,6 @@
padding: 0 $unit; padding: 0 $unit;
max-width: auto; max-width: auto;
width: 100%; width: 100%;
&.Editable {
justify-content: flex-start;
}
} }
.SegmentedControl { .SegmentedControl {

View file

@ -2,17 +2,16 @@
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 431px; min-height: 430px;
width: 600px;
height: 480px; height: 480px;
gap: 0; gap: 0;
padding: 0; padding: 0;
@include breakpoint(phone) { @include breakpoint(phone) {
animation: none;
border-radius: 0;
min-width: inherit; min-width: inherit;
min-height: inherit; min-height: 100vh;
width: 96%; // is this even right
height: 96vh;
} }
#Header { #Header {

View file

@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react'
import * as RadixSelect from '@radix-ui/react-select' import * as RadixSelect from '@radix-ui/react-select'
import classNames from 'classnames' import classNames from 'classnames'
import Overlay from '~components/Overlay'
import ArrowIcon from '~public/icons/Arrow.svg' import ArrowIcon from '~public/icons/Arrow.svg'
import './index.scss' import './index.scss'
@ -76,19 +78,24 @@ const Select = React.forwardRef<HTMLButtonElement, Props>(function Select(
</RadixSelect.Trigger> </RadixSelect.Trigger>
<RadixSelect.Portal className="Select"> <RadixSelect.Portal className="Select">
<RadixSelect.Content <>
onCloseAutoFocus={onCloseAutoFocus} <Overlay open={open} visible={false} />
onEscapeKeyDown={onEscapeKeyDown}
onPointerDownOutside={onPointerDownOutside} <RadixSelect.Content
> className="Select"
<RadixSelect.ScrollUpButton className="Scroll Up"> onCloseAutoFocus={onCloseAutoFocus}
<ArrowIcon /> onEscapeKeyDown={onEscapeKeyDown}
</RadixSelect.ScrollUpButton> onPointerDownOutside={onPointerDownOutside}
<RadixSelect.Viewport>{props.children}</RadixSelect.Viewport> >
<RadixSelect.ScrollDownButton className="Scroll Down"> <RadixSelect.ScrollUpButton className="Scroll Up">
<ArrowIcon /> <ArrowIcon />
</RadixSelect.ScrollDownButton> </RadixSelect.ScrollUpButton>
</RadixSelect.Content> <RadixSelect.Viewport>{props.children}</RadixSelect.Viewport>
<RadixSelect.ScrollDownButton className="Scroll Down">
<ArrowIcon />
</RadixSelect.ScrollDownButton>
</RadixSelect.Content>
</>
</RadixSelect.Portal> </RadixSelect.Portal>
</RadixSelect.Root> </RadixSelect.Root>
) )

View file

@ -33,9 +33,6 @@ const SummonGrid = (props: Props) => {
const accountData: AccountCookie = cookie const accountData: AccountCookie = cookie
? JSON.parse(cookie as string) ? JSON.parse(cookie as string)
: null : null
const headers = accountData
? { headers: { Authorization: `Bearer ${accountData.token}` } }
: {}
// Localization // Localization
const { t } = useTranslation('common') const { t } = useTranslation('common')
@ -112,19 +109,16 @@ const SummonGrid = (props: Props) => {
if (summon.uncap.ulb) uncapLevel = 5 if (summon.uncap.ulb) uncapLevel = 5
else if (summon.uncap.flb) uncapLevel = 4 else if (summon.uncap.flb) uncapLevel = 4
return await api.endpoints.summons.create( return await api.endpoints.summons.create({
{ summon: {
summon: { party_id: partyId,
party_id: partyId, summon_id: summon.id,
summon_id: summon.id, position: position,
position: position, main: position == -1,
main: position == -1, friend: position == 6,
friend: position == 6, uncap_level: uncapLevel,
uncap_level: uncapLevel,
},
}, },
headers })
)
} }
function storeGridSummon(gridSummon: GridSummon) { function storeGridSummon(gridSummon: GridSummon) {

View file

@ -153,7 +153,7 @@ const WeaponSearchFilterBar = (props: Props) => {
const renderSingleWeaponSeries = (id: number, slug: string) => { const renderSingleWeaponSeries = (id: number, slug: string) => {
return ( return (
<SearchFilterCheckboxItem <SearchFilterCheckboxItem
key={id} key={slug}
onCheckedChange={handleSeriesChange} onCheckedChange={handleSeriesChange}
checked={seriesState[slug].checked} checked={seriesState[slug].checked}
valueKey={slug} valueKey={slug}
@ -171,6 +171,7 @@ const WeaponSearchFilterBar = (props: Props) => {
<div className="SearchFilterBar"> <div className="SearchFilterBar">
<SearchFilter <SearchFilter
label={t('filters.labels.rarity')} label={t('filters.labels.rarity')}
key="rarity"
numSelected={ numSelected={
Object.values(rarityState) Object.values(rarityState)
.map((x) => x.checked) .map((x) => x.checked)
@ -198,6 +199,7 @@ const WeaponSearchFilterBar = (props: Props) => {
<SearchFilter <SearchFilter
label={t('filters.labels.element')} label={t('filters.labels.element')}
key="element"
numSelected={ numSelected={
Object.values(elementState) Object.values(elementState)
.map((x) => x.checked) .map((x) => x.checked)
@ -225,6 +227,7 @@ const WeaponSearchFilterBar = (props: Props) => {
<SearchFilter <SearchFilter
label={t('filters.labels.proficiency')} label={t('filters.labels.proficiency')}
key="proficiency"
numSelected={ numSelected={
Object.values(proficiencyState) Object.values(proficiencyState)
.map((x) => x.checked) .map((x) => x.checked)
@ -278,6 +281,7 @@ const WeaponSearchFilterBar = (props: Props) => {
<SearchFilter <SearchFilter
label={t('filters.labels.series')} label={t('filters.labels.series')}
key="series"
numSelected={ numSelected={
Object.values(seriesState) Object.values(seriesState)
.map((x) => x.checked) .map((x) => x.checked)

View file

@ -119,16 +119,6 @@ select {
} }
} }
.Overlay {
background: rgba(0, 0, 0, 0.6);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 20;
}
.Hovercard { .Hovercard {
background: #222; background: #222;
border-radius: $unit; border-radius: $unit;
@ -298,7 +288,7 @@ i.tag {
} }
} }
@keyframes openModal { @keyframes openModalDesktop {
0% { 0% {
opacity: 0; opacity: 0;
transform: translate(-50%, -48%) scale(0.96); transform: translate(-50%, -48%) scale(0.96);
@ -309,3 +299,15 @@ i.tag {
transform: translate(-50%, -50%) scale(1); transform: translate(-50%, -50%) scale(1);
} }
} }
@keyframes openModalMobile {
0% {
opacity: 0;
transform: translate(0%, 100%);
}
100% {
// opacity: 1;
transform: translate(0, 30%);
}
}

View file

@ -1,7 +1,7 @@
// use with @include // use with @include
@mixin breakpoint($breakpoint) { @mixin breakpoint($breakpoint) {
$phone-width: 430px; $phone-width: 430px;
$phone-height: 850px; $phone-height: 920px;
$tablet-width: 1024px; $tablet-width: 1024px;
$tablet-height: 1024px; $tablet-height: 1024px;