mirror of
https://github.com/dathere/ckan-devstaller.git
synced 2025-11-09 13:39:49 +00:00
feat: add /docs deployed at https://ckan-devstaller.dathere.com
This commit is contained in:
parent
16088fc929
commit
64708d2d68
26 changed files with 1376 additions and 0 deletions
BIN
docs/app/(home)/ckan-devstaller-demo.gif
Normal file
BIN
docs/app/(home)/ckan-devstaller-demo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.8 MiB |
6
docs/app/(home)/layout.tsx
Normal file
6
docs/app/(home)/layout.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { HomeLayout } from "fumadocs-ui/layouts/home";
|
||||
import { baseOptions } from "@/lib/layout.shared";
|
||||
|
||||
export default function Layout({ children }: LayoutProps<"/">) {
|
||||
return <HomeLayout {...baseOptions()}>{children}</HomeLayout>;
|
||||
}
|
||||
159
docs/app/(home)/page.tsx
Normal file
159
docs/app/(home)/page.tsx
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/** biome-ignore-all lint/a11y/useButtonType: <explanation> */
|
||||
/** biome-ignore-all lint/suspicious/noArrayIndexKey: <explanation> */
|
||||
"use client";
|
||||
|
||||
import { cva } from "class-variance-authority";
|
||||
import { cn } from "fumadocs-ui/utils/cn";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import CkanDevstallerDemo from "./ckan-devstaller-demo.gif";
|
||||
|
||||
export default function HomePage() {
|
||||
const gridColor =
|
||||
"color-mix(in oklab, var(--color-fd-primary) 10%, transparent)";
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="absolute inset-x-0 top-[360px] h-[250px] max-md:hidden"
|
||||
style={{
|
||||
background: `repeating-linear-gradient(to right, ${gridColor}, ${gridColor} 1px,transparent 1px,transparent 50px), repeating-linear-gradient(to bottom, ${gridColor}, ${gridColor} 1px,transparent 1px,transparent 50px)`,
|
||||
}}
|
||||
/>
|
||||
<main className="container relative max-w-[1100px] px-2 py-4 z-2 lg:py-8">
|
||||
<div
|
||||
style={{
|
||||
background:
|
||||
"repeating-linear-gradient(to bottom, transparent, color-mix(in oklab, var(--color-fd-primary) 1%, transparent) 500px, transparent 1000px)",
|
||||
}}
|
||||
>
|
||||
<div className="relative">
|
||||
<Hero />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Hero() {
|
||||
return (
|
||||
<div className="relative z-2 flex flex-col border-x border-t bg-fd-background/80 px-4 pt-12 max-md:text-center md:px-12 md:pt-16 [.uwu_&]:hidden overflow-hidden">
|
||||
<div
|
||||
className="absolute inset-0 z-[-1] blur-2xl hidden dark:block"
|
||||
style={{
|
||||
maskImage:
|
||||
"linear-gradient(to bottom, transparent, white, transparent)",
|
||||
background:
|
||||
"repeating-linear-gradient(65deg, var(--color-blue-500), var(--color-blue-500) 12px, color-mix(in oklab, var(--color-blue-600) 30%, transparent) 20px, transparent 200px)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0 z-[-1] blur-2xl dark:hidden"
|
||||
style={{
|
||||
maskImage:
|
||||
"linear-gradient(to bottom, transparent, white, transparent)",
|
||||
background:
|
||||
"repeating-linear-gradient(65deg, var(--color-purple-300), var(--color-purple-300) 12px, color-mix(in oklab, var(--color-blue-600) 30%, transparent) 20px, transparent 200px)",
|
||||
}}
|
||||
/>
|
||||
<h1 className="mb-8 text-4xl font-medium md:hidden">Build Your Docs</h1>
|
||||
<h1 className="mb-8 max-w-[800px] text-4xl font-medium max-md:hidden">
|
||||
<span className="text-5xl">ckan-devstaller</span>
|
||||
<br />
|
||||
Launch CKAN dev instances within minutes
|
||||
</h1>
|
||||
<p className="mb-2 text-fd-muted-foreground md:max-w-[80%] md:text-xl">
|
||||
ckan-devstaller is a command-line tool to automate installing CKAN for
|
||||
development using ckan-compose on a new Ubuntu 22.04 instance.
|
||||
</p>
|
||||
<p className="mb-8 text-fd-muted-foreground md:max-w-[80%] md:text-sm">
|
||||
Provided by{" "}
|
||||
<Link className="text-fd-info" href="https://dathere.com">
|
||||
datHere
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<div className="inline-flex items-center gap-3 max-md:mx-auto">
|
||||
<Link
|
||||
href="/docs"
|
||||
className={cn(
|
||||
buttonVariants({ size: "lg", className: "rounded-full" }),
|
||||
)}
|
||||
>
|
||||
Getting Started
|
||||
</Link>
|
||||
<Link
|
||||
href="https://github.com/dathere/ckan-devstaller"
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: "secondary",
|
||||
size: "lg",
|
||||
className: "rounded-full",
|
||||
}),
|
||||
)}
|
||||
>
|
||||
Source Code
|
||||
</Link>
|
||||
</div>
|
||||
<PreviewImages />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const previewButtonVariants = cva(
|
||||
"w-22 h-9 text-sm font-medium transition-colors rounded-full",
|
||||
{
|
||||
variants: {
|
||||
active: {
|
||||
true: "text-fd-primary-foreground",
|
||||
false: "text-fd-muted-foreground",
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
export function PreviewImages() {
|
||||
const [active, setActive] = useState(0);
|
||||
const previews = [
|
||||
{
|
||||
image: CkanDevstallerDemo,
|
||||
name: "Demo",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="mt-12 p-8 min-w-[800px] overflow-hidden xl:-mx-12 dark:[mask-image:linear-gradient(to_top,transparent,white_40px)]">
|
||||
<div className="absolute flex flex-row left-1/2 -translate-1/2 bottom-4 z-2 p-1 rounded-full bg-fd-card border shadow-xl dark:shadow-fd-background">
|
||||
{/* <div
|
||||
role="none"
|
||||
className="absolute bg-fd-primary rounded-full w-22 h-9 transition-transform z-[-1]"
|
||||
style={{
|
||||
transform: `translateX(calc(var(--spacing) * 22 * ${active}))`,
|
||||
}}
|
||||
/> */}
|
||||
{/* {previews.map((item, i) => (
|
||||
<button
|
||||
key={i}
|
||||
className={cn(previewButtonVariants({ active: active === i }))}
|
||||
onClick={() => setActive(i)}
|
||||
>
|
||||
{item.name}
|
||||
</button>
|
||||
))} */}
|
||||
</div>
|
||||
{previews.map((item, i) => (
|
||||
<Image
|
||||
key={i}
|
||||
src={item.image}
|
||||
alt="preview"
|
||||
priority
|
||||
className={cn(
|
||||
"rounded-xl w-full select-none duration-1000 animate-in fade-in -mb-60 slide-in-from-bottom-12 lg:-mb-0",
|
||||
active !== i && "hidden",
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
docs/app/api/search/route.ts
Normal file
7
docs/app/api/search/route.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { createFromSource } from "fumadocs-core/search/server";
|
||||
import { source } from "@/lib/source";
|
||||
|
||||
export const { GET } = createFromSource(source, {
|
||||
// https://docs.orama.com/docs/orama-js/supported-languages
|
||||
language: "english",
|
||||
});
|
||||
54
docs/app/docs/[[...slug]]/page.tsx
Normal file
54
docs/app/docs/[[...slug]]/page.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { createRelativeLink } from "fumadocs-ui/mdx";
|
||||
import {
|
||||
DocsBody,
|
||||
DocsDescription,
|
||||
DocsPage,
|
||||
DocsTitle,
|
||||
} from "fumadocs-ui/page";
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { getPageImage, source } from "@/lib/source";
|
||||
import { getMDXComponents } from "@/mdx-components";
|
||||
|
||||
export default async function Page(props: PageProps<"/docs/[[...slug]]">) {
|
||||
const params = await props.params;
|
||||
const page = source.getPage(params.slug);
|
||||
if (!page) notFound();
|
||||
|
||||
const MDX = page.data.body;
|
||||
|
||||
return (
|
||||
<DocsPage toc={page.data.toc} full={page.data.full}>
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<DocsDescription>{page.data.description}</DocsDescription>
|
||||
<DocsBody>
|
||||
<MDX
|
||||
components={getMDXComponents({
|
||||
// this allows you to link to other pages with relative file paths
|
||||
a: createRelativeLink(source, page),
|
||||
})}
|
||||
/>
|
||||
</DocsBody>
|
||||
</DocsPage>
|
||||
);
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return source.generateParams();
|
||||
}
|
||||
|
||||
export async function generateMetadata(
|
||||
props: PageProps<"/docs/[[...slug]]">,
|
||||
): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const page = source.getPage(params.slug);
|
||||
if (!page) notFound();
|
||||
|
||||
return {
|
||||
title: page.data.title,
|
||||
description: page.data.description,
|
||||
openGraph: {
|
||||
images: getPageImage(page).url,
|
||||
},
|
||||
};
|
||||
}
|
||||
11
docs/app/docs/layout.tsx
Normal file
11
docs/app/docs/layout.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { DocsLayout } from "fumadocs-ui/layouts/docs";
|
||||
import { baseOptions } from "@/lib/layout.shared";
|
||||
import { source } from "@/lib/source";
|
||||
|
||||
export default function Layout({ children }: LayoutProps<"/docs">) {
|
||||
return (
|
||||
<DocsLayout tree={source.pageTree} {...baseOptions()}>
|
||||
{children}
|
||||
</DocsLayout>
|
||||
);
|
||||
}
|
||||
4
docs/app/global.css
Normal file
4
docs/app/global.css
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
@import 'tailwindcss';
|
||||
@import 'fumadocs-ui/css/neutral.css';
|
||||
@import 'fumadocs-ui/css/ocean.css';
|
||||
@import 'fumadocs-ui/css/preset.css';
|
||||
15
docs/app/layout.tsx
Normal file
15
docs/app/layout.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import "@/app/global.css";
|
||||
import { RootProvider } from "fumadocs-ui/provider";
|
||||
import localFont from "next/font/local";
|
||||
|
||||
const inter = localFont({ src: "../lib/inter.ttf" });
|
||||
|
||||
export default function Layout({ children }: LayoutProps<"/">) {
|
||||
return (
|
||||
<html lang="en" className={inter.className} suppressHydrationWarning>
|
||||
<body className="flex flex-col min-h-screen">
|
||||
<RootProvider>{children}</RootProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
10
docs/app/llms-full.txt/route.ts
Normal file
10
docs/app/llms-full.txt/route.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { getLLMText, source } from '@/lib/source';
|
||||
|
||||
export const revalidate = false;
|
||||
|
||||
export async function GET() {
|
||||
const scan = source.getPages().map(getLLMText);
|
||||
const scanned = await Promise.all(scan);
|
||||
|
||||
return new Response(scanned.join('\n\n'));
|
||||
}
|
||||
34
docs/app/og/docs/[...slug]/route.tsx
Normal file
34
docs/app/og/docs/[...slug]/route.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { generate as DefaultImage } from "fumadocs-ui/og";
|
||||
import { notFound } from "next/navigation";
|
||||
import { ImageResponse } from "next/og";
|
||||
import { getPageImage, source } from "@/lib/source";
|
||||
|
||||
export const revalidate = false;
|
||||
|
||||
export async function GET(
|
||||
_req: Request,
|
||||
{ params }: RouteContext<"/og/docs/[...slug]">,
|
||||
) {
|
||||
const { slug } = await params;
|
||||
const page = source.getPage(slug.slice(0, -1));
|
||||
if (!page) notFound();
|
||||
|
||||
return new ImageResponse(
|
||||
<DefaultImage
|
||||
title={page.data.title}
|
||||
description={page.data.description}
|
||||
site="ckan-devstaller"
|
||||
/>,
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return source.getPages().map((page) => ({
|
||||
lang: page.locale,
|
||||
slug: getPageImage(page).segments,
|
||||
}));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue