Migrate documentation to Mintlify and configure 301 redirects (#15502)
## Summary Completes the migration of all documentation from twenty-website to a new Mintlify-powered documentation site at docs.twenty.com. ## Changes Made ### New Package: `twenty-docs` - ✅ Created new Mintlify documentation package - ✅ Migrated 95 content pages (user-guide, developers, twenty-ui) - ✅ Migrated 81 images - ✅ Converted all custom components to Mintlify native components - ✅ Configured navigation with 2 tabs and 94 pages - ✅ Added Helper AI Agent with searchArticles tool for docs search ### Updated: `twenty-website` - ✅ Added 11 redirect rules (301 permanent) in next.config.js - ✅ Removed all documentation content (111 files) - ✅ Removed documentation routes (user-guide, developers, twenty-ui) - ✅ Removed documentation components (9 files) - ✅ Updated keystatic.config.ts - ✅ Preserved all marketing/release pages ### Updated: Core Files - ✅ Updated README.md - docs links point to docs.twenty.com - ✅ Updated CONTRIBUTING.md - code quality link updated - ✅ Updated SupportDropdown.tsx - user guide link updated - ✅ Updated Footer.tsx - user guide link updated
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
import { type DocsArticlesProps } from '@/content/user-guide/constants/getDocsArticles';
|
||||
|
||||
export const constructSections = (
|
||||
docsArticleCards: DocsArticlesProps[],
|
||||
isSection: boolean,
|
||||
): { name: string; info: string }[] => {
|
||||
if (isSection) {
|
||||
return [
|
||||
{
|
||||
name: docsArticleCards[0]?.topic,
|
||||
info: docsArticleCards[0]?.sectionInfo,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return Array.from(
|
||||
new Map(
|
||||
docsArticleCards
|
||||
.filter((guide) => guide.numberOfFiles > 0)
|
||||
.map((guide) => [guide.section, guide]),
|
||||
).values(),
|
||||
).map((guide) => ({
|
||||
name: guide.section,
|
||||
info: guide.sectionInfo,
|
||||
}));
|
||||
}
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
import { getPost } from '@/app/_server-utils/get-posts';
|
||||
|
||||
export async function fetchArticleFromSlug(slug: string, basePath: string) {
|
||||
const effectiveSlug = slug && slug.length > 0 ? slug : 'home';
|
||||
return await getPost(effectiveSlug, basePath);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { type DocsArticlesProps } from '@/content/user-guide/constants/getDocsArticles';
|
||||
|
||||
export const filterDocsIndex = (
|
||||
docsIndex: DocsArticlesProps[],
|
||||
sectionName: string,
|
||||
): DocsArticlesProps[] => {
|
||||
return docsIndex.filter(
|
||||
(guide) =>
|
||||
guide.section.includes(sectionName) && guide.title.includes(guide.topic),
|
||||
);
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
import { type DocsArticlesProps } from '@/content/user-guide/constants/getDocsArticles';
|
||||
|
||||
export const getCardPath = (
|
||||
card: DocsArticlesProps,
|
||||
basePath: string,
|
||||
isSection: boolean,
|
||||
sectionName?: string,
|
||||
) => {
|
||||
const isPlayground = [
|
||||
'core-api-rest',
|
||||
'metadata-api-rest',
|
||||
'core-api-graphql',
|
||||
'metadata-api-graphql',
|
||||
];
|
||||
|
||||
if (isPlayground.includes(card.fileName)) {
|
||||
const apiType = card.fileName.includes('rest') ? 'rest-api' : 'graphql';
|
||||
const apiName = card.fileName.includes('core') ? 'core' : 'metadata';
|
||||
return `/developers/${apiType}/${apiName}`;
|
||||
} else if (card.fileName.includes('storybook')) {
|
||||
return 'https://storybook.twenty.com';
|
||||
} else if (card.fileName.includes('components')) {
|
||||
return `/twenty-ui`;
|
||||
} else {
|
||||
if (sectionName) {
|
||||
return card.numberOfFiles > 1
|
||||
? `${basePath}section/${sectionName}/${card.fileName}`
|
||||
: `${basePath}${card.fileName}`;
|
||||
} else {
|
||||
return card.numberOfFiles > 1 && !isSection
|
||||
? `${basePath}/section/${card.fileName}`
|
||||
: `${basePath}/${card.fileName}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
import {
|
||||
IconBook,
|
||||
IconCode,
|
||||
IconComponents,
|
||||
IconGitPullRequest,
|
||||
IconTool,
|
||||
} from '@tabler/icons-react';
|
||||
|
||||
import { Theme } from '@/app/_components/ui/theme/theme';
|
||||
|
||||
export const getSectionIcon = (section: string): JSX.Element => {
|
||||
const iconSize = Theme.icon.size.md;
|
||||
|
||||
const sectionIcons: Record<string, JSX.Element> = {
|
||||
'Getting started': <IconCode size={iconSize} />,
|
||||
Contributing: <IconGitPullRequest size={iconSize} />,
|
||||
Extending: <IconTool size={iconSize} />,
|
||||
Components: <IconComponents size={iconSize} />,
|
||||
Developers: <IconCode size={iconSize} />,
|
||||
};
|
||||
for (const key of Object.keys(sectionIcons)) {
|
||||
if (section.includes(key)) {
|
||||
return sectionIcons[key];
|
||||
}
|
||||
}
|
||||
return <IconBook size={iconSize} />;
|
||||
};
|
||||
Reference in New Issue
Block a user