@farming-labs/docs 0.0.2-beta.2 → 0.0.2-beta.21

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.mts CHANGED
@@ -137,6 +137,13 @@ interface UIConfig {
137
137
  toc?: {
138
138
  enabled?: boolean;
139
139
  depth?: number;
140
+ /**
141
+ * Visual style of the TOC indicator.
142
+ * - `"default"` — highlight active link text color only
143
+ * - `"directional"` — animated thumb bar that tracks active headings (fumadocs style)
144
+ * @default "default"
145
+ */
146
+ style?: "default" | "directional";
140
147
  };
141
148
  header?: {
142
149
  height?: number;
@@ -223,6 +230,8 @@ interface PageFrontmatter {
223
230
  icon?: string;
224
231
  /** Path to custom OG image for this page */
225
232
  ogImage?: string;
233
+ /** Sort order in the sidebar. Lower numbers appear first. Pages without `order` are sorted alphabetically after ordered pages. */
234
+ order?: number;
226
235
  }
227
236
  interface DocsNav {
228
237
  /**
@@ -319,6 +328,17 @@ interface SidebarConfig {
319
328
  * @default true
320
329
  */
321
330
  collapsible?: boolean;
331
+ /**
332
+ * When true, all folder children are rendered flat in the sidebar
333
+ * (no collapsible sections). Folder index pages appear as category
334
+ * headings with all children listed directly below them.
335
+ *
336
+ * This creates a Mintlify-style sidebar where all navigation items
337
+ * are always visible.
338
+ *
339
+ * @default false
340
+ */
341
+ flat?: boolean;
322
342
  }
323
343
  /**
324
344
  * A single "Open in …" provider shown in the Open dropdown.
@@ -404,6 +424,39 @@ interface PageActionsConfig {
404
424
  * @default "below-title"
405
425
  */
406
426
  position?: "above-title" | "below-title";
427
+ /**
428
+ * Horizontal alignment of page action buttons.
429
+ *
430
+ * - `"left"` — align to the left (default)
431
+ * - `"right"` — align to the right
432
+ *
433
+ * @default "left"
434
+ */
435
+ alignment?: "left" | "right";
436
+ }
437
+ /**
438
+ * Configuration for the "Last updated" date display.
439
+ *
440
+ * @example
441
+ * ```ts
442
+ * lastUpdated: { position: "below-title" }
443
+ * ```
444
+ */
445
+ interface LastUpdatedConfig {
446
+ /**
447
+ * Whether to show the "Last updated" date.
448
+ * @default true
449
+ */
450
+ enabled?: boolean;
451
+ /**
452
+ * Where to render the "Last updated" date.
453
+ *
454
+ * - `"footer"` — next to the "Edit on GitHub" link at the bottom (default)
455
+ * - `"below-title"` — below the page title/description, above the content
456
+ *
457
+ * @default "footer"
458
+ */
459
+ position?: "footer" | "below-title";
407
460
  }
408
461
  /**
409
462
  * GitHub repository configuration for "Edit on GitHub" links
@@ -442,9 +495,295 @@ interface GithubConfig {
442
495
  */
443
496
  directory?: string;
444
497
  }
498
+ /**
499
+ * Configuration for "Ask AI" — a RAG-powered chat that lets users
500
+ * ask questions about the documentation content.
501
+ *
502
+ * The AI handler searches relevant doc pages, builds context, and
503
+ * streams a response from an LLM (OpenAI-compatible API).
504
+ *
505
+ * The API key is **never** stored in the config. It is read from the
506
+ * `OPENAI_API_KEY` environment variable at runtime on the server.
507
+ *
508
+ * @example
509
+ * ```ts
510
+ * ai: {
511
+ * enabled: true,
512
+ * model: "gpt-4o-mini",
513
+ * systemPrompt: "You are a helpful assistant for our developer docs.",
514
+ * }
515
+ * ```
516
+ */
517
+ interface AIConfig {
518
+ /**
519
+ * Whether to enable "Ask AI" functionality.
520
+ * When enabled, the unified `/api/docs` route handler will accept
521
+ * POST requests for AI chat.
522
+ * @default false
523
+ */
524
+ enabled?: boolean;
525
+ /**
526
+ * How the AI chat UI is presented.
527
+ *
528
+ * - `"search"` — AI tab integrated into the Cmd+K search dialog (default)
529
+ * - `"floating"` — A floating chat widget (bubble button + slide-out panel)
530
+ *
531
+ * @default "search"
532
+ *
533
+ * @example
534
+ * ```ts
535
+ * // Floating chat bubble in the bottom-right corner
536
+ * ai: {
537
+ * enabled: true,
538
+ * mode: "floating",
539
+ * position: "bottom-right",
540
+ * }
541
+ * ```
542
+ */
543
+ mode?: "search" | "floating" | "sidebar-icon";
544
+ /**
545
+ * Position of the floating chat button on screen.
546
+ * Only used when `mode` is `"floating"`.
547
+ *
548
+ * - `"bottom-right"` — bottom-right corner (default)
549
+ * - `"bottom-left"` — bottom-left corner
550
+ * - `"bottom-center"` — bottom center
551
+ *
552
+ * @default "bottom-right"
553
+ */
554
+ position?: "bottom-right" | "bottom-left" | "bottom-center";
555
+ /**
556
+ * Visual style of the floating chat when opened.
557
+ * Only used when `mode` is `"floating"`.
558
+ *
559
+ * - `"panel"` — A tall panel that slides up from the button position (default).
560
+ * Stays anchored near the floating button. No backdrop overlay.
561
+ *
562
+ * - `"modal"` — A centered modal dialog with a backdrop overlay,
563
+ * similar to the Cmd+K search dialog. Feels more focused and immersive.
564
+ *
565
+ * - `"popover"` — A compact popover near the button. Smaller than the
566
+ * panel, suitable for quick questions without taking much screen space.
567
+ *
568
+ * - `"full-modal"` — A full-screen immersive overlay (inspired by better-auth).
569
+ * Messages scroll in the center, input is pinned at the bottom.
570
+ * Suggested questions appear as horizontal pills. Best for
571
+ * documentation-heavy sites that want a premium AI experience.
572
+ *
573
+ * @default "panel"
574
+ *
575
+ * @example
576
+ * ```ts
577
+ * ai: {
578
+ * enabled: true,
579
+ * mode: "floating",
580
+ * position: "bottom-right",
581
+ * floatingStyle: "full-modal",
582
+ * }
583
+ * ```
584
+ */
585
+ floatingStyle?: "panel" | "modal" | "popover" | "full-modal";
586
+ /**
587
+ * Custom trigger component for the floating chat button (Next.js only).
588
+ * Only used when `mode` is `"floating"`.
589
+ *
590
+ * The click handler is attached automatically by the wrapper.
591
+ *
592
+ * - **Next.js**: Pass a JSX element via this config option.
593
+ * - **SvelteKit**: Use the `aiTrigger` snippet on `<DocsLayout>`.
594
+ * - **Nuxt / Vue**: Use the `ai-trigger` slot on `<DocsLayout>`.
595
+ * - **Astro**: Use `<MyTrigger slot="ai-trigger" />` on `<DocsLayout>`.
596
+ *
597
+ * @example
598
+ * ```tsx
599
+ * // Next.js — pass JSX directly in config
600
+ * triggerComponent: <button className="my-chat-btn">Ask AI</button>,
601
+ * ```
602
+ *
603
+ * ```svelte
604
+ * <!-- SvelteKit — use snippet in layout -->
605
+ * <DocsLayout {tree} {config}>
606
+ * {#snippet aiTrigger()}<AskAITrigger />{/snippet}
607
+ * {@render children()}
608
+ * </DocsLayout>
609
+ * ```
610
+ *
611
+ * ```vue
612
+ * <!-- Nuxt / Vue — use named slot in layout -->
613
+ * <DocsLayout :tree="tree" :config="config">
614
+ * <template #ai-trigger><AskAITrigger /></template>
615
+ * <DocsContent />
616
+ * </DocsLayout>
617
+ * ```
618
+ *
619
+ * ```astro
620
+ * <!-- Astro — use named slot in layout -->
621
+ * <DocsLayout tree={tree} config={config}>
622
+ * <AskAITrigger slot="ai-trigger" />
623
+ * <DocsContent />
624
+ * </DocsLayout>
625
+ * ```
626
+ */
627
+ triggerComponent?: unknown;
628
+ /**
629
+ * The LLM model to use for chat completions.
630
+ * Must be compatible with the OpenAI Chat Completions API.
631
+ * @default "gpt-4o-mini"
632
+ */
633
+ model?: string;
634
+ /**
635
+ * Custom system prompt prepended to the AI conversation.
636
+ * The documentation context is automatically appended after this prompt.
637
+ *
638
+ * @default "You are a helpful documentation assistant. Answer questions
639
+ * based on the provided documentation context. Be concise and accurate.
640
+ * If the answer is not in the context, say so honestly."
641
+ */
642
+ systemPrompt?: string;
643
+ /**
644
+ * Base URL for an OpenAI-compatible API endpoint.
645
+ * Use this to point to a self-hosted model, Azure OpenAI, or any
646
+ * compatible provider (e.g. Groq, Together, OpenRouter).
647
+ * @default "https://api.openai.com/v1"
648
+ */
649
+ baseUrl?: string;
650
+ /**
651
+ * API key for the LLM provider.
652
+ * Pass it via an environment variable to keep it out of source control.
653
+ *
654
+ * @default process.env.OPENAI_API_KEY
655
+ *
656
+ * @example
657
+ * ```ts
658
+ * // Default — reads OPENAI_API_KEY automatically
659
+ * ai: { enabled: true }
660
+ *
661
+ * // Custom provider key
662
+ * ai: {
663
+ * enabled: true,
664
+ * apiKey: process.env.GROQ_API_KEY,
665
+ * }
666
+ * ```
667
+ */
668
+ apiKey?: string;
669
+ /**
670
+ * Maximum number of search results to include as context for the AI.
671
+ * More results = more context but higher token usage.
672
+ * @default 5
673
+ */
674
+ maxResults?: number;
675
+ /**
676
+ * Pre-filled suggested questions shown in the AI chat when empty.
677
+ * When a user clicks one, it fills the input and submits automatically.
678
+ *
679
+ * @example
680
+ * ```ts
681
+ * ai: {
682
+ * enabled: true,
683
+ * suggestedQuestions: [
684
+ * "How do I install this?",
685
+ * "What themes are available?",
686
+ * "How do I create a custom component?",
687
+ * ],
688
+ * }
689
+ * ```
690
+ */
691
+ suggestedQuestions?: string[];
692
+ /**
693
+ * Display name for the AI assistant in the chat UI.
694
+ * Shown as the message label, header title, and passed to the loading component.
695
+ *
696
+ * @default "AI"
697
+ *
698
+ * @example
699
+ * ```ts
700
+ * ai: {
701
+ * enabled: true,
702
+ * aiLabel: "DocsBot",
703
+ * }
704
+ * ```
705
+ */
706
+ aiLabel?: string;
707
+ /**
708
+ * The npm package name used in import examples.
709
+ * The AI will use this in code snippets instead of generic placeholders.
710
+ *
711
+ * @example
712
+ * ```ts
713
+ * ai: {
714
+ * enabled: true,
715
+ * packageName: "@farming-labs/docs",
716
+ * }
717
+ * ```
718
+ */
719
+ packageName?: string;
720
+ /**
721
+ * The public URL of the documentation site.
722
+ * The AI will use this for links instead of relative paths.
723
+ *
724
+ * @example
725
+ * ```ts
726
+ * ai: {
727
+ * enabled: true,
728
+ * docsUrl: "https://docs.farming-labs.dev",
729
+ * }
730
+ * ```
731
+ */
732
+ docsUrl?: string;
733
+ /**
734
+ * Custom loading indicator shown while the AI is generating a response.
735
+ * Replaces the default "AI is thinking..." indicator.
736
+ *
737
+ * Pass a function that receives `{ name }` (the `aiLabel` value) and
738
+ * returns a React element. This way you don't need to duplicate the label.
739
+ *
740
+ * @example
741
+ * ```tsx
742
+ * ai: {
743
+ * enabled: true,
744
+ * aiLabel: "Sage",
745
+ * loadingComponent: ({ name }) => (
746
+ * <div className="flex items-center gap-2 text-sm text-zinc-400">
747
+ * <span className="animate-pulse">🤔</span>
748
+ * <span>{name} is thinking...</span>
749
+ * </div>
750
+ * ),
751
+ * }
752
+ * ```
753
+ */
754
+ loadingComponent?: (props: {
755
+ name: string;
756
+ }) => unknown;
757
+ }
758
+ /**
759
+ * A single item in the slug-based sidebar ordering.
760
+ *
761
+ * @example
762
+ * ```ts
763
+ * ordering: [
764
+ * { slug: "installation" },
765
+ * { slug: "cli" },
766
+ * { slug: "themes", children: [
767
+ * { slug: "default" },
768
+ * { slug: "darksharp" },
769
+ * { slug: "pixel-border" },
770
+ * { slug: "creating-themes" },
771
+ * ]},
772
+ * { slug: "reference" },
773
+ * ]
774
+ * ```
775
+ */
776
+ interface OrderingItem {
777
+ /** Folder name (not the full path, just the directory name at this level) */
778
+ slug: string;
779
+ /** Ordering for child pages within this folder */
780
+ children?: OrderingItem[];
781
+ }
445
782
  interface DocsConfig {
446
783
  /** Entry folder for docs (e.g. "docs" → /docs) */
447
784
  entry: string;
785
+ /** Path to the content directory. Defaults to `entry` value. */
786
+ contentDir?: string;
448
787
  /** Theme configuration - single source of truth for UI */
449
788
  theme?: DocsTheme;
450
789
  /**
@@ -579,6 +918,91 @@ interface DocsConfig {
579
918
  * ```
580
919
  */
581
920
  pageActions?: PageActionsConfig;
921
+ /**
922
+ * Configuration for the "Last updated" date display.
923
+ *
924
+ * - `true` or `undefined` → shown in footer next to "Edit on GitHub" (default)
925
+ * - `false` → hidden
926
+ * - `{ position: "below-title" }` → shown below the page title
927
+ * - `{ position: "footer" }` → shown next to "Edit on GitHub" (default)
928
+ *
929
+ * @example
930
+ * ```ts
931
+ * // Show below title (Mintlify style)
932
+ * lastUpdated: { position: "below-title" }
933
+ *
934
+ * // Hide entirely
935
+ * lastUpdated: false
936
+ * ```
937
+ */
938
+ lastUpdated?: boolean | LastUpdatedConfig;
939
+ /**
940
+ * AI-powered "Ask AI" chat for documentation.
941
+ *
942
+ * When enabled, the unified API route handler (`/api/docs`) accepts
943
+ * POST requests for AI chat. The handler uses RAG (Retrieval-Augmented
944
+ * Generation) — it searches relevant docs, builds context, and streams
945
+ * a response from an LLM.
946
+ *
947
+ * The API key defaults to `process.env.OPENAI_API_KEY`. For other providers,
948
+ * pass the key via `apiKey: process.env.YOUR_KEY`.
949
+ *
950
+ * @example
951
+ * ```ts
952
+ * // Enable with defaults (gpt-4o-mini, OPENAI_API_KEY)
953
+ * ai: { enabled: true }
954
+ *
955
+ * // Custom model + system prompt
956
+ * ai: {
957
+ * enabled: true,
958
+ * model: "gpt-4o",
959
+ * systemPrompt: "You are an expert on our SDK. Be concise.",
960
+ * }
961
+ *
962
+ * // Use a different provider (e.g. Groq)
963
+ * ai: {
964
+ * enabled: true,
965
+ * baseUrl: "https://api.groq.com/openai/v1",
966
+ * apiKey: process.env.GROQ_API_KEY,
967
+ * model: "llama-3.1-70b-versatile",
968
+ * }
969
+ * ```
970
+ */
971
+ ai?: AIConfig;
972
+ /**
973
+ * Sidebar ordering strategy.
974
+ *
975
+ * - `"alphabetical"` — sort pages alphabetically by folder name (default)
976
+ * - `"numeric"` — sort by frontmatter `order` field (lower first, unset pages last)
977
+ * - `OrderingItem[]` — explicit slug-based ordering with nested children
978
+ *
979
+ * @default "alphabetical"
980
+ *
981
+ * @example
982
+ * ```ts
983
+ * // Alphabetical (default)
984
+ * ordering: "alphabetical",
985
+ *
986
+ * // Use frontmatter `order: 1`, `order: 2`, etc.
987
+ * ordering: "numeric",
988
+ *
989
+ * // Explicit slug-based ordering
990
+ * ordering: [
991
+ * { slug: "installation" },
992
+ * { slug: "cli" },
993
+ * { slug: "configuration" },
994
+ * { slug: "themes", children: [
995
+ * { slug: "default" },
996
+ * { slug: "darksharp" },
997
+ * { slug: "pixel-border" },
998
+ * { slug: "creating-themes" },
999
+ * ]},
1000
+ * { slug: "customization" },
1001
+ * { slug: "reference" },
1002
+ * ]
1003
+ * ```
1004
+ */
1005
+ ordering?: "alphabetical" | "numeric" | OrderingItem[];
582
1006
  /** SEO metadata - separate from theme */
583
1007
  metadata?: DocsMetadata;
584
1008
  /** Open Graph image handling */
@@ -632,7 +1056,7 @@ declare function createTheme(baseTheme: DocsTheme): (overrides?: Partial<DocsThe
632
1056
  * @example
633
1057
  * ```ts
634
1058
  * import { extendTheme } from "@farming-labs/docs";
635
- * import { fumadocs } from "@farming-labs/fumadocs/default";
1059
+ * import { fumadocs } from "@farming-labs/theme/default";
636
1060
  *
637
1061
  * // Start with fumadocs defaults, override some values
638
1062
  * export const myTheme = extendTheme(fumadocs(), {
@@ -654,4 +1078,4 @@ declare function resolveTitle(pageTitle: string, metadata?: DocsMetadata): strin
654
1078
  */
655
1079
  declare function resolveOGImage(page: PageFrontmatter, ogConfig?: OGConfig, baseUrl?: string): string | undefined;
656
1080
  //#endregion
657
- export { type BreadcrumbConfig, type CopyMarkdownConfig, type DocsConfig, type DocsMetadata, type DocsNav, type DocsTheme, type FontStyle, type GithubConfig, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, type PageActionsConfig, type PageFrontmatter, type SidebarConfig, type ThemeToggleConfig, type TypographyConfig, type UIConfig, createTheme, deepMerge, defineDocs, extendTheme, resolveOGImage, resolveTitle };
1081
+ export { type AIConfig, type BreadcrumbConfig, type CopyMarkdownConfig, type DocsConfig, type DocsMetadata, type DocsNav, type DocsTheme, type FontStyle, type GithubConfig, type LastUpdatedConfig, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, type OrderingItem, type PageActionsConfig, type PageFrontmatter, type SidebarConfig, type ThemeToggleConfig, type TypographyConfig, type UIConfig, createTheme, deepMerge, defineDocs, extendTheme, resolveOGImage, resolveTitle };
package/dist/index.mjs CHANGED
@@ -5,6 +5,7 @@
5
5
  function defineDocs(config) {
6
6
  return {
7
7
  entry: config.entry ?? "docs",
8
+ contentDir: config.contentDir,
8
9
  theme: config.theme,
9
10
  nav: config.nav,
10
11
  github: config.github,
@@ -14,6 +15,9 @@ function defineDocs(config) {
14
15
  components: config.components,
15
16
  icons: config.icons,
16
17
  pageActions: config.pageActions,
18
+ lastUpdated: config.lastUpdated,
19
+ ai: config.ai,
20
+ ordering: config.ordering,
17
21
  metadata: config.metadata,
18
22
  og: config.og
19
23
  };
@@ -81,7 +85,7 @@ function createTheme(baseTheme) {
81
85
  * @example
82
86
  * ```ts
83
87
  * import { extendTheme } from "@farming-labs/docs";
84
- * import { fumadocs } from "@farming-labs/fumadocs/default";
88
+ * import { fumadocs } from "@farming-labs/theme/default";
85
89
  *
86
90
  * // Start with fumadocs defaults, override some values
87
91
  * export const myTheme = extendTheme(fumadocs(), {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/docs",
3
- "version": "0.0.2-beta.2",
3
+ "version": "0.0.2-beta.21",
4
4
  "description": "Modern, flexible MDX-based docs framework — core types, config, and CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",