MQ Facepaint introduced (#4169)

* MQ Facepaint introduced

* Remove useDeviceType

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
Kanav Arora 2024-02-25 02:08:27 +05:30 committed by GitHub
parent 1b04dfe3c6
commit a9b0f88521
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 132 additions and 147 deletions

View File

@ -53,6 +53,7 @@
"@stoplight/elements": "^8.0.5", "@stoplight/elements": "^8.0.5",
"@swc/jest": "^0.2.29", "@swc/jest": "^0.2.29",
"@tabler/icons-react": "^2.44.0", "@tabler/icons-react": "^2.44.0",
"@types/facepaint": "^1.2.5",
"@types/lodash.camelcase": "^4.3.7", "@types/lodash.camelcase": "^4.3.7",
"@types/lodash.merge": "^4.6.7", "@types/lodash.merge": "^4.6.7",
"@types/mailparser": "^3.4.4", "@types/mailparser": "^3.4.4",
@ -80,6 +81,7 @@
"dotenv-cli": "^7.2.1", "dotenv-cli": "^7.2.1",
"drizzle-orm": "^0.29.3", "drizzle-orm": "^0.29.3",
"esbuild-plugin-svgr": "^2.1.0", "esbuild-plugin-svgr": "^2.1.0",
"facepaint": "^1.2.1",
"file-type": "16.5.4", "file-type": "16.5.4",
"framer-motion": "^10.12.17", "framer-motion": "^10.12.17",
"googleapis": "105", "googleapis": "105",

View File

@ -1,22 +0,0 @@
import { useMediaQuery } from 'react-responsive';
export enum DeviceType {
DESKTOP = 'DESKTOP',
TABLET = 'TABLET',
MOBILE = 'MOBILE',
}
export const useDeviceType = () => {
const isTablet = useMediaQuery({
query: '(max-width: 1199px) and (min-width: 810px)',
});
const isMobile = useMediaQuery({ query: '(max-width: 809px)' });
if (isMobile) {
return DeviceType.MOBILE;
}
if (isTablet) {
return DeviceType.TABLET;
}
return DeviceType.DESKTOP;
};

View File

@ -5,16 +5,15 @@ import styled from '@emotion/styled';
import { IconChevronLeft } from '@tabler/icons-react'; import { IconChevronLeft } from '@tabler/icons-react';
import Link from 'next/link'; import Link from 'next/link';
import { import mq from '@/app/_components/ui/theme/mq';
DeviceType,
useDeviceType,
} from '@/app/_components/client-utils/useDeviceType';
import { Theme } from '@/app/_components/ui/theme/theme'; import { Theme } from '@/app/_components/ui/theme/theme';
const Container = styled.div` const Container = styled.div`
display: flex; ${mq({
gap: ${Theme.spacing(2)}; display: ['none', 'flex', 'flex'],
color: #b3b3b3; gap: `${Theme.spacing(2)}`,
color: '#b3b3b3',
})};
`; `;
const InternalLinkItem = styled(Link)` const InternalLinkItem = styled(Link)`
@ -45,12 +44,14 @@ const StyledSection = styled.div`
`; `;
const StyledMobileContainer = styled.div` const StyledMobileContainer = styled.div`
display: flex; ${mq({
flex-direction: row; display: ['flex', 'none', 'none'],
align-items: center; flexDirection: 'row',
gap: ${Theme.spacing(1)}; alignItems: 'center',
color: ${Theme.text.color.quarternary}; gap: `${Theme.spacing(1)}`,
font-size: ${Theme.font.size.sm}; color: `${Theme.text.color.quarternary}`,
fontSize: `${Theme.font.size.sm}`,
})};
`; `;
interface BreadcrumbsProps { interface BreadcrumbsProps {
@ -68,31 +69,29 @@ export const Breadcrumbs = ({
activePage, activePage,
separator, separator,
}: BreadcrumbsProps) => { }: BreadcrumbsProps) => {
const isMobile = useDeviceType() === DeviceType.MOBILE; const lastItem = items[items.length - 1];
if (isMobile) {
const lastItem = items[items.length - 1]; return (
return ( <div>
<StyledMobileContainer> <StyledMobileContainer>
<IconChevronLeft size={Theme.icon.size.md} /> <IconChevronLeft size={Theme.icon.size.md} />
<InternalLinkItem href={lastItem.uri}> <InternalLinkItem href={lastItem.uri}>
{lastItem.label} {lastItem.label}
</InternalLinkItem> </InternalLinkItem>
</StyledMobileContainer> </StyledMobileContainer>
); <Container>
} {items.map((item, index) => (
return ( <StyledSection key={`${item?.uri ?? 'item'}-${index}`}>
<Container> {item.isExternal ? (
{items.map((item, index) => ( <ExternalLinkItem href={item.uri}>{item.label}</ExternalLinkItem>
<StyledSection key={`${item?.uri ?? 'item'}-${index}`}> ) : (
{item.isExternal ? ( <InternalLinkItem href={item.uri}>{item.label}</InternalLinkItem>
<ExternalLinkItem href={item.uri}>{item.label}</ExternalLinkItem> )}
) : ( <div>{separator}</div>
<InternalLinkItem href={item.uri}>{item.label}</InternalLinkItem> </StyledSection>
)} ))}
<div>{separator}</div> <ActivePage>{activePage}</ActivePage>
</StyledSection> </Container>
))} </div>
<ActivePage>{activePage}</ActivePage>
</Container>
); );
}; };

View File

@ -0,0 +1,7 @@
import facepaint from 'facepaint';
const breakpoints = [810, 1200];
const mq = facepaint(breakpoints.map((bp) => `@media (min-width: ${bp}px)`));
export default mq;

View File

@ -2,26 +2,20 @@
import React from 'react'; import React from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import {
DeviceType,
useDeviceType,
} from '@/app/_components/client-utils/useDeviceType';
import { Breadcrumbs } from '@/app/_components/ui/layout/Breadcrumbs'; import { Breadcrumbs } from '@/app/_components/ui/layout/Breadcrumbs';
import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme'; import { Theme } from '@/app/_components/ui/theme/theme';
import { FileContent } from '@/app/_server-utils/get-posts'; import { FileContent } from '@/app/_server-utils/get-posts';
const StyledContainer = styled.div<{ devicetype: string }>` const StyledContainer = styled('div')`
width: ${({ devicetype }) => ${mq({
devicetype === DeviceType.TABLET width: ['100%', '70%', '60%'],
? '70%' display: 'flex',
: devicetype === DeviceType.DESKTOP flexDirection: 'row',
? '60%' justifyContent: 'center',
: '100%'}; borderBottom: `1px solid ${Theme.background.transparent.medium}`,
display: flex; fontFamily: `${Theme.font.family}`,
flex-direction: row; })};
justify-content: center;
font-family: ${Theme.font.family};
border-bottom: 1px solid ${Theme.background.transparent.medium};
`; `;
const StyledWrapper = styled.div` const StyledWrapper = styled.div`
@ -74,9 +68,8 @@ export default function UserGuideContent({ item }: { item: FileContent }) {
label: 'User Guide', label: 'User Guide',
}, },
]; ];
const deviceType = useDeviceType();
return ( return (
<StyledContainer devicetype={deviceType}> <StyledContainer>
<StyledWrapper> <StyledWrapper>
<StyledHeader> <StyledHeader>
<Breadcrumbs <Breadcrumbs

View File

@ -1,19 +1,18 @@
'use client'; 'use client';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { import mq from '@/app/_components/ui/theme/mq';
DeviceType,
useDeviceType,
} from '@/app/_components/client-utils/useDeviceType';
import { Theme } from '@/app/_components/ui/theme/theme'; import { Theme } from '@/app/_components/ui/theme/theme';
import UserGuideCard from '@/app/_components/user-guide/UserGuideCard'; import UserGuideCard from '@/app/_components/user-guide/UserGuideCard';
import { UserGuideHomeCards } from '@/content/user-guide/constants/UserGuideHomeCards'; import { UserGuideHomeCards } from '@/content/user-guide/constants/UserGuideHomeCards';
const StyledContainer = styled.div<{ isMobile: boolean }>` const StyledContainer = styled.div`
width: ${({ isMobile }) => (isMobile ? '100%' : '60%')}; ${mq({
display: flex; width: ['100%', '60%', '60%'],
flex-direction: row; display: 'flex',
justify-content: center; flexDirection: 'row',
justifyContent: 'center',
})};
`; `;
const StyledWrapper = styled.div` const StyledWrapper = styled.div`
@ -46,27 +45,21 @@ const StyledSubHeading = styled.h1`
color: ${Theme.text.color.tertiary}; color: ${Theme.text.color.tertiary};
`; `;
const StyledContentGrid = styled.div` const StyledContent = styled.div`
width: 100%; ${mq({
padding-top: ${Theme.spacing(6)}; width: '100%',
display: grid; paddingTop: `${Theme.spacing(6)}`,
grid-template-rows: auto auto; display: ['flex', 'flex', 'grid'],
grid-template-columns: auto auto; flexDirection: 'column',
gap: ${Theme.spacing(6)}; gridTemplateRows: 'auto auto',
`; gridTemplateColumns: 'auto auto',
gap: `${Theme.spacing(6)}`,
const StyledContentFlex = styled.div` })};
width: 100%;
padding-top: ${Theme.spacing(6)};
display: flex;
flex-direction: column;
gap: ${Theme.spacing(6)};
`; `;
export default function UserGuideMain() { export default function UserGuideMain() {
const deviceType = useDeviceType();
return ( return (
<StyledContainer isMobile={deviceType === DeviceType.MOBILE}> <StyledContainer>
<StyledWrapper> <StyledWrapper>
<StyledHeader> <StyledHeader>
<StyledHeading>User Guide</StyledHeading> <StyledHeading>User Guide</StyledHeading>
@ -74,19 +67,11 @@ export default function UserGuideMain() {
A brief guide to grasp the basics of Twenty A brief guide to grasp the basics of Twenty
</StyledSubHeading> </StyledSubHeading>
</StyledHeader> </StyledHeader>
{deviceType === DeviceType.DESKTOP ? ( <StyledContent>
<StyledContentGrid> {UserGuideHomeCards.map((card) => {
{UserGuideHomeCards.map((card) => { return <UserGuideCard key={card.title} card={card} />;
return <UserGuideCard key={card.title} card={card} />; })}
})} </StyledContent>
</StyledContentGrid>
) : (
<StyledContentFlex>
{UserGuideHomeCards.map((card) => {
return <UserGuideCard key={card.title} card={card} />;
})}
</StyledContentFlex>
)}
</StyledWrapper> </StyledWrapper>
</StyledContainer> </StyledContainer>
); );

View File

@ -3,24 +3,23 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import {
DeviceType,
useDeviceType,
} from '@/app/_components/client-utils/useDeviceType';
import { IconBook } from '@/app/_components/ui/icons'; import { IconBook } from '@/app/_components/ui/icons';
import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme'; import { Theme } from '@/app/_components/ui/theme/theme';
import UserGuideSidebarSection from '@/app/_components/user-guide/UserGuideSidebarSection'; import UserGuideSidebarSection from '@/app/_components/user-guide/UserGuideSidebarSection';
import { UserGuideIndex } from '@/content/user-guide/constants/UserGuideIndex'; import { UserGuideIndex } from '@/content/user-guide/constants/UserGuideIndex';
const StyledContainer = styled.div<{ isTablet: boolean }>` const StyledContainer = styled.div`
width: ${({ isTablet }) => (isTablet ? '30%' : '20%')}; ${mq({
background: ${Theme.background.secondary}; width: ['20%', '30%', '20%'],
display: flex; display: ['none', 'flex', 'flex'],
flex-direction: column; flexDirection: 'column',
border-right: 1px solid ${Theme.background.transparent.medium}; background: `${Theme.background.secondary}`,
border-bottom: 1px solid ${Theme.background.transparent.medium}; borderRight: `1px solid ${Theme.background.transparent.medium}`,
padding: ${Theme.spacing(10)} ${Theme.spacing(3)}; borderBottom: `1px solid ${Theme.background.transparent.medium}`,
gap: ${Theme.spacing(6)}; padding: `${Theme.spacing(10)} ${Theme.spacing(3)}`,
gap: `${Theme.spacing(6)}`,
})};
`; `;
const StyledHeading = styled.div` const StyledHeading = styled.div`
@ -55,9 +54,8 @@ const StyledHeadingText = styled.div`
const UserGuideSidebar = () => { const UserGuideSidebar = () => {
const router = useRouter(); const router = useRouter();
const isTablet = useDeviceType() === DeviceType.TABLET;
return ( return (
<StyledContainer isTablet={isTablet}> <StyledContainer>
<StyledHeading> <StyledHeading>
<StyledIconContainer> <StyledIconContainer>
<IconBook size={Theme.icon.size.md} /> <IconBook size={Theme.icon.size.md} />

View File

@ -3,17 +3,23 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme'; import { Theme } from '@/app/_components/ui/theme/theme';
const StyledContainer = styled.div` const StyledContainer = styled.div`
width: 20%; ${mq({
background: ${Theme.background.secondary}; width: '20%',
display: flex; display: ['none', 'none', 'flex'],
flex-direction: column; flexDirection: 'column',
border-left: 1px solid ${Theme.background.transparent.medium}; background: `${Theme.background.secondary}`,
border-bottom: 1px solid ${Theme.background.transparent.medium}; borderLeft: `1px solid ${Theme.background.transparent.medium}`,
padding: ${Theme.spacing(10)} ${Theme.spacing(6)}; borderBottom: `1px solid ${Theme.background.transparent.medium}`,
gap: ${Theme.spacing(6)}; padding: `${Theme.spacing(10)} ${Theme.spacing(6)}`,
gap: `${Theme.spacing(6)}`,
'body nav': {
display: ['none', 'none', ''],
},
})};
`; `;
const StyledContent = styled.div` const StyledContent = styled.div`

View File

@ -30,6 +30,12 @@ a {
} }
} }
@media (max-width: 1199px) {
nav {
display: none;
}
}
nav.toc { nav.toc {
width: 20%; width: 20%;
position: fixed; position: fixed;

View File

@ -3,14 +3,10 @@ import { ReactNode } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { import mq from '@/app/_components/ui/theme/mq';
DeviceType,
useDeviceType,
} from '@/app/_components/client-utils/useDeviceType';
import { Theme } from '@/app/_components/ui/theme/theme'; import { Theme } from '@/app/_components/ui/theme/theme';
import UserGuideSidebar from '@/app/_components/user-guide/UserGuideSidebar'; import UserGuideSidebar from '@/app/_components/user-guide/UserGuideSidebar';
import UserGuideTableContents from '@/app/_components/user-guide/UserGuideTableContents'; import UserGuideTableContents from '@/app/_components/user-guide/UserGuideTableContents';
const StyledContainer = styled.div` const StyledContainer = styled.div`
width: 100%; width: 100%;
display: flex; display: flex;
@ -20,20 +16,19 @@ const StyledContainer = styled.div`
`; `;
const StyledEmptySideBar = styled.div` const StyledEmptySideBar = styled.div`
width: 20%; ${mq({
width: '20%',
display: ['none', 'none', ''],
})};
`; `;
export default function UserGuideLayout({ children }: { children: ReactNode }) { export default function UserGuideLayout({ children }: { children: ReactNode }) {
const pathname = usePathname(); const pathname = usePathname();
const deviceType = useDeviceType();
return ( return (
<StyledContainer> <StyledContainer>
{deviceType !== DeviceType.MOBILE && <UserGuideSidebar />} <UserGuideSidebar />
{children} {children}
{deviceType !== DeviceType.DESKTOP ? ( {pathname === '/user-guide' ? (
<></>
) : pathname === '/user-guide' ? (
<StyledEmptySideBar /> <StyledEmptySideBar />
) : ( ) : (
<UserGuideTableContents /> <UserGuideTableContents />

View File

@ -15247,6 +15247,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/facepaint@npm:^1.2.5":
version: 1.2.5
resolution: "@types/facepaint@npm:1.2.5"
checksum: e759fef0858f2f691625c47d59124e35d745c33d7229b99607158361ac0346f012ffad5c24a7312b49d54c097862ca7fe66a3ca37dbf8074154edb093b9fa0fc
languageName: node
linkType: hard
"@types/filesystem@npm:*": "@types/filesystem@npm:*":
version: 0.0.35 version: 0.0.35
resolution: "@types/filesystem@npm:0.0.35" resolution: "@types/filesystem@npm:0.0.35"
@ -25336,6 +25343,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"facepaint@npm:^1.2.1":
version: 1.2.1
resolution: "facepaint@npm:1.2.1"
checksum: bc4e974f4db7e860afb86cfeaf25720f4058e100a0cc79d42e69b0518363a538643de18753f6ed0161cc9d7280ff49d9f07351dc1d614b5dc79a28837dd6cd50
languageName: node
linkType: hard
"fast-decode-uri-component@npm:^1.0.1": "fast-decode-uri-component@npm:^1.0.1":
version: 1.0.1 version: 1.0.1
resolution: "fast-decode-uri-component@npm:1.0.1" resolution: "fast-decode-uri-component@npm:1.0.1"
@ -44262,6 +44276,7 @@ __metadata:
"@types/bytes": "npm:^3.1.1" "@types/bytes": "npm:^3.1.1"
"@types/deep-equal": "npm:^1.0.1" "@types/deep-equal": "npm:^1.0.1"
"@types/express": "npm:^4.17.13" "@types/express": "npm:^4.17.13"
"@types/facepaint": "npm:^1.2.5"
"@types/graphql-fields": "npm:^1.3.6" "@types/graphql-fields": "npm:^1.3.6"
"@types/graphql-upload": "npm:^8.0.12" "@types/graphql-upload": "npm:^8.0.12"
"@types/jest": "npm:^29.5.11" "@types/jest": "npm:^29.5.11"
@ -44333,6 +44348,7 @@ __metadata:
eslint-plugin-simple-import-sort: "npm:^10.0.0" eslint-plugin-simple-import-sort: "npm:^10.0.0"
eslint-plugin-storybook: "npm:^0.6.15" eslint-plugin-storybook: "npm:^0.6.15"
eslint-plugin-unused-imports: "npm:^3.0.0" eslint-plugin-unused-imports: "npm:^3.0.0"
facepaint: "npm:^1.2.1"
file-type: "npm:16.5.4" file-type: "npm:16.5.4"
framer-motion: "npm:^10.12.17" framer-motion: "npm:^10.12.17"
googleapis: "npm:105" googleapis: "npm:105"