Files
twenty/packages/twenty-website/src/app/_components/docs/DocsSideBar.tsx
Baptiste Devessier 2c465bd42e Integrate Keystatic to edit twenty.com content (#10709)
This PR introduces Keystatic to let us edit twenty.com's content with a
CMS. For now, we'll focus on creating release notes through Keystatic as
it uses quite simple Markdown. Other types of content will need some
refactoring to work with Keystatic.


https://github.com/user-attachments/assets/e9f85bbf-daff-4b41-bc97-d1baf63758b2

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-03-07 07:59:06 +01:00

119 lines
3.4 KiB
TypeScript

'use client';
import styled from '@emotion/styled';
import { usePathname, useRouter } from 'next/navigation';
import { AlgoliaDocSearch } from '@/app/_components/docs/AlgoliaDocSearch';
import DocsSidebarSection from '@/app/_components/docs/DocsSidebarSection';
import mq from '@/app/_components/ui/theme/mq';
import { Theme } from '@/app/_components/ui/theme/theme';
import { DocsArticlesProps } from '@/content/user-guide/constants/getDocsArticles';
import { getSectionIcon } from '@/shared-utils/getSectionIcons';
import '@docsearch/css';
import '../../(public)/user-guide/algolia.css';
const StyledContainer = styled.div`
${mq({
display: ['none', 'flex', 'flex'],
flexDirection: 'column',
background: `${Theme.background.secondary}`,
borderRight: `1px solid ${Theme.background.transparent.medium}`,
padding: `${Theme.spacing(10)} ${Theme.spacing(4)}`,
gap: `${Theme.spacing(6)}`,
})}
width: 300px;
min-width: 300px;
overflow: scroll;
overflow-x: hidden;
height: calc(100vh - 60px);
position: sticky;
top: 64px;
`;
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};
margin-bottom: 8px;
`;
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)};
`;
const StyledHeadingText = styled.h1`
cursor: pointer;
font-size: ${Theme.font.size.sm};
font-weight: ${Theme.font.weight.medium};
color: ${Theme.text.color.secondary};
`;
const DocsSidebar = ({ docsIndex }: { docsIndex: DocsArticlesProps[] }) => {
const router = useRouter();
const pathName = usePathname();
const path = pathName.includes('user-guide')
? '/user-guide'
: pathName.includes('developers')
? '/developers'
: '/twenty-ui';
const sections = Array.from(
new Set(docsIndex.map((guide) => guide.section)),
).map((section) => ({
name: section,
icon: getSectionIcon(section),
guides: docsIndex.filter((guide) => {
const isInSection = guide.section === section;
const hasFiles = guide.numberOfFiles > 0;
const isNotSingleFileTopic = !(
guide.numberOfFiles > 1 && guide.topic === guide.title
);
return isInSection && hasFiles && isNotSingleFileTopic;
}),
}));
return (
<StyledContainer>
<AlgoliaDocSearch pathname={pathName} />
{sections.map((section) => (
<div key={section.name}>
<StyledHeading>
<StyledIconContainer>{section.icon}</StyledIconContainer>
<StyledHeadingText
onClick={() =>
router.push(
section.name === 'User Guide'
? '/user-guide'
: section.name === 'Developers'
? '/developers'
: path,
)
}
>
{section.name}
</StyledHeadingText>
</StyledHeading>
<DocsSidebarSection docsIndex={section.guides} />
</div>
))}
</StyledContainer>
);
};
export default DocsSidebar;