diff --git a/package.json b/package.json
index 048fce7c0d..88b835a7ae 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
"@stoplight/elements": "^8.0.5",
"@swc/jest": "^0.2.29",
"@tabler/icons-react": "^2.44.0",
+ "@types/facepaint": "^1.2.5",
"@types/lodash.camelcase": "^4.3.7",
"@types/lodash.merge": "^4.6.7",
"@types/mailparser": "^3.4.4",
@@ -80,6 +81,7 @@
"dotenv-cli": "^7.2.1",
"drizzle-orm": "^0.29.3",
"esbuild-plugin-svgr": "^2.1.0",
+ "facepaint": "^1.2.1",
"file-type": "16.5.4",
"framer-motion": "^10.12.17",
"googleapis": "105",
diff --git a/packages/twenty-website/src/app/_components/client-utils/useDeviceType.ts b/packages/twenty-website/src/app/_components/client-utils/useDeviceType.ts
deleted file mode 100644
index d608211896..0000000000
--- a/packages/twenty-website/src/app/_components/client-utils/useDeviceType.ts
+++ /dev/null
@@ -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;
-};
diff --git a/packages/twenty-website/src/app/_components/ui/layout/Breadcrumbs.tsx b/packages/twenty-website/src/app/_components/ui/layout/Breadcrumbs.tsx
index 0b90803e48..830049c7a3 100644
--- a/packages/twenty-website/src/app/_components/ui/layout/Breadcrumbs.tsx
+++ b/packages/twenty-website/src/app/_components/ui/layout/Breadcrumbs.tsx
@@ -5,16 +5,15 @@ import styled from '@emotion/styled';
import { IconChevronLeft } from '@tabler/icons-react';
import Link from 'next/link';
-import {
- DeviceType,
- useDeviceType,
-} from '@/app/_components/client-utils/useDeviceType';
+import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme';
const Container = styled.div`
- display: flex;
- gap: ${Theme.spacing(2)};
- color: #b3b3b3;
+ ${mq({
+ display: ['none', 'flex', 'flex'],
+ gap: `${Theme.spacing(2)}`,
+ color: '#b3b3b3',
+ })};
`;
const InternalLinkItem = styled(Link)`
@@ -45,12 +44,14 @@ const StyledSection = styled.div`
`;
const StyledMobileContainer = styled.div`
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: ${Theme.spacing(1)};
- color: ${Theme.text.color.quarternary};
- font-size: ${Theme.font.size.sm};
+ ${mq({
+ display: ['flex', 'none', 'none'],
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: `${Theme.spacing(1)}`,
+ color: `${Theme.text.color.quarternary}`,
+ fontSize: `${Theme.font.size.sm}`,
+ })};
`;
interface BreadcrumbsProps {
@@ -68,31 +69,29 @@ export const Breadcrumbs = ({
activePage,
separator,
}: BreadcrumbsProps) => {
- const isMobile = useDeviceType() === DeviceType.MOBILE;
- if (isMobile) {
- const lastItem = items[items.length - 1];
- return (
+ const lastItem = items[items.length - 1];
+
+ return (
+
{lastItem.label}
- );
- }
- return (
-
- {items.map((item, index) => (
-
- {item.isExternal ? (
- {item.label}
- ) : (
- {item.label}
- )}
- {separator}
-
- ))}
- {activePage}
-
+
+ {items.map((item, index) => (
+
+ {item.isExternal ? (
+ {item.label}
+ ) : (
+ {item.label}
+ )}
+ {separator}
+
+ ))}
+ {activePage}
+
+
);
};
diff --git a/packages/twenty-website/src/app/_components/ui/theme/mq.ts b/packages/twenty-website/src/app/_components/ui/theme/mq.ts
new file mode 100644
index 0000000000..7aefe8ba84
--- /dev/null
+++ b/packages/twenty-website/src/app/_components/ui/theme/mq.ts
@@ -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;
diff --git a/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx b/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx
index c5c15d3605..bac56089fd 100644
--- a/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx
+++ b/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx
@@ -2,26 +2,20 @@
import React from 'react';
import styled from '@emotion/styled';
-import {
- DeviceType,
- useDeviceType,
-} from '@/app/_components/client-utils/useDeviceType';
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 { FileContent } from '@/app/_server-utils/get-posts';
-const StyledContainer = styled.div<{ devicetype: string }>`
- width: ${({ devicetype }) =>
- devicetype === DeviceType.TABLET
- ? '70%'
- : devicetype === DeviceType.DESKTOP
- ? '60%'
- : '100%'};
- display: flex;
- flex-direction: row;
- justify-content: center;
- font-family: ${Theme.font.family};
- border-bottom: 1px solid ${Theme.background.transparent.medium};
+const StyledContainer = styled('div')`
+ ${mq({
+ width: ['100%', '70%', '60%'],
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ borderBottom: `1px solid ${Theme.background.transparent.medium}`,
+ fontFamily: `${Theme.font.family}`,
+ })};
`;
const StyledWrapper = styled.div`
@@ -74,9 +68,8 @@ export default function UserGuideContent({ item }: { item: FileContent }) {
label: 'User Guide',
},
];
- const deviceType = useDeviceType();
return (
-
+
`
- width: ${({ isMobile }) => (isMobile ? '100%' : '60%')};
- display: flex;
- flex-direction: row;
- justify-content: center;
+const StyledContainer = styled.div`
+ ${mq({
+ width: ['100%', '60%', '60%'],
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ })};
`;
const StyledWrapper = styled.div`
@@ -46,27 +45,21 @@ const StyledSubHeading = styled.h1`
color: ${Theme.text.color.tertiary};
`;
-const StyledContentGrid = styled.div`
- width: 100%;
- padding-top: ${Theme.spacing(6)};
- display: grid;
- grid-template-rows: auto auto;
- grid-template-columns: 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)};
+const StyledContent = styled.div`
+ ${mq({
+ width: '100%',
+ paddingTop: `${Theme.spacing(6)}`,
+ display: ['flex', 'flex', 'grid'],
+ flexDirection: 'column',
+ gridTemplateRows: 'auto auto',
+ gridTemplateColumns: 'auto auto',
+ gap: `${Theme.spacing(6)}`,
+ })};
`;
export default function UserGuideMain() {
- const deviceType = useDeviceType();
return (
-
+
User Guide
@@ -74,19 +67,11 @@ export default function UserGuideMain() {
A brief guide to grasp the basics of Twenty
- {deviceType === DeviceType.DESKTOP ? (
-
- {UserGuideHomeCards.map((card) => {
- return ;
- })}
-
- ) : (
-
- {UserGuideHomeCards.map((card) => {
- return ;
- })}
-
- )}
+
+ {UserGuideHomeCards.map((card) => {
+ return ;
+ })}
+
);
diff --git a/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebar.tsx b/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebar.tsx
index ddbdaa6cce..23ab69513c 100644
--- a/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebar.tsx
+++ b/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebar.tsx
@@ -3,24 +3,23 @@
import styled from '@emotion/styled';
import { useRouter } from 'next/navigation';
-import {
- DeviceType,
- useDeviceType,
-} from '@/app/_components/client-utils/useDeviceType';
import { IconBook } from '@/app/_components/ui/icons';
+import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme';
import UserGuideSidebarSection from '@/app/_components/user-guide/UserGuideSidebarSection';
import { UserGuideIndex } from '@/content/user-guide/constants/UserGuideIndex';
-const StyledContainer = styled.div<{ isTablet: boolean }>`
- width: ${({ isTablet }) => (isTablet ? '30%' : '20%')};
- background: ${Theme.background.secondary};
- display: flex;
- flex-direction: column;
- border-right: 1px solid ${Theme.background.transparent.medium};
- border-bottom: 1px solid ${Theme.background.transparent.medium};
- padding: ${Theme.spacing(10)} ${Theme.spacing(3)};
- gap: ${Theme.spacing(6)};
+const StyledContainer = styled.div`
+ ${mq({
+ width: ['20%', '30%', '20%'],
+ display: ['none', 'flex', 'flex'],
+ flexDirection: 'column',
+ background: `${Theme.background.secondary}`,
+ borderRight: `1px solid ${Theme.background.transparent.medium}`,
+ borderBottom: `1px solid ${Theme.background.transparent.medium}`,
+ padding: `${Theme.spacing(10)} ${Theme.spacing(3)}`,
+ gap: `${Theme.spacing(6)}`,
+ })};
`;
const StyledHeading = styled.div`
@@ -55,9 +54,8 @@ const StyledHeadingText = styled.div`
const UserGuideSidebar = () => {
const router = useRouter();
- const isTablet = useDeviceType() === DeviceType.TABLET;
return (
-
+
diff --git a/packages/twenty-website/src/app/_components/user-guide/UserGuideTableContents.tsx b/packages/twenty-website/src/app/_components/user-guide/UserGuideTableContents.tsx
index a395285c4d..721ae4d11a 100644
--- a/packages/twenty-website/src/app/_components/user-guide/UserGuideTableContents.tsx
+++ b/packages/twenty-website/src/app/_components/user-guide/UserGuideTableContents.tsx
@@ -3,17 +3,23 @@
import styled from '@emotion/styled';
import { useRouter } from 'next/navigation';
+import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme';
const StyledContainer = styled.div`
- width: 20%;
- background: ${Theme.background.secondary};
- display: flex;
- flex-direction: column;
- border-left: 1px solid ${Theme.background.transparent.medium};
- border-bottom: 1px solid ${Theme.background.transparent.medium};
- padding: ${Theme.spacing(10)} ${Theme.spacing(6)};
- gap: ${Theme.spacing(6)};
+ ${mq({
+ width: '20%',
+ display: ['none', 'none', 'flex'],
+ flexDirection: 'column',
+ background: `${Theme.background.secondary}`,
+ borderLeft: `1px solid ${Theme.background.transparent.medium}`,
+ borderBottom: `1px solid ${Theme.background.transparent.medium}`,
+ padding: `${Theme.spacing(10)} ${Theme.spacing(6)}`,
+ gap: `${Theme.spacing(6)}`,
+ 'body nav': {
+ display: ['none', 'none', ''],
+ },
+ })};
`;
const StyledContent = styled.div`
diff --git a/packages/twenty-website/src/app/layout.css b/packages/twenty-website/src/app/layout.css
index 1e7c318abf..b8370346b9 100644
--- a/packages/twenty-website/src/app/layout.css
+++ b/packages/twenty-website/src/app/layout.css
@@ -30,6 +30,12 @@ a {
}
}
+@media (max-width: 1199px) {
+nav {
+ display: none;
+ }
+}
+
nav.toc {
width: 20%;
position: fixed;
diff --git a/packages/twenty-website/src/app/user-guide/layout.tsx b/packages/twenty-website/src/app/user-guide/layout.tsx
index c49fd5bb39..163e363851 100644
--- a/packages/twenty-website/src/app/user-guide/layout.tsx
+++ b/packages/twenty-website/src/app/user-guide/layout.tsx
@@ -3,14 +3,10 @@ import { ReactNode } from 'react';
import styled from '@emotion/styled';
import { usePathname } from 'next/navigation';
-import {
- DeviceType,
- useDeviceType,
-} from '@/app/_components/client-utils/useDeviceType';
+import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme';
import UserGuideSidebar from '@/app/_components/user-guide/UserGuideSidebar';
import UserGuideTableContents from '@/app/_components/user-guide/UserGuideTableContents';
-
const StyledContainer = styled.div`
width: 100%;
display: flex;
@@ -20,20 +16,19 @@ const StyledContainer = styled.div`
`;
const StyledEmptySideBar = styled.div`
- width: 20%;
+ ${mq({
+ width: '20%',
+ display: ['none', 'none', ''],
+ })};
`;
export default function UserGuideLayout({ children }: { children: ReactNode }) {
const pathname = usePathname();
- const deviceType = useDeviceType();
-
return (
- {deviceType !== DeviceType.MOBILE && }
+
{children}
- {deviceType !== DeviceType.DESKTOP ? (
- <>>
- ) : pathname === '/user-guide' ? (
+ {pathname === '/user-guide' ? (
) : (
diff --git a/yarn.lock b/yarn.lock
index 035c4f388a..c42f71fa49 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15247,6 +15247,13 @@ __metadata:
languageName: node
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:*":
version: 0.0.35
resolution: "@types/filesystem@npm:0.0.35"
@@ -25336,6 +25343,13 @@ __metadata:
languageName: node
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":
version: 1.0.1
resolution: "fast-decode-uri-component@npm:1.0.1"
@@ -44262,6 +44276,7 @@ __metadata:
"@types/bytes": "npm:^3.1.1"
"@types/deep-equal": "npm:^1.0.1"
"@types/express": "npm:^4.17.13"
+ "@types/facepaint": "npm:^1.2.5"
"@types/graphql-fields": "npm:^1.3.6"
"@types/graphql-upload": "npm:^8.0.12"
"@types/jest": "npm:^29.5.11"
@@ -44333,6 +44348,7 @@ __metadata:
eslint-plugin-simple-import-sort: "npm:^10.0.0"
eslint-plugin-storybook: "npm:^0.6.15"
eslint-plugin-unused-imports: "npm:^3.0.0"
+ facepaint: "npm:^1.2.1"
file-type: "npm:16.5.4"
framer-motion: "npm:^10.12.17"
googleapis: "npm:105"