@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.
@@ -0,0 +1,9 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ /**
5
+ * Merge Tailwind CSS classes with clsx
6
+ */
7
+ export function cn(...inputs: ClassValue[]) {
8
+ return twMerge(clsx(inputs))
9
+ }
package/src/ssr.tsx ADDED
@@ -0,0 +1,39 @@
1
+ import { createInertiaApp } from '@inertiajs/react'
2
+ import createServer from '@inertiajs/react/server'
3
+ import ReactDOMServer from 'react-dom/server'
4
+ import type { DocsAppConfig } from './types'
5
+
6
+ /**
7
+ * Create an SSR server for documentation.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * import { createDocsServer, DocsPage } from '@usecross/docs'
12
+ *
13
+ * createDocsServer({
14
+ * pages: {
15
+ * 'docs/DocsPage': DocsPage,
16
+ * },
17
+ * title: (title) => `${title} - My Docs`,
18
+ * })
19
+ * ```
20
+ */
21
+ export function createDocsServer(config: DocsAppConfig): void {
22
+ const { pages, title } = config
23
+
24
+ createServer((page) =>
25
+ createInertiaApp({
26
+ page,
27
+ render: ReactDOMServer.renderToString,
28
+ title: title ?? ((pageTitle) => (pageTitle ? `${pageTitle}` : 'Documentation')),
29
+ resolve: (name) => {
30
+ const pageComponent = pages[name]
31
+ if (!pageComponent) {
32
+ throw new Error(`Page component "${name}" not found`)
33
+ }
34
+ return pageComponent
35
+ },
36
+ setup: ({ App, props }) => <App {...props} />,
37
+ })
38
+ )
39
+ }
package/src/styles.css ADDED
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Cross-Docs default styles
3
+ *
4
+ * Import this file in your app's CSS entry point:
5
+ * @import '@usecross/docs/styles.css';
6
+ *
7
+ * Then add Tailwind directives:
8
+ * @tailwind base;
9
+ * @tailwind components;
10
+ * @tailwind utilities;
11
+ */
12
+
13
+ @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&display=swap');
14
+
15
+ @layer base {
16
+ :root {
17
+ /* Font stacks */
18
+ --font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial,
19
+ sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
20
+ --font-heading: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
21
+ --font-mono: 'Fira Code', Consolas, Monaco, 'Andale Mono', monospace;
22
+
23
+ /* Code highlighting - matches Starlight/Expressive Code dark theme */
24
+ --shiki-color-text: #e2e8f0;
25
+ --shiki-color-background: #24292f;
26
+ --shiki-token-constant: #7dd3fc;
27
+ --shiki-token-string: #86efac;
28
+ --shiki-token-comment: #64748b;
29
+ --shiki-token-keyword: #f472b6;
30
+ --shiki-token-parameter: #e2e8f0;
31
+ --shiki-token-function: #c4b5fd;
32
+ --shiki-token-string-expression: #86efac;
33
+ --shiki-token-punctuation: #94a3b8;
34
+ --shiki-token-link: #38bdf8;
35
+ }
36
+
37
+ html {
38
+ /* Note: scroll-behavior: smooth removed to prevent animated scroll on page refresh */
39
+ }
40
+
41
+ /* Only apply smooth scrolling when navigating to anchor links */
42
+ html:focus-within {
43
+ scroll-behavior: smooth;
44
+ }
45
+
46
+ body {
47
+ @apply antialiased;
48
+ font-family: var(--font-sans);
49
+ font-weight: 400;
50
+ background: #ffffff;
51
+ color: #1f2937;
52
+ }
53
+
54
+ /* Headings use heading font */
55
+ h1, h2, h3, h4, h5, h6 {
56
+ font-family: var(--font-heading);
57
+ font-weight: 700;
58
+ }
59
+
60
+ /* Monospace fonts for code */
61
+ code, pre, kbd, samp {
62
+ font-family: var(--font-mono);
63
+ }
64
+ }
65
+
66
+ @layer components {
67
+ /* Prose content styles */
68
+ .prose {
69
+ font-size: 1rem;
70
+ line-height: 1.75;
71
+ }
72
+
73
+ /* Scroll margin for headings (so they don't hide under fixed header) */
74
+ .prose h1,
75
+ .prose h2,
76
+ .prose h3,
77
+ .prose h4,
78
+ .prose h5,
79
+ .prose h6 {
80
+ scroll-margin-top: 6rem;
81
+ }
82
+
83
+ /* Code block styling - rounded corners like Starlight */
84
+ .prose pre {
85
+ @apply !bg-[#24292f] !p-0 overflow-hidden rounded-lg;
86
+ }
87
+
88
+ .prose pre code {
89
+ @apply !bg-transparent !p-4 block overflow-x-auto text-sm;
90
+ }
91
+
92
+ /* Inline code styling */
93
+ .prose :not(pre) > code {
94
+ @apply bg-gray-100 px-1.5 py-0.5 rounded text-sm font-medium text-gray-800;
95
+ }
96
+
97
+ .prose :not(pre) > code::before,
98
+ .prose :not(pre) > code::after {
99
+ content: none;
100
+ }
101
+ }
102
+
103
+ /* Syntax highlighting - rounded corners like Starlight */
104
+ .shiki {
105
+ @apply !bg-[#24292f] overflow-hidden rounded-lg;
106
+ }
107
+
108
+ .shiki code {
109
+ @apply block p-4 overflow-x-auto text-sm leading-relaxed;
110
+ }
111
+
112
+ /* Scrollbar styling */
113
+ ::-webkit-scrollbar {
114
+ width: 8px;
115
+ height: 8px;
116
+ }
117
+
118
+ ::-webkit-scrollbar-track {
119
+ @apply bg-transparent;
120
+ }
121
+
122
+ ::-webkit-scrollbar-thumb {
123
+ @apply bg-gray-300 rounded-full;
124
+ }
125
+
126
+ ::-webkit-scrollbar-thumb:hover {
127
+ @apply bg-gray-400;
128
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Cross-Docs Tailwind CSS preset
3
+ *
4
+ * @example
5
+ * ```js
6
+ * // tailwind.config.js
7
+ * const docsPreset = require('@usecross/docs/tailwind.preset')
8
+ *
9
+ * module.exports = {
10
+ * presets: [docsPreset],
11
+ * content: [
12
+ * './frontend/**\/*.{ts,tsx}',
13
+ * './node_modules/@usecross/docs/**\/*.{js,tsx}',
14
+ * ],
15
+ * theme: {
16
+ * extend: {
17
+ * colors: {
18
+ * primary: { // Override with your brand colors },
19
+ * },
20
+ * },
21
+ * },
22
+ * }
23
+ * ```
24
+ */
25
+ module.exports = {
26
+ darkMode: 'class',
27
+ theme: {
28
+ extend: {
29
+ maxWidth: {
30
+ '8xl': '88rem',
31
+ },
32
+ fontFamily: {
33
+ sans: [
34
+ 'system-ui',
35
+ '-apple-system',
36
+ 'Segoe UI',
37
+ 'Roboto',
38
+ 'Helvetica',
39
+ 'Arial',
40
+ 'sans-serif',
41
+ 'Apple Color Emoji',
42
+ 'Segoe UI Emoji',
43
+ 'Segoe UI Symbol',
44
+ ],
45
+ heading: [
46
+ 'system-ui',
47
+ '-apple-system',
48
+ 'Segoe UI',
49
+ 'Roboto',
50
+ 'sans-serif',
51
+ ],
52
+ mono: ['Fira Code', 'Consolas', 'Monaco', 'Andale Mono', 'monospace'],
53
+ },
54
+ colors: {
55
+ // Default primary colors - sky blue (can be overridden)
56
+ primary: {
57
+ 50: '#f0f9ff',
58
+ 100: '#e0f2fe',
59
+ 200: '#bae6fd',
60
+ 300: '#7dd3fc',
61
+ 400: '#38bdf8',
62
+ 500: '#0ea5e9',
63
+ 600: '#0284c7',
64
+ 700: '#0369a1',
65
+ 800: '#075985',
66
+ 900: '#0c4a6e',
67
+ 950: '#082f49',
68
+ },
69
+ // Dark colors for code blocks
70
+ dark: {
71
+ 800: '#1e293b',
72
+ 900: '#0f172a',
73
+ },
74
+ },
75
+ typography: (theme) => ({
76
+ DEFAULT: {
77
+ css: {
78
+ maxWidth: 'none',
79
+ color: theme('colors.gray.700'),
80
+ a: {
81
+ color: theme('colors.primary.600'),
82
+ '&:hover': {
83
+ color: theme('colors.primary.700'),
84
+ },
85
+ },
86
+ 'code::before': {
87
+ content: '""',
88
+ },
89
+ 'code::after': {
90
+ content: '""',
91
+ },
92
+ code: {
93
+ backgroundColor: theme('colors.gray.100'),
94
+ padding: '0.25rem 0.375rem',
95
+ borderRadius: '0.25rem',
96
+ fontWeight: '500',
97
+ },
98
+ },
99
+ },
100
+ invert: {
101
+ css: {
102
+ color: theme('colors.gray.300'),
103
+ a: {
104
+ color: theme('colors.primary.400'),
105
+ '&:hover': {
106
+ color: theme('colors.primary.300'),
107
+ },
108
+ },
109
+ code: {
110
+ backgroundColor: theme('colors.gray.800'),
111
+ },
112
+ },
113
+ },
114
+ }),
115
+ },
116
+ },
117
+ plugins: [require('@tailwindcss/typography')],
118
+ }
package/src/types.ts ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Cross-Docs TypeScript type definitions
3
+ */
4
+
5
+ import type { ReactNode } from 'react'
6
+
7
+ /** Single navigation item */
8
+ export interface NavItem {
9
+ title: string
10
+ href: string
11
+ }
12
+
13
+ /** Navigation section containing multiple items */
14
+ export interface NavSection {
15
+ title: string
16
+ items: NavItem[]
17
+ }
18
+
19
+ /** Shared props passed to all pages via Inertia */
20
+ export interface SharedProps {
21
+ nav: NavSection[]
22
+ currentPath: string
23
+ /** Logo image URL (from Python backend) */
24
+ logoUrl?: string
25
+ /** Logo image URL for dark/inverted contexts (from Python backend) */
26
+ logoInvertedUrl?: string
27
+ /** Footer logo image URL (from Python backend) */
28
+ footerLogoUrl?: string
29
+ /** GitHub repository URL (from Python backend) */
30
+ githubUrl?: string
31
+ /** Additional navigation links (from Python backend) */
32
+ navLinks?: Array<{ label: string; href: string }>
33
+ }
34
+
35
+ /** Document content structure */
36
+ export interface DocContent {
37
+ title: string
38
+ description: string
39
+ body: string
40
+ }
41
+
42
+ /** Props for DocsLayout component */
43
+ export interface DocsLayoutProps {
44
+ children: ReactNode
45
+ title: string
46
+ description?: string
47
+ /** Custom logo component (React node) */
48
+ logo?: ReactNode
49
+ /** Custom logo for dark/inverted contexts (React node) */
50
+ logoInverted?: ReactNode
51
+ /** Logo image URL (alternative to logo prop, can be passed from backend) */
52
+ logoUrl?: string
53
+ /** Logo image URL for dark/inverted contexts */
54
+ logoInvertedUrl?: string
55
+ /** GitHub repository URL (shows GitHub icon in nav) */
56
+ githubUrl?: string
57
+ /** Additional navigation links */
58
+ navLinks?: Array<{ label: string; href: string }>
59
+ /** Custom footer component */
60
+ footer?: ReactNode
61
+ }
62
+
63
+ /** Props for Sidebar component */
64
+ export interface SidebarProps {
65
+ nav: NavSection[]
66
+ currentPath: string
67
+ className?: string
68
+ }
69
+
70
+ /** Props for Markdown component */
71
+ export interface MarkdownProps {
72
+ content: string
73
+ /** Override default markdown components */
74
+ components?: Record<string, React.ComponentType<any>>
75
+ }
76
+
77
+ /** Props for CodeBlock component */
78
+ export interface CodeBlockProps {
79
+ code: string
80
+ language?: string
81
+ filename?: string
82
+ showLineNumbers?: boolean
83
+ theme?: string
84
+ className?: string
85
+ }
86
+
87
+ /** Configuration for createDocsApp */
88
+ export interface DocsAppConfig {
89
+ pages: Record<string, React.ComponentType<any>>
90
+ title?: (pageTitle: string) => string
91
+ }