first commit

This commit is contained in:
lendry
2026-06-24 14:37:15 +03:00
commit 995adeedd4
188 changed files with 28810 additions and 0 deletions

View 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'
}
}
);
}

View 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>
</>
);
}

View 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>
);
}

View 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
View 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
View 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
View File

@@ -0,0 +1,5 @@
import { redirect } from 'next/navigation';
export default function HomePage() {
redirect('/docs');
}