💄(frontend) add left panel
In the new interface there is a new left panel. We implement it and add it to the MainLayout
This commit is contained in:
committed by
Anthony LC
parent
e83c404e21
commit
8d514bd571
@@ -13,6 +13,7 @@ and this project adheres to
|
|||||||
|
|
||||||
- 🔧(backend) add option to configure list of essential OIDC claims #525 & #531
|
- 🔧(backend) add option to configure list of essential OIDC claims #525 & #531
|
||||||
- 🔧(helm) add option to disable default tls setting by @dominikkaminski #519
|
- 🔧(helm) add option to disable default tls setting by @dominikkaminski #519
|
||||||
|
- 💄(frontend) Add left panel #420
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import { Text, TextType } from '@/components';
|
import { Text, TextType } from '@/components';
|
||||||
import { useCunninghamTheme } from '@/cunningham';
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
|
||||||
|
type IconProps = {
|
||||||
|
iconName: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
export const Icon = ({ iconName, className }: IconProps) => {
|
||||||
|
return <span className={`material-icons ${className}`}>{iconName}</span>;
|
||||||
|
};
|
||||||
|
|
||||||
interface IconBGProps extends TextType {
|
interface IconBGProps extends TextType {
|
||||||
iconName: string;
|
iconName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export * from './Icon';
|
|||||||
export * from './InfiniteScroll';
|
export * from './InfiniteScroll';
|
||||||
export * from './Link';
|
export * from './Link';
|
||||||
export * from './SideModal';
|
export * from './SideModal';
|
||||||
|
export * from './separators/SeparatedSection';
|
||||||
export * from './Text';
|
export * from './Text';
|
||||||
export * from './TextErrors';
|
export * from './TextErrors';
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
import { css } from 'styled-components';
|
||||||
|
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
|
||||||
|
import { Box } from '../Box';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
showSeparator?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SeparatedSection = ({
|
||||||
|
showSeparator = true,
|
||||||
|
children,
|
||||||
|
}: PropsWithChildren<Props>) => {
|
||||||
|
const theme = useCunninghamTheme();
|
||||||
|
const colors = theme.colorsTokens();
|
||||||
|
const spacings = theme.spacingsTokens();
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
$css={css`
|
||||||
|
padding: ${spacings['base']} 0;
|
||||||
|
${showSeparator &&
|
||||||
|
css`
|
||||||
|
border-bottom: 1px solid ${colors?.['greyscale-200']};
|
||||||
|
`}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ import { tokens } from './cunningham-tokens';
|
|||||||
|
|
||||||
type Tokens = typeof tokens.themes.default & Partial<typeof tokens.themes.dsfr>;
|
type Tokens = typeof tokens.themes.default & Partial<typeof tokens.themes.dsfr>;
|
||||||
type ColorsTokens = Tokens['theme']['colors'];
|
type ColorsTokens = Tokens['theme']['colors'];
|
||||||
|
type SpacingsTokens = Tokens['theme']['spacings'];
|
||||||
type ComponentTokens = Tokens['components'];
|
type ComponentTokens = Tokens['components'];
|
||||||
export type Theme = keyof typeof tokens.themes;
|
export type Theme = keyof typeof tokens.themes;
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ interface AuthStore {
|
|||||||
setTheme: (theme: Theme) => void;
|
setTheme: (theme: Theme) => void;
|
||||||
themeTokens: () => Partial<Tokens['theme']>;
|
themeTokens: () => Partial<Tokens['theme']>;
|
||||||
colorsTokens: () => Partial<ColorsTokens>;
|
colorsTokens: () => Partial<ColorsTokens>;
|
||||||
|
spacingsTokens: () => Partial<SpacingsTokens>;
|
||||||
componentTokens: () => ComponentTokens;
|
componentTokens: () => ComponentTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ export const useCunninghamTheme = create<AuthStore>((set, get) => {
|
|||||||
themeTokens: () => currentTheme().theme,
|
themeTokens: () => currentTheme().theme,
|
||||||
colorsTokens: () => currentTheme().theme.colors,
|
colorsTokens: () => currentTheme().theme.colors,
|
||||||
componentTokens: () => currentTheme().components,
|
componentTokens: () => currentTheme().components,
|
||||||
|
spacingsTokens: () => currentTheme().theme.spacings,
|
||||||
setTheme: (theme: Theme) => {
|
setTheme: (theme: Theme) => {
|
||||||
set({ theme });
|
set({ theme });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
|
|||||||
<>
|
<>
|
||||||
<DocHeader doc={doc} />
|
<DocHeader doc={doc} />
|
||||||
{!doc.abilities.partial_update && (
|
{!doc.abilities.partial_update && (
|
||||||
<Box $margin={{ all: 'small', top: 'none' }}>
|
<Box $width="100%" $margin={{ all: 'small', top: 'none' }}>
|
||||||
<Alert type={VariantType.WARNING}>
|
<Alert type={VariantType.WARNING}>
|
||||||
{t(`Read only, you cannot edit this document.`)}
|
{t(`Read only, you cannot edit this document.`)}
|
||||||
</Alert>
|
</Alert>
|
||||||
@@ -58,10 +58,10 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
|
|||||||
)}
|
)}
|
||||||
<Box
|
<Box
|
||||||
$background={colorsTokens()['primary-bg']}
|
$background={colorsTokens()['primary-bg']}
|
||||||
$height="100%"
|
|
||||||
$direction="row"
|
$direction="row"
|
||||||
|
$width="100%"
|
||||||
$margin={{ all: isMobile ? 'tiny' : 'small', top: 'none' }}
|
$margin={{ all: isMobile ? 'tiny' : 'small', top: 'none' }}
|
||||||
$css="overflow-x: clip;"
|
$css="overflow-x: clip; flex: 1;"
|
||||||
$position="relative"
|
$position="relative"
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export const DocHeader = ({ doc }: DocHeaderProps) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card
|
<Card
|
||||||
|
$width="100%"
|
||||||
$margin={isMobile ? 'tiny' : 'small'}
|
$margin={isMobile ? 'tiny' : 'small'}
|
||||||
aria-label={t('It is the card information about the document.')}
|
aria-label={t('It is the card information about the document.')}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Box, BoxButton, Text } from '@/components';
|
import { Box, BoxButton, Text } from '@/components';
|
||||||
import { useEditorStore, useHeadingStore } from '@/features/docs/doc-editor';
|
import { useEditorStore, useHeadingStore } from '@/features/docs/doc-editor';
|
||||||
|
import { MAIN_LAYOUT_ID } from '@/layouts/conf';
|
||||||
import { useResponsiveStore } from '@/stores';
|
import { useResponsiveStore } from '@/stores';
|
||||||
|
|
||||||
import { Heading } from './Heading';
|
import { Heading } from './Heading';
|
||||||
@@ -43,7 +44,7 @@ export const TableContent = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('scroll', () => {
|
document.getElementById(MAIN_LAYOUT_ID)?.addEventListener('scroll', () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleScroll();
|
handleScroll();
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import { Button } from '@openfun/cunningham-react';
|
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import React from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import { Box } from '@/components';
|
|
||||||
import { useCreateDoc, useTrans } from '@/features/docs/doc-management/';
|
|
||||||
import { useResponsiveStore } from '@/stores';
|
|
||||||
|
|
||||||
import { DocsGrid } from './DocsGrid';
|
|
||||||
|
|
||||||
export const DocsGridContainer = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { untitledDocument } = useTrans();
|
|
||||||
const { push } = useRouter();
|
|
||||||
const { isMobile } = useResponsiveStore();
|
|
||||||
|
|
||||||
const { mutate: createDoc } = useCreateDoc({
|
|
||||||
onSuccess: (doc) => {
|
|
||||||
void push(`/docs/${doc.id}`);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleCreateDoc = () => {
|
|
||||||
createDoc({ title: untitledDocument });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box $overflow="auto">
|
|
||||||
<Box
|
|
||||||
$align="flex-end"
|
|
||||||
$justify="center"
|
|
||||||
$margin={isMobile ? 'small' : 'big'}
|
|
||||||
>
|
|
||||||
<Button onClick={handleCreateDoc}>{t('Create a new document')}</Button>
|
|
||||||
</Box>
|
|
||||||
<DocsGrid />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './DocsGridContainer';
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import React from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Box, StyledLink } from '@/components/';
|
import { Box, StyledLink } from '@/components/';
|
||||||
@@ -24,7 +23,7 @@ export const Header = () => {
|
|||||||
$width="100%"
|
$width="100%"
|
||||||
$zIndex="100"
|
$zIndex="100"
|
||||||
$padding={{ vertical: 'xtiny' }}
|
$padding={{ vertical: 'xtiny' }}
|
||||||
$css="box-shadow: 0 1px 4px #00000040;"
|
$css="border-bottom: 1px solid #EDEDED;"
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
$margin={{
|
$margin={{
|
||||||
|
|||||||
1
src/frontend/apps/impress/src/features/header/conf.ts
Normal file
1
src/frontend/apps/impress/src/features/header/conf.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const HEADER_HEIGHT = 52;
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { Button } from '@openfun/cunningham-react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Box, Icon, SeparatedSection } from '@/components';
|
||||||
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
import { useCreateDoc } from '@/features/docs';
|
||||||
|
import { HEADER_HEIGHT } from '@/features/header/conf';
|
||||||
|
import { useResponsiveStore } from '@/stores';
|
||||||
|
|
||||||
|
export const LeftPanel = ({ children }: PropsWithChildren) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const router = useRouter();
|
||||||
|
const { isDesktop } = useResponsiveStore();
|
||||||
|
const theme = useCunninghamTheme();
|
||||||
|
const colors = theme.colorsTokens();
|
||||||
|
|
||||||
|
const { mutate: createDoc } = useCreateDoc({
|
||||||
|
onSuccess: (doc) => {
|
||||||
|
router.push(`/docs/${doc.id}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const goToHome = () => {
|
||||||
|
router.push('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
const createNewDoc = () => {
|
||||||
|
createDoc({ title: t('Untitled document') });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isDesktop && (
|
||||||
|
<Box
|
||||||
|
data-testid="left-panel-desktop"
|
||||||
|
$css={`
|
||||||
|
height: calc(100vh - ${HEADER_HEIGHT}px);
|
||||||
|
width: 300px;
|
||||||
|
min-width: 300px;
|
||||||
|
border-right: 1px solid ${colors['greyscale-200']};
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<SeparatedSection>
|
||||||
|
<Box
|
||||||
|
$padding={{ horizontal: 'sm' }}
|
||||||
|
$direction="row"
|
||||||
|
$justify="space-between"
|
||||||
|
$align="center"
|
||||||
|
>
|
||||||
|
<Box $direction="row" $gap="2px">
|
||||||
|
<Button
|
||||||
|
onClick={goToHome}
|
||||||
|
size="medium"
|
||||||
|
color="primary-text"
|
||||||
|
icon={<Icon iconName="house" />}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Button onClick={createNewDoc}>{t('New doc')}</Button>
|
||||||
|
</Box>
|
||||||
|
</SeparatedSection>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './LeftPanel';
|
||||||
@@ -4,33 +4,56 @@ import { Box } from '@/components';
|
|||||||
import { useCunninghamTheme } from '@/cunningham';
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
import { Footer } from '@/features/footer';
|
import { Footer } from '@/features/footer';
|
||||||
import { Header } from '@/features/header';
|
import { Header } from '@/features/header';
|
||||||
|
import { HEADER_HEIGHT } from '@/features/header/conf';
|
||||||
|
import { LeftPanel } from '@/features/left-panel';
|
||||||
|
import { MAIN_LAYOUT_ID } from '@/layouts/conf';
|
||||||
|
import { useResponsiveStore } from '@/stores';
|
||||||
|
|
||||||
interface MainLayoutProps {
|
type MainLayoutProps = {
|
||||||
|
backgroundColor?: 'white' | 'grey';
|
||||||
withoutFooter?: boolean;
|
withoutFooter?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function MainLayout({
|
export function MainLayout({
|
||||||
children,
|
children,
|
||||||
withoutFooter,
|
backgroundColor = 'white',
|
||||||
|
withoutFooter = false,
|
||||||
}: PropsWithChildren<MainLayoutProps>) {
|
}: PropsWithChildren<MainLayoutProps>) {
|
||||||
|
const { isDesktop } = useResponsiveStore();
|
||||||
const { colorsTokens } = useCunninghamTheme();
|
const { colorsTokens } = useCunninghamTheme();
|
||||||
|
|
||||||
|
const colors = colorsTokens();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<div>
|
||||||
<Box $minHeight="100vh">
|
<Header />
|
||||||
<Header />
|
<Box $direction="row" $width="100%">
|
||||||
<Box $css="flex: 1;" $direction="row">
|
<LeftPanel />
|
||||||
<Box
|
<Box
|
||||||
as="main"
|
as="main"
|
||||||
$minHeight="100vh"
|
id={MAIN_LAYOUT_ID}
|
||||||
$width="100%"
|
$align="center"
|
||||||
$background={colorsTokens()['primary-bg']}
|
$flex={1}
|
||||||
>
|
$width="100%"
|
||||||
{children}
|
$height={`calc(100dvh - ${HEADER_HEIGHT}px)`}
|
||||||
</Box>
|
$padding={{
|
||||||
|
vertical: isDesktop ? 'base' : 'xs',
|
||||||
|
horizontal: isDesktop ? '6xl' : 'xs',
|
||||||
|
}}
|
||||||
|
$background={
|
||||||
|
backgroundColor === 'white'
|
||||||
|
? colors['greyscale-000']
|
||||||
|
: colors['greyscale-050']
|
||||||
|
}
|
||||||
|
$css={`
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: clip;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{!withoutFooter && <Footer />}
|
{!withoutFooter && <Footer />}
|
||||||
</Box>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/frontend/apps/impress/src/layouts/conf.ts
Normal file
1
src/frontend/apps/impress/src/layouts/conf.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const MAIN_LAYOUT_ID = `mainContent`;
|
||||||
@@ -33,6 +33,7 @@ export function DocLayout() {
|
|||||||
<Head>
|
<Head>
|
||||||
<meta name="robots" content="noindex" />
|
<meta name="robots" content="noindex" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<MainLayout withoutFooter>
|
<MainLayout withoutFooter>
|
||||||
<DocPage id={id} />
|
<DocPage id={id} />
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
|
|
||||||
import { DocsGridContainer } from '@/features/docs/docs-grid';
|
import { Box } from '@/components';
|
||||||
|
import { DocsGrid } from '@/features/docs/docs-grid/components/DocsGrid';
|
||||||
import { MainLayout } from '@/layouts';
|
import { MainLayout } from '@/layouts';
|
||||||
import { NextPageWithLayout } from '@/types/next';
|
import { NextPageWithLayout } from '@/types/next';
|
||||||
|
|
||||||
const Page: NextPageWithLayout = () => {
|
const Page: NextPageWithLayout = () => {
|
||||||
return <DocsGridContainer />;
|
return (
|
||||||
|
<Box $width="100%">
|
||||||
|
<DocsGrid />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Page.getLayout = function getLayout(page: ReactElement) {
|
Page.getLayout = function getLayout(page: ReactElement) {
|
||||||
return <MainLayout>{page}</MainLayout>;
|
return <MainLayout backgroundColor="grey">{page}</MainLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|||||||
@@ -4,41 +4,67 @@ export type ScreenSize = 'small-mobile' | 'mobile' | 'tablet' | 'desktop';
|
|||||||
|
|
||||||
export interface UseResponsiveStore {
|
export interface UseResponsiveStore {
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
|
isTablet: boolean;
|
||||||
isSmallMobile: boolean;
|
isSmallMobile: boolean;
|
||||||
screenSize: ScreenSize;
|
screenSize: ScreenSize;
|
||||||
screenWidth: number;
|
screenWidth: number;
|
||||||
setScreenSize: (size: ScreenSize) => void;
|
setScreenSize: (size: ScreenSize) => void;
|
||||||
|
isDesktop: boolean;
|
||||||
initializeResizeListener: () => () => void;
|
initializeResizeListener: () => () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
isSmallMobile: false,
|
isSmallMobile: false,
|
||||||
|
isTablet: false,
|
||||||
|
isDesktop: false,
|
||||||
screenSize: 'desktop' as ScreenSize,
|
screenSize: 'desktop' as ScreenSize,
|
||||||
screenWidth: 0,
|
screenWidth: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useResponsiveStore = create<UseResponsiveStore>((set) => ({
|
export const useResponsiveStore = create<UseResponsiveStore>((set) => ({
|
||||||
isMobile: initialState.isMobile,
|
isMobile: initialState.isMobile,
|
||||||
|
isTablet: initialState.isTablet,
|
||||||
isSmallMobile: initialState.isSmallMobile,
|
isSmallMobile: initialState.isSmallMobile,
|
||||||
screenSize: initialState.screenSize,
|
screenSize: initialState.screenSize,
|
||||||
screenWidth: initialState.screenWidth,
|
screenWidth: initialState.screenWidth,
|
||||||
setScreenSize: (size: ScreenSize) => set(() => ({ screenSize: size })),
|
setScreenSize: (size: ScreenSize) => set(() => ({ screenSize: size })),
|
||||||
|
isDesktop: initialState.isDesktop,
|
||||||
initializeResizeListener: () => {
|
initializeResizeListener: () => {
|
||||||
const resizeHandler = () => {
|
const resizeHandler = () => {
|
||||||
const width = window.innerWidth;
|
const width = window.innerWidth;
|
||||||
if (width < 560) {
|
if (width < 560) {
|
||||||
set({
|
set({
|
||||||
|
isDesktop: false,
|
||||||
screenSize: 'small-mobile',
|
screenSize: 'small-mobile',
|
||||||
isMobile: true,
|
isMobile: true,
|
||||||
|
isTablet: false,
|
||||||
isSmallMobile: true,
|
isSmallMobile: true,
|
||||||
});
|
});
|
||||||
} else if (width < 768) {
|
} else if (width < 768) {
|
||||||
set({ screenSize: 'mobile', isMobile: true, isSmallMobile: false });
|
set({
|
||||||
|
isDesktop: false,
|
||||||
|
screenSize: 'mobile',
|
||||||
|
isTablet: false,
|
||||||
|
isMobile: true,
|
||||||
|
isSmallMobile: false,
|
||||||
|
});
|
||||||
} else if (width >= 768 && width < 1024) {
|
} else if (width >= 768 && width < 1024) {
|
||||||
set({ screenSize: 'tablet', isMobile: false, isSmallMobile: false });
|
set({
|
||||||
|
isDesktop: false,
|
||||||
|
screenSize: 'tablet',
|
||||||
|
isTablet: true,
|
||||||
|
isMobile: false,
|
||||||
|
isSmallMobile: false,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
set({ screenSize: 'desktop', isMobile: false, isSmallMobile: false });
|
set({
|
||||||
|
isDesktop: true,
|
||||||
|
screenSize: 'desktop',
|
||||||
|
isTablet: false,
|
||||||
|
isMobile: false,
|
||||||
|
isSmallMobile: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
set({ screenWidth: width });
|
set({ screenWidth: width });
|
||||||
|
|||||||
Reference in New Issue
Block a user