@usecross/docs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +178 -0
- package/dist/index.js +616 -0
- package/dist/index.js.map +1 -0
- package/dist/ssr.d.ts +21 -0
- package/dist/ssr.js +27 -0
- package/dist/ssr.js.map +1 -0
- package/dist/types-Vodb50Bj.d.ts +91 -0
- package/package.json +71 -0
- package/src/app.tsx +46 -0
- package/src/components/CodeBlock.tsx +87 -0
- package/src/components/DocsLayout.tsx +178 -0
- package/src/components/DocsPage.tsx +19 -0
- package/src/components/HomePage.tsx +434 -0
- package/src/components/Markdown.tsx +93 -0
- package/src/components/Sidebar.tsx +37 -0
- package/src/components/index.ts +6 -0
- package/src/index.ts +49 -0
- package/src/lib/shiki.ts +59 -0
- package/src/lib/utils.ts +9 -0
- package/src/ssr.tsx +39 -0
- package/src/styles.css +128 -0
- package/src/tailwind.preset.cjs +118 -0
- package/src/types.ts +91 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/CodeBlock.tsx","../src/lib/utils.ts","../src/lib/shiki.ts","../src/components/DocsLayout.tsx","../src/components/Sidebar.tsx","../src/components/Markdown.tsx","../src/components/DocsPage.tsx","../src/components/HomePage.tsx","../src/app.tsx"],"sourcesContent":["import { useEffect, useState } from 'react'\nimport { cn } from '../lib/utils'\nimport { getHighlighter } from '../lib/shiki'\nimport type { CodeBlockProps } from '../types'\n\n/**\n * Syntax-highlighted code block component using Shiki.\n */\nexport function CodeBlock({\n code,\n language = 'python',\n filename,\n showLineNumbers = false,\n theme = 'github-dark-dimmed',\n className,\n}: CodeBlockProps) {\n const [html, setHtml] = useState<string>('')\n const [copied, setCopied] = useState(false)\n\n useEffect(() => {\n async function highlight() {\n const highlighter = await getHighlighter()\n const langs = highlighter.getLoadedLanguages()\n const lang = langs.includes(language) ? language : 'text'\n const highlighted = highlighter.codeToHtml(code.trim(), {\n lang,\n theme,\n })\n setHtml(highlighted)\n }\n highlight()\n }, [code, language, theme])\n\n const copyToClipboard = async () => {\n await navigator.clipboard.writeText(code.trim())\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n\n return (\n <div className={cn('group relative overflow-hidden rounded-lg bg-[#24292f] not-prose', className)}>\n {filename && (\n <div className=\"flex items-center gap-2 border-b border-slate-700 bg-slate-900 px-4 py-2 text-sm text-slate-400\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n {filename}\n </div>\n )}\n <button\n onClick={copyToClipboard}\n className=\"absolute right-2 top-2 z-10 rounded-md bg-slate-700/50 px-2 py-1 text-xs text-slate-400 opacity-0 transition-opacity hover:bg-slate-600 hover:text-white group-hover:opacity-100\"\n >\n {copied ? 'Copied!' : 'Copy'}\n </button>\n {html ? (\n <div\n className={cn(\n 'overflow-x-auto text-sm [&_pre]:!m-0 [&_pre]:!bg-transparent [&_code]:!p-4',\n showLineNumbers && '[&_code]:grid [&_code]:grid-cols-[auto_1fr]'\n )}\n dangerouslySetInnerHTML={{ __html: html }}\n />\n ) : (\n <pre className=\"shiki overflow-x-auto !m-0 !bg-transparent\">\n <code className=\"block p-4 text-sm leading-relaxed text-gray-300\">{code.trim()}</code>\n </pre>\n )}\n </div>\n )\n}\n\n/**\n * Simple inline code component.\n */\nexport function InlineCode({ children }: { children: React.ReactNode }) {\n return (\n <code className=\"rounded bg-slate-100 px-1.5 py-0.5 text-sm font-medium text-slate-800\">\n {children}\n </code>\n )\n}\n","import { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\n/**\n * Merge Tailwind CSS classes with clsx\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import { createHighlighterCore, type HighlighterCore } from 'shiki/core'\nimport { createJavaScriptRegexEngine } from 'shiki/engine/javascript'\n\nlet highlighterPromise: Promise<HighlighterCore> | null = null\n\n// Default languages to load\nconst defaultLangs = [\n import('shiki/langs/python.mjs'),\n import('shiki/langs/javascript.mjs'),\n import('shiki/langs/typescript.mjs'),\n import('shiki/langs/tsx.mjs'),\n import('shiki/langs/jsx.mjs'),\n import('shiki/langs/bash.mjs'),\n import('shiki/langs/shellscript.mjs'),\n import('shiki/langs/json.mjs'),\n import('shiki/langs/html.mjs'),\n import('shiki/langs/css.mjs'),\n import('shiki/langs/yaml.mjs'),\n import('shiki/langs/toml.mjs'),\n import('shiki/langs/markdown.mjs'),\n]\n\n// Default theme\nconst defaultTheme = import('shiki/themes/github-dark-dimmed.mjs')\n\n/**\n * Get or create a Shiki highlighter instance.\n * Uses a singleton pattern to avoid creating multiple highlighters.\n */\nexport function getHighlighter(): Promise<HighlighterCore> {\n if (!highlighterPromise) {\n highlighterPromise = createHighlighterCore({\n themes: [defaultTheme],\n langs: defaultLangs,\n engine: createJavaScriptRegexEngine(),\n })\n }\n return highlighterPromise\n}\n\n/**\n * Configure the highlighter with custom themes and languages.\n * Must be called before getHighlighter() is first called.\n */\nexport function configureHighlighter(options: {\n theme?: Promise<any>\n langs?: Promise<any>[]\n}): void {\n if (highlighterPromise) {\n console.warn('configureHighlighter called after highlighter was created')\n return\n }\n\n highlighterPromise = createHighlighterCore({\n themes: [options.theme ?? defaultTheme],\n langs: options.langs ?? defaultLangs,\n engine: createJavaScriptRegexEngine(),\n })\n}\n","import { Head, Link, usePage } from '@inertiajs/react'\nimport { useState } from 'react'\nimport { Sidebar } from './Sidebar'\nimport type { DocsLayoutProps, SharedProps } from '../types'\n\nfunction MobileMenuButton({ onClick, isOpen }: { onClick: () => void; isOpen: boolean }) {\n return (\n <button\n onClick={onClick}\n className=\"inline-flex items-center justify-center p-2 -ml-2 text-black hover:text-primary-500 lg:hidden\"\n aria-expanded={isOpen}\n >\n <span className=\"sr-only\">{isOpen ? 'Close menu' : 'Open menu'}</span>\n {isOpen ? (\n <svg className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n ) : (\n <svg className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6h16M4 12h16M4 18h16\" />\n </svg>\n )}\n </button>\n )\n}\n\nfunction GitHubIcon() {\n return (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n fillRule=\"evenodd\"\n d=\"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )\n}\n\n/**\n * Full-featured documentation layout with sidebar, mobile menu, and header.\n */\nexport function DocsLayout({\n children,\n title,\n description: _description,\n logo,\n logoInverted,\n logoUrl: propLogoUrl,\n logoInvertedUrl: propLogoInvertedUrl,\n githubUrl: propGithubUrl,\n navLinks: propNavLinks,\n footer,\n}: DocsLayoutProps) {\n const sharedProps = usePage<{ props: SharedProps }>().props as unknown as SharedProps\n const { nav, currentPath } = sharedProps\n const [mobileMenuOpen, setMobileMenuOpen] = useState(false)\n\n // Merge props - component props take precedence over shared props from Python\n const logoUrl = propLogoUrl ?? sharedProps.logoUrl\n const logoInvertedUrl = propLogoInvertedUrl ?? sharedProps.logoInvertedUrl\n const githubUrl = propGithubUrl ?? sharedProps.githubUrl\n const navLinks = propNavLinks ?? sharedProps.navLinks ?? []\n\n // Determine which logo to display in header (prefer inverted/dark version)\n const headerLogo = logoInverted || logo || (logoInvertedUrl ? (\n <img src={logoInvertedUrl} alt=\"Logo\" className=\"h-8\" />\n ) : logoUrl ? (\n <img src={logoUrl} alt=\"Logo\" className=\"h-8\" />\n ) : null)\n\n // Determine which logo to display in footer (prefer footer-specific logo)\n const footerLogoUrl = sharedProps.footerLogoUrl || logoUrl\n const footerLogo = logo || (footerLogoUrl ? (\n <img src={footerLogoUrl} alt=\"Logo\" className=\"h-6\" />\n ) : null)\n\n return (\n <div className=\"min-h-screen bg-white flex flex-col\">\n <Head title={title} />\n\n {/* Fixed navigation */}\n <nav className=\"fixed w-full z-50 bg-white border-b border-gray-200\">\n <div className=\"px-4 lg:px-10\">\n <div className=\"flex justify-between h-16 items-center\">\n <div className=\"flex items-center gap-2\">\n <MobileMenuButton onClick={() => setMobileMenuOpen(!mobileMenuOpen)} isOpen={mobileMenuOpen} />\n {headerLogo ? (\n <Link href=\"/\" className=\"flex items-center\">\n {headerLogo}\n </Link>\n ) : (\n <Link href=\"/\" className=\"font-bold text-lg\">\n Docs\n </Link>\n )}\n </div>\n <div className=\"flex items-center space-x-8\">\n {navLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className=\"text-black font-medium hover:text-primary-500 transition-colors\"\n >\n {link.label}\n </Link>\n ))}\n {githubUrl && (\n <a\n href={githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-black hover:text-primary-500 transition-colors\"\n >\n <GitHubIcon />\n </a>\n )}\n </div>\n </div>\n </div>\n </nav>\n\n {/* Mobile sidebar */}\n {mobileMenuOpen && (\n <div className=\"fixed inset-0 z-40 lg:hidden\">\n <div className=\"fixed inset-0 bg-black/50\" onClick={() => setMobileMenuOpen(false)} />\n <div className=\"fixed inset-y-0 left-0 w-72 overflow-y-auto bg-white px-4 lg:px-10 py-6 pt-20 border-r border-gray-200\">\n <Sidebar nav={nav} currentPath={currentPath} />\n </div>\n </div>\n )}\n\n {/* Main content area */}\n <div className=\"bg-white pt-16 w-full flex-1\">\n <div className=\"grid grid-cols-12\">\n {/* Desktop sidebar */}\n <aside className=\"hidden lg:block lg:col-span-3 xl:col-span-2 border-r border-gray-200 min-h-[calc(100vh-4rem)]\">\n <nav className=\"sticky top-16 px-4 lg:px-10 py-6 max-h-[calc(100vh-4rem)] overflow-y-auto\">\n <Sidebar nav={nav} currentPath={currentPath} />\n </nav>\n </aside>\n\n {/* Main content */}\n <main className=\"col-span-12 lg:col-span-9 xl:col-span-10 p-4 lg:px-10 lg:py-6\">\n <article className=\"prose prose-lg max-w-3xl prose-headings:font-bold prose-headings:tracking-tight prose-h1:text-3xl prose-h1:mb-4 prose-h2:text-2xl prose-h2:mt-10 first:prose-h2:mt-0 prose-h3:text-xl prose-a:text-primary-600 prose-a:no-underline hover:prose-a:underline prose-code:bg-gray-100 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-code:before:content-none prose-code:after:content-none\">\n {children}\n </article>\n </main>\n </div>\n </div>\n\n {/* Footer */}\n {footer || (\n <footer className=\"border-t border-gray-200 py-8\">\n <div className=\"px-4 lg:px-10 flex flex-col md:flex-row justify-between items-center gap-6\">\n {footerLogo && <Link href=\"/\">{footerLogo}</Link>}\n <div className=\"flex gap-8 text-sm text-gray-600\">\n {navLinks.map((link) => (\n <Link key={link.href} href={link.href} className=\"hover:text-black transition-colors\">\n {link.label}\n </Link>\n ))}\n {githubUrl && (\n <a\n href={githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hover:text-black transition-colors\"\n >\n GitHub\n </a>\n )}\n </div>\n </div>\n </footer>\n )}\n </div>\n )\n}\n","import { Link } from '@inertiajs/react'\nimport { cn } from '../lib/utils'\nimport type { SidebarProps } from '../types'\n\n/**\n * Documentation sidebar with section-based navigation.\n */\nexport function Sidebar({ nav, currentPath, className }: SidebarProps) {\n return (\n <nav className={cn('space-y-8', className)}>\n {nav.map((section) => (\n <div key={section.title}>\n <h3 className=\"mb-3 text-xs font-mono uppercase tracking-widest text-gray-500\">\n {section.title}\n </h3>\n <ul className=\"space-y-1 border-l-2 border-gray-200\">\n {section.items.map((item) => (\n <li key={item.href}>\n <Link\n href={item.href}\n className={cn(\n 'block border-l-2 py-1.5 pl-4 text-sm transition-colors -ml-0.5',\n currentPath === item.href\n ? 'border-primary-500 text-black font-bold'\n : 'border-transparent text-gray-600 hover:border-black hover:text-black'\n )}\n >\n {item.title}\n </Link>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </nav>\n )\n}\n","import ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport rehypeRaw from 'rehype-raw'\nimport { CodeBlock } from './CodeBlock'\nimport type { MarkdownProps } from '../types'\n\n/**\n * Markdown renderer with syntax highlighting and GFM support.\n */\nexport function Markdown({ content, components }: MarkdownProps) {\n return (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={[rehypeRaw]}\n components={{\n // Override pre to avoid double wrapping with CodeBlock\n pre({ children }) {\n return <>{children}</>\n },\n // Custom code block rendering with syntax highlighting\n code({ node, className, children, ...props }) {\n const match = /language-(\\w+)/.exec(className || '')\n const isInline = !match && !className\n\n if (isInline) {\n return (\n <code\n className=\"rounded bg-gray-100 px-1.5 py-0.5 text-sm font-medium text-gray-800 dark:bg-gray-800 dark:text-gray-200\"\n {...props}\n >\n {children}\n </code>\n )\n }\n\n // Parse meta string from the code fence (e.g., ```python title=\"app.py\" showLineNumbers)\n const meta = (node?.data?.meta as string) || ''\n const titleMatch = /title=\"([^\"]+)\"/.exec(meta)\n const filename = titleMatch ? titleMatch[1] : undefined\n const showLineNumbers = meta.includes('showLineNumbers')\n\n return (\n <CodeBlock\n code={String(children).replace(/\\n$/, '')}\n language={match ? match[1] : 'text'}\n filename={filename}\n showLineNumbers={showLineNumbers}\n />\n )\n },\n // Custom link styling\n a({ href, children }) {\n const isExternal = href?.startsWith('http')\n return (\n <a\n href={href}\n className=\"text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300\"\n {...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}\n >\n {children}\n </a>\n )\n },\n // Tables\n table({ children }) {\n return (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-left text-sm\">{children}</table>\n </div>\n )\n },\n th({ children }) {\n return (\n <th className=\"border-b border-gray-200 bg-gray-50 px-4 py-2 font-semibold dark:border-gray-700 dark:bg-gray-800\">\n {children}\n </th>\n )\n },\n td({ children }) {\n return (\n <td className=\"border-b border-gray-200 px-4 py-2 dark:border-gray-700\">\n {children}\n </td>\n )\n },\n // Allow component overrides\n ...components,\n }}\n >\n {content}\n </ReactMarkdown>\n )\n}\n","import { DocsLayout } from './DocsLayout'\nimport { Markdown } from './Markdown'\nimport type { DocContent, DocsLayoutProps } from '../types'\n\ninterface DocsPageProps extends Omit<DocsLayoutProps, 'children' | 'title'> {\n content: DocContent\n}\n\n/**\n * Default documentation page component.\n * Renders markdown content within the DocsLayout.\n */\nexport function DocsPage({ content, ...layoutProps }: DocsPageProps) {\n return (\n <DocsLayout title={content?.title ?? ''} description={content?.description} {...layoutProps}>\n <Markdown content={content?.body ?? ''} />\n </DocsLayout>\n )\n}\n","import { Head, Link } from '@inertiajs/react'\nimport { createContext, useContext, useState, type ReactNode } from 'react'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface HomeFeature {\n title: string\n description: ReactNode\n}\n\nexport interface HomePageContextValue {\n title: string\n tagline: string\n description: string\n installCommand: string\n ctaText: string\n ctaHref: string\n features: HomeFeature[]\n logoUrl?: string\n heroLogoUrl?: string\n footerLogoUrl?: string\n githubUrl?: string\n navLinks: Array<{ label: string; href: string }>\n}\n\nexport interface HomePageProps extends Omit<HomePageContextValue, 'navLinks'> {\n navLinks?: Array<{ label: string; href: string }>\n children?: ReactNode\n}\n\nexport interface HomeHeaderProps {\n renderLogo?: () => ReactNode\n}\n\nexport interface HomeFeaturesProps {\n renderFeature?: (\n feature: HomeFeature,\n index: number,\n DefaultFeature: typeof HomeFeatureItem\n ) => ReactNode\n}\n\nexport interface HomeFeatureItemProps {\n feature: HomeFeature\n index: number\n totalFeatures: number\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst HomePageContext = createContext<HomePageContextValue | null>(null)\n\nfunction useHomePage(): HomePageContextValue {\n const context = useContext(HomePageContext)\n if (!context) {\n throw new Error('HomePage sub-components must be used within <HomePage>')\n }\n return context\n}\n\n// ============================================================================\n// Utility Components\n// ============================================================================\n\nfunction InstallCommand({ command }: { command: string }) {\n const [copied, setCopied] = useState(false)\n\n const copyToClipboard = async () => {\n await navigator.clipboard.writeText(command)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n\n return (\n <button\n onClick={copyToClipboard}\n className=\"group relative flex items-center bg-black border border-black px-4 h-14 font-mono text-sm text-white hover:bg-white hover:text-black transition-colors cursor-pointer\"\n >\n <span className=\"text-primary-500 mr-2\">$</span>\n <span>{command}</span>\n <svg\n className={`ml-4 w-4 h-4 transition ${copied ? 'text-green-400' : 'opacity-50 group-hover:opacity-100'}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n </svg>\n <span\n className={`absolute -top-8 left-1/2 -translate-x-1/2 bg-black text-white text-xs py-1 px-2 rounded transition-opacity duration-300 whitespace-nowrap ${\n copied ? 'opacity-100' : 'opacity-0'\n }`}\n >\n Copied!\n </span>\n </button>\n )\n}\n\nfunction GitHubIcon() {\n return (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n fillRule=\"evenodd\"\n d=\"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )\n}\n\n// ============================================================================\n// Sub-Components\n// ============================================================================\n\n/**\n * Default logo component that renders an image or text.\n */\nfunction DefaultLogo() {\n const { title, logoUrl } = useHomePage()\n\n if (logoUrl) {\n return (\n <Link href=\"/\" className=\"flex items-center\">\n <img src={logoUrl} alt={title} className=\"h-8\" />\n </Link>\n )\n }\n\n return (\n <Link href=\"/\" className=\"font-bold text-lg\">\n {title}\n </Link>\n )\n}\n\n/**\n * Navigation header for the homepage.\n * Accepts an optional renderLogo prop for custom logo rendering.\n */\nexport function HomeHeader({ renderLogo }: HomeHeaderProps = {}) {\n const { navLinks, githubUrl } = useHomePage()\n\n return (\n <nav className=\"fixed w-full z-50 bg-white border-b border-gray-200\">\n <div className=\"px-4 lg:px-10\">\n <div className=\"flex justify-between h-16 items-center\">\n {renderLogo ? renderLogo() : <DefaultLogo />}\n <div className=\"flex items-center space-x-8\">\n {navLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className=\"text-black font-medium hover:text-primary-500 transition-colors\"\n >\n {link.label}\n </Link>\n ))}\n {githubUrl && (\n <a\n href={githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-black hover:text-primary-500 transition-colors\"\n >\n <GitHubIcon />\n </a>\n )}\n </div>\n </div>\n </div>\n </nav>\n )\n}\n\n/**\n * Hero section with title, tagline, description, and CTA.\n * If heroLogoUrl is provided, displays an image instead of text title.\n */\nexport function HomeHero() {\n const { title, tagline, description, ctaText, ctaHref, installCommand, heroLogoUrl } = useHomePage()\n\n return (\n <section className=\"pt-16\">\n <div className=\"px-4 lg:px-10 py-16 lg:py-24\">\n <div className=\"max-w-4xl\">\n <div className=\"mb-4 text-sm font-mono uppercase tracking-widest text-gray-500\">\n {tagline}\n </div>\n {heroLogoUrl ? (\n <h1 className=\"mb-6 lg:mb-8\">\n <img\n src={heroLogoUrl}\n alt={title}\n className=\"h-auto w-auto max-w-[580px]\"\n />\n </h1>\n ) : (\n <h1 className=\"text-5xl lg:text-7xl font-bold tracking-tight mb-6\">\n {title}\n </h1>\n )}\n <p className=\"text-xl lg:text-2xl text-gray-700 max-w-2xl leading-relaxed mb-8\">\n {description}\n </p>\n\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <Link\n href={ctaHref}\n className=\"inline-flex items-center justify-center px-8 h-14 bg-black text-white font-bold text-lg hover:bg-primary-500 transition-colors border border-black\"\n >\n {ctaText}\n </Link>\n {installCommand && <InstallCommand command={installCommand} />}\n </div>\n </div>\n </div>\n </section>\n )\n}\n\n/**\n * Single feature item within the features grid.\n */\nexport function HomeFeatureItem({ feature, index, totalFeatures }: HomeFeatureItemProps) {\n return (\n <div\n className={`p-4 lg:p-10 border-b sm:border-b border-gray-200 ${\n index % 2 === 0 ? 'sm:border-r' : ''\n } ${index >= totalFeatures - 2 ? 'sm:border-b-0' : ''} ${\n index === totalFeatures - 1 && totalFeatures % 2 === 1 ? 'border-b-0' : ''\n }`}\n >\n <div className=\"text-5xl font-bold text-primary-500 mb-4\">\n {String(index + 1).padStart(2, '0')}\n </div>\n <h3 className=\"text-xl font-bold mb-2\">{feature.title}</h3>\n <p className=\"text-gray-600\">{feature.description}</p>\n </div>\n )\n}\n\n/**\n * Features section with customizable feature rendering.\n */\nexport function HomeFeatures({ renderFeature }: HomeFeaturesProps = {}) {\n const { title, features } = useHomePage()\n\n if (features.length === 0) {\n return null\n }\n\n return (\n <section className=\"border-t border-gray-200\">\n <div className=\"grid grid-cols-12\">\n <div className=\"col-span-12 lg:col-span-4 p-4 lg:p-10 border-b lg:border-b-0 lg:border-r border-gray-200\">\n <div className=\"text-sm font-mono uppercase tracking-widest text-gray-500 mb-4\">\n Features\n </div>\n <h2 className=\"text-4xl lg:text-5xl font-bold tracking-tight\">\n Why {title}?\n </h2>\n </div>\n\n <div className=\"col-span-12 lg:col-span-8 grid grid-cols-1 sm:grid-cols-2\">\n {features.map((feature, index) =>\n renderFeature ? (\n <div key={index}>\n {renderFeature(feature, index, HomeFeatureItem)}\n </div>\n ) : (\n <HomeFeatureItem\n key={index}\n feature={feature}\n index={index}\n totalFeatures={features.length}\n />\n )\n )}\n </div>\n </div>\n </section>\n )\n}\n\n/**\n * Call-to-action section.\n */\nexport function HomeCTA() {\n const { ctaHref } = useHomePage()\n\n return (\n <section className=\"border-t border-gray-200\">\n <div className=\"grid grid-cols-12 items-center\">\n <div className=\"col-span-12 lg:col-span-8 p-4 lg:p-10\">\n <h2 className=\"text-4xl lg:text-6xl font-bold tracking-tight mb-4\">\n Ready to start?\n </h2>\n <p className=\"text-xl text-gray-600 mb-8 max-w-2xl\">\n Get up and running in minutes. Check out our documentation to learn more.\n </p>\n <Link\n href={ctaHref}\n className=\"inline-flex items-center justify-center px-8 py-4 bg-primary-500 text-white font-bold text-lg hover:bg-black transition-colors border border-primary-500 hover:border-black\"\n >\n Read the Docs\n </Link>\n </div>\n <Link\n href={ctaHref}\n className=\"col-span-12 lg:col-span-4 h-full bg-primary-500 hidden lg:flex items-center justify-center p-4 lg:p-10 hover:bg-black transition-colors min-h-[200px]\"\n >\n <div className=\"text-white text-8xl font-bold\">→</div>\n </Link>\n </div>\n </section>\n )\n}\n\n/**\n * Footer section.\n */\nexport function HomeFooter() {\n const { title, logoUrl, footerLogoUrl, navLinks, githubUrl } = useHomePage()\n\n return (\n <footer className=\"border-t border-gray-200 py-8\">\n <div className=\"px-4 lg:px-10 flex flex-col md:flex-row justify-between items-center gap-6\">\n {(footerLogoUrl || logoUrl) && (\n <Link href=\"/\">\n <img src={footerLogoUrl || logoUrl} alt={title} className=\"h-6\" />\n </Link>\n )}\n <div className=\"flex gap-8 text-sm text-gray-600\">\n {navLinks.map((link) => (\n <Link key={link.href} href={link.href} className=\"hover:text-black transition-colors\">\n {link.label}\n </Link>\n ))}\n {githubUrl && (\n <a\n href={githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hover:text-black transition-colors\"\n >\n GitHub\n </a>\n )}\n </div>\n </div>\n </footer>\n )\n}\n\n/**\n * Default layout when no children are provided.\n */\nfunction DefaultHomeLayout() {\n return (\n <>\n <HomeHeader />\n <HomeHero />\n <HomeFeatures />\n <HomeCTA />\n <HomeFooter />\n </>\n )\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\n/**\n * Homepage component for documentation sites.\n *\n * Can be used in two ways:\n *\n * 1. Simple - everything from config:\n * ```tsx\n * <HomePage {...props} />\n * ```\n *\n * 2. Composable - full control via children:\n * ```tsx\n * <HomePage {...props}>\n * <HomePage.Header />\n * <HomePage.Hero />\n * <MyCustomSection />\n * <HomePage.Features renderFeature={(feature, i, Default) => (\n * <Default feature={feature} index={i} totalFeatures={4} />\n * )} />\n * <HomePage.CTA />\n * <HomePage.Footer />\n * </HomePage>\n * ```\n */\nexport function HomePage({\n children,\n navLinks = [],\n ...props\n}: HomePageProps) {\n const contextValue: HomePageContextValue = {\n ...props,\n navLinks,\n }\n\n return (\n <HomePageContext.Provider value={contextValue}>\n <div className=\"min-h-screen bg-white\">\n <Head title={props.title} />\n {children || <DefaultHomeLayout />}\n </div>\n </HomePageContext.Provider>\n )\n}\n\n// Attach sub-components for compound component pattern\nHomePage.Header = HomeHeader\nHomePage.Hero = HomeHero\nHomePage.Features = HomeFeatures\nHomePage.Feature = HomeFeatureItem\nHomePage.CTA = HomeCTA\nHomePage.Footer = HomeFooter\n","import { createInertiaApp } from '@inertiajs/react'\nimport { createRoot, hydrateRoot } from 'react-dom/client'\nimport type { DocsAppConfig } from './types'\n\n/**\n * Create and mount an Inertia.js documentation app.\n *\n * @example\n * ```tsx\n * import { createDocsApp, DocsPage } from '@usecross/docs'\n *\n * createDocsApp({\n * pages: {\n * 'docs/DocsPage': DocsPage,\n * },\n * title: (title) => `${title} - My Docs`,\n * })\n * ```\n */\nexport function createDocsApp(config: DocsAppConfig): void {\n const { pages, title } = config\n\n // Disable scroll restoration on initial page load\n if (typeof window !== 'undefined') {\n window.history.scrollRestoration = 'manual'\n window.scrollTo(0, 0)\n }\n\n createInertiaApp({\n title: title ?? ((pageTitle) => (pageTitle ? `${pageTitle}` : 'Documentation')),\n resolve: (name) => {\n const page = pages[name]\n if (!page) {\n throw new Error(`Page component \"${name}\" not found`)\n }\n return page\n },\n setup({ el, App, props }) {\n if (el.hasChildNodes()) {\n hydrateRoot(el, <App {...props} />)\n } else {\n createRoot(el).render(<App {...props} />)\n }\n },\n })\n}\n"],"mappings":"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","names":["Link","useState","jsx","jsxs","jsx","jsxs","useState","Link","jsx","jsx","Head","Link","useState","Fragment","jsx","jsxs","GitHubIcon","jsx"]}
|
package/dist/ssr.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { b as DocsAppConfig } from './types-Vodb50Bj.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create an SSR server for documentation.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { createDocsServer, DocsPage } from '@usecross/docs'
|
|
10
|
+
*
|
|
11
|
+
* createDocsServer({
|
|
12
|
+
* pages: {
|
|
13
|
+
* 'docs/DocsPage': DocsPage,
|
|
14
|
+
* },
|
|
15
|
+
* title: (title) => `${title} - My Docs`,
|
|
16
|
+
* })
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
declare function createDocsServer(config: DocsAppConfig): void;
|
|
20
|
+
|
|
21
|
+
export { createDocsServer };
|
package/dist/ssr.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/ssr.tsx
|
|
2
|
+
import { createInertiaApp } from "@inertiajs/react";
|
|
3
|
+
import createServer from "@inertiajs/react/server";
|
|
4
|
+
import ReactDOMServer from "react-dom/server";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
function createDocsServer(config) {
|
|
7
|
+
const { pages, title } = config;
|
|
8
|
+
createServer(
|
|
9
|
+
(page) => createInertiaApp({
|
|
10
|
+
page,
|
|
11
|
+
render: ReactDOMServer.renderToString,
|
|
12
|
+
title: title ?? ((pageTitle) => pageTitle ? `${pageTitle}` : "Documentation"),
|
|
13
|
+
resolve: (name) => {
|
|
14
|
+
const pageComponent = pages[name];
|
|
15
|
+
if (!pageComponent) {
|
|
16
|
+
throw new Error(`Page component "${name}" not found`);
|
|
17
|
+
}
|
|
18
|
+
return pageComponent;
|
|
19
|
+
},
|
|
20
|
+
setup: ({ App, props }) => /* @__PURE__ */ jsx(App, { ...props })
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
createDocsServer
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=ssr.js.map
|
package/dist/ssr.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ssr.tsx"],"sourcesContent":["import { createInertiaApp } from '@inertiajs/react'\nimport createServer from '@inertiajs/react/server'\nimport ReactDOMServer from 'react-dom/server'\nimport type { DocsAppConfig } from './types'\n\n/**\n * Create an SSR server for documentation.\n *\n * @example\n * ```tsx\n * import { createDocsServer, DocsPage } from '@usecross/docs'\n *\n * createDocsServer({\n * pages: {\n * 'docs/DocsPage': DocsPage,\n * },\n * title: (title) => `${title} - My Docs`,\n * })\n * ```\n */\nexport function createDocsServer(config: DocsAppConfig): void {\n const { pages, title } = config\n\n createServer((page) =>\n createInertiaApp({\n page,\n render: ReactDOMServer.renderToString,\n title: title ?? ((pageTitle) => (pageTitle ? `${pageTitle}` : 'Documentation')),\n resolve: (name) => {\n const pageComponent = pages[name]\n if (!pageComponent) {\n throw new Error(`Page component \"${name}\" not found`)\n }\n return pageComponent\n },\n setup: ({ App, props }) => <App {...props} />,\n })\n )\n}\n"],"mappings":";AAAA,SAAS,wBAAwB;AACjC,OAAO,kBAAkB;AACzB,OAAO,oBAAoB;AAiCM;AAf1B,SAAS,iBAAiB,QAA6B;AAC5D,QAAM,EAAE,OAAO,MAAM,IAAI;AAEzB;AAAA,IAAa,CAAC,SACZ,iBAAiB;AAAA,MACf;AAAA,MACA,QAAQ,eAAe;AAAA,MACvB,OAAO,UAAU,CAAC,cAAe,YAAY,GAAG,SAAS,KAAK;AAAA,MAC9D,SAAS,CAAC,SAAS;AACjB,cAAM,gBAAgB,MAAM,IAAI;AAChC,YAAI,CAAC,eAAe;AAClB,gBAAM,IAAI,MAAM,mBAAmB,IAAI,aAAa;AAAA,QACtD;AACA,eAAO;AAAA,MACT;AAAA,MACA,OAAO,CAAC,EAAE,KAAK,MAAM,MAAM,oBAAC,OAAK,GAAG,OAAO;AAAA,IAC7C,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cross-Docs TypeScript type definitions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Single navigation item */
|
|
8
|
+
interface NavItem {
|
|
9
|
+
title: string;
|
|
10
|
+
href: string;
|
|
11
|
+
}
|
|
12
|
+
/** Navigation section containing multiple items */
|
|
13
|
+
interface NavSection {
|
|
14
|
+
title: string;
|
|
15
|
+
items: NavItem[];
|
|
16
|
+
}
|
|
17
|
+
/** Shared props passed to all pages via Inertia */
|
|
18
|
+
interface SharedProps {
|
|
19
|
+
nav: NavSection[];
|
|
20
|
+
currentPath: string;
|
|
21
|
+
/** Logo image URL (from Python backend) */
|
|
22
|
+
logoUrl?: string;
|
|
23
|
+
/** Logo image URL for dark/inverted contexts (from Python backend) */
|
|
24
|
+
logoInvertedUrl?: string;
|
|
25
|
+
/** Footer logo image URL (from Python backend) */
|
|
26
|
+
footerLogoUrl?: string;
|
|
27
|
+
/** GitHub repository URL (from Python backend) */
|
|
28
|
+
githubUrl?: string;
|
|
29
|
+
/** Additional navigation links (from Python backend) */
|
|
30
|
+
navLinks?: Array<{
|
|
31
|
+
label: string;
|
|
32
|
+
href: string;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
/** Document content structure */
|
|
36
|
+
interface DocContent {
|
|
37
|
+
title: string;
|
|
38
|
+
description: string;
|
|
39
|
+
body: string;
|
|
40
|
+
}
|
|
41
|
+
/** Props for DocsLayout component */
|
|
42
|
+
interface DocsLayoutProps {
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
title: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
/** Custom logo component (React node) */
|
|
47
|
+
logo?: ReactNode;
|
|
48
|
+
/** Custom logo for dark/inverted contexts (React node) */
|
|
49
|
+
logoInverted?: ReactNode;
|
|
50
|
+
/** Logo image URL (alternative to logo prop, can be passed from backend) */
|
|
51
|
+
logoUrl?: string;
|
|
52
|
+
/** Logo image URL for dark/inverted contexts */
|
|
53
|
+
logoInvertedUrl?: string;
|
|
54
|
+
/** GitHub repository URL (shows GitHub icon in nav) */
|
|
55
|
+
githubUrl?: string;
|
|
56
|
+
/** Additional navigation links */
|
|
57
|
+
navLinks?: Array<{
|
|
58
|
+
label: string;
|
|
59
|
+
href: string;
|
|
60
|
+
}>;
|
|
61
|
+
/** Custom footer component */
|
|
62
|
+
footer?: ReactNode;
|
|
63
|
+
}
|
|
64
|
+
/** Props for Sidebar component */
|
|
65
|
+
interface SidebarProps {
|
|
66
|
+
nav: NavSection[];
|
|
67
|
+
currentPath: string;
|
|
68
|
+
className?: string;
|
|
69
|
+
}
|
|
70
|
+
/** Props for Markdown component */
|
|
71
|
+
interface MarkdownProps {
|
|
72
|
+
content: string;
|
|
73
|
+
/** Override default markdown components */
|
|
74
|
+
components?: Record<string, React.ComponentType<any>>;
|
|
75
|
+
}
|
|
76
|
+
/** Props for CodeBlock component */
|
|
77
|
+
interface CodeBlockProps {
|
|
78
|
+
code: string;
|
|
79
|
+
language?: string;
|
|
80
|
+
filename?: string;
|
|
81
|
+
showLineNumbers?: boolean;
|
|
82
|
+
theme?: string;
|
|
83
|
+
className?: string;
|
|
84
|
+
}
|
|
85
|
+
/** Configuration for createDocsApp */
|
|
86
|
+
interface DocsAppConfig {
|
|
87
|
+
pages: Record<string, React.ComponentType<any>>;
|
|
88
|
+
title?: (pageTitle: string) => string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type { CodeBlockProps as C, DocsLayoutProps as D, MarkdownProps as M, NavItem as N, SidebarProps as S, DocContent as a, DocsAppConfig as b, NavSection as c, SharedProps as d };
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@usecross/docs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Documentation framework built on Cross-Inertia",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"development": "./src/index.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./ssr": {
|
|
16
|
+
"types": "./dist/ssr.d.ts",
|
|
17
|
+
"development": "./src/ssr.tsx",
|
|
18
|
+
"default": "./dist/ssr.js"
|
|
19
|
+
},
|
|
20
|
+
"./styles.css": "./src/styles.css",
|
|
21
|
+
"./tailwind.preset": "./src/tailwind.preset.cjs"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"src"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"dev": "tsup --watch",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"lint": "eslint src",
|
|
32
|
+
"prepublishOnly": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"documentation",
|
|
36
|
+
"inertia",
|
|
37
|
+
"react",
|
|
38
|
+
"fastapi",
|
|
39
|
+
"ssr",
|
|
40
|
+
"cross-inertia"
|
|
41
|
+
],
|
|
42
|
+
"author": "Patrick Arminio <patrick.arminio@gmail.com>",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/usecross/cross-docs.git",
|
|
47
|
+
"directory": "js"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://cross-docs.dev",
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"clsx": "^2.1.1",
|
|
52
|
+
"react-markdown": "^10.1.0",
|
|
53
|
+
"rehype-raw": "^7.0.0",
|
|
54
|
+
"remark-gfm": "^4.0.1",
|
|
55
|
+
"shiki": "^1.24.0",
|
|
56
|
+
"tailwind-merge": "^2.6.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@inertiajs/react": "^2.0.0",
|
|
60
|
+
"@tailwindcss/typography": "^0.5.0",
|
|
61
|
+
"react": "^18.0.0",
|
|
62
|
+
"react-dom": "^18.0.0",
|
|
63
|
+
"tailwindcss": "^3.0.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/react": "^18.3.3",
|
|
67
|
+
"@types/react-dom": "^18.3.0",
|
|
68
|
+
"tsup": "^8.3.5",
|
|
69
|
+
"typescript": "^5.5.3"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/app.tsx
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createInertiaApp } from '@inertiajs/react'
|
|
2
|
+
import { createRoot, hydrateRoot } from 'react-dom/client'
|
|
3
|
+
import type { DocsAppConfig } from './types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create and mount an Inertia.js documentation app.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { createDocsApp, DocsPage } from '@usecross/docs'
|
|
11
|
+
*
|
|
12
|
+
* createDocsApp({
|
|
13
|
+
* pages: {
|
|
14
|
+
* 'docs/DocsPage': DocsPage,
|
|
15
|
+
* },
|
|
16
|
+
* title: (title) => `${title} - My Docs`,
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function createDocsApp(config: DocsAppConfig): void {
|
|
21
|
+
const { pages, title } = config
|
|
22
|
+
|
|
23
|
+
// Disable scroll restoration on initial page load
|
|
24
|
+
if (typeof window !== 'undefined') {
|
|
25
|
+
window.history.scrollRestoration = 'manual'
|
|
26
|
+
window.scrollTo(0, 0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
createInertiaApp({
|
|
30
|
+
title: title ?? ((pageTitle) => (pageTitle ? `${pageTitle}` : 'Documentation')),
|
|
31
|
+
resolve: (name) => {
|
|
32
|
+
const page = pages[name]
|
|
33
|
+
if (!page) {
|
|
34
|
+
throw new Error(`Page component "${name}" not found`)
|
|
35
|
+
}
|
|
36
|
+
return page
|
|
37
|
+
},
|
|
38
|
+
setup({ el, App, props }) {
|
|
39
|
+
if (el.hasChildNodes()) {
|
|
40
|
+
hydrateRoot(el, <App {...props} />)
|
|
41
|
+
} else {
|
|
42
|
+
createRoot(el).render(<App {...props} />)
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { cn } from '../lib/utils'
|
|
3
|
+
import { getHighlighter } from '../lib/shiki'
|
|
4
|
+
import type { CodeBlockProps } from '../types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Syntax-highlighted code block component using Shiki.
|
|
8
|
+
*/
|
|
9
|
+
export function CodeBlock({
|
|
10
|
+
code,
|
|
11
|
+
language = 'python',
|
|
12
|
+
filename,
|
|
13
|
+
showLineNumbers = false,
|
|
14
|
+
theme = 'github-dark-dimmed',
|
|
15
|
+
className,
|
|
16
|
+
}: CodeBlockProps) {
|
|
17
|
+
const [html, setHtml] = useState<string>('')
|
|
18
|
+
const [copied, setCopied] = useState(false)
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
async function highlight() {
|
|
22
|
+
const highlighter = await getHighlighter()
|
|
23
|
+
const langs = highlighter.getLoadedLanguages()
|
|
24
|
+
const lang = langs.includes(language) ? language : 'text'
|
|
25
|
+
const highlighted = highlighter.codeToHtml(code.trim(), {
|
|
26
|
+
lang,
|
|
27
|
+
theme,
|
|
28
|
+
})
|
|
29
|
+
setHtml(highlighted)
|
|
30
|
+
}
|
|
31
|
+
highlight()
|
|
32
|
+
}, [code, language, theme])
|
|
33
|
+
|
|
34
|
+
const copyToClipboard = async () => {
|
|
35
|
+
await navigator.clipboard.writeText(code.trim())
|
|
36
|
+
setCopied(true)
|
|
37
|
+
setTimeout(() => setCopied(false), 2000)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className={cn('group relative overflow-hidden rounded-lg bg-[#24292f] not-prose', className)}>
|
|
42
|
+
{filename && (
|
|
43
|
+
<div className="flex items-center gap-2 border-b border-slate-700 bg-slate-900 px-4 py-2 text-sm text-slate-400">
|
|
44
|
+
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
45
|
+
<path
|
|
46
|
+
strokeLinecap="round"
|
|
47
|
+
strokeLinejoin="round"
|
|
48
|
+
strokeWidth={2}
|
|
49
|
+
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
50
|
+
/>
|
|
51
|
+
</svg>
|
|
52
|
+
{filename}
|
|
53
|
+
</div>
|
|
54
|
+
)}
|
|
55
|
+
<button
|
|
56
|
+
onClick={copyToClipboard}
|
|
57
|
+
className="absolute right-2 top-2 z-10 rounded-md bg-slate-700/50 px-2 py-1 text-xs text-slate-400 opacity-0 transition-opacity hover:bg-slate-600 hover:text-white group-hover:opacity-100"
|
|
58
|
+
>
|
|
59
|
+
{copied ? 'Copied!' : 'Copy'}
|
|
60
|
+
</button>
|
|
61
|
+
{html ? (
|
|
62
|
+
<div
|
|
63
|
+
className={cn(
|
|
64
|
+
'overflow-x-auto text-sm [&_pre]:!m-0 [&_pre]:!bg-transparent [&_code]:!p-4',
|
|
65
|
+
showLineNumbers && '[&_code]:grid [&_code]:grid-cols-[auto_1fr]'
|
|
66
|
+
)}
|
|
67
|
+
dangerouslySetInnerHTML={{ __html: html }}
|
|
68
|
+
/>
|
|
69
|
+
) : (
|
|
70
|
+
<pre className="shiki overflow-x-auto !m-0 !bg-transparent">
|
|
71
|
+
<code className="block p-4 text-sm leading-relaxed text-gray-300">{code.trim()}</code>
|
|
72
|
+
</pre>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Simple inline code component.
|
|
80
|
+
*/
|
|
81
|
+
export function InlineCode({ children }: { children: React.ReactNode }) {
|
|
82
|
+
return (
|
|
83
|
+
<code className="rounded bg-slate-100 px-1.5 py-0.5 text-sm font-medium text-slate-800">
|
|
84
|
+
{children}
|
|
85
|
+
</code>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Head, Link, usePage } from '@inertiajs/react'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { Sidebar } from './Sidebar'
|
|
4
|
+
import type { DocsLayoutProps, SharedProps } from '../types'
|
|
5
|
+
|
|
6
|
+
function MobileMenuButton({ onClick, isOpen }: { onClick: () => void; isOpen: boolean }) {
|
|
7
|
+
return (
|
|
8
|
+
<button
|
|
9
|
+
onClick={onClick}
|
|
10
|
+
className="inline-flex items-center justify-center p-2 -ml-2 text-black hover:text-primary-500 lg:hidden"
|
|
11
|
+
aria-expanded={isOpen}
|
|
12
|
+
>
|
|
13
|
+
<span className="sr-only">{isOpen ? 'Close menu' : 'Open menu'}</span>
|
|
14
|
+
{isOpen ? (
|
|
15
|
+
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
16
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
17
|
+
</svg>
|
|
18
|
+
) : (
|
|
19
|
+
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
20
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
|
21
|
+
</svg>
|
|
22
|
+
)}
|
|
23
|
+
</button>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function GitHubIcon() {
|
|
28
|
+
return (
|
|
29
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
30
|
+
<path
|
|
31
|
+
fillRule="evenodd"
|
|
32
|
+
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
|
33
|
+
clipRule="evenodd"
|
|
34
|
+
/>
|
|
35
|
+
</svg>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Full-featured documentation layout with sidebar, mobile menu, and header.
|
|
41
|
+
*/
|
|
42
|
+
export function DocsLayout({
|
|
43
|
+
children,
|
|
44
|
+
title,
|
|
45
|
+
description: _description,
|
|
46
|
+
logo,
|
|
47
|
+
logoInverted,
|
|
48
|
+
logoUrl: propLogoUrl,
|
|
49
|
+
logoInvertedUrl: propLogoInvertedUrl,
|
|
50
|
+
githubUrl: propGithubUrl,
|
|
51
|
+
navLinks: propNavLinks,
|
|
52
|
+
footer,
|
|
53
|
+
}: DocsLayoutProps) {
|
|
54
|
+
const sharedProps = usePage<{ props: SharedProps }>().props as unknown as SharedProps
|
|
55
|
+
const { nav, currentPath } = sharedProps
|
|
56
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
|
57
|
+
|
|
58
|
+
// Merge props - component props take precedence over shared props from Python
|
|
59
|
+
const logoUrl = propLogoUrl ?? sharedProps.logoUrl
|
|
60
|
+
const logoInvertedUrl = propLogoInvertedUrl ?? sharedProps.logoInvertedUrl
|
|
61
|
+
const githubUrl = propGithubUrl ?? sharedProps.githubUrl
|
|
62
|
+
const navLinks = propNavLinks ?? sharedProps.navLinks ?? []
|
|
63
|
+
|
|
64
|
+
// Determine which logo to display in header (prefer inverted/dark version)
|
|
65
|
+
const headerLogo = logoInverted || logo || (logoInvertedUrl ? (
|
|
66
|
+
<img src={logoInvertedUrl} alt="Logo" className="h-8" />
|
|
67
|
+
) : logoUrl ? (
|
|
68
|
+
<img src={logoUrl} alt="Logo" className="h-8" />
|
|
69
|
+
) : null)
|
|
70
|
+
|
|
71
|
+
// Determine which logo to display in footer (prefer footer-specific logo)
|
|
72
|
+
const footerLogoUrl = sharedProps.footerLogoUrl || logoUrl
|
|
73
|
+
const footerLogo = logo || (footerLogoUrl ? (
|
|
74
|
+
<img src={footerLogoUrl} alt="Logo" className="h-6" />
|
|
75
|
+
) : null)
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className="min-h-screen bg-white flex flex-col">
|
|
79
|
+
<Head title={title} />
|
|
80
|
+
|
|
81
|
+
{/* Fixed navigation */}
|
|
82
|
+
<nav className="fixed w-full z-50 bg-white border-b border-gray-200">
|
|
83
|
+
<div className="px-4 lg:px-10">
|
|
84
|
+
<div className="flex justify-between h-16 items-center">
|
|
85
|
+
<div className="flex items-center gap-2">
|
|
86
|
+
<MobileMenuButton onClick={() => setMobileMenuOpen(!mobileMenuOpen)} isOpen={mobileMenuOpen} />
|
|
87
|
+
{headerLogo ? (
|
|
88
|
+
<Link href="/" className="flex items-center">
|
|
89
|
+
{headerLogo}
|
|
90
|
+
</Link>
|
|
91
|
+
) : (
|
|
92
|
+
<Link href="/" className="font-bold text-lg">
|
|
93
|
+
Docs
|
|
94
|
+
</Link>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
<div className="flex items-center space-x-8">
|
|
98
|
+
{navLinks.map((link) => (
|
|
99
|
+
<Link
|
|
100
|
+
key={link.href}
|
|
101
|
+
href={link.href}
|
|
102
|
+
className="text-black font-medium hover:text-primary-500 transition-colors"
|
|
103
|
+
>
|
|
104
|
+
{link.label}
|
|
105
|
+
</Link>
|
|
106
|
+
))}
|
|
107
|
+
{githubUrl && (
|
|
108
|
+
<a
|
|
109
|
+
href={githubUrl}
|
|
110
|
+
target="_blank"
|
|
111
|
+
rel="noopener noreferrer"
|
|
112
|
+
className="text-black hover:text-primary-500 transition-colors"
|
|
113
|
+
>
|
|
114
|
+
<GitHubIcon />
|
|
115
|
+
</a>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</nav>
|
|
121
|
+
|
|
122
|
+
{/* Mobile sidebar */}
|
|
123
|
+
{mobileMenuOpen && (
|
|
124
|
+
<div className="fixed inset-0 z-40 lg:hidden">
|
|
125
|
+
<div className="fixed inset-0 bg-black/50" onClick={() => setMobileMenuOpen(false)} />
|
|
126
|
+
<div className="fixed inset-y-0 left-0 w-72 overflow-y-auto bg-white px-4 lg:px-10 py-6 pt-20 border-r border-gray-200">
|
|
127
|
+
<Sidebar nav={nav} currentPath={currentPath} />
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
{/* Main content area */}
|
|
133
|
+
<div className="bg-white pt-16 w-full flex-1">
|
|
134
|
+
<div className="grid grid-cols-12">
|
|
135
|
+
{/* Desktop sidebar */}
|
|
136
|
+
<aside className="hidden lg:block lg:col-span-3 xl:col-span-2 border-r border-gray-200 min-h-[calc(100vh-4rem)]">
|
|
137
|
+
<nav className="sticky top-16 px-4 lg:px-10 py-6 max-h-[calc(100vh-4rem)] overflow-y-auto">
|
|
138
|
+
<Sidebar nav={nav} currentPath={currentPath} />
|
|
139
|
+
</nav>
|
|
140
|
+
</aside>
|
|
141
|
+
|
|
142
|
+
{/* Main content */}
|
|
143
|
+
<main className="col-span-12 lg:col-span-9 xl:col-span-10 p-4 lg:px-10 lg:py-6">
|
|
144
|
+
<article className="prose prose-lg max-w-3xl prose-headings:font-bold prose-headings:tracking-tight prose-h1:text-3xl prose-h1:mb-4 prose-h2:text-2xl prose-h2:mt-10 first:prose-h2:mt-0 prose-h3:text-xl prose-a:text-primary-600 prose-a:no-underline hover:prose-a:underline prose-code:bg-gray-100 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-code:before:content-none prose-code:after:content-none">
|
|
145
|
+
{children}
|
|
146
|
+
</article>
|
|
147
|
+
</main>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
{/* Footer */}
|
|
152
|
+
{footer || (
|
|
153
|
+
<footer className="border-t border-gray-200 py-8">
|
|
154
|
+
<div className="px-4 lg:px-10 flex flex-col md:flex-row justify-between items-center gap-6">
|
|
155
|
+
{footerLogo && <Link href="/">{footerLogo}</Link>}
|
|
156
|
+
<div className="flex gap-8 text-sm text-gray-600">
|
|
157
|
+
{navLinks.map((link) => (
|
|
158
|
+
<Link key={link.href} href={link.href} className="hover:text-black transition-colors">
|
|
159
|
+
{link.label}
|
|
160
|
+
</Link>
|
|
161
|
+
))}
|
|
162
|
+
{githubUrl && (
|
|
163
|
+
<a
|
|
164
|
+
href={githubUrl}
|
|
165
|
+
target="_blank"
|
|
166
|
+
rel="noopener noreferrer"
|
|
167
|
+
className="hover:text-black transition-colors"
|
|
168
|
+
>
|
|
169
|
+
GitHub
|
|
170
|
+
</a>
|
|
171
|
+
)}
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</footer>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
)
|
|
178
|
+
}
|