draft mobile layout

This commit is contained in:
SammCheese 2023-04-15 21:34:03 +02:00
parent 50eb02f68b
commit 2edd032ec7
No known key found for this signature in database
GPG Key ID: 28CFE2321A140BA1
19 changed files with 433 additions and 221 deletions

View File

@ -4,7 +4,7 @@
"version": "0.0.1",
"scripts": {
"prepare": "cd ../../../ && husky install invokeai/frontend/web/.husky",
"dev": "concurrently \"vite dev\" \"yarn run theme:watch\"",
"dev": "concurrently \"vite dev --host\" \"yarn run theme:watch\"",
"build": "yarn run lint && vite build",
"preview": "vite preview",
"lint:madge": "madge --circular src/main.tsx",
@ -65,6 +65,7 @@
"react-konva": "^18.2.4",
"react-konva-utils": "^0.3.2",
"react-redux": "^8.0.5",
"react-responsive": "^9.0.2",
"react-transition-group": "^4.4.5",
"react-zoom-pan-pinch": "^2.6.1",
"redux-deep-persist": "^1.0.7",

View File

@ -1,6 +1,7 @@
import { Flex, Spinner, Text } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import { updateIsMobile } from 'theme/util/isMobile';
interface LoaderProps {
showText?: boolean;
text?: string;
@ -9,6 +10,7 @@ interface LoaderProps {
// This component loads before the theme so we cannot use theme tokens here
const Loading = (props: LoaderProps) => {
updateIsMobile();
const { t } = useTranslation();
const { showText = false, text = t('common.loadingInvokeAI') } = props;

View File

@ -15,6 +15,8 @@ import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel';
import Lightbox from 'features/lightbox/components/Lightbox';
import { useAppSelector } from './storeHooks';
import { PropsWithChildren, useEffect } from 'react';
import { isMobile } from 'theme/util/isMobile';
import MediaQuery from 'react-responsive';
keepGUIAlive();
@ -35,16 +37,23 @@ const App = (props: PropsWithChildren) => {
<ProgressBar />
<Grid
gap={4}
p={4}
gridAutoRows="min-content auto"
p={isMobile ? 1 : 4}
gridAutoRows="max-content auto"
w={APP_WIDTH}
h={APP_HEIGHT}
>
{props.children || <SiteHeader />}
<Flex gap={4} w="full" h="full">
<InvokeTabs />
<ImageGalleryPanel />
</Flex>
<MediaQuery minDeviceWidth={768}>
<Flex gap={4} w="full" h="full">
<InvokeTabs />
<ImageGalleryPanel />
</Flex>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<Box position="relative" overflowY="scroll">
<InvokeTabs />
</Box>
</MediaQuery>
</Grid>
<Box>
<Console />

View File

@ -233,6 +233,7 @@ const IAICanvasToolbar = () => {
<Flex
sx={{
alignItems: 'center',
flexWrap: 'wrap',
gap: 2,
}}
>

View File

@ -409,6 +409,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
justifyContent: 'center',
alignItems: 'center',
columnGap: '0.5em',
flexWrap: 'wrap',
}}
{...props}
>

View File

@ -7,6 +7,7 @@ import { MdPhoto } from 'react-icons/md';
import { gallerySelector } from '../store/gallerySelectors';
import CurrentImageButtons from './CurrentImageButtons';
import CurrentImagePreview from './CurrentImagePreview';
import { isMobile } from 'theme/util/isMobile';
export const currentImageDisplaySelector = createSelector(
[gallerySelector],
@ -36,7 +37,7 @@ const CurrentImageDisplay = () => {
flexDirection: 'column',
height: '100%',
width: '100%',
rowGap: 4,
rowGap: isMobile ? 0 : 4,
borderRadius: 'base',
}}
>

View File

@ -26,6 +26,8 @@ import {
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
import { isMobile } from 'theme/util/isMobile';
import MediaQuery from 'react-responsive';
const GALLERY_TAB_WIDTHS: Record<
InvokeTabName,
@ -147,6 +149,7 @@ export default function ImageGalleryPanel() {
);
const IMAGE_SIZE_STEP = 32;
const screenWidth = window.innerWidth;
useHotkeys(
'shift+up',
@ -179,24 +182,35 @@ export default function ImageGalleryPanel() {
);
return (
<ResizableDrawer
direction="right"
isResizable={isResizable || !shouldPinGallery}
isOpen={shouldShowGallery}
onClose={handleCloseGallery}
isPinned={shouldPinGallery && !isLightboxOpen}
minWidth={
shouldPinGallery
? GALLERY_TAB_WIDTHS[activeTabName].galleryMinWidth
: 200
}
maxWidth={
shouldPinGallery
? GALLERY_TAB_WIDTHS[activeTabName].galleryMaxWidth
: undefined
}
>
<ImageGalleryContent />
</ResizableDrawer>
<>
<MediaQuery minDeviceWidth={768}>
<ResizableDrawer
direction="right"
isResizable={isResizable || !shouldPinGallery}
isOpen={shouldShowGallery}
onClose={handleCloseGallery}
isPinned={shouldPinGallery && !isLightboxOpen}
minWidth={
shouldPinGallery
? isMobile
? screenWidth
: GALLERY_TAB_WIDTHS[activeTabName].galleryMinWidth
: 200
}
maxWidth={
shouldPinGallery
? isMobile
? screenWidth
: GALLERY_TAB_WIDTHS[activeTabName].galleryMaxWidth
: undefined
}
>
<ImageGalleryContent />
</ResizableDrawer>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<ImageGalleryContent />
</MediaQuery>
</>
);
}

View File

@ -23,7 +23,7 @@ export default function InvokeAccordionItem(props: InvokeAccordionItemProps) {
return (
<AccordionItem>
<AccordionButton>
<Flex width="100%" gap={2} align="center">
<Flex width="100vw" gap={2} align="center">
<Box flexGrow={1} textAlign="start">
{header}
</Box>

View File

@ -15,6 +15,7 @@ import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { isEqual } from 'lodash';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { isMobile } from 'theme/util/isMobile';
const promptInputSelector = createSelector(
[(state: RootState) => state.generation, activeTabNameSelector],
@ -76,7 +77,7 @@ const PromptInput = () => {
onKeyDown={handleKeyDown}
resize="vertical"
ref={promptRef}
minH={40}
minH={isMobile ? 20 : 40}
/>
</FormControl>
</Box>

View File

@ -2,6 +2,7 @@ import { Flex, Text, Image } from '@chakra-ui/react';
import { RootState } from 'app/store';
import { useAppSelector } from 'app/storeHooks';
import InvokeAILogoImage from 'assets/images/logo.png';
import MediaQuery from 'react-responsive';
const InvokeAILogoComponent = () => {
const appVersion = useAppSelector(
@ -11,18 +12,20 @@ const InvokeAILogoComponent = () => {
return (
<Flex alignItems="center" gap={3} ps={1}>
<Image src={InvokeAILogoImage} alt="invoke-ai-logo" w="32px" h="32px" />
<Text fontSize="xl">
invoke <strong>ai</strong>
</Text>
<Text
sx={{
fontWeight: 300,
marginTop: 1,
}}
variant="subtext"
>
{appVersion}
</Text>
<MediaQuery minDeviceWidth={768}>
<Text fontSize="xl">
invoke <strong>ai</strong>
</Text>
<Text
sx={{
fontWeight: 300,
marginTop: 1,
}}
variant="subtext"
>
{appVersion}
</Text>
</MediaQuery>
</Flex>
);
};

View File

@ -1,127 +1,63 @@
import { Flex, Grid, Link } from '@chakra-ui/react';
import { FaBug, FaCube, FaDiscord, FaGithub, FaKeyboard } from 'react-icons/fa';
import IAIIconButton from 'common/components/IAIIconButton';
import HotkeysModal from './HotkeysModal/HotkeysModal';
import ModelManagerModal from './ModelManager/ModelManagerModal';
import { Box, Flex, Grid } from '@chakra-ui/react';
import React, { useState } from 'react';
import ModelSelect from './ModelSelect';
import SettingsModal from './SettingsModal/SettingsModal';
import StatusIndicator from './StatusIndicator';
import ThemeChanger from './ThemeChanger';
import LanguagePicker from './LanguagePicker';
import { useTranslation } from 'react-i18next';
import { MdSettings } from 'react-icons/md';
import InvokeAILogoComponent from './InvokeAILogoComponent';
import MediaQuery from 'react-responsive';
import SiteHeaderMenu from './SiteHeaderMenu';
import { FaBars } from 'react-icons/fa';
/**
* Header, includes color mode toggle, settings button, status message.
* Header, includes logo, model select and status message.
*/
const SiteHeader = () => {
const { t } = useTranslation();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const handleMenuToggle = () => {
setIsMenuOpen(!isMenuOpen);
};
return (
<Grid gridTemplateColumns="auto max-content">
<InvokeAILogoComponent />
<>
<MediaQuery minDeviceWidth={768}>
<Grid gridTemplateColumns="auto max-content">
<InvokeAILogoComponent />
<Flex alignItems="center" gap={2}>
<StatusIndicator />
<Flex alignItems="center" gap={2}>
<StatusIndicator />
<ModelSelect />
<ModelSelect />
<ModelManagerModal>
<IAIIconButton
aria-label={t('modelManager.modelManager')}
tooltip={t('modelManager.modelManager')}
size="sm"
variant="link"
data-variant="link"
fontSize={20}
icon={<FaCube />}
/>
</ModelManagerModal>
<SiteHeaderMenu />
</Flex>
</Grid>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<Flex>
<InvokeAILogoComponent />
<HotkeysModal>
<IAIIconButton
aria-label={t('common.hotkeysLabel')}
tooltip={t('common.hotkeysLabel')}
size="sm"
variant="link"
data-variant="link"
fontSize={20}
icon={<FaKeyboard />}
/>
</HotkeysModal>
<Flex alignItems="center" gap={3} marginLeft="2rem">
<StatusIndicator />
<ThemeChanger />
<LanguagePicker />
<Link
isExternal
href="http://github.com/invoke-ai/InvokeAI/issues"
marginBottom="-0.25rem"
>
<IAIIconButton
aria-label={t('common.reportBugLabel')}
tooltip={t('common.reportBugLabel')}
variant="link"
data-variant="link"
fontSize={20}
size="sm"
icon={<FaBug />}
/>
</Link>
<Link
isExternal
href="http://github.com/invoke-ai/InvokeAI"
marginBottom="-0.25rem"
>
<IAIIconButton
aria-label={t('common.githubLabel')}
tooltip={t('common.githubLabel')}
variant="link"
data-variant="link"
fontSize={20}
size="sm"
icon={<FaGithub />}
/>
</Link>
<Link
isExternal
href="https://discord.gg/ZmtBAhwWhy"
marginBottom="-0.25rem"
>
<IAIIconButton
aria-label={t('common.discordLabel')}
tooltip={t('common.discordLabel')}
variant="link"
data-variant="link"
fontSize={20}
size="sm"
icon={<FaDiscord />}
/>
</Link>
<SettingsModal>
<IAIIconButton
aria-label={t('common.settingsLabel')}
tooltip={t('common.settingsLabel')}
variant="link"
data-variant="link"
fontSize={22}
size="sm"
icon={<MdSettings />}
/>
</SettingsModal>
</Flex>
</Grid>
<ModelSelect />
</Flex>
<Box
onClick={handleMenuToggle}
sx={{
marginLeft: '20px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<FaBars />
</Box>
</Flex>
{isMenuOpen && <SiteHeaderMenu />}
</MediaQuery>
</>
);
};

View File

@ -0,0 +1,120 @@
import { Flex, Grid, Link } from '@chakra-ui/react';
import { FaBug, FaCube, FaDiscord, FaGithub, FaKeyboard } from 'react-icons/fa';
import IAIIconButton from 'common/components/IAIIconButton';
import HotkeysModal from './HotkeysModal/HotkeysModal';
import ModelManagerModal from './ModelManager/ModelManagerModal';
import SettingsModal from './SettingsModal/SettingsModal';
import ThemeChanger from './ThemeChanger';
import LanguagePicker from './LanguagePicker';
import { useTranslation } from 'react-i18next';
import { MdSettings } from 'react-icons/md';
/**
* HeaderMenu, includes color mode toggle, settings button.
*/
const SiteHeaderMenu = () => {
const { t } = useTranslation();
return (
<Grid gridTemplateColumns="auto max-content">
<Flex alignItems="center" gap={2}>
<ModelManagerModal>
<IAIIconButton
aria-label={t('modelManager.modelManager')}
tooltip={t('modelManager.modelManager')}
size="sm"
variant="link"
data-variant="link"
fontSize={20}
icon={<FaCube />}
/>
</ModelManagerModal>
<HotkeysModal>
<IAIIconButton
aria-label={t('common.hotkeysLabel')}
tooltip={t('common.hotkeysLabel')}
size="sm"
variant="link"
data-variant="link"
fontSize={20}
icon={<FaKeyboard />}
/>
</HotkeysModal>
<ThemeChanger />
<LanguagePicker />
<Link
isExternal
href="http://github.com/invoke-ai/InvokeAI/issues"
marginBottom="-0.25rem"
>
<IAIIconButton
aria-label={t('common.reportBugLabel')}
tooltip={t('common.reportBugLabel')}
variant="link"
data-variant="link"
fontSize={20}
size="sm"
icon={<FaBug />}
/>
</Link>
<Link
isExternal
href="http://github.com/invoke-ai/InvokeAI"
marginBottom="-0.25rem"
>
<IAIIconButton
aria-label={t('common.githubLabel')}
tooltip={t('common.githubLabel')}
variant="link"
data-variant="link"
fontSize={20}
size="sm"
icon={<FaGithub />}
/>
</Link>
<Link
isExternal
href="https://discord.gg/ZmtBAhwWhy"
marginBottom="-0.25rem"
>
<IAIIconButton
aria-label={t('common.discordLabel')}
tooltip={t('common.discordLabel')}
variant="link"
data-variant="link"
fontSize={20}
size="sm"
icon={<FaDiscord />}
/>
</Link>
<SettingsModal>
<IAIIconButton
aria-label={t('common.settingsLabel')}
tooltip={t('common.settingsLabel')}
variant="link"
data-variant="link"
fontSize={22}
size="sm"
icon={<MdSettings />}
/>
</SettingsModal>
</Flex>
</Grid>
);
};
SiteHeaderMenu.displayName = 'SiteHeaderMenu';
export default SiteHeaderMenu;

View File

@ -13,6 +13,9 @@ import useGetImageByUuid from 'features/gallery/hooks/useGetImageByUuid';
import { isEqual } from 'lodash';
import { APP_CONTENT_HEIGHT } from 'theme/util/constants';
import ParametersPanel from './ParametersPanel';
import MediaQuery from 'react-responsive';
import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel';
import { isMobile } from 'theme/util/isMobile';
const workareaSelector = createSelector(
[uiSelector, activeTabNameSelector],
@ -54,12 +57,31 @@ const InvokeWorkarea = (props: InvokeWorkareaProps) => {
};
return (
<Flex {...rest} pos="relative" w="full" h={APP_CONTENT_HEIGHT} gap={4}>
<ParametersPanel>{parametersPanelContent}</ParametersPanel>
<Box pos="relative" w="100%" h="100%" onDrop={handleDrop}>
{children}
</Box>
</Flex>
<>
<MediaQuery minDeviceWidth={768}>
<Flex {...rest} pos="relative" w="full" h={APP_CONTENT_HEIGHT} gap={4}>
<ParametersPanel>{parametersPanelContent}</ParametersPanel>
<Box pos="relative" w="100%" h="100%" onDrop={handleDrop}>
{children}
</Box>
</Flex>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<Flex
{...rest}
display="block"
pos="relative"
w="full"
h={APP_CONTENT_HEIGHT}
>
<Box pos="sticky" w="full" h="70%" onDrop={handleDrop}>
{children}
</Box>
<ParametersPanel>{parametersPanelContent}</ParametersPanel>
{isMobile && <ImageGalleryPanel />}
</Flex>
</MediaQuery>
</>
);
};

View File

@ -1,4 +1,4 @@
import { Flex } from '@chakra-ui/react';
import { Box, Flex } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import { memo, ReactNode } from 'react';
@ -19,6 +19,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { activeTabNameSelector, uiSelector } from '../store/uiSelectors';
import { isEqual } from 'lodash';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
import MediaQuery from 'react-responsive';
const parametersPanelSelector = createSelector(
[uiSelector, activeTabNameSelector, lightboxSelector],
@ -89,40 +90,49 @@ const ParametersPanel = ({ children }: ParametersPanelProps) => {
[]
);
return (
<ResizableDrawer
direction="left"
isResizable={isResizable || !shouldPinParametersPanel}
isOpen={shouldShowParametersPanel}
onClose={closeParametersPanel}
isPinned={shouldPinParametersPanel || isLightboxOpen}
sx={{
borderColor: 'base.700',
p: shouldPinParametersPanel ? 0 : 4,
bg: 'base.900',
}}
initialWidth={PARAMETERS_PANEL_WIDTH}
minWidth={PARAMETERS_PANEL_WIDTH}
>
<Flex flexDir="column" position="relative" h="full" w="full">
{!shouldPinParametersPanel && (
<Flex
paddingTop={1.5}
paddingBottom={4}
justifyContent="space-between"
alignItems="center"
>
<InvokeAILogoComponent />
<PinParametersPanelButton />
<>
<MediaQuery minDeviceWidth={768}>
<ResizableDrawer
direction="left"
isResizable={isResizable || !shouldPinParametersPanel}
isOpen={shouldShowParametersPanel}
onClose={closeParametersPanel}
isPinned={shouldPinParametersPanel || isLightboxOpen}
sx={{
borderColor: 'base.700',
p: shouldPinParametersPanel ? 0 : 4,
bg: 'base.900',
}}
initialWidth={PARAMETERS_PANEL_WIDTH}
minWidth={PARAMETERS_PANEL_WIDTH}
>
<Flex flexDir="column" position="relative" h="full" w="full">
{!shouldPinParametersPanel && (
<Flex
paddingTop={1.5}
paddingBottom={4}
justifyContent="space-between"
alignItems="center"
>
<InvokeAILogoComponent />
<PinParametersPanelButton />
</Flex>
)}
<Scrollable>{children}</Scrollable>
{shouldPinParametersPanel && (
<PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/>
)}
</Flex>
)}
<Scrollable>{children}</Scrollable>
{shouldPinParametersPanel && (
<PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/>
)}
</Flex>
</ResizableDrawer>
</ResizableDrawer>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<Box flexDir="column" w="full" h="50rem">
{children}
</Box>
</MediaQuery>
</>
);
};

View File

@ -4,6 +4,7 @@ import { useAppSelector } from 'app/storeHooks';
import ImageUploadButton from 'common/components/ImageUploaderButton';
import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay';
import InitImagePreview from './InitImagePreview';
import MediaQuery from 'react-responsive';
const workareaSplitViewStyle: ChakraProps['sx'] = {
flexDirection: 'column',
@ -28,22 +29,44 @@ const ImageToImageContent = () => {
);
return (
<Grid
sx={{
w: '100%',
h: '100%',
gridTemplateColumns: '1fr 1fr',
borderRadius: 'base',
bg: 'base.850',
}}
>
<Flex sx={{ ...workareaSplitViewStyle, paddingInlineEnd: 2 }}>
{imageToImageComponent}
</Flex>
<Flex sx={{ ...workareaSplitViewStyle, paddingInlineStart: 2 }}>
<CurrentImageDisplay />
</Flex>
</Grid>
<>
<MediaQuery minDeviceWidth={768}>
<Grid
sx={{
w: '100%',
h: '100%',
gridTemplateColumns: '1fr 1fr',
borderRadius: 'base',
bg: 'base.850',
}}
>
<Flex sx={{ ...workareaSplitViewStyle, paddingInlineEnd: 2 }}>
{imageToImageComponent}
</Flex>
<Flex sx={{ ...workareaSplitViewStyle, paddingInlineStart: 2 }}>
<CurrentImageDisplay />
</Flex>
</Grid>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<Grid
sx={{
w: '100%',
h: '100%',
gridTemplateColumns: '1fr 3fr',
borderRadius: 'base',
bg: 'base.850',
}}
>
<Flex sx={{ ...workareaSplitViewStyle, paddingInlineEnd: 2 }}>
{imageToImageComponent}
</Flex>
<Flex sx={{ ...workareaSplitViewStyle, paddingInlineStart: 2 }}>
<CurrentImageDisplay />
</Flex>
</Grid>
</MediaQuery>
</>
);
};

View File

@ -1,20 +1,39 @@
import { Box, Flex } from '@chakra-ui/react';
import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay';
import MediaQuery from 'react-responsive';
const TextToImageContent = () => {
return (
<Box
sx={{
width: '100%',
height: '100%',
borderRadius: 'base',
bg: 'base.850',
}}
>
<Flex sx={{ p: 4, width: '100%', height: '100%' }}>
<CurrentImageDisplay />
</Flex>
</Box>
<>
<MediaQuery minDeviceWidth={768}>
<Box
sx={{
width: '100%',
height: '100%',
borderRadius: 'base',
bg: 'base.850',
}}
>
<Flex sx={{ p: 4, width: '100%', height: '100%' }}>
<CurrentImageDisplay />
</Flex>
</Box>
</MediaQuery>
<MediaQuery maxDeviceWidth={768}>
<Box
sx={{
position: 'relative',
width: 'full',
height: 'full',
bg: 'base.850',
}}
>
<Flex sx={{ height: '100%' }}>
<CurrentImageDisplay />
</Flex>
</Box>
</MediaQuery>
</>
);
};

View File

@ -4,6 +4,8 @@ import {
defineStyle,
} from '@chakra-ui/styled-system';
import { isMobile } from 'theme/util/isMobile';
const { defineMultiStyleConfig, definePartsStyle } =
createMultiStyleConfigHelpers(parts.keys);
@ -14,16 +16,26 @@ const invokeAIRoot = defineStyle((_props) => {
};
});
const invokeAIRootMobile = defineStyle((_props) => {
return {
position: 'relative',
display: 'block',
};
});
const invokeAITab = defineStyle((_props) => ({}));
const invokeAITablist = defineStyle((_props) => ({
display: 'flex',
flexDirection: 'column',
flexDirection: isMobile ? 'row' : 'column',
gap: 1,
color: 'base.700',
justifyContent: isMobile ? 'center' : '',
button: {
fontSize: 'sm',
padding: 2,
paddingLeft: isMobile ? '5vw' : '',
paddingRight: isMobile ? '5vw' : '',
borderRadius: 'base',
_selected: {
bg: 'accent.700',
@ -46,7 +58,7 @@ const invokeAITabpanel = defineStyle((_props) => ({
}));
const invokeAI = definePartsStyle((props) => ({
root: invokeAIRoot(props),
root: isMobile ? invokeAIRootMobile(props) : invokeAIRoot(props),
tab: invokeAITab(props),
tablist: invokeAITablist(props),
tabpanel: invokeAITabpanel(props),

View File

@ -0,0 +1,5 @@
export let isMobile = false;
export function updateIsMobile() {
isMobile = window.innerWidth <= 768 || document.body.clientWidth <= 768;
}

View File

@ -2201,6 +2201,11 @@ css-box-model@1.2.1:
dependencies:
tiny-invariant "^1.0.6"
css-mediaquery@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0"
integrity sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==
csstype@^3.0.11, csstype@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
@ -3280,6 +3285,11 @@ husky@^8.0.3:
resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==
hyphenate-style-name@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
i18next-browser-languagedetector@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz#ead34592edc96c6c3a618a51cb57ad027c5b5d87"
@ -3927,6 +3937,13 @@ make-error@^1.1.1:
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
matchmediaquery@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.3.1.tgz#8247edc47e499ebb7c58f62a9ff9ccf5b815c6d7"
integrity sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ==
dependencies:
css-mediaquery "^0.1.2"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@ -4440,7 +4457,7 @@ pretty-ms@^7.0.1:
dependencies:
parse-ms "^2.1.0"
prop-types@^15.6.2, prop-types@^15.8.1:
prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -4630,6 +4647,16 @@ react-remove-scroll@^2.5.5:
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
react-responsive@^9.0.2:
version "9.0.2"
resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-9.0.2.tgz#34531ca77a61e7a8775714016d21241df7e4205c"
integrity sha512-+4CCab7z8G8glgJoRjAwocsgsv6VA2w7JPxFWHRc7kvz8mec1/K5LutNC2MG28Mn8mu6+bu04XZxHv5gyfT7xQ==
dependencies:
hyphenate-style-name "^1.0.0"
matchmediaquery "^0.3.0"
prop-types "^15.6.1"
shallow-equal "^1.2.1"
react-style-singleton@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
@ -4912,6 +4939,11 @@ semver@^7.3.4, semver@^7.3.5, semver@^7.3.7:
dependencies:
lru-cache "^6.0.0"
shallow-equal@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"