chore: rename docs-v2 to docs
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { Link } from '@tanstack/react-router';
|
||||
import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
||||
|
||||
export function NotFound() {
|
||||
return (
|
||||
<HomeLayout
|
||||
nav={{
|
||||
title: 'ClassroomIO'
|
||||
}}
|
||||
className="justify-center py-32 text-center"
|
||||
>
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<h1 className="text-fd-muted-foreground text-6xl font-bold">404</h1>
|
||||
<h2 className="text-2xl font-semibold">Page Not Found</h2>
|
||||
<p className="text-fd-muted-foreground max-w-md">
|
||||
The page you are looking for might have been removed, had its name changed, or is
|
||||
temporarily unavailable.
|
||||
</p>
|
||||
<Link
|
||||
to="/"
|
||||
className="bg-fd-primary text-fd-primary-foreground mt-4 rounded-lg px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90"
|
||||
>
|
||||
Back to Home
|
||||
</Link>
|
||||
</div>
|
||||
</HomeLayout>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
|
||||
import { SquareArrowOutUpRight } from 'lucide-react';
|
||||
|
||||
export function baseOptions(): BaseLayoutProps {
|
||||
return {
|
||||
nav: {
|
||||
title: (
|
||||
<div className="flex items-center gap-2">
|
||||
<img src="/docs/logo-192.png" className="size-8" alt="ClassroomIO logo" />
|
||||
<span className="font-medium">ClassroomIO</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
links: [
|
||||
{
|
||||
text: (
|
||||
<div className="flex items-center gap-2">
|
||||
Contact <SquareArrowOutUpRight />
|
||||
</div>
|
||||
),
|
||||
url: 'https://twitter.com/classroomio',
|
||||
external: true
|
||||
},
|
||||
{
|
||||
text: (
|
||||
<div className="flex items-center gap-2">
|
||||
Demo <SquareArrowOutUpRight />
|
||||
</div>
|
||||
),
|
||||
url: 'https://dub.sh/ciodemo',
|
||||
external: true
|
||||
},
|
||||
{
|
||||
text: (
|
||||
<div className="flex items-center gap-2">
|
||||
Dashboard <SquareArrowOutUpRight />
|
||||
</div>
|
||||
),
|
||||
url: 'https://app.classroomio.com/',
|
||||
external: true
|
||||
},
|
||||
{
|
||||
type: 'icon',
|
||||
label: 'Discord',
|
||||
icon: (
|
||||
<img
|
||||
src="/docs/discord-blue.png"
|
||||
alt="discord icon"
|
||||
className="w-7 transition-all duration-500 hover:scale-90"
|
||||
/>
|
||||
),
|
||||
text: 'Discord',
|
||||
url: 'https://dub.sh/ciodiscord',
|
||||
external: true
|
||||
}
|
||||
],
|
||||
githubUrl: 'https://github.com/classroomio/classroomio'
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { loader } from 'fumadocs-core/source';
|
||||
import * as icons from 'lucide-static';
|
||||
import { docs } from 'fumadocs-mdx:collections/server';
|
||||
|
||||
export const source = loader({
|
||||
source: docs.toFumadocsSource(),
|
||||
baseUrl: '/',
|
||||
icon(icon) {
|
||||
if (!icon) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (icon in icons) return icons[icon as keyof typeof icons];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NotFound } from '@/components/not-found';
|
||||
import { createRouter as createTanStackRouter } from '@tanstack/react-router';
|
||||
import { routeTree } from './routeTree.gen';
|
||||
|
||||
export function getRouter() {
|
||||
return createTanStackRouter({
|
||||
basepath: '/docs',
|
||||
defaultNotFoundComponent: NotFound,
|
||||
defaultPreload: 'intent',
|
||||
routeTree,
|
||||
scrollRestoration: true
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { useMemo } from 'react';
|
||||
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||
import { createServerFn } from '@tanstack/react-start';
|
||||
import type * as PageTree from 'fumadocs-core/page-tree';
|
||||
import browserCollections from 'fumadocs-mdx:collections/browser';
|
||||
import { createFileRoute, notFound } from '@tanstack/react-router';
|
||||
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
|
||||
|
||||
import { source } from '@/lib/source';
|
||||
import { baseOptions } from '@/lib/layout.shared';
|
||||
import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
||||
|
||||
export const Route = createFileRoute('/$')({
|
||||
component: Page,
|
||||
loader: async ({ params }) => {
|
||||
const slugs = params._splat?.split('/') ?? [];
|
||||
const data = await loader({ data: slugs });
|
||||
await clientLoader.preload(data.path);
|
||||
return data;
|
||||
}
|
||||
});
|
||||
|
||||
const loader = createServerFn({
|
||||
method: 'GET'
|
||||
})
|
||||
.inputValidator((slugs: string[]) => slugs)
|
||||
.handler(async ({ data: slugs }) => {
|
||||
const page = source.getPage(slugs);
|
||||
if (!page) throw notFound();
|
||||
|
||||
return {
|
||||
tree: source.pageTree as object,
|
||||
path: page.path
|
||||
};
|
||||
});
|
||||
|
||||
const clientLoader = browserCollections.docs.createClientLoader({
|
||||
component({ toc, frontmatter, default: MDX }) {
|
||||
return (
|
||||
<DocsPage toc={toc}>
|
||||
<DocsTitle>{frontmatter.title}</DocsTitle>
|
||||
<DocsDescription>{frontmatter.description}</DocsDescription>
|
||||
<DocsBody>
|
||||
<MDX
|
||||
components={{
|
||||
...defaultMdxComponents
|
||||
}}
|
||||
/>
|
||||
</DocsBody>
|
||||
</DocsPage>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function Page() {
|
||||
const data = Route.useLoaderData();
|
||||
const Content = clientLoader.getComponent(data.path);
|
||||
const tree = useMemo(() => transformPageTree(data.tree as PageTree.Folder), [data.tree]);
|
||||
|
||||
return (
|
||||
<HomeLayout {...baseOptions()}>
|
||||
<DocsLayout
|
||||
sidebar={{
|
||||
collapsible: false
|
||||
}}
|
||||
themeSwitch={{
|
||||
enabled: false
|
||||
}}
|
||||
searchToggle={{
|
||||
enabled: false
|
||||
}}
|
||||
tree={tree}
|
||||
>
|
||||
<Content />
|
||||
</DocsLayout>
|
||||
</HomeLayout>
|
||||
);
|
||||
}
|
||||
|
||||
function transformPageTree(root: PageTree.Root): PageTree.Root {
|
||||
function mapNode<T extends PageTree.Node>(item: T): T {
|
||||
if (typeof item.icon === 'string') {
|
||||
item = {
|
||||
...item,
|
||||
icon: (
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.icon
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
if (item.type === 'folder') {
|
||||
return {
|
||||
...item,
|
||||
index: item.index ? mapNode(item.index) : undefined,
|
||||
children: item.children.map(mapNode)
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
return {
|
||||
...root,
|
||||
children: root.children.map(mapNode),
|
||||
fallback: root.fallback ? transformPageTree(root.fallback) : undefined
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { HeadContent, Outlet, Scripts, createRootRoute } from '@tanstack/react-router';
|
||||
|
||||
import { RootProvider } from 'fumadocs-ui/provider/tanstack';
|
||||
import appCss from '@/styles/app.css?url';
|
||||
|
||||
export const Route = createRootRoute({
|
||||
head: () => ({
|
||||
meta: [
|
||||
{
|
||||
charSet: 'utf-8'
|
||||
},
|
||||
{
|
||||
name: 'viewport',
|
||||
content: 'width=device-width, initial-scale=1'
|
||||
},
|
||||
{
|
||||
title: 'ClassroomIO | The Open Source Learning Management System for Companies'
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
content:
|
||||
'A flexible, user-friendly platform for creating, managing, and delivering courses for companies and training organisations'
|
||||
},
|
||||
{
|
||||
property: 'og:url',
|
||||
content: 'https://classroomio.com/docs'
|
||||
},
|
||||
{
|
||||
property: 'og:type',
|
||||
content: 'website'
|
||||
},
|
||||
{
|
||||
property: 'og:title',
|
||||
content: 'ClassroomIO | The Open Source Learning Management System for Companies'
|
||||
},
|
||||
{
|
||||
property: 'og:description',
|
||||
content:
|
||||
'A flexible, user-friendly platform for creating, managing, and delivering courses for companies and training organisations'
|
||||
},
|
||||
{
|
||||
property: 'og:image:type',
|
||||
content: 'image/png'
|
||||
},
|
||||
{
|
||||
property: 'og:image:width',
|
||||
content: '1920'
|
||||
},
|
||||
{
|
||||
property: 'og:image:height',
|
||||
content: '1080'
|
||||
},
|
||||
{
|
||||
property: 'og:image:secure_url',
|
||||
itemProp: 'image',
|
||||
content: 'https://brand.cdn.clsrio.com/og/classroomio-og.png'
|
||||
},
|
||||
{
|
||||
name: 'twitter:card',
|
||||
content: 'summary_large_image'
|
||||
},
|
||||
{
|
||||
property: 'twitter:domain',
|
||||
content: 'classroomio.com'
|
||||
},
|
||||
{
|
||||
property: 'twitter:url',
|
||||
content: 'https://classroomio.com/docs'
|
||||
},
|
||||
{
|
||||
name: 'twitter:title',
|
||||
content: 'ClassroomIO | The Open Source Learning Management System for Companies'
|
||||
},
|
||||
{
|
||||
name: 'twitter:description',
|
||||
content:
|
||||
'A flexible, user-friendly platform for creating, managing, and delivering courses for companies and training organisations'
|
||||
},
|
||||
{
|
||||
name: 'twitter:creator',
|
||||
content: '@classroomio'
|
||||
},
|
||||
{
|
||||
name: 'twitter:image',
|
||||
content: 'https://brand.cdn.clsrio.com/og/classroomio-og.png'
|
||||
}
|
||||
],
|
||||
links: [
|
||||
{ rel: 'stylesheet', href: appCss },
|
||||
{ rel: 'icon', href: '/docs/favicon.ico' }
|
||||
]
|
||||
}),
|
||||
component: RootComponent
|
||||
});
|
||||
|
||||
function RootComponent() {
|
||||
return (
|
||||
<RootDocument>
|
||||
<Outlet />
|
||||
</RootDocument>
|
||||
);
|
||||
}
|
||||
|
||||
function RootDocument({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html suppressHydrationWarning>
|
||||
<head>
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body className="flex min-h-screen flex-col">
|
||||
<RootProvider>{children}</RootProvider>
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { source } from '@/lib/source';
|
||||
import { createFromSource } from 'fumadocs-core/search/server';
|
||||
|
||||
const server = createFromSource(source, {
|
||||
// https://docs.orama.com/docs/orama-js/supported-languages
|
||||
language: 'english',
|
||||
});
|
||||
|
||||
export const Route = createFileRoute('/api/search')({
|
||||
server: {
|
||||
handlers: {
|
||||
GET: async ({ request }) => server.GET(request),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { createFileRoute, redirect } from '@tanstack/react-router';
|
||||
|
||||
export const Route = createFileRoute('/')({
|
||||
beforeLoad: () => {
|
||||
throw redirect({
|
||||
to: '/$',
|
||||
params: {
|
||||
_splat: 'home'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
@import 'tailwindcss';
|
||||
@import 'fumadocs-ui/css/black.css';
|
||||
@import 'fumadocs-ui/css/preset.css';
|
||||
|
||||
body {
|
||||
--color-fd-primary: var(--color-blue-700);
|
||||
}
|
||||
Reference in New Issue
Block a user