New folder structure for website (#4159)

New folder structure
This commit is contained in:
Félix Malfait
2024-02-23 17:42:13 +01:00
committed by GitHub
parent 06c4665a44
commit 5de1c2c31d
65 changed files with 128 additions and 537 deletions

View File

@ -0,0 +1,48 @@
'use client';
import styled from '@emotion/styled';
import { useRouter } from 'next/navigation';
import { Theme } from '@/app/_components/ui/theme/theme';
import { UserGuideHomeCardsType } from '@/content/user-guide/constants/UserGuideHomeCards';
const StyledContainer = styled.div`
color: ${Theme.border.color.plain};
border: 2px solid ${Theme.border.color.plain};
border-radius: ${Theme.border.radius.md};
padding: ${Theme.spacing(6)};
gap: ${Theme.spacing(4)};
display: flex;
flex-direction: column;
cursor: pointer;
width: 348px;
`;
const StyledHeading = styled.div`
font-size: ${Theme.font.size.lg};
color: ${Theme.text.color.primary};
`;
const StyledSubHeading = styled.div`
font-size: ${Theme.font.size.sm};
color: ${Theme.text.color.secondary};
font-family: ${Theme.font.family};
`;
const StyledImage = styled.img`
width: 300px;
`;
export default function UserGuideCard({
card,
}: {
card: UserGuideHomeCardsType;
}) {
const router = useRouter();
return (
<StyledContainer onClick={() => router.push(`/user-guide/${card.url}`)}>
<StyledImage src={card.image} alt={card.title} />
<StyledHeading>{card.title}</StyledHeading>
<StyledSubHeading>{card.subtitle}</StyledSubHeading>
</StyledContainer>
);
}

View File

@ -0,0 +1,109 @@
'use client';
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 { 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 StyledWrapper = styled.div`
width: 79.3%;
padding: ${Theme.spacing(10)} 0px ${Theme.spacing(20)} 0px;
`;
const StyledHeader = styled.div`
display: flex;
flex-direction: column;
gap: ${Theme.spacing(8)};
`;
const StyledHeading = styled.div`
font-size: 40px;
font-weight: 700;
`;
const StyledHeaderInfoSection = styled.div`
display: flex;
flex-direction: column;
gap: ${Theme.spacing(4)};
`;
const StyledHeaderInfoSectionTitle = styled.div`
font-size: ${Theme.font.size.sm};
padding: ${Theme.spacing(2)} 0px;
color: ${Theme.text.color.secondary};
font-weight: ${Theme.font.weight.medium};
`;
const StyledHeaderInfoSectionSub = styled.div`
display: flex;
flex-direction: column;
gap: ${Theme.spacing(4)};
color: ${Theme.text.color.tertiary};
font-family: ${Theme.font.family};
`;
const StyledRectangle = styled.div`
width: 100%;
height: 1px;
background: ${Theme.background.transparent.medium};
`;
export default function UserGuideContent({ item }: { item: FileContent }) {
const BREADCRUMB_ITEMS = [
{
uri: '/user-guide',
label: 'User Guide',
},
];
const deviceType = useDeviceType();
return (
<StyledContainer devicetype={deviceType}>
<StyledWrapper>
<StyledHeader>
<Breadcrumbs
items={BREADCRUMB_ITEMS}
activePage={item.itemInfo.title}
separator="/"
/>
<StyledHeading>{item.itemInfo.title}</StyledHeading>
{item.itemInfo.image && (
<img
id={`img-${item.itemInfo.title}`}
src={item.itemInfo.image}
alt={item.itemInfo.title}
/>
)}
<StyledHeaderInfoSection>
<StyledHeaderInfoSectionTitle>
In this article
</StyledHeaderInfoSectionTitle>
<StyledHeaderInfoSectionSub>
{item.itemInfo.info}
</StyledHeaderInfoSectionSub>
</StyledHeaderInfoSection>
<StyledRectangle />
</StyledHeader>
<div>{item.content}</div>
</StyledWrapper>
</StyledContainer>
);
}

View File

@ -0,0 +1,93 @@
'use client';
import styled from '@emotion/styled';
import {
DeviceType,
useDeviceType,
} from '@/app/_components/client-utils/useDeviceType';
import { Theme } from '@/app/_components/ui/theme/theme';
import UserGuideCard from '@/app/_components/user-guide/UserGuideCard';
import { UserGuideHomeCards } from '@/content/user-guide/constants/UserGuideHomeCards';
const StyledContainer = styled.div<{ isMobile: boolean }>`
width: ${({ isMobile }) => (isMobile ? '100%' : '60%')};
display: flex;
flex-direction: row;
justify-content: center;
`;
const StyledWrapper = styled.div`
width: 79.3%;
padding: ${Theme.spacing(10)} 0px ${Theme.spacing(20)} 0px;
display: flex;
flex-direction: column;
gap: ${Theme.spacing(8)};
`;
const StyledHeader = styled.div`
display: flex;
flex-direction: column;
gap: 0px;
`;
const StyledHeading = styled.h1`
line-height: 38px;
font-weight: 700;
font-size: 38px;
color: ${Theme.text.color.primary};
margin: 0px;
`;
const StyledSubHeading = styled.h1`
line-height: 12px;
font-family: ${Theme.font.family};
font-size: ${Theme.font.size.sm};
font-weight: ${Theme.font.weight.regular};
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)};
`;
export default function UserGuideMain() {
const deviceType = useDeviceType();
return (
<StyledContainer isMobile={deviceType === DeviceType.MOBILE}>
<StyledWrapper>
<StyledHeader>
<StyledHeading>User Guide</StyledHeading>
<StyledSubHeading>
A brief guide to grasp the basics of Twenty
</StyledSubHeading>
</StyledHeader>
{deviceType === DeviceType.DESKTOP ? (
<StyledContentGrid>
{UserGuideHomeCards.map((card) => {
return <UserGuideCard key={card.title} card={card} />;
})}
</StyledContentGrid>
) : (
<StyledContentFlex>
{UserGuideHomeCards.map((card) => {
return <UserGuideCard key={card.title} card={card} />;
})}
</StyledContentFlex>
)}
</StyledWrapper>
</StyledContainer>
);
}

View File

@ -0,0 +1,80 @@
'use client';
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 { 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 StyledHeading = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: ${Theme.spacing(2)};
font-size: ${Theme.font.size.sm};
font-weight: ${Theme.font.weight.medium};
`;
const StyledIconContainer = styled.div`
width: 24px;
height: 24px;
display: flex;
flex-direction: row;
justify-content: center;
font-size: ${Theme.font.size.sm};
font-weight: ${Theme.font.weight.medium};
color: ${Theme.text.color.secondary};
border: 1px solid ${Theme.text.color.secondary};
border-radius: ${Theme.border.radius.sm};
padding: ${Theme.spacing(1)} ${Theme.spacing(1)} ${Theme.spacing(1)}
${Theme.spacing(1)};
`;
const StyledHeadingText = styled.div`
cursor: pointer;
font-size: ${Theme.font.size.sm};
font-weight: ${Theme.font.weight.medium};
`;
const UserGuideSidebar = () => {
const router = useRouter();
const isTablet = useDeviceType() === DeviceType.TABLET;
return (
<StyledContainer isTablet={isTablet}>
<StyledHeading>
<StyledIconContainer>
<IconBook size={Theme.icon.size.md} />
</StyledIconContainer>
<StyledHeadingText onClick={() => router.push('/user-guide')}>
User Guide
</StyledHeadingText>
</StyledHeading>
{Object.entries(UserGuideIndex).map(([heading, subtopics]) => (
<UserGuideSidebarSection
key={heading}
title={heading}
subTopics={subtopics}
/>
))}
</StyledContainer>
);
};
export default UserGuideSidebar;

View File

@ -0,0 +1,114 @@
'use client';
import { useState } from 'react';
import styled from '@emotion/styled';
import { useRouter } from 'next/navigation';
import { usePathname } from 'next/navigation';
import { IconChevronDown, IconChevronRight } from '@/app/_components/ui/icons';
import { Theme } from '@/app/_components/ui/theme/theme';
import { IndexSubtopic } from '@/content/user-guide/constants/UserGuideIndex';
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
`;
const StyledTitle = styled.div`
cursor: pointer;
display: flex;
flex-direction: row;
align-items: center;
gap: ${Theme.spacing(2)};
color: ${Theme.text.color.quarternary};
padding-bottom: ${Theme.spacing(2)};
font-family: ${Theme.font.family};
font-size: ${Theme.font.size.xs};
`;
const StyledSubTopicItem = styled.div<{ isselected: boolean }>`
cursor: pointer;
display: flex;
flex-direction: row;
align-items: center;
height: ${Theme.spacing(8)};
color: ${(props) =>
props.isselected ? Theme.text.color.primary : Theme.text.color.secondary};
font-weight: ${(props) =>
props.isselected ? Theme.font.weight.medium : Theme.font.weight.regular};
font-family: ${Theme.font.family};
font-size: ${Theme.font.size.xs};
gap: 19px;
padding: ${(props) =>
props.isselected ? '6px 12px 6px 11px' : '0px 12px 0px 11px'};
background: ${(props) =>
props.isselected
? Theme.background.transparent.light
: Theme.background.secondary};
border-radius: ${Theme.border.radius.md};
text-decoration: none;
&:focus,
&:hover,
&:visited,
&:link,
&:active {
text-decoration: none;
}
`;
const StyledIcon = styled.div`
padding: 0px 4px 0px 4px;
`;
const StyledRectangle = styled.div<{ isselected: boolean }>`
height: 100%;
width: 2px;
background: ${(props) =>
props.isselected
? Theme.border.color.plain
: Theme.background.transparent.light};
`;
const UserGuideSidebarSection = ({
title,
subTopics,
}: {
title: string;
subTopics: IndexSubtopic[];
}) => {
const [isUnfolded, setUnfoldedState] = useState(true);
const pathname = usePathname();
const router = useRouter();
return (
<StyledContainer>
<StyledTitle onClick={() => setUnfoldedState(!isUnfolded)}>
{isUnfolded ? (
<StyledIcon>
<IconChevronDown size={Theme.icon.size.md} />
</StyledIcon>
) : (
<StyledIcon>
<IconChevronRight size={Theme.icon.size.md} />
</StyledIcon>
)}
<div>{title}</div>
</StyledTitle>
{isUnfolded &&
subTopics.map((subtopic, index) => {
const isselected = pathname === `/user-guide/${subtopic.url}`;
return (
<StyledSubTopicItem
key={index}
isselected={isselected}
onClick={() => router.push(`/user-guide/${subtopic.url}`)}
>
<StyledRectangle isselected={isselected} />
{subtopic.title}
</StyledSubTopicItem>
);
})}
</StyledContainer>
);
};
export default UserGuideSidebarSection;

View File

@ -0,0 +1,41 @@
'use client';
import styled from '@emotion/styled';
import { useRouter } from 'next/navigation';
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)};
`;
const StyledContent = styled.div`
position: fixed;
`;
const StyledHeadingText = styled.div`
font-size: ${Theme.font.size.sm};
color: ${Theme.text.color.quarternary};
`;
const UserGuideTableContents = () => {
const router = useRouter();
return (
<StyledContainer>
<StyledContent>
<StyledHeadingText onClick={() => router.push('/user-guide')}>
Table of Contents
</StyledHeadingText>
</StyledContent>
</StyledContainer>
);
};
export default UserGuideTableContents;

View File

@ -0,0 +1,21 @@
interface Heading {
id: string;
value: string;
}
const UserGuideTocComponent = ({ headings }: { headings: Heading[] }) => {
return (
<div>
<h2>Table of Contents</h2>
<ul>
{headings.map((heading, index) => (
<li key={index}>
<a href={`#${heading.id}`}>{heading.value}</a>
</li>
))}
</ul>
</div>
);
};
export default UserGuideTocComponent;