first commit
This commit is contained in:
17
apps/docs/app/api/public-settings/route.ts
Normal file
17
apps/docs/app/api/public-settings/route.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { fetchPublicSettings } from '@/lib/api';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export async function GET() {
|
||||
const settings = await fetchPublicSettings();
|
||||
return Response.json(
|
||||
{
|
||||
settings: Object.entries(settings).map(([key, value]) => ({ key, value }))
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Cache-Control': 'no-store, max-age=0'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
45
apps/docs/app/docs/[slug]/page.tsx
Normal file
45
apps/docs/app/docs/[slug]/page.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { DocBlockRenderer } from '@/components/doc-block-renderer';
|
||||
import { DocsToc } from '@/components/docs-shell';
|
||||
import { getAllDocSlugs, getDocPage } from '@/lib/docs-pages';
|
||||
|
||||
export function generateStaticParams() {
|
||||
return getAllDocSlugs().map((slug) => ({ slug }));
|
||||
}
|
||||
|
||||
export default async function DocPage({ params }: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = await params;
|
||||
const page = getDocPage(slug);
|
||||
if (!page) notFound();
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="min-w-0 max-w-3xl prose-docs">
|
||||
<div className="mb-10 border-b border-zinc-200 pb-8 dark:border-zinc-800">
|
||||
<p className="text-sm font-medium text-zinc-500">Документация</p>
|
||||
<h1 className="mt-2 text-4xl font-bold tracking-tight text-zinc-950 dark:text-zinc-50">{page.title}</h1>
|
||||
<p className="mt-4 text-lg leading-relaxed text-zinc-600 dark:text-zinc-400">{page.description}</p>
|
||||
</div>
|
||||
|
||||
<article className="space-y-12 pb-16">
|
||||
{page.sections.map((section) => (
|
||||
<section id={section.id} key={section.id} className="scroll-mt-24">
|
||||
<h2 className="mb-4 text-2xl font-semibold tracking-tight text-zinc-950 dark:text-zinc-50">{section.title}</h2>
|
||||
<div className="space-y-4">
|
||||
{section.blocks.map((block, index) => (
|
||||
<DocBlockRenderer key={`${section.id}-${index}`} block={block} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<aside className="hidden xl:block">
|
||||
<div className="sticky top-20">
|
||||
<DocsToc sections={page.sections.map((s) => ({ id: s.id, title: s.title }))} />
|
||||
</div>
|
||||
</aside>
|
||||
</>
|
||||
);
|
||||
}
|
||||
27
apps/docs/app/docs/layout.tsx
Normal file
27
apps/docs/app/docs/layout.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { docNavigation, groupDocNavigation } from '@/lib/navigation';
|
||||
import { fetchPublicSettings } from '@/lib/api';
|
||||
import { PublicSettingsProvider } from '@/providers/public-settings-provider';
|
||||
import { DocsHeader, DocsSidebar } from '@/components/docs-shell';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export default async function DocsLayout({ children }: { children: React.ReactNode }) {
|
||||
const initialSettings = await fetchPublicSettings();
|
||||
const groups = groupDocNavigation(docNavigation);
|
||||
|
||||
return (
|
||||
<PublicSettingsProvider initialSettings={initialSettings}>
|
||||
<div className="min-h-screen bg-white dark:bg-zinc-950">
|
||||
<DocsHeader />
|
||||
<div className="mx-auto grid max-w-screen-2xl grid-cols-1 gap-8 px-4 py-8 lg:grid-cols-[240px_minmax(0,1fr)] lg:px-8 xl:grid-cols-[240px_minmax(0,1fr)_200px]">
|
||||
<aside className="hidden lg:block">
|
||||
<div className="sticky top-20">
|
||||
<DocsSidebar groups={groups} />
|
||||
</div>
|
||||
</aside>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</PublicSettingsProvider>
|
||||
);
|
||||
}
|
||||
5
apps/docs/app/docs/page.tsx
Normal file
5
apps/docs/app/docs/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { DocsHomeContent } from '@/components/docs-home-content';
|
||||
|
||||
export default function DocsHomePage() {
|
||||
return <DocsHomeContent />;
|
||||
}
|
||||
46
apps/docs/app/globals.css
Normal file
46
apps/docs/app/globals.css
Normal file
@@ -0,0 +1,46 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #09090b;
|
||||
--muted: #f4f4f5;
|
||||
--border: #e4e4e7;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: #09090b;
|
||||
--foreground: #fafafa;
|
||||
--muted: #18181b;
|
||||
--border: #27272a;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: var(--font-geist-mono), ui-monospace, monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: rgb(24 24 27 / 0.15);
|
||||
}
|
||||
|
||||
.dark ::selection {
|
||||
background: rgb(250 250 250 / 0.15);
|
||||
}
|
||||
|
||||
.prose-docs h2 {
|
||||
scroll-margin-top: 5rem;
|
||||
}
|
||||
37
apps/docs/app/layout.tsx
Normal file
37
apps/docs/app/layout.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
import { ThemeProvider } from '@/providers/theme-provider';
|
||||
import './globals.css';
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: '--font-geist-sans',
|
||||
subsets: ['latin', 'cyrillic']
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: '--font-geist-mono',
|
||||
subsets: ['latin']
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: 'Документация',
|
||||
template: '%s — Docs'
|
||||
},
|
||||
description: 'Документация по интеграции, OAuth 2.0, развёртыванию и REST API Identity Provider.'
|
||||
};
|
||||
|
||||
const themeScript = `(function(){try{var t=localStorage.getItem('docs-theme');var dark=t==='dark'||(t!=='light'&&window.matchMedia('(prefers-color-scheme: dark)').matches);document.documentElement.classList.toggle('dark',dark);}catch(e){}})();`;
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="ru" suppressHydrationWarning>
|
||||
<head>
|
||||
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
|
||||
</head>
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} min-h-screen antialiased`}>
|
||||
<ThemeProvider>{children}</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
5
apps/docs/app/page.tsx
Normal file
5
apps/docs/app/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default function HomePage() {
|
||||
redirect('/docs');
|
||||
}
|
||||
Reference in New Issue
Block a user