Skip to content

Commit a7186a4

Browse files
authored
Merge pull request #147 from deploystackio/main
prod deployment
2 parents f337772 + 888ede7 commit a7186a4

91 files changed

Lines changed: 8879 additions & 4426 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,8 @@ coverage/
7171
.jest/
7272

7373
._*.mdx
74+
._*.md
75+
._*.json
7476
._*.ts
77+
._*.tsx
7578
out/
Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import type { Metadata } from 'next';
2+
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3+
import { HomeLayout } from 'fumadocs-ui/layouts/home';
24
import { DocsPage, DocsBody } from 'fumadocs-ui/page';
35
import { notFound } from 'next/navigation';
46
import { source } from '@/lib/source';
57
import { generatePageMetadata, getCanonicalUrl } from '@/lib/seo-utils';
6-
import { CustomNavbar } from '@/lib/components/CustomNavbar';
78
import { getFinalPageTitle } from '@/lib/h1-extractor';
89
import { readFile } from 'fs/promises';
910
import { getMDXComponents } from '@/mdx-components';
11+
import { homeOptions, docsOptions } from '../layout.config';
12+
import { docs } from '@/.source/index';
1013

1114
export default async function Page({
1215
params,
@@ -22,18 +25,56 @@ export default async function Page({
2225

2326
const MDX = page.data.body;
2427

28+
// Determine if this is the root page (no sidebar needed)
29+
const isRootPage = !slug || slug.length === 0;
30+
31+
// Use HomeLayout for root page (no sidebar), DocsLayout for all other pages
32+
if (isRootPage) {
33+
return (
34+
<HomeLayout {...homeOptions}>
35+
<div className="container max-w-6xl mx-auto px-4 py-8">
36+
<article className="prose prose-neutral dark:prose-invert max-w-none">
37+
<MDX components={getMDXComponents()} />
38+
</article>
39+
</div>
40+
</HomeLayout>
41+
);
42+
}
43+
2544
return (
26-
<DocsPage toc={page.data.toc} full={page.data.full}>
27-
<CustomNavbar />
28-
<DocsBody>
29-
<MDX components={getMDXComponents()} />
30-
</DocsBody>
31-
</DocsPage>
45+
<DocsLayout
46+
{...docsOptions}
47+
tree={source.pageTree}
48+
nav={{
49+
title: 'DeployStack Docs',
50+
url: '/',
51+
}}
52+
sidebar={{
53+
defaultOpenLevel: 1
54+
}}
55+
>
56+
<DocsPage toc={page.data.toc} full={page.data.full}>
57+
<DocsBody>
58+
<MDX components={getMDXComponents()} />
59+
</DocsBody>
60+
</DocsPage>
61+
</DocsLayout>
3262
);
3363
}
3464

3565
export async function generateStaticParams() {
36-
return source.generateParams();
66+
const params = source.generateParams();
67+
68+
const result = [
69+
...params,
70+
...docs.docs
71+
.filter((page: any) => page._file.flattenedPath)
72+
.map((page: any) => ({
73+
slug: page._file.flattenedPath.split('/'),
74+
})),
75+
];
76+
77+
return result;
3778
}
3879

3980
export async function generateMetadata({

app/docs/layout.tsx

Lines changed: 0 additions & 22 deletions
This file was deleted.

app/docs/sitemap.xml/route.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

app/layout.config.tsx

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,47 @@
11
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
22

3-
export const baseOptions: BaseLayoutProps = {
4-
// Navigation bar configuration (now handled by CustomNavbar)
3+
// Base configuration shared between both layouts
4+
const baseConfig = {
55
nav: {
66
title: 'DeployStack Docs',
7-
url: '/docs',
7+
url: '/',
88
},
9-
10-
// GitHub repository for edit links
119
githubUrl: 'https://github.com/deploystackio/documentation',
1210
};
11+
12+
// Configuration for the home page (root URL) with all links visible
13+
export const homeOptions: BaseLayoutProps = {
14+
...baseConfig,
15+
links: [
16+
{
17+
text: 'MCP Server',
18+
url: 'https://deploystack.io/mcp',
19+
external: true,
20+
},
21+
{
22+
text: 'Changelog',
23+
url: 'https://deploystack.io/changelog',
24+
external: true,
25+
},
26+
{
27+
type: 'custom',
28+
secondary: true,
29+
children: (
30+
<a
31+
href="https://cloud.deploystack.io/login"
32+
target="_blank"
33+
rel="noopener noreferrer"
34+
className="text-slate-100 bg-slate-800 border border-slate-700 ml-1.5 focus:outline-none hover:bg-slate-900 hover:text-slate-50 focus:ring-4 focus:ring-gray-100 font-medium rounded-full text-sm px-5 py-2 me-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700 transition-colors"
35+
>
36+
Login
37+
</a>
38+
),
39+
},
40+
],
41+
};
42+
43+
export const docsOptions: BaseLayoutProps = {
44+
...baseConfig
45+
};
46+
47+
export const baseOptions = docsOptions;

app/sitemap.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { MetadataRoute } from 'next';
2+
import { source } from '@/lib/source';
3+
4+
export const dynamic = 'force-static';
5+
6+
function getPages(tree: any): any[] {
7+
const pages: any[] = [];
8+
9+
function traverse(nodes: any[]) {
10+
for (const node of nodes) {
11+
if (node.type === 'page') {
12+
pages.push(node);
13+
} else if ('children' in node) {
14+
traverse(node.children);
15+
}
16+
}
17+
}
18+
19+
traverse(tree.children);
20+
return pages;
21+
}
22+
23+
export default function sitemap(): MetadataRoute.Sitemap {
24+
const pages = getPages(source.pageTree).map((page) => ({
25+
url: new URL(page.url, 'https://docs.deploystack.io').toString(),
26+
lastModified: page.lastModified,
27+
}));
28+
29+
return pages;
30+
}

check-links.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,35 @@ const extractLinks = (content) => {
2525

2626
// Check if a local file exists
2727
const checkLocalFile = (linkPath, filePath) => {
28-
if (linkPath.startsWith('/docs/')) {
28+
// Check for internal links (starting with / but not external URLs)
29+
if (linkPath.startsWith('/') && !linkPath.startsWith('//') && !linkPath.startsWith('http')) {
2930
// Remove hash fragment before checking file existence
3031
const [baseUrl] = linkPath.split('#');
31-
const localPath = path.join(process.cwd(), baseUrl);
3232

33-
try {
34-
fs.accessSync(localPath, fs.constants.F_OK);
35-
console.log(` ✅ ${linkPath}`);
36-
return true;
37-
} catch (err) {
38-
console.log(` ❌ ${linkPath} → File not found`);
39-
return false;
33+
// Map the URL to the actual file location
34+
// Since our URLs are now root-level but files are in docs/
35+
const actualFilePath = path.join(process.cwd(), 'docs', baseUrl.substring(1));
36+
37+
// Try both .mdx and .md extensions
38+
const possiblePaths = [
39+
actualFilePath + '.mdx',
40+
actualFilePath + '.md',
41+
path.join(actualFilePath, 'index.mdx'),
42+
path.join(actualFilePath, 'index.md')
43+
];
44+
45+
for (const possiblePath of possiblePaths) {
46+
try {
47+
fs.accessSync(possiblePath, fs.constants.F_OK);
48+
console.log(` ✅ ${linkPath}`);
49+
return true;
50+
} catch (err) {
51+
// Continue to next possible path
52+
}
4053
}
54+
55+
console.log(` ❌ ${linkPath} → File not found (checked: ${possiblePaths.map(p => path.relative(process.cwd(), p)).join(', ')})`);
56+
return false;
4157
}
4258
return null; // not a local file
4359
};
@@ -79,7 +95,8 @@ const processFile = async (filePath) => {
7995

8096
let allValid = true;
8197
for (const link of links) {
82-
if (link.url.startsWith('/docs/')) {
98+
if (link.url.startsWith('/') && !link.url.startsWith('//') && !link.url.startsWith('http')) {
99+
// Internal link (root-level)
83100
const isValid = checkLocalFile(link.url, filePath);
84101
if (!isValid) allValid = false;
85102
} else if (link.url.startsWith('http')) {
@@ -109,7 +126,7 @@ const processDirectory = async (dir) => {
109126
if (stat.isDirectory()) {
110127
const isValid = await processDirectory(filePath);
111128
if (!isValid) allValid = false;
112-
} else if (file.endsWith('.md')) {
129+
} else if (file.endsWith('.md') || file.endsWith('.mdx')) {
113130
const isValid = await processFile(filePath);
114131
if (!isValid) allValid = false;
115132
}

0 commit comments

Comments
 (0)