Migrated Developer Docs (#5683)
- Migrated developer docs to Twenty website - Modified User Guide and Docs layout to include sections and subsections **Section Example:** <img width="549" alt="Screenshot 2024-05-30 at 15 44 42" src="https://github.com/twentyhq/twenty/assets/102751374/41bd4037-4b76-48e6-bc79-48d3d6be9ab8"> **Subsection Example:** <img width="557" alt="Screenshot 2024-05-30 at 15 44 55" src="https://github.com/twentyhq/twenty/assets/102751374/f14c65a9-ab0c-4530-b624-5b20fc00511a"> - Created different components (Tabs, Tables, Editors etc.) for the mdx files **Tabs & Editor** <img width="665" alt="Screenshot 2024-05-30 at 15 47 39" src="https://github.com/twentyhq/twenty/assets/102751374/5166b5c7-b6cf-417d-9f29-b1f674c1c531"> **Tables** <img width="698" alt="Screenshot 2024-05-30 at 15 57 39" src="https://github.com/twentyhq/twenty/assets/102751374/2bbfe937-ec19-4004-ab00-f7a56e96db4a"> <img width="661" alt="Screenshot 2024-05-30 at 16 03 32" src="https://github.com/twentyhq/twenty/assets/102751374/ae95b47c-dd92-44f9-b535-ccdc953f71ff"> - Created a crawler for Twenty Developers (now that it will be on the twenty website). Once this PR is merged and the website is re-deployed, we need to start crawling and make sure the index name is ‘twenty-developer’ - Added a dropdown menu in the header to access User Guide and Developers + added Developers to footer https://github.com/twentyhq/twenty/assets/102751374/1bd1fbbd-1e65-4461-b18b-84d4ddbb8ea1 - Made new layout responsive Please fill in the information for each mdx file so that it can appear on its card, as well as in the ‘In this article’ section. Example with ‘Getting Started’ in the User Guide: <img width="786" alt="Screenshot 2024-05-30 at 16 29 39" src="https://github.com/twentyhq/twenty/assets/102751374/2714b01d-a664-4ddc-9291-528632ee12ea"> Example with info and sectionInfo filled in for 'Getting Started': <img width="620" alt="Screenshot 2024-05-30 at 16 33 57" src="https://github.com/twentyhq/twenty/assets/102751374/bc69e880-da6a-4b7e-bace-1effea866c11"> Please keep in mind that the images that are being used for Developers are the same as those found in User Guide and may not match the article. --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
31
packages/twenty-website/src/app/developers/[slug]/page.tsx
Normal file
31
packages/twenty-website/src/app/developers/[slug]/page.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
import DocsContent from '@/app/_components/docs/DocsContent';
|
||||
import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug';
|
||||
import { formatSlug } from '@/shared-utils/formatSlug';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
}): Promise<Metadata> {
|
||||
const formattedSlug = formatSlug(params.slug);
|
||||
const basePath = '/src/content/developers';
|
||||
const mainPost = await fetchArticleFromSlug(params.slug, basePath);
|
||||
return {
|
||||
title: 'Twenty - ' + formattedSlug,
|
||||
description: mainPost?.itemInfo?.info,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function DocsSlug({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
}) {
|
||||
const basePath = '/src/content/developers';
|
||||
const mainPost = await fetchArticleFromSlug(params.slug, basePath);
|
||||
return mainPost && <DocsContent item={mainPost} />;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import GraphQlPlayground from '../../../_components/playground/graphql-playground';
|
||||
|
||||
const CoreGraphql = () => {
|
||||
return <GraphQlPlayground subDoc={'core'} />;
|
||||
};
|
||||
|
||||
export default CoreGraphql;
|
||||
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import GraphQlPlayground from '../../../_components/playground/graphql-playground';
|
||||
|
||||
const CoreGraphql = () => {
|
||||
return <GraphQlPlayground subDoc={'metadata'} />;
|
||||
};
|
||||
|
||||
export default CoreGraphql;
|
||||
11
packages/twenty-website/src/app/developers/layout.tsx
Normal file
11
packages/twenty-website/src/app/developers/layout.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { DocsMainLayout } from '@/app/_components/docs/DocsMainLayout';
|
||||
import { getDocsArticles } from '@/content/user-guide/constants/getDocsArticles';
|
||||
|
||||
export default function DocsLayout({ children }: { children: ReactNode }) {
|
||||
const filePath = 'src/content/developers/';
|
||||
const getAllArticles = true;
|
||||
const docsIndex = getDocsArticles(filePath, getAllArticles);
|
||||
return <DocsMainLayout docsIndex={docsIndex}>{children}</DocsMainLayout>;
|
||||
}
|
||||
17
packages/twenty-website/src/app/developers/page.tsx
Normal file
17
packages/twenty-website/src/app/developers/page.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import DocsMain from '@/app/_components/docs/DocsMain';
|
||||
import { getDocsArticles } from '@/content/user-guide/constants/getDocsArticles';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Twenty - Docs',
|
||||
description: 'Twenty is a CRM designed to fit your unique business needs.',
|
||||
icons: '/images/core/logo.svg',
|
||||
};
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export default async function DocsHome() {
|
||||
const filePath = 'src/content/developers/';
|
||||
const docsArticleCards = getDocsArticles(filePath);
|
||||
|
||||
return <DocsMain docsArticleCards={docsArticleCards} />;
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
'use client';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
// @ts-expect-error Migration loader as text not passing warnings
|
||||
import { API } from '@stoplight/elements';
|
||||
|
||||
import Playground from '@/app/_components/playground/playground';
|
||||
|
||||
// @ts-expect-error Migration loader as text not passing warnings
|
||||
import spotlightTheme from '!css-loader!@stoplight/elements/styles.min.css';
|
||||
|
||||
const RestApiComponent = ({ openApiJson }: { openApiJson: any }) => {
|
||||
// We load spotlightTheme style using useEffect as it breaks remaining docs style
|
||||
useEffect(() => {
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.innerHTML = spotlightTheme.toString();
|
||||
document.head.append(styleElement);
|
||||
|
||||
return () => styleElement.remove();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: 'calc(100vh - var(--ifm-navbar-height) - 45px)',
|
||||
width: '100%',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<API apiDescriptionDocument={JSON.stringify(openApiJson)} router="hash" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const restApi = () => {
|
||||
const [openApiJson, setOpenApiJson] = useState({});
|
||||
|
||||
const children = <RestApiComponent openApiJson={openApiJson} />;
|
||||
|
||||
return (
|
||||
<div style={{ width: '100vw' }}>
|
||||
<Playground
|
||||
children={children}
|
||||
setOpenApiJson={setOpenApiJson}
|
||||
subDoc="core"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default restApi;
|
||||
@ -0,0 +1,47 @@
|
||||
'use client';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
// @ts-expect-error Migration loader as text not passing warnings
|
||||
import { API } from '@stoplight/elements';
|
||||
|
||||
import Playground from '@/app/_components/playground/playground';
|
||||
|
||||
// @ts-expect-error Migration loader as text not passing warnings
|
||||
import spotlightTheme from '!css-loader!@stoplight/elements/styles.min.css';
|
||||
|
||||
const RestApiComponent = ({ openApiJson }: { openApiJson: any }) => {
|
||||
// We load spotlightTheme style using useEffect as it breaks remaining docs style
|
||||
useEffect(() => {
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.innerHTML = spotlightTheme.toString();
|
||||
document.head.append(styleElement);
|
||||
|
||||
return () => styleElement.remove();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: 'calc(100vh - var(--ifm-navbar-height) - 45px)',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<API apiDescriptionDocument={JSON.stringify(openApiJson)} router="hash" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const restApi = () => {
|
||||
const [openApiJson, setOpenApiJson] = useState({});
|
||||
|
||||
const children = <RestApiComponent openApiJson={openApiJson} />;
|
||||
|
||||
return (
|
||||
<Playground
|
||||
children={children}
|
||||
setOpenApiJson={setOpenApiJson}
|
||||
subDoc="metadata"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default restApi;
|
||||
@ -0,0 +1,31 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
import DocsContent from '@/app/_components/docs/DocsContent';
|
||||
import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug';
|
||||
import { formatSlug } from '@/shared-utils/formatSlug';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { folder: string; documentation: string };
|
||||
}): Promise<Metadata> {
|
||||
const basePath = `/src/content/developers/${params.folder}`;
|
||||
const formattedSlug = formatSlug(params.documentation);
|
||||
const mainPost = await fetchArticleFromSlug(params.documentation, basePath);
|
||||
return {
|
||||
title: 'Twenty - ' + formattedSlug,
|
||||
description: mainPost?.itemInfo?.info,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function DocsSlug({
|
||||
params,
|
||||
}: {
|
||||
params: { documentation: string; folder: string };
|
||||
}) {
|
||||
const basePath = `/src/content/developers/${params.folder}`;
|
||||
const mainPost = await fetchArticleFromSlug(params.documentation, basePath);
|
||||
return mainPost && <DocsContent item={mainPost} />;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
import DocsMain from '@/app/_components/docs/DocsMain';
|
||||
import { getDocsArticles } from '@/content/user-guide/constants/getDocsArticles';
|
||||
import { fetchArticleFromSlug } from '@/shared-utils/fetchArticleFromSlug';
|
||||
import { formatSlug } from '@/shared-utils/formatSlug';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { folder: string };
|
||||
}): Promise<Metadata> {
|
||||
const formattedSlug = formatSlug(params.folder);
|
||||
const basePath = '/src/content/developers';
|
||||
const mainPost = await fetchArticleFromSlug(params.folder, basePath);
|
||||
return {
|
||||
title: 'Twenty - ' + formattedSlug,
|
||||
description: mainPost?.itemInfo?.info,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function DocsSlug({
|
||||
params,
|
||||
}: {
|
||||
params: { folder: string };
|
||||
}) {
|
||||
const filePath = `src/content/developers/${params.folder}/`;
|
||||
const docsArticleCards = getDocsArticles(filePath);
|
||||
const isSection = true;
|
||||
return <DocsMain docsArticleCards={docsArticleCards} isSection={isSection} />;
|
||||
}
|
||||
Reference in New Issue
Block a user