doccupine 0.0.108 → 0.0.110

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.
Files changed (58) hide show
  1. package/dist/templates/components/SideBar.d.ts +1 -1
  2. package/dist/templates/components/SideBar.js +45 -3
  3. package/dist/templates/components/layout/DocsComponents.d.ts +1 -1
  4. package/dist/templates/components/layout/DocsComponents.js +2 -1
  5. package/dist/templates/mdx/accordion.mdx.d.ts +1 -1
  6. package/dist/templates/mdx/accordion.mdx.js +19 -21
  7. package/dist/templates/mdx/ai-assistant.mdx.d.ts +1 -1
  8. package/dist/templates/mdx/ai-assistant.mdx.js +8 -0
  9. package/dist/templates/mdx/analytics.mdx.d.ts +1 -1
  10. package/dist/templates/mdx/analytics.mdx.js +1 -1
  11. package/dist/templates/mdx/buttons.mdx.d.ts +1 -1
  12. package/dist/templates/mdx/buttons.mdx.js +6 -6
  13. package/dist/templates/mdx/callouts.mdx.d.ts +1 -1
  14. package/dist/templates/mdx/callouts.mdx.js +1 -9
  15. package/dist/templates/mdx/cards.mdx.d.ts +1 -1
  16. package/dist/templates/mdx/cards.mdx.js +2 -2
  17. package/dist/templates/mdx/code.mdx.d.ts +1 -1
  18. package/dist/templates/mdx/code.mdx.js +8 -8
  19. package/dist/templates/mdx/color-swatches.mdx.d.ts +1 -1
  20. package/dist/templates/mdx/color-swatches.mdx.js +2 -2
  21. package/dist/templates/mdx/columns.mdx.d.ts +1 -1
  22. package/dist/templates/mdx/columns.mdx.js +1 -3
  23. package/dist/templates/mdx/deployment-and-hosting.mdx.d.ts +1 -1
  24. package/dist/templates/mdx/deployment-and-hosting.mdx.js +2 -2
  25. package/dist/templates/mdx/fields.mdx.d.ts +1 -1
  26. package/dist/templates/mdx/fields.mdx.js +1 -1
  27. package/dist/templates/mdx/fonts.mdx.d.ts +1 -1
  28. package/dist/templates/mdx/fonts.mdx.js +1 -1
  29. package/dist/templates/mdx/footer-links.mdx.d.ts +1 -1
  30. package/dist/templates/mdx/footer-links.mdx.js +1 -1
  31. package/dist/templates/mdx/globals.mdx.d.ts +1 -1
  32. package/dist/templates/mdx/globals.mdx.js +1 -1
  33. package/dist/templates/mdx/icons.mdx.d.ts +1 -1
  34. package/dist/templates/mdx/icons.mdx.js +2 -2
  35. package/dist/templates/mdx/index.mdx.d.ts +1 -1
  36. package/dist/templates/mdx/index.mdx.js +1 -1
  37. package/dist/templates/mdx/media-and-assets.mdx.d.ts +1 -1
  38. package/dist/templates/mdx/media-and-assets.mdx.js +4 -4
  39. package/dist/templates/mdx/navigation.mdx.d.ts +1 -1
  40. package/dist/templates/mdx/navigation.mdx.js +1 -1
  41. package/dist/templates/mdx/platform/file-editor.mdx.d.ts +1 -1
  42. package/dist/templates/mdx/platform/file-editor.mdx.js +2 -2
  43. package/dist/templates/mdx/sections.mdx.d.ts +1 -1
  44. package/dist/templates/mdx/sections.mdx.js +1 -1
  45. package/dist/templates/mdx/steps.mdx.d.ts +1 -1
  46. package/dist/templates/mdx/steps.mdx.js +4 -8
  47. package/dist/templates/mdx/tabs.mdx.d.ts +1 -1
  48. package/dist/templates/mdx/tabs.mdx.js +8 -10
  49. package/dist/templates/mdx/theme.mdx.d.ts +1 -1
  50. package/dist/templates/mdx/theme.mdx.js +1 -1
  51. package/dist/templates/mdx/update.mdx.d.ts +1 -1
  52. package/dist/templates/mdx/update.mdx.js +13 -15
  53. package/dist/templates/package.js +2 -2
  54. package/dist/templates/prettierignore.d.ts +1 -1
  55. package/dist/templates/prettierignore.js +1 -0
  56. package/dist/templates/services/search.d.ts +1 -1
  57. package/dist/templates/services/search.js +28 -2
  58. package/package.json +3 -3
@@ -1 +1 @@
1
- export declare const sideBarTemplate = "\"use client\";\nimport { useContext, useState } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { Flex, Space, ThemeToggle } from \"cherry-styled-components\";\nimport {\n DocsSidebar,\n SectionBarContext,\n StyledSidebar,\n StyledSidebarList,\n StyledSidebarListItem,\n StyledStrong,\n StyledSidebarListItemLink,\n StyledSidebarGroupButton,\n StyledSidebarGroupRow,\n StyledSidebarGroupLink,\n StyledSidebarGroupChevron,\n StyledSidebarGroupContent,\n StyledSidebarFooter,\n StyleMobileBar,\n StyledMobileBurger,\n} from \"@/components/layout/DocsComponents\";\nimport { Icon } from \"@/components/layout/Icon\";\nimport { useLockBodyScroll } from \"@/components/LockBodyScroll\";\n\n// A link can be a leaf (slug + title) or a group with nested children. Both the\n// category icon and the per-link icon are optional Lucide names.\ntype NavItemLink = {\n slug?: string;\n title: string;\n icon?: string;\n links?: NavItemLink[];\n};\n\ntype NavItem = {\n label: string;\n icon?: string;\n links: NavItemLink[];\n};\n\ninterface SideBarProps {\n result: NavItem[];\n}\n\nfunction linkContainsActivePath(link: NavItemLink, pathname: string): boolean {\n if (link.slug !== undefined && pathname === `/${link.slug}`) {\n return true;\n }\n return (link.links ?? []).some((child) =>\n linkContainsActivePath(child, pathname),\n );\n}\n\nfunction SidebarNavLink({\n link,\n depth,\n pathname,\n onNavigate,\n}: {\n link: NavItemLink;\n depth: number;\n pathname: string;\n onNavigate: () => void;\n}) {\n const children = link.links ?? [];\n const hasChildren = children.length > 0;\n const href = link.slug !== undefined ? `/${link.slug}` : undefined;\n const isActive = href !== undefined && pathname === href;\n const indent = { paddingLeft: `${20 + depth * 14}px` };\n\n // Open collapsible groups that contain the active page so deep links land\n // with their ancestors already expanded.\n const [isOpen, setIsOpen] = useState(\n hasChildren\n ? children.some((child) => linkContainsActivePath(child, pathname))\n : false,\n );\n\n if (!hasChildren) {\n return (\n <StyledSidebarListItem>\n <StyledSidebarListItemLink\n href={href ?? \"#\"}\n $isActive={isActive}\n onClick={onNavigate}\n style={indent}\n >\n {link.icon && <Icon name={link.icon} size={16} />}\n {link.title}\n </StyledSidebarListItemLink>\n </StyledSidebarListItem>\n );\n }\n\n const toggle = () => setIsOpen((prev) => !prev);\n const toggleLabel = isOpen\n ? `Collapse ${link.title}`\n : `Expand ${link.title}`;\n const groupActive = linkContainsActivePath(link, pathname);\n\n return (\n <li>\n {href !== undefined ? (\n <StyledSidebarGroupRow\n $isActive={groupActive}\n $isOpen={isOpen}\n style={indent}\n >\n <StyledSidebarGroupLink href={href} onClick={onNavigate}>\n {link.icon && <Icon name={link.icon} size={16} />}\n {link.title}\n </StyledSidebarGroupLink>\n <StyledSidebarGroupChevron\n type=\"button\"\n onClick={toggle}\n aria-expanded={isOpen}\n aria-label={toggleLabel}\n >\n <Icon name=\"chevron-right\" size={16} />\n </StyledSidebarGroupChevron>\n </StyledSidebarGroupRow>\n ) : (\n <StyledSidebarGroupButton\n type=\"button\"\n onClick={toggle}\n $isActive={groupActive}\n $isOpen={isOpen}\n style={indent}\n aria-expanded={isOpen}\n aria-label={toggleLabel}\n >\n {link.icon && <Icon name={link.icon} size={16} />}\n {link.title}\n <Icon name=\"chevron-right\" size={16} />\n </StyledSidebarGroupButton>\n )}\n <StyledSidebarGroupContent $isOpen={isOpen}>\n {children.map((child: NavItemLink, index: number) => (\n <SidebarNavLink\n key={index}\n link={child}\n depth={depth + 1}\n pathname={pathname}\n onNavigate={onNavigate}\n />\n ))}\n </StyledSidebarGroupContent>\n </li>\n );\n}\n\nfunction SideBar({ result }: SideBarProps) {\n const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);\n const hasSectionBar = useContext(SectionBarContext);\n const pathname = usePathname();\n\n useLockBodyScroll(isMobileMenuOpen);\n\n return (\n <DocsSidebar>\n <StyleMobileBar\n onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}\n $isActive={isMobileMenuOpen}\n aria-label={\n isMobileMenuOpen ? \"Close navigation menu\" : \"Open navigation menu\"\n }\n aria-expanded={isMobileMenuOpen}\n >\n <StyledMobileBurger $isActive={isMobileMenuOpen} />\n </StyleMobileBar>\n\n <StyledSidebar\n $isActive={isMobileMenuOpen}\n $hasSectionBar={hasSectionBar}\n >\n {result &&\n result.map((item: NavItem, index: number) => {\n return (\n <StyledSidebarList key={index}>\n <StyledSidebarListItem>\n <StyledStrong>\n {item.icon && <Icon name={item.icon} size={16} />}\n {item.label}\n </StyledStrong>{\" \"}\n </StyledSidebarListItem>\n <li>\n <Space $size={20} />\n </li>\n {item.links &&\n item.links.map((link: NavItemLink, indexChild: number) => (\n <SidebarNavLink\n key={indexChild}\n link={link}\n depth={0}\n pathname={pathname}\n onNavigate={() => setIsMobileMenuOpen(false)}\n />\n ))}\n <li aria-hidden=\"true\">\n <Space $size={20} />\n </li>\n </StyledSidebarList>\n );\n })}\n <StyledSidebarFooter>\n <Flex $xsJustifyContent=\"flex-start\" $lgJustifyContent=\"flex-end\">\n <ThemeToggle />\n </Flex>\n </StyledSidebarFooter>\n </StyledSidebar>\n </DocsSidebar>\n );\n}\n\nexport { SideBar };\n";
1
+ export declare const sideBarTemplate = "\"use client\";\nimport { useContext, useEffect, useRef, useState } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { Flex, Space, ThemeToggle } from \"cherry-styled-components\";\nimport {\n DocsSidebar,\n SectionBarContext,\n StyledSidebar,\n StyledSidebarList,\n StyledSidebarListItem,\n StyledStrong,\n StyledSidebarListItemLink,\n StyledSidebarGroupButton,\n StyledSidebarGroupRow,\n StyledSidebarGroupLink,\n StyledSidebarGroupChevron,\n StyledSidebarGroupContent,\n StyledSidebarFooter,\n StyleMobileBar,\n StyledMobileBurger,\n} from \"@/components/layout/DocsComponents\";\nimport { Icon } from \"@/components/layout/Icon\";\nimport { useLockBodyScroll } from \"@/components/LockBodyScroll\";\n\n// A link can be a leaf (slug + title) or a group with nested children. Both the\n// category icon and the per-link icon are optional Lucide names.\ntype NavItemLink = {\n slug?: string;\n title: string;\n icon?: string;\n links?: NavItemLink[];\n};\n\ntype NavItem = {\n label: string;\n icon?: string;\n links: NavItemLink[];\n};\n\ninterface SideBarProps {\n result: NavItem[];\n}\n\nfunction linkContainsActivePath(link: NavItemLink, pathname: string): boolean {\n if (link.slug !== undefined && pathname === `/${link.slug}`) {\n return true;\n }\n return (link.links ?? []).some((child) =>\n linkContainsActivePath(child, pathname),\n );\n}\n\nfunction SidebarNavLink({\n link,\n depth,\n pathname,\n onNavigate,\n}: {\n link: NavItemLink;\n depth: number;\n pathname: string;\n onNavigate: () => void;\n}) {\n const children = link.links ?? [];\n const hasChildren = children.length > 0;\n const href = link.slug !== undefined ? `/${link.slug}` : undefined;\n const isActive = href !== undefined && pathname === href;\n const indent = { paddingLeft: `${20 + depth * 14}px` };\n\n // Open collapsible groups that contain the active page so deep links land\n // with their ancestors already expanded.\n const [isOpen, setIsOpen] = useState(\n hasChildren\n ? children.some((child) => linkContainsActivePath(child, pathname))\n : false,\n );\n\n if (!hasChildren) {\n return (\n <StyledSidebarListItem>\n <StyledSidebarListItemLink\n href={href ?? \"#\"}\n $isActive={isActive}\n aria-current={isActive ? \"page\" : undefined}\n onClick={onNavigate}\n style={indent}\n >\n {link.icon && <Icon name={link.icon} size={16} />}\n {link.title}\n </StyledSidebarListItemLink>\n </StyledSidebarListItem>\n );\n }\n\n const toggle = () => setIsOpen((prev) => !prev);\n const toggleLabel = isOpen\n ? `Collapse ${link.title}`\n : `Expand ${link.title}`;\n const groupActive = linkContainsActivePath(link, pathname);\n\n return (\n <li>\n {href !== undefined ? (\n <StyledSidebarGroupRow\n $isActive={groupActive}\n $isOpen={isOpen}\n style={indent}\n >\n <StyledSidebarGroupLink\n href={href}\n aria-current={pathname === href ? \"page\" : undefined}\n onClick={onNavigate}\n >\n {link.icon && <Icon name={link.icon} size={16} />}\n {link.title}\n </StyledSidebarGroupLink>\n <StyledSidebarGroupChevron\n type=\"button\"\n onClick={toggle}\n aria-expanded={isOpen}\n aria-label={toggleLabel}\n >\n <Icon name=\"chevron-right\" size={16} />\n </StyledSidebarGroupChevron>\n </StyledSidebarGroupRow>\n ) : (\n <StyledSidebarGroupButton\n type=\"button\"\n onClick={toggle}\n $isActive={groupActive}\n $isOpen={isOpen}\n style={indent}\n aria-expanded={isOpen}\n aria-label={toggleLabel}\n >\n {link.icon && <Icon name={link.icon} size={16} />}\n {link.title}\n <Icon name=\"chevron-right\" size={16} />\n </StyledSidebarGroupButton>\n )}\n <StyledSidebarGroupContent $isOpen={isOpen}>\n {children.map((child: NavItemLink, index: number) => (\n <SidebarNavLink\n key={index}\n link={child}\n depth={depth + 1}\n pathname={pathname}\n onNavigate={onNavigate}\n />\n ))}\n </StyledSidebarGroupContent>\n </li>\n );\n}\n\nfunction SideBar({ result }: SideBarProps) {\n const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);\n const hasSectionBar = useContext(SectionBarContext);\n const pathname = usePathname();\n const navRef = useRef<HTMLElement>(null);\n const footerRef = useRef<HTMLDivElement>(null);\n\n useLockBodyScroll(isMobileMenuOpen);\n\n // Bring the current page's link into view within the sidebar's own scroll\n // area when it starts off-screen (deep pages, in-content links, search).\n // Scoped to the nav via scrollTo so the main document never jumps.\n useEffect(() => {\n const nav = navRef.current;\n if (!nav) return;\n const active = nav.querySelector<HTMLElement>('[aria-current=\"page\"]');\n if (!active) return;\n\n const navRect = nav.getBoundingClientRect();\n const activeRect = active.getBoundingClientRect();\n\n // The theme-toggle footer is sticky over the bottom of the scroll area\n // (~60px tall), so links underneath it are covered rather than visible.\n // Clamp the visible bottom to the footer's top edge when it's pinned.\n const footerRect = footerRef.current?.getBoundingClientRect();\n const visibleBottom = footerRect\n ? Math.min(navRect.bottom, footerRect.top)\n : navRect.bottom;\n\n const isOutOfView =\n activeRect.top < navRect.top || activeRect.bottom > visibleBottom;\n if (!isOutOfView) return;\n\n // Center within the visible band (nav top .. footer top), not the full\n // nav height, so the link never settles behind the footer.\n const visibleHeight = visibleBottom - navRect.top;\n const target =\n nav.scrollTop +\n (activeRect.top - navRect.top) -\n (visibleHeight - active.clientHeight) / 2;\n nav.scrollTo({ top: Math.max(0, target) });\n }, [pathname]);\n\n return (\n <DocsSidebar>\n <StyleMobileBar\n onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}\n $isActive={isMobileMenuOpen}\n aria-label={\n isMobileMenuOpen ? \"Close navigation menu\" : \"Open navigation menu\"\n }\n aria-expanded={isMobileMenuOpen}\n >\n <StyledMobileBurger $isActive={isMobileMenuOpen} />\n </StyleMobileBar>\n\n <StyledSidebar\n ref={navRef}\n $isActive={isMobileMenuOpen}\n $hasSectionBar={hasSectionBar}\n >\n {result &&\n result.map((item: NavItem, index: number) => {\n return (\n <StyledSidebarList key={index}>\n <StyledSidebarListItem>\n <StyledStrong>\n {item.icon && <Icon name={item.icon} size={16} />}\n {item.label}\n </StyledStrong>{\" \"}\n </StyledSidebarListItem>\n <li>\n <Space $size={20} />\n </li>\n {item.links &&\n item.links.map((link: NavItemLink, indexChild: number) => (\n <SidebarNavLink\n key={indexChild}\n link={link}\n depth={0}\n pathname={pathname}\n onNavigate={() => setIsMobileMenuOpen(false)}\n />\n ))}\n <li aria-hidden=\"true\">\n <Space $size={20} />\n </li>\n </StyledSidebarList>\n );\n })}\n <StyledSidebarFooter ref={footerRef}>\n <Flex $xsJustifyContent=\"flex-start\" $lgJustifyContent=\"flex-end\">\n <ThemeToggle />\n </Flex>\n </StyledSidebarFooter>\n </StyledSidebar>\n </DocsSidebar>\n );\n}\n\nexport { SideBar };\n";
@@ -1,5 +1,5 @@
1
1
  export const sideBarTemplate = `"use client";
2
- import { useContext, useState } from "react";
2
+ import { useContext, useEffect, useRef, useState } from "react";
3
3
  import { usePathname } from "next/navigation";
4
4
  import { Flex, Space, ThemeToggle } from "cherry-styled-components";
5
5
  import {
@@ -81,6 +81,7 @@ function SidebarNavLink({
81
81
  <StyledSidebarListItemLink
82
82
  href={href ?? "#"}
83
83
  $isActive={isActive}
84
+ aria-current={isActive ? "page" : undefined}
84
85
  onClick={onNavigate}
85
86
  style={indent}
86
87
  >
@@ -105,7 +106,11 @@ function SidebarNavLink({
105
106
  $isOpen={isOpen}
106
107
  style={indent}
107
108
  >
108
- <StyledSidebarGroupLink href={href} onClick={onNavigate}>
109
+ <StyledSidebarGroupLink
110
+ href={href}
111
+ aria-current={pathname === href ? "page" : undefined}
112
+ onClick={onNavigate}
113
+ >
109
114
  {link.icon && <Icon name={link.icon} size={16} />}
110
115
  {link.title}
111
116
  </StyledSidebarGroupLink>
@@ -152,9 +157,45 @@ function SideBar({ result }: SideBarProps) {
152
157
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
153
158
  const hasSectionBar = useContext(SectionBarContext);
154
159
  const pathname = usePathname();
160
+ const navRef = useRef<HTMLElement>(null);
161
+ const footerRef = useRef<HTMLDivElement>(null);
155
162
 
156
163
  useLockBodyScroll(isMobileMenuOpen);
157
164
 
165
+ // Bring the current page's link into view within the sidebar's own scroll
166
+ // area when it starts off-screen (deep pages, in-content links, search).
167
+ // Scoped to the nav via scrollTo so the main document never jumps.
168
+ useEffect(() => {
169
+ const nav = navRef.current;
170
+ if (!nav) return;
171
+ const active = nav.querySelector<HTMLElement>('[aria-current="page"]');
172
+ if (!active) return;
173
+
174
+ const navRect = nav.getBoundingClientRect();
175
+ const activeRect = active.getBoundingClientRect();
176
+
177
+ // The theme-toggle footer is sticky over the bottom of the scroll area
178
+ // (~60px tall), so links underneath it are covered rather than visible.
179
+ // Clamp the visible bottom to the footer's top edge when it's pinned.
180
+ const footerRect = footerRef.current?.getBoundingClientRect();
181
+ const visibleBottom = footerRect
182
+ ? Math.min(navRect.bottom, footerRect.top)
183
+ : navRect.bottom;
184
+
185
+ const isOutOfView =
186
+ activeRect.top < navRect.top || activeRect.bottom > visibleBottom;
187
+ if (!isOutOfView) return;
188
+
189
+ // Center within the visible band (nav top .. footer top), not the full
190
+ // nav height, so the link never settles behind the footer.
191
+ const visibleHeight = visibleBottom - navRect.top;
192
+ const target =
193
+ nav.scrollTop +
194
+ (activeRect.top - navRect.top) -
195
+ (visibleHeight - active.clientHeight) / 2;
196
+ nav.scrollTo({ top: Math.max(0, target) });
197
+ }, [pathname]);
198
+
158
199
  return (
159
200
  <DocsSidebar>
160
201
  <StyleMobileBar
@@ -169,6 +210,7 @@ function SideBar({ result }: SideBarProps) {
169
210
  </StyleMobileBar>
170
211
 
171
212
  <StyledSidebar
213
+ ref={navRef}
172
214
  $isActive={isMobileMenuOpen}
173
215
  $hasSectionBar={hasSectionBar}
174
216
  >
@@ -201,7 +243,7 @@ function SideBar({ result }: SideBarProps) {
201
243
  </StyledSidebarList>
202
244
  );
203
245
  })}
204
- <StyledSidebarFooter>
246
+ <StyledSidebarFooter ref={footerRef}>
205
247
  <Flex $xsJustifyContent="flex-start" $lgJustifyContent="flex-end">
206
248
  <ThemeToggle />
207
249
  </Flex>
@@ -1 +1 @@
1
- export declare const docsComponentsTemplate = "\"use client\";\nimport React, { createContext, useContext } from \"react\";\nimport styled, { css } from \"styled-components\";\nimport {\n resetButton,\n styledSmall,\n styledStrong,\n styledText,\n} from \"cherry-styled-components\";\nimport Link from \"next/link\";\nimport { mq, Theme } from \"@/app/theme\";\nimport {\n styledAnchor,\n styledTable,\n stylesLists,\n} from \"@/components/layout/SharedStyled\";\nimport { ChatContext } from \"@/components/Chat\";\n\nconst SectionBarContext = createContext(false);\n\nfunction SectionBarProvider({\n hasSectionBar,\n children,\n}: {\n hasSectionBar: boolean;\n children: React.ReactNode;\n}) {\n return (\n <SectionBarContext.Provider value={hasSectionBar}>\n {children}\n </SectionBarContext.Provider>\n );\n}\n\ninterface DocsProps {\n children: React.ReactNode;\n}\n\nconst StyledDocsWrapper = styled.main<{ theme: Theme }>`\n position: relative;\n`;\n\nconst StyledDocsSidebar = styled.div<{ theme: Theme }>`\n clear: both;\n`;\n\nconst StyledDocsContainer = styled.div<{ theme: Theme; $isChatOpen?: boolean }>`\n position: relative;\n padding: 0 20px 100px 20px;\n width: 100%;\n ${({ theme }) => styledText(theme)};\n transition: all 0.3s ease;\n\n ${mq(\"lg\")} {\n padding: 0 300px 80px 300px;\n\n ${({ $isChatOpen }) =>\n $isChatOpen &&\n css`\n padding: 0 440px 80px 300px;\n `}\n }\n\n & p {\n color: ${({ theme }) => theme.colors.grayDark};\n hyphens: auto;\n }\n\n & pre {\n max-width: 100%;\n }\n\n ${styledAnchor};\n ${stylesLists};\n ${styledTable};\n\n & img,\n & video,\n & iframe {\n max-width: 100%;\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n }\n\n & code:not([class]) {\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 20%, transparent)`};\n color: ${({ theme }) => theme.colors.dark};\n padding: 2px 4px;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n white-space: pre;\n }\n\n & .lucide {\n color: ${({ theme }) => theme.colors.primary};\n }\n\n & .aspect-video {\n aspect-ratio: 16 / 9;\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n }\n`;\n\nexport const StyledMarkdownContainer = styled.div`\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex-wrap: wrap;\n flex: 1;\n max-width: 640px;\n margin: auto;\n`;\n\ninterface Props {\n theme?: Theme;\n $isActive?: boolean;\n $isOpen?: boolean;\n $hasSectionBar?: boolean;\n}\n\nexport const StyledSidebar = styled.nav<Props>`\n position: fixed;\n overflow-y: auto;\n max-height: calc(\n 100dvh - ${({ $hasSectionBar }) => ($hasSectionBar ? 104 : 62)}px\n );\n width: 100%;\n z-index: 99;\n top: ${({ $hasSectionBar }) => ($hasSectionBar ? 104 : 62)}px;\n height: 100%;\n padding: 20px;\n opacity: 0;\n pointer-events: none;\n transition: all 0.3s ease;\n transform: translateY(30px);\n left: 0;\n background: ${({ theme }) => theme.colors.light};\n -webkit-overflow-scrolling: touch;\n display: flex;\n flex-direction: column;\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n ${mq(\"lg\")} {\n border-right: solid 1px ${({ theme }) => theme.colors.grayLight};\n transition: none;\n max-height: 100dvh;\n width: 220px;\n background: transparent;\n padding: 82px 20px 20px 20px;\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 5%, transparent)`};\n top: 0;\n width: 280px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n transform: translateY(0);\n opacity: 1;\n pointer-events: all;\n `}\n`;\n\nexport const StyledSidebarFooter = styled.div`\n padding: 22px 20px;\n position: sticky;\n border-top: 1px solid ${({ theme }) => theme.colors.grayLight};\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 5%, transparent)`};\n margin: 0 -20px -20px;\n bottom: -20px;\n backdrop-filter: blur(10px);\n\n ${mq(\"lg\")} {\n padding: 16px 20px;\n }\n`;\n\nexport const StyledIndexSidebar = styled.ul<{ theme: Theme }>`\n display: none;\n list-style: none;\n margin: 0;\n padding: 0;\n position: fixed;\n top: 0;\n right: 0;\n width: 280px;\n height: 100dvh;\n overflow-y: auto;\n z-index: 1;\n padding: 82px 20px 20px 20px;\n background: ${({ theme }) => theme.colors.light};\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n -webkit-overflow-scrolling: touch;\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n ${mq(\"lg\")} {\n display: block;\n }\n\n & li {\n padding: 5px 0;\n }\n`;\n\nexport const StyledIndexSidebarLabel = styled.span<{ theme: Theme }>`\n ${({ theme }) => styledSmall(theme)};\n color: ${({ theme }) => theme.colors.grayDark};\n`;\n\nexport const StyledIndexSidebarLi = styled.li<{\n theme: Theme;\n $isActive: boolean;\n}>`\n &::before {\n content: \"\";\n display: block;\n position: absolute;\n left: 0;\n height: 20px;\n width: 1px;\n background: transparent;\n transition: all 0.3s ease;\n }\n\n ${({ $isActive, theme }) =>\n $isActive &&\n css`\n &::before {\n background: ${theme.colors.primary};\n }\n `}\n`;\n\nexport const StyledIndexSidebarLink = styled.a<{\n theme: Theme;\n $isActive: boolean;\n}>`\n ${({ theme }) => styledSmall(theme)};\n color: ${({ theme, $isActive }) =>\n $isActive ? theme.colors.primary : theme.colors.dark};\n font-weight: ${({ $isActive }) => ($isActive ? \"600\" : \"400\")};\n text-decoration: none;\n transition: all 0.3s ease;\n\n &:hover {\n color: ${({ theme }) => theme.colors.primary};\n }\n`;\n\nexport const StyledSidebarList = styled.ul`\n list-style: none;\n margin: 0;\n padding: 0;\n\n &:last-of-type {\n margin-bottom: auto;\n }\n`;\n\nexport const StyledStrong = styled.strong<{ theme: Theme }>`\n font-weight: 600;\n ${({ theme }) => styledStrong(theme)};\n color: ${({ theme }) => theme.colors.accentStrong};\n display: inline-flex;\n align-items: center;\n gap: 8px;\n\n & svg {\n flex-shrink: 0;\n }\n`;\n\nexport const StyledSidebarListItem = styled.li`\n display: flex;\n gap: 10px;\n clear: both;\n`;\n\n// Shared appearance for every sidebar row - leaf links AND nested group\n// headers - so hover, active state, and the left rail read identically.\nconst sidebarRowStyles = css<Props>`\n text-decoration: none;\n font-size: ${({ theme }) => theme.fontSizes.small.lg};\n line-height: 1.6;\n color: ${({ theme }) => theme.colors.accentMuted};\n padding: 5px 0 5px 20px;\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n transition: all 0.3s ease;\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n & svg {\n flex-shrink: 0;\n }\n\n &:hover {\n color: ${({ theme }) => theme.colors.accent};\n border-color: ${({ theme }) => theme.colors.primary};\n }\n\n ${({ $isActive, theme }) =>\n $isActive &&\n css`\n color: ${theme.colors.accentStrong};\n border-color: ${theme.colors.primary};\n font-weight: 600;\n `};\n`;\n\n// The collapse chevron points right when closed and rotates to point down\n// when the group is open.\nconst sidebarChevron = css<Props>`\n & .lucide-chevron-right {\n margin-left: auto;\n transition: transform 0.3s ease;\n\n ${({ $isOpen }) =>\n $isOpen &&\n css`\n transform: rotate(90deg);\n `}\n }\n`;\n\nexport const StyledSidebarListItemLink = styled(Link)<Props>`\n ${sidebarRowStyles};\n`;\n\n// Nested navigation group. The header shares the link appearance/hover; a\n// non-navigable group is a single toggle button, while a group that is also a\n// page pairs a link with a chevron toggle. Children live in\n// StyledSidebarGroupContent, which animates open/closed via height 0 <-> auto\n// (enabled by interpolate-size in GlobalStyles, same as the Accordion).\nexport const StyledSidebarGroupButton = styled.button<Props>`\n ${resetButton};\n ${sidebarRowStyles};\n ${sidebarChevron};\n width: 100%;\n text-align: left;\n\n /* Buttons aren't covered by the global a:focus-visible ring, so this\n nav-row toggle carries its own copy of it. */\n &:focus-visible {\n outline: none;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n`;\n\nexport const StyledSidebarGroupRow = styled.div<Props>`\n ${sidebarRowStyles};\n ${sidebarChevron};\n\n /* The row is a plain div, so it never matches :focus-visible itself. Ring the\n whole row when its inner link or chevron takes keyboard focus instead, to\n match the leaf-row focus treatment. */\n &:has(:focus-visible) {\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n`;\n\nexport const StyledSidebarGroupLink = styled(Link)`\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n color: inherit;\n text-decoration: none;\n\n & svg {\n flex-shrink: 0;\n }\n\n /* Ring is drawn on the parent row via :has(:focus-visible); suppress the\n global a:focus-visible glow so it isn't drawn twice. */\n &:focus-visible {\n outline: none;\n box-shadow: none;\n }\n`;\n\nexport const StyledSidebarGroupChevron = styled.button`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n padding: 0;\n border: 0;\n background: none;\n color: inherit;\n cursor: pointer;\n\n /* Ring is drawn on the parent row via :has(:focus-visible). */\n &:focus-visible {\n outline: none;\n }\n`;\n\nexport const StyledSidebarGroupContent = styled.ul<Props>`\n list-style: none;\n margin: 0;\n padding: 0;\n height: 0;\n overflow: clip;\n transition: all 0.3s ease;\n\n ${({ $isOpen }) =>\n $isOpen &&\n css`\n height: auto;\n `}\n`;\n\nexport const StyleMobileBar = styled.button<Props>`\n ${resetButton};\n position: fixed;\n z-index: 999;\n bottom: 0;\n right: 20px;\n font-size: ${({ theme }) => theme.fontSizes.strong.lg};\n line-height: ${({ theme }) => theme.fontSizes.strong.lg};\n box-shadow: ${({ theme }) => theme.shadows.sm};\n background: ${({ theme }) => theme.colors.primary};\n color: ${({ theme }) => theme.colors.surface};\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n padding: 10px;\n border-radius: 100px;\n margin: 0 0 20px 0;\n font-weight: 600;\n display: flex;\n justify-content: flex-start;\n width: auto;\n\n ${mq(\"lg\")} {\n display: none;\n }\n\n ${({ $isActive }) => $isActive && `position: fixed;`};\n`;\n\nexport const StyledMobileBurger = styled.span<Props>`\n display: block;\n margin: auto 0;\n width: 18px;\n height: 18px;\n position: relative;\n overflow: hidden;\n background: transparent;\n position: relative;\n transform: scale(0.8);\n\n &::before,\n &::after {\n content: \"\";\n display: block;\n position: absolute;\n width: 18px;\n height: 3px;\n border-radius: 3px;\n background: ${({ theme }) => theme.colors.surface};\n transition: all 0.3s ease;\n }\n\n &::before {\n top: 3px;\n }\n\n &::after {\n bottom: 3px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n &::before {\n transform: translateY(5px) rotate(45deg);\n }\n\n &::after {\n transform: translateY(-4px) rotate(-45deg);\n }\n `};\n`;\n\nexport const StyledMissingComponent = styled.div`\n background: ${({ theme }) => theme.colors.error};\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n padding: 20px;\n font-size: ${({ theme }) => theme.fontSizes.small.lg};\n color: ${({ theme }) => theme.colors.surface};\n font-weight: 600;\n display: flex;\n gap: 10px;\n align-items: center;\n`;\n\ninterface DocsWrapperProps {\n children: React.ReactNode;\n}\n\nfunction DocsWrapper({ children }: DocsWrapperProps) {\n return <StyledDocsWrapper>{children}</StyledDocsWrapper>;\n}\n\nfunction DocsSidebar({ children }: DocsProps) {\n return <StyledDocsSidebar>{children}</StyledDocsSidebar>;\n}\n\nfunction DocsContainer({ children }: DocsProps) {\n const { isOpen } = useContext(ChatContext);\n\n return (\n <StyledDocsContainer $isChatOpen={isOpen}>{children}</StyledDocsContainer>\n );\n}\n\nexport {\n DocsWrapper,\n DocsSidebar,\n DocsContainer,\n SectionBarContext,\n SectionBarProvider,\n};\n";
1
+ export declare const docsComponentsTemplate = "\"use client\";\nimport React, { createContext, useContext } from \"react\";\nimport styled, { css } from \"styled-components\";\nimport {\n resetButton,\n styledSmall,\n styledStrong,\n styledText,\n} from \"cherry-styled-components\";\nimport Link from \"next/link\";\nimport { mq, Theme } from \"@/app/theme\";\nimport {\n styledAnchor,\n styledTable,\n stylesLists,\n} from \"@/components/layout/SharedStyled\";\nimport { ChatContext } from \"@/components/Chat\";\n\nconst SectionBarContext = createContext(false);\n\nfunction SectionBarProvider({\n hasSectionBar,\n children,\n}: {\n hasSectionBar: boolean;\n children: React.ReactNode;\n}) {\n return (\n <SectionBarContext.Provider value={hasSectionBar}>\n {children}\n </SectionBarContext.Provider>\n );\n}\n\ninterface DocsProps {\n children: React.ReactNode;\n}\n\nconst StyledDocsWrapper = styled.main<{ theme: Theme }>`\n position: relative;\n`;\n\nconst StyledDocsSidebar = styled.div<{ theme: Theme }>`\n clear: both;\n`;\n\nconst StyledDocsContainer = styled.div<{ theme: Theme; $isChatOpen?: boolean }>`\n position: relative;\n padding: 0 20px 100px 20px;\n width: 100%;\n ${({ theme }) => styledText(theme)};\n transition: all 0.3s ease;\n\n ${mq(\"lg\")} {\n padding: 0 300px 80px 300px;\n\n ${({ $isChatOpen }) =>\n $isChatOpen &&\n css`\n padding: 0 440px 80px 300px;\n `}\n }\n\n & p {\n color: ${({ theme }) => theme.colors.grayDark};\n hyphens: auto;\n }\n\n & pre {\n max-width: 100%;\n }\n\n ${styledAnchor};\n ${stylesLists};\n ${styledTable};\n\n & img,\n & video,\n & iframe {\n max-width: 100%;\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n }\n\n & code:not([class]),\n & kbd {\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 20%, transparent)`};\n color: ${({ theme }) => theme.colors.dark};\n padding: 2px 4px;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n white-space: pre;\n }\n\n & .lucide {\n color: ${({ theme }) => theme.colors.primary};\n }\n\n & .aspect-video {\n aspect-ratio: 16 / 9;\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n }\n`;\n\nexport const StyledMarkdownContainer = styled.div`\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex-wrap: wrap;\n flex: 1;\n max-width: 640px;\n margin: auto;\n`;\n\ninterface Props {\n theme?: Theme;\n $isActive?: boolean;\n $isOpen?: boolean;\n $hasSectionBar?: boolean;\n}\n\nexport const StyledSidebar = styled.nav<Props>`\n position: fixed;\n overflow-y: auto;\n max-height: calc(\n 100dvh - ${({ $hasSectionBar }) => ($hasSectionBar ? 104 : 62)}px\n );\n width: 100%;\n z-index: 99;\n top: ${({ $hasSectionBar }) => ($hasSectionBar ? 104 : 62)}px;\n height: 100%;\n padding: 20px;\n opacity: 0;\n pointer-events: none;\n transition: all 0.3s ease;\n transform: translateY(30px);\n left: 0;\n background: ${({ theme }) => theme.colors.light};\n -webkit-overflow-scrolling: touch;\n display: flex;\n flex-direction: column;\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n ${mq(\"lg\")} {\n border-right: solid 1px ${({ theme }) => theme.colors.grayLight};\n transition: none;\n max-height: 100dvh;\n width: 220px;\n background: transparent;\n padding: 82px 20px 20px 20px;\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 5%, transparent)`};\n top: 0;\n width: 280px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n transform: translateY(0);\n opacity: 1;\n pointer-events: all;\n `}\n`;\n\nexport const StyledSidebarFooter = styled.div`\n padding: 22px 20px;\n position: sticky;\n border-top: 1px solid ${({ theme }) => theme.colors.grayLight};\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 5%, transparent)`};\n margin: 0 -20px -20px;\n bottom: -20px;\n backdrop-filter: blur(10px);\n\n ${mq(\"lg\")} {\n padding: 16px 20px;\n }\n`;\n\nexport const StyledIndexSidebar = styled.ul<{ theme: Theme }>`\n display: none;\n list-style: none;\n margin: 0;\n padding: 0;\n position: fixed;\n top: 0;\n right: 0;\n width: 280px;\n height: 100dvh;\n overflow-y: auto;\n z-index: 1;\n padding: 82px 20px 20px 20px;\n background: ${({ theme }) => theme.colors.light};\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n -webkit-overflow-scrolling: touch;\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n ${mq(\"lg\")} {\n display: block;\n }\n\n & li {\n padding: 5px 0;\n }\n`;\n\nexport const StyledIndexSidebarLabel = styled.span<{ theme: Theme }>`\n ${({ theme }) => styledSmall(theme)};\n color: ${({ theme }) => theme.colors.grayDark};\n`;\n\nexport const StyledIndexSidebarLi = styled.li<{\n theme: Theme;\n $isActive: boolean;\n}>`\n &::before {\n content: \"\";\n display: block;\n position: absolute;\n left: 0;\n height: 20px;\n width: 1px;\n background: transparent;\n transition: all 0.3s ease;\n }\n\n ${({ $isActive, theme }) =>\n $isActive &&\n css`\n &::before {\n background: ${theme.colors.primary};\n }\n `}\n`;\n\nexport const StyledIndexSidebarLink = styled.a<{\n theme: Theme;\n $isActive: boolean;\n}>`\n ${({ theme }) => styledSmall(theme)};\n color: ${({ theme, $isActive }) =>\n $isActive ? theme.colors.primary : theme.colors.dark};\n font-weight: ${({ $isActive }) => ($isActive ? \"600\" : \"400\")};\n text-decoration: none;\n transition: all 0.3s ease;\n\n &:hover {\n color: ${({ theme }) => theme.colors.primary};\n }\n`;\n\nexport const StyledSidebarList = styled.ul`\n list-style: none;\n margin: 0;\n padding: 0;\n\n &:last-of-type {\n margin-bottom: auto;\n }\n`;\n\nexport const StyledStrong = styled.strong<{ theme: Theme }>`\n font-weight: 600;\n ${({ theme }) => styledStrong(theme)};\n color: ${({ theme }) => theme.colors.accentStrong};\n display: inline-flex;\n align-items: center;\n gap: 8px;\n\n & svg {\n flex-shrink: 0;\n }\n`;\n\nexport const StyledSidebarListItem = styled.li`\n display: flex;\n gap: 10px;\n clear: both;\n`;\n\n// Shared appearance for every sidebar row - leaf links AND nested group\n// headers - so hover, active state, and the left rail read identically.\nconst sidebarRowStyles = css<Props>`\n text-decoration: none;\n font-size: ${({ theme }) => theme.fontSizes.small.lg};\n line-height: 1.6;\n color: ${({ theme }) => theme.colors.accentMuted};\n padding: 5px 0 5px 20px;\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n transition: all 0.3s ease;\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n & svg {\n flex-shrink: 0;\n }\n\n &:hover {\n color: ${({ theme }) => theme.colors.accent};\n border-color: ${({ theme }) => theme.colors.primary};\n }\n\n ${({ $isActive, theme }) =>\n $isActive &&\n css`\n color: ${theme.colors.accentStrong};\n border-color: ${theme.colors.primary};\n font-weight: 600;\n `};\n`;\n\n// The collapse chevron points right when closed and rotates to point down\n// when the group is open.\nconst sidebarChevron = css<Props>`\n & .lucide-chevron-right {\n margin-left: auto;\n transition: transform 0.3s ease;\n\n ${({ $isOpen }) =>\n $isOpen &&\n css`\n transform: rotate(90deg);\n `}\n }\n`;\n\nexport const StyledSidebarListItemLink = styled(Link)<Props>`\n ${sidebarRowStyles};\n`;\n\n// Nested navigation group. The header shares the link appearance/hover; a\n// non-navigable group is a single toggle button, while a group that is also a\n// page pairs a link with a chevron toggle. Children live in\n// StyledSidebarGroupContent, which animates open/closed via height 0 <-> auto\n// (enabled by interpolate-size in GlobalStyles, same as the Accordion).\nexport const StyledSidebarGroupButton = styled.button<Props>`\n ${resetButton};\n ${sidebarRowStyles};\n ${sidebarChevron};\n width: 100%;\n text-align: left;\n\n /* Buttons aren't covered by the global a:focus-visible ring, so this\n nav-row toggle carries its own copy of it. */\n &:focus-visible {\n outline: none;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n`;\n\nexport const StyledSidebarGroupRow = styled.div<Props>`\n ${sidebarRowStyles};\n ${sidebarChevron};\n\n /* The row is a plain div, so it never matches :focus-visible itself. Ring the\n whole row when its inner link or chevron takes keyboard focus instead, to\n match the leaf-row focus treatment. */\n &:has(:focus-visible) {\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n`;\n\nexport const StyledSidebarGroupLink = styled(Link)`\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n color: inherit;\n text-decoration: none;\n\n & svg {\n flex-shrink: 0;\n }\n\n /* Ring is drawn on the parent row via :has(:focus-visible); suppress the\n global a:focus-visible glow so it isn't drawn twice. */\n &:focus-visible {\n outline: none;\n box-shadow: none;\n }\n`;\n\nexport const StyledSidebarGroupChevron = styled.button`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n padding: 0;\n border: 0;\n background: none;\n color: inherit;\n cursor: pointer;\n\n /* Ring is drawn on the parent row via :has(:focus-visible). */\n &:focus-visible {\n outline: none;\n }\n`;\n\nexport const StyledSidebarGroupContent = styled.ul<Props>`\n list-style: none;\n margin: 0;\n padding: 0;\n height: 0;\n overflow: clip;\n transition: all 0.3s ease;\n\n ${({ $isOpen }) =>\n $isOpen &&\n css`\n height: auto;\n `}\n`;\n\nexport const StyleMobileBar = styled.button<Props>`\n ${resetButton};\n position: fixed;\n z-index: 999;\n bottom: 0;\n right: 20px;\n font-size: ${({ theme }) => theme.fontSizes.strong.lg};\n line-height: ${({ theme }) => theme.fontSizes.strong.lg};\n box-shadow: ${({ theme }) => theme.shadows.sm};\n background: ${({ theme }) => theme.colors.primary};\n color: ${({ theme }) => theme.colors.surface};\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n padding: 10px;\n border-radius: 100px;\n margin: 0 0 20px 0;\n font-weight: 600;\n display: flex;\n justify-content: flex-start;\n width: auto;\n\n ${mq(\"lg\")} {\n display: none;\n }\n\n ${({ $isActive }) => $isActive && `position: fixed;`};\n`;\n\nexport const StyledMobileBurger = styled.span<Props>`\n display: block;\n margin: auto 0;\n width: 18px;\n height: 18px;\n position: relative;\n overflow: hidden;\n background: transparent;\n position: relative;\n transform: scale(0.8);\n\n &::before,\n &::after {\n content: \"\";\n display: block;\n position: absolute;\n width: 18px;\n height: 3px;\n border-radius: 3px;\n background: ${({ theme }) => theme.colors.surface};\n transition: all 0.3s ease;\n }\n\n &::before {\n top: 3px;\n }\n\n &::after {\n bottom: 3px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n &::before {\n transform: translateY(5px) rotate(45deg);\n }\n\n &::after {\n transform: translateY(-4px) rotate(-45deg);\n }\n `};\n`;\n\nexport const StyledMissingComponent = styled.div`\n background: ${({ theme }) => theme.colors.error};\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n padding: 20px;\n font-size: ${({ theme }) => theme.fontSizes.small.lg};\n color: ${({ theme }) => theme.colors.surface};\n font-weight: 600;\n display: flex;\n gap: 10px;\n align-items: center;\n`;\n\ninterface DocsWrapperProps {\n children: React.ReactNode;\n}\n\nfunction DocsWrapper({ children }: DocsWrapperProps) {\n return <StyledDocsWrapper>{children}</StyledDocsWrapper>;\n}\n\nfunction DocsSidebar({ children }: DocsProps) {\n return <StyledDocsSidebar>{children}</StyledDocsSidebar>;\n}\n\nfunction DocsContainer({ children }: DocsProps) {\n const { isOpen } = useContext(ChatContext);\n\n return (\n <StyledDocsContainer $isChatOpen={isOpen}>{children}</StyledDocsContainer>\n );\n}\n\nexport {\n DocsWrapper,\n DocsSidebar,\n DocsContainer,\n SectionBarContext,\n SectionBarProvider,\n};\n";
@@ -82,7 +82,8 @@ const StyledDocsContainer = styled.div<{ theme: Theme; $isChatOpen?: boolean }>\
82
82
  border-radius: \${({ theme }) => theme.spacing.radius.lg};
83
83
  }
84
84
 
85
- & code:not([class]) {
85
+ & code:not([class]),
86
+ & kbd {
86
87
  background: \${({ theme }) =>
87
88
  \`color-mix(in srgb, \${theme.colors.primaryLight} 20%, transparent)\`};
88
89
  color: \${({ theme }) => theme.colors.dark};
@@ -1 +1 @@
1
- export declare const accordionMdxTemplate = "---\ntitle: \"Accordion\"\ndescription: \"Interactive panels for toggling visibility of content.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 4\n---\n\n# Accordion\n\nInteractive panels for toggling visibility of content.\n\nAccordion elements help organize information by letting users show or hide sections as needed. They\u2019re an effective way to manage progressive disclosure and simplify navigation through dense or optional content.\n\n## Accordion Usage\n\nYou can use the Accordion component directly within your MDX files without any import. The following example shows a basic usage:\n\n````mdx\n<Accordion title=\"What is MDX?\">\n You can put any content in here, including other components, like code:\n\n```java HelloWorld.java\n class HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n }\n```\n\n</Accordion>\n````\n\n<Accordion title=\"What is MDX?\">\n You can put any content in here, including other components, like code:\n\n```java HelloWorld.java\n class HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n }\n```\n\n</Accordion>\n\n## Properties\n\n<Field value=\"title\" type=\"string\" required>\n The title of the accordion.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the accordion.\n</Field>";
1
+ export declare const accordionMdxTemplate = "---\ntitle: \"Accordion\"\ndescription: \"Interactive panels for toggling visibility of content.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 4\n---\n\n# Accordion\n\nInteractive panels for toggling visibility of content.\n\nAccordion elements help organize information by letting users show or hide sections as needed. They\u2019re an effective way to manage progressive disclosure and simplify navigation through dense or optional content.\n\n## Accordion Usage\n\nYou can use the Accordion component directly within your MDX files without any import. The following example shows a basic usage:\n\n````html\n<Accordion title=\"What is MDX?\">\n You can put any content in here, including other components, like code:\n\n ```java\n class HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n }\n ```\n</Accordion>\n````\n\n<Accordion title=\"What is MDX?\">\n You can put any content in here, including other components, like code:\n\n ```java\n class HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n }\n ```\n</Accordion>\n\n## Properties\n\n<Field value=\"title\" type=\"string\" required>\n The title of the accordion.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the accordion.\n</Field>";
@@ -17,32 +17,30 @@ Accordion elements help organize information by letting users show or hide secti
17
17
 
18
18
  You can use the Accordion component directly within your MDX files without any import. The following example shows a basic usage:
19
19
 
20
- \`\`\`\`mdx
20
+ \`\`\`\`html
21
21
  <Accordion title="What is MDX?">
22
- You can put any content in here, including other components, like code:
23
-
24
- \`\`\`java HelloWorld.java
25
- class HelloWorld {
26
- public static void main(String[] args) {
27
- System.out.println("Hello, World!");
28
- }
29
- }
30
- \`\`\`
31
-
22
+ You can put any content in here, including other components, like code:
23
+
24
+ \`\`\`java
25
+ class HelloWorld {
26
+ public static void main(String[] args) {
27
+ System.out.println("Hello, World!");
28
+ }
29
+ }
30
+ \`\`\`
32
31
  </Accordion>
33
32
  \`\`\`\`
34
33
 
35
34
  <Accordion title="What is MDX?">
36
- You can put any content in here, including other components, like code:
37
-
38
- \`\`\`java HelloWorld.java
39
- class HelloWorld {
40
- public static void main(String[] args) {
41
- System.out.println("Hello, World!");
42
- }
43
- }
44
- \`\`\`
45
-
35
+ You can put any content in here, including other components, like code:
36
+
37
+ \`\`\`java
38
+ class HelloWorld {
39
+ public static void main(String[] args) {
40
+ System.out.println("Hello, World!");
41
+ }
42
+ }
43
+ \`\`\`
46
44
  </Accordion>
47
45
 
48
46
  ## Properties
@@ -1 +1 @@
1
- export declare const aiAssistantMdxTemplate = "---\ntitle: \"AI Assistant\"\ndescription: \"Integrate AI capabilities into your Doccupine documentation using OpenAI, Anthropic, or Google Gemini.\"\ndate: \"2026-02-19\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 8\n---\n\n# AI Assistant\n\nDoccupine supports AI integration to enhance your documentation experience. You can use OpenAI, Anthropic, or Google Gemini to power AI features in your documentation site. The AI assistant uses your documentation content as context, allowing users to ask questions about your docs and receive accurate answers based on the documentation.\n\n## Setup\n\nTo enable AI features, create an `.env` file in the directory where your website is generated. By default, this is the `nextjs-app/` directory.\n\n## Configuration\n\nCreate an `.env` file with the following configuration options:\n\n```env\n# LLM Provider Configuration\n# Choose your preferred LLM provider: openai, anthropic, or google\nLLM_PROVIDER=openai\n\n# API Keys (set the one matching your provider)\nOPENAI_API_KEY=your_openai_api_key_here\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nGOOGLE_API_KEY=your_google_api_key_here\n\n# Optional: Override default chat model (see your provider's docs for available models)\n# LLM_CHAT_MODEL=your-model-id\n\n# Optional: Override default embedding model (see your provider's docs for available models)\n# Note: Anthropic doesn't provide embeddings, will fallback to OpenAI\n# LLM_EMBEDDING_MODEL=your-embedding-model-id\n\n# Optional: Set temperature (0-1, default: 0)\n# LLM_TEMPERATURE=0\n```\n\n## Provider Selection\n\nSet `LLM_PROVIDER` to one of the following values:\n\n- `openai` - Use OpenAI's models\n- `anthropic` - Use Anthropic's models\n- `google` - Use Google's models\n\n## API Keys\n\nYou need to set the API key that matches your chosen provider:\n\n- For OpenAI: Set `OPENAI_API_KEY`\n- For Anthropic: Set `ANTHROPIC_API_KEY`\n- For Google: Set `GOOGLE_API_KEY`\n\n<Callout type=\"warning\">\n Keep your API keys secure. Never commit your `.env` file to version control.\n</Callout>\n\n<Callout type=\"note\">\n Doccupine automatically adds `.env` to your `.gitignore` file.\n</Callout>\n\n## Using Anthropic with OpenAI\n\nIf you want to use Anthropic as your LLM provider, you must also have an OpenAI API key set. Here's why:\n\n### The Situation\n\nAnthropic (Claude) does not provide an embeddings API. They only offer chat/completion models, not text embeddings.\n\nYour RAG (Retrieval-Augmented Generation) system has two components:\n\n- **Chat/Completion** - Generates answers, works with Anthropic.\n- **Embeddings** - Creates vector representations of text for search, Anthropic doesn't provide this.\n\nWhen using Anthropic as your `LLM_PROVIDER`, Doccupine will use Anthropic for chat/completion tasks, but will automatically fallback to OpenAI for embeddings. This means you need both API keys configured:\n\n```env\nLLM_PROVIDER=anthropic\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nOPENAI_API_KEY=your_openai_api_key_here\n```\n\nThis hybrid approach allows you to leverage Anthropic's powerful chat models while still having access to embeddings functionality through OpenAI.\n\n## Default models\n\n| Provider | Chat model | Embedding model |\n| --------- | ---------------------------- | ------------------------ |\n| OpenAI | `gpt-4.1-nano` | `text-embedding-3-small` |\n| Anthropic | `claude-sonnet-4-5-20250929` | OpenAI fallback |\n| Google | `gemini-2.5-flash-lite` | `gemini-embedding-001` |\n\n## Optional Settings\n\n### Chat Model\n\nOverride the default chat model by uncommenting and setting `LLM_CHAT_MODEL`. You can use any available model from your chosen provider. For a complete list of available models, refer to the official documentation:\n\n- [OpenAI Models](https://platform.openai.com/docs/models)\n- [Anthropic Models](https://docs.anthropic.com/claude/docs/models-overview)\n- [Google Gemini Models](https://ai.google.dev/models/gemini)\n\n### Embedding Model\n\nOverride the default embedding model by uncommenting and setting `LLM_EMBEDDING_MODEL`. For a complete list of available embedding models, refer to the official documentation:\n\n- [OpenAI Embeddings](https://platform.openai.com/docs/guides/embeddings)\n- [Google Gemini Embeddings](https://ai.google.dev/gemini-api/docs/embeddings)\n- **Anthropic**: Anthropic doesn't provide embeddings. If you use Anthropic as your provider, Doccupine will fallback to OpenAI for embeddings.\n\n### Temperature\n\nControl the randomness of AI responses by setting `LLM_TEMPERATURE` to a value between 0 and 1:\n\n- `0` - More deterministic and focused responses (default)\n- `1` - More creative and varied responses";
1
+ export declare const aiAssistantMdxTemplate = "---\ntitle: \"AI Assistant\"\ndescription: \"Integrate AI capabilities into your Doccupine documentation using OpenAI, Anthropic, or Google Gemini.\"\ndate: \"2026-02-19\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 8\n---\n\n# AI Assistant\n\nDoccupine supports AI integration to enhance your documentation experience. You can use OpenAI, Anthropic, or Google Gemini to power AI features in your documentation site. The AI assistant uses your documentation content as context, allowing users to ask questions about your docs and receive accurate answers based on the documentation.\n\n## Opening the Assistant\n\nOnce a provider is configured, an assistant button appears in the header. You can open and close the assistant from anywhere on the site by pressing <kbd>Command</kbd> + <kbd>I</kbd> (<kbd>Ctrl</kbd> + <kbd>I</kbd> on Windows). Press the same shortcut again to dismiss it.\n\n<Callout type=\"note\">\n The keyboard shortcut is only active once you have configured an LLM provider, as described below.\n</Callout>\n\n## Setup\n\nTo enable AI features, create an `.env` file in the directory where your website is generated. By default, this is the `nextjs-app/` directory.\n\n## Configuration\n\nCreate an `.env` file with the following configuration options:\n\n```env\n# LLM Provider Configuration\n# Choose your preferred LLM provider: openai, anthropic, or google\nLLM_PROVIDER=openai\n\n# API Keys (set the one matching your provider)\nOPENAI_API_KEY=your_openai_api_key_here\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nGOOGLE_API_KEY=your_google_api_key_here\n\n# Optional: Override default chat model (see your provider's docs for available models)\n# LLM_CHAT_MODEL=your-model-id\n\n# Optional: Override default embedding model (see your provider's docs for available models)\n# Note: Anthropic doesn't provide embeddings, will fallback to OpenAI\n# LLM_EMBEDDING_MODEL=your-embedding-model-id\n\n# Optional: Set temperature (0-1, default: 0)\n# LLM_TEMPERATURE=0\n```\n\n## Provider Selection\n\nSet `LLM_PROVIDER` to one of the following values:\n\n- `openai` - Use OpenAI's models\n- `anthropic` - Use Anthropic's models\n- `google` - Use Google's models\n\n## API Keys\n\nYou need to set the API key that matches your chosen provider:\n\n- For OpenAI: Set `OPENAI_API_KEY`\n- For Anthropic: Set `ANTHROPIC_API_KEY`\n- For Google: Set `GOOGLE_API_KEY`\n\n<Callout type=\"warning\">\n Keep your API keys secure. Never commit your `.env` file to version control.\n</Callout>\n\n<Callout type=\"note\">\n Doccupine automatically adds `.env` to your `.gitignore` file.\n</Callout>\n\n## Using Anthropic with OpenAI\n\nIf you want to use Anthropic as your LLM provider, you must also have an OpenAI API key set. Here's why:\n\n### The Situation\n\nAnthropic (Claude) does not provide an embeddings API. They only offer chat/completion models, not text embeddings.\n\nYour RAG (Retrieval-Augmented Generation) system has two components:\n\n- **Chat/Completion** - Generates answers, works with Anthropic.\n- **Embeddings** - Creates vector representations of text for search, Anthropic doesn't provide this.\n\nWhen using Anthropic as your `LLM_PROVIDER`, Doccupine will use Anthropic for chat/completion tasks, but will automatically fallback to OpenAI for embeddings. This means you need both API keys configured:\n\n```env\nLLM_PROVIDER=anthropic\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nOPENAI_API_KEY=your_openai_api_key_here\n```\n\nThis hybrid approach allows you to leverage Anthropic's powerful chat models while still having access to embeddings functionality through OpenAI.\n\n## Default models\n\n| Provider | Chat model | Embedding model |\n| --------- | ---------------------------- | ------------------------ |\n| OpenAI | `gpt-4.1-nano` | `text-embedding-3-small` |\n| Anthropic | `claude-sonnet-4-5-20250929` | OpenAI fallback |\n| Google | `gemini-2.5-flash-lite` | `gemini-embedding-001` |\n\n## Optional Settings\n\n### Chat Model\n\nOverride the default chat model by uncommenting and setting `LLM_CHAT_MODEL`. You can use any available model from your chosen provider. For a complete list of available models, refer to the official documentation:\n\n- [OpenAI Models](https://platform.openai.com/docs/models)\n- [Anthropic Models](https://docs.anthropic.com/claude/docs/models-overview)\n- [Google Gemini Models](https://ai.google.dev/models/gemini)\n\n### Embedding Model\n\nOverride the default embedding model by uncommenting and setting `LLM_EMBEDDING_MODEL`. For a complete list of available embedding models, refer to the official documentation:\n\n- [OpenAI Embeddings](https://platform.openai.com/docs/guides/embeddings)\n- [Google Gemini Embeddings](https://ai.google.dev/gemini-api/docs/embeddings)\n- **Anthropic**: Anthropic doesn't provide embeddings. If you use Anthropic as your provider, Doccupine will fallback to OpenAI for embeddings.\n\n### Temperature\n\nControl the randomness of AI responses by setting `LLM_TEMPERATURE` to a value between 0 and 1:\n\n- `0` - More deterministic and focused responses (default)\n- `1` - More creative and varied responses";
@@ -11,6 +11,14 @@ order: 8
11
11
 
12
12
  Doccupine supports AI integration to enhance your documentation experience. You can use OpenAI, Anthropic, or Google Gemini to power AI features in your documentation site. The AI assistant uses your documentation content as context, allowing users to ask questions about your docs and receive accurate answers based on the documentation.
13
13
 
14
+ ## Opening the Assistant
15
+
16
+ Once a provider is configured, an assistant button appears in the header. You can open and close the assistant from anywhere on the site by pressing <kbd>Command</kbd> + <kbd>I</kbd> (<kbd>Ctrl</kbd> + <kbd>I</kbd> on Windows). Press the same shortcut again to dismiss it.
17
+
18
+ <Callout type="note">
19
+ The keyboard shortcut is only active once you have configured an LLM provider, as described below.
20
+ </Callout>
21
+
14
22
  ## Setup
15
23
 
16
24
  To enable AI features, create an \`.env\` file in the directory where your website is generated. By default, this is the \`nextjs-app/\` directory.
@@ -1 +1 @@
1
- export declare const analyticsMdxTemplate = "---\ntitle: \"Analytics\"\ndescription: \"Add PostHog analytics to your documentation site with an analytics.json file for both client-side and server-side tracking.\"\ndate: \"2026-02-24\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 10\n---\n\n# Analytics\n\nTrack how users interact with your documentation using PostHog. Doccupine supports both client-side and server-side tracking out of the box, with a privacy-first proxy that routes analytics through your own domain.\n\n## analytics.json\n\nPlace an `analytics.json` at your project root (the same folder where you execute `npx doccupine`).\n\n```json\n{\n \"provider\": \"posthog\",\n \"posthog\": {\n \"key\": \"phc_your_project_api_key\",\n \"host\": \"https://us.i.posthog.com\"\n }\n}\n```\n\n## Fields\n\n- **provider**: The analytics provider to use. Currently only `\"posthog\"` is supported.\n- **posthog.key**: Your PostHog project API key. You can find this in your PostHog project settings under \"Project API Key\". This is a public identifier - it is safe to commit to version control.\n- **posthog.host**: The PostHog ingestion endpoint. Use `https://us.i.posthog.com` for US Cloud or `https://eu.i.posthog.com` for EU Cloud. If you self-host PostHog, use your instance URL.\n\n<Callout type=\"note\">\n The PostHog project API key is a public identifier used to send events. It is not a secret and is safe to include in your repository.\n</Callout>\n\n## What gets tracked\n\nWhen `analytics.json` is configured, Doccupine enables two layers of tracking:\n\n### Client-side\n\n- **Page views**: Captured on every client-side navigation using Next.js router hooks.\n- **Page leave**: Automatically captured when a user navigates away from a page.\n\n### Server-side\n\n- **Page views**: Captured in middleware on every page request, including the initial server render.\n- **Request metadata**: URL, pathname, host, referrer, and user agent are sent with each event.\n- **Smart filtering**: API routes, internal Next.js routes, and prefetch requests are automatically excluded.\n\n## Privacy proxy\n\nDoccupine routes all analytics traffic through your documentation domain using Next.js rewrites. Instead of sending data directly to PostHog (which ad blockers may intercept), requests go through `/ingest` on your own domain and are proxied to PostHog.\n\nThis means:\n\n- No third-party domains appear in network requests.\n- Ad blockers are less likely to interfere with tracking.\n- Your users' browsing data stays within your domain boundary before reaching PostHog.\n\nThe proxy destinations are derived automatically from the `host` field in your configuration.\n\n## Getting a PostHog key\n\n1. Sign up at [posthog.com](https://posthog.com) (free tier available).\n2. Create a new project.\n3. Go to **Project Settings** and copy the **Project API Key**.\n4. Paste it into your `analytics.json` as the `posthog.key` value.\n\n## Behavior\n\n- **Placement**: Put `analytics.json` in the project root alongside `config.json` and `theme.json`.\n- **Hot reload**: Changes to `analytics.json` are picked up automatically in watch mode. The layout, middleware, and Next.js config are regenerated.\n- **Graceful degradation**: If `analytics.json` is missing, empty, or has an invalid configuration, no tracking code runs. Your site works exactly the same without it.\n- **Dev server restart**: After adding or removing `analytics.json` for the first time, you may need to restart the Next.js dev server for proxy rewrites to take effect.\n\n<Callout type=\"warning\">\n After adding `analytics.json` for the first time, restart the dev server so the proxy rewrites are picked up by Next.js.\n</Callout>\n\n## Regions\n\nPostHog offers two cloud regions. Set the `host` field accordingly:\n\n| Region | Host |\n| -------- | -------------------------- |\n| US Cloud | `https://us.i.posthog.com` |\n| EU Cloud | `https://eu.i.posthog.com` |\n\nIf you omit the `host` field, it defaults to the US Cloud endpoint.\n\n## Example\n\n### Minimal configuration (US Cloud)\n\n```json\n{\n \"provider\": \"posthog\",\n \"posthog\": {\n \"key\": \"phc_your_project_api_key\"\n }\n}\n```\n\n### EU Cloud\n\n```json\n{\n \"provider\": \"posthog\",\n \"posthog\": {\n \"key\": \"phc_your_project_api_key\",\n \"host\": \"https://eu.i.posthog.com\"\n }\n}\n```\n\n## Tips\n\n- **Start simple**: Add the config with just your key and verify events appear in your PostHog dashboard before customizing further.\n- **Check your dashboard**: After deploying, visit your PostHog project to confirm page view events are flowing in.\n- **Production only**: Consider adding `analytics.json` only in your production/deployment setup to avoid tracking local development traffic.";
1
+ export declare const analyticsMdxTemplate = "---\ntitle: \"Analytics\"\ndescription: \"Add PostHog analytics to your documentation site with an analytics.json file for both client-side and server-side tracking.\"\ndate: \"2026-02-24\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 10\n---\n\n# Analytics\n\nTrack how users interact with your documentation using PostHog. Doccupine supports both client-side and server-side tracking out of the box, with a privacy-first proxy that routes analytics through your own domain.\n\n## analytics.json\n\nPlace an `analytics.json` at your project root (the same directory where you execute `npx doccupine`).\n\n```json\n{\n \"provider\": \"posthog\",\n \"posthog\": {\n \"key\": \"phc_your_project_api_key\",\n \"host\": \"https://us.i.posthog.com\"\n }\n}\n```\n\n## Fields\n\n- **provider**: The analytics provider to use. Currently only `\"posthog\"` is supported.\n- **posthog.key**: Your PostHog project API key. You can find this in your PostHog project settings under \"Project API Key\". This is a public identifier - it is safe to commit to version control.\n- **posthog.host**: The PostHog ingestion endpoint. Use `https://us.i.posthog.com` for US Cloud or `https://eu.i.posthog.com` for EU Cloud. If you self-host PostHog, use your instance URL.\n\n<Callout type=\"note\">\n The PostHog project API key is a public identifier used to send events. It is not a secret and is safe to include in your repository.\n</Callout>\n\n## What gets tracked\n\nWhen `analytics.json` is configured, Doccupine enables two layers of tracking:\n\n### Client-side\n\n- **Page views**: Captured on every client-side navigation using Next.js router hooks.\n- **Page leave**: Automatically captured when a user navigates away from a page.\n\n### Server-side\n\n- **Page views**: Captured in middleware on every page request, including the initial server render.\n- **Request metadata**: URL, pathname, host, referrer, and user agent are sent with each event.\n- **Smart filtering**: API routes, internal Next.js routes, and prefetch requests are automatically excluded.\n\n## Privacy proxy\n\nDoccupine routes all analytics traffic through your documentation domain using Next.js rewrites. Instead of sending data directly to PostHog (which ad blockers may intercept), requests go through `/ingest` on your own domain and are proxied to PostHog.\n\nThis means:\n\n- No third-party domains appear in network requests.\n- Ad blockers are less likely to interfere with tracking.\n- Your users' browsing data stays within your domain boundary before reaching PostHog.\n\nThe proxy destinations are derived automatically from the `host` field in your configuration.\n\n## Getting a PostHog key\n\n1. Sign up at [posthog.com](https://posthog.com) (free tier available).\n2. Create a new project.\n3. Go to **Project Settings** and copy the **Project API Key**.\n4. Paste it into your `analytics.json` as the `posthog.key` value.\n\n## Behavior\n\n- **Placement**: Put `analytics.json` in the project root alongside `config.json` and `theme.json`.\n- **Hot reload**: Changes to `analytics.json` are picked up automatically in watch mode. The layout, middleware, and Next.js config are regenerated.\n- **Graceful degradation**: If `analytics.json` is missing, empty, or has an invalid configuration, no tracking code runs. Your site works exactly the same without it.\n- **Dev server restart**: After adding or removing `analytics.json` for the first time, you may need to restart the Next.js dev server for proxy rewrites to take effect.\n\n<Callout type=\"warning\">\n After adding `analytics.json` for the first time, restart the dev server so the proxy rewrites are picked up by Next.js.\n</Callout>\n\n## Regions\n\nPostHog offers two cloud regions. Set the `host` field accordingly:\n\n| Region | Host |\n| -------- | -------------------------- |\n| US Cloud | `https://us.i.posthog.com` |\n| EU Cloud | `https://eu.i.posthog.com` |\n\nIf you omit the `host` field, it defaults to the US Cloud endpoint.\n\n## Example\n\n### Minimal configuration (US Cloud)\n\n```json\n{\n \"provider\": \"posthog\",\n \"posthog\": {\n \"key\": \"phc_your_project_api_key\"\n }\n}\n```\n\n### EU Cloud\n\n```json\n{\n \"provider\": \"posthog\",\n \"posthog\": {\n \"key\": \"phc_your_project_api_key\",\n \"host\": \"https://eu.i.posthog.com\"\n }\n}\n```\n\n## Tips\n\n- **Start simple**: Add the config with just your key and verify events appear in your PostHog dashboard before customizing further.\n- **Check your dashboard**: After deploying, visit your PostHog project to confirm page view events are flowing in.\n- **Production only**: Consider adding `analytics.json` only in your production/deployment setup to avoid tracking local development traffic.";
@@ -13,7 +13,7 @@ Track how users interact with your documentation using PostHog. Doccupine suppor
13
13
 
14
14
  ## analytics.json
15
15
 
16
- Place an \`analytics.json\` at your project root (the same folder where you execute \`npx doccupine\`).
16
+ Place an \`analytics.json\` at your project root (the same directory where you execute \`npx doccupine\`).
17
17
 
18
18
  \`\`\`json
19
19
  {
@@ -1 +1 @@
1
- export declare const buttonsMdxTemplate = "---\ntitle: \"Buttons\"\ndescription: \"A flexible action component supporting variants, sizes, icons, and links.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 7\n---\n\n# Buttons\n\nA flexible action component supporting variants, sizes, icons, and links.\n\nButtons help users initiate actions or navigate to other pages. Use variants to convey emphasis, size for hierarchy, and icons to add clarity.\n\n## Button Usage\n\nYou can use the Button component directly within your MDX files without any import. The following examples show basic usage:\n\n```mdx\n<Button>Primary</Button>\n<Button variant=\"secondary\">Secondary</Button>\n<Button variant=\"tertiary\">Tertiary</Button>\n```\n\n<Button>Primary</Button>\n<Button variant=\"secondary\">Secondary</Button>\n<Button variant=\"tertiary\">Tertiary</Button>\n\n### Sizes\n\n```mdx\n<Button size=\"default\">Default size</Button>\n<Button size=\"big\">Big size</Button>\n```\n\n<Button size=\"default\">Default size</Button>\n<Button size=\"big\">Big size</Button>\n\n### Outline\n\n```mdx\n<Button outline>Outlined</Button>\n```\n\n<Button outline>Outlined</Button>\n\n### Full width\n\n```mdx\n<Button fullWidth>Full width button</Button>\n```\n\n<Button fullWidth>Full width button</Button>\n\n### With icon\n\n```mdx\n<Button icon=\"arrow-right\" iconPosition=\"left\">\n With left icon\n</Button>\n<Button icon=\"arrow-right\" iconPosition=\"right\">\n With right icon\n</Button>\n```\n\n<Button icon=\"arrow-right\" iconPosition=\"left\">With left icon</Button>\n<Button icon=\"arrow-right\" iconPosition=\"right\">With right icon</Button>\n\n### As a link\n\nButtons can render as links when you provide an `href`.\n\n```mdx\n<Button href=\"/\">Home</Button>\n```\n\n<Button href=\"/\">Home</Button>\n\n## Properties\n\n<Field value=\"children\" type=\"node\" required>\n The content of the button.\n</Field>\n\n<Field value=\"variant\" type=\"string\">\n Controls visual emphasis.\n</Field>\n\n- **primary**\n- **secondary**\n- **tertiary**\n\n<Field value=\"size\" type=\"string\">\n Controls the size of the button.\n</Field>\n\n- **default**\n- **big**\n\n<Field value=\"outline\" type=\"boolean\">\n When true, renders the outlined style of the selected variant.\n</Field>\n\n<Field value=\"fullWidth\" type=\"boolean\">\n When true, the button expands to the full width of its container.\n</Field>\n\n<Field value=\"icon\" type=\"string\">\n Optional icon to display inside the button.\n</Field>\n\n- [**Lucide icon**](https://lucide.dev/icons) name or icon node\n\n<Field value=\"iconPosition\" type=\"string\">\n The position of the icon relative to the text.\n</Field>\n\n- **left**\n- **right**\n\n<Field value=\"href\" type=\"string\">\n When provided, the button renders as a link (`<a>`), enabling navigation.\n</Field>";
1
+ export declare const buttonsMdxTemplate = "---\ntitle: \"Buttons\"\ndescription: \"A flexible action component supporting variants, sizes, icons, and links.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 7\n---\n\n# Buttons\n\nA flexible action component supporting variants, sizes, icons, and links.\n\nButtons help users initiate actions or navigate to other pages. Use variants to convey emphasis, size for hierarchy, and icons to add clarity.\n\n## Button Usage\n\nYou can use the Button component directly within your MDX files without any import. The following examples show basic usage:\n\n```html\n<Button>Primary</Button>\n<Button variant=\"secondary\">Secondary</Button>\n<Button variant=\"tertiary\">Tertiary</Button>\n```\n\n<Button>Primary</Button>\n<Button variant=\"secondary\">Secondary</Button>\n<Button variant=\"tertiary\">Tertiary</Button>\n\n### Sizes\n\n```html\n<Button size=\"default\">Default size</Button>\n<Button size=\"big\">Big size</Button>\n```\n\n<Button size=\"default\">Default size</Button>\n<Button size=\"big\">Big size</Button>\n\n### Outline\n\n```html\n<Button outline>Outlined</Button>\n```\n\n<Button outline>Outlined</Button>\n\n### Full width\n\n```html\n<Button fullWidth>Full width button</Button>\n```\n\n<Button fullWidth>Full width button</Button>\n\n### With icon\n\n```html\n<Button icon=\"arrow-right\" iconPosition=\"left\">\n With left icon\n</Button>\n<Button icon=\"arrow-right\" iconPosition=\"right\">\n With right icon\n</Button>\n```\n\n<Button icon=\"arrow-right\" iconPosition=\"left\">With left icon</Button>\n<Button icon=\"arrow-right\" iconPosition=\"right\">With right icon</Button>\n\n### As a link\n\nButtons can render as links when you provide an `href`.\n\n```html\n<Button href=\"/\">Home</Button>\n```\n\n<Button href=\"/\">Home</Button>\n\n## Properties\n\n<Field value=\"children\" type=\"node\" required>\n The content of the button.\n</Field>\n\n<Field value=\"variant\" type=\"string\">\n Controls visual emphasis.\n</Field>\n\n- **primary**\n- **secondary**\n- **tertiary**\n\n<Field value=\"size\" type=\"string\">\n Controls the size of the button.\n</Field>\n\n- **default**\n- **big**\n\n<Field value=\"outline\" type=\"boolean\">\n When true, renders the outlined style of the selected variant.\n</Field>\n\n<Field value=\"fullWidth\" type=\"boolean\">\n When true, the button expands to the full width of its container.\n</Field>\n\n<Field value=\"icon\" type=\"string\">\n Optional icon to display inside the button.\n</Field>\n\n- [**Lucide icon**](https://lucide.dev/icons) name or icon node\n\n<Field value=\"iconPosition\" type=\"string\">\n The position of the icon relative to the text.\n</Field>\n\n- **left**\n- **right**\n\n<Field value=\"href\" type=\"string\">\n When provided, the button renders as a link (`<a>`), enabling navigation.\n</Field>";
@@ -17,7 +17,7 @@ Buttons help users initiate actions or navigate to other pages. Use variants to
17
17
 
18
18
  You can use the Button component directly within your MDX files without any import. The following examples show basic usage:
19
19
 
20
- \`\`\`mdx
20
+ \`\`\`html
21
21
  <Button>Primary</Button>
22
22
  <Button variant="secondary">Secondary</Button>
23
23
  <Button variant="tertiary">Tertiary</Button>
@@ -29,7 +29,7 @@ You can use the Button component directly within your MDX files without any impo
29
29
 
30
30
  ### Sizes
31
31
 
32
- \`\`\`mdx
32
+ \`\`\`html
33
33
  <Button size="default">Default size</Button>
34
34
  <Button size="big">Big size</Button>
35
35
  \`\`\`
@@ -39,7 +39,7 @@ You can use the Button component directly within your MDX files without any impo
39
39
 
40
40
  ### Outline
41
41
 
42
- \`\`\`mdx
42
+ \`\`\`html
43
43
  <Button outline>Outlined</Button>
44
44
  \`\`\`
45
45
 
@@ -47,7 +47,7 @@ You can use the Button component directly within your MDX files without any impo
47
47
 
48
48
  ### Full width
49
49
 
50
- \`\`\`mdx
50
+ \`\`\`html
51
51
  <Button fullWidth>Full width button</Button>
52
52
  \`\`\`
53
53
 
@@ -55,7 +55,7 @@ You can use the Button component directly within your MDX files without any impo
55
55
 
56
56
  ### With icon
57
57
 
58
- \`\`\`mdx
58
+ \`\`\`html
59
59
  <Button icon="arrow-right" iconPosition="left">
60
60
  With left icon
61
61
  </Button>
@@ -71,7 +71,7 @@ You can use the Button component directly within your MDX files without any impo
71
71
 
72
72
  Buttons can render as links when you provide an \`href\`.
73
73
 
74
- \`\`\`mdx
74
+ \`\`\`html
75
75
  <Button href="/">Home</Button>
76
76
  \`\`\`
77
77
 
@@ -1 +1 @@
1
- export declare const calloutsMdxTemplate = "---\ntitle: \"Callouts\"\ndescription: \"Make your content stand out by using callouts for extra emphasis.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 8\n---\n\n# Callouts\n\nMake your content stand out by using callouts for extra emphasis.\n\nYou can format them as Note, Warning, Info, Danger and Success.\n\n## Callouts Usage\n\nYou can use the Callouts component directly within your MDX files without any import. The following example shows a basic usage:\n\n```mdx\n<Callout type=\"note\">This is a note callout</Callout>\n\n<Callout type=\"warning\">This is a warning callout</Callout>\n\n<Callout type=\"info\">This is an info callout</Callout>\n\n<Callout type=\"danger\">This is a danger callout</Callout>\n\n<Callout type=\"success\">This is a success callout</Callout>\n```\n\n<Callout type=\"note\">\n This is a note callout\n</Callout>\n\n<Callout type=\"warning\">\n This is a warning callout\n</Callout>\n\n<Callout type=\"info\">\n This is an info callout\n</Callout>\n\n<Callout type=\"danger\">\n This is a danger callout\n</Callout>\n\n<Callout type=\"success\">\n This is a success callout\n</Callout>\n\n## Properties\n\n<Field value=\"type\" type=\"string\">\n The type of the callout: `note`, `info`, `warning`, `danger`, or `success`.\n</Field>\n\n<Field value=\"icon\" type=\"string\">\n A custom [Lucide](https://lucide.dev/icons) icon name. Overrides the default icon for the callout type.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the callout.\n</Field>";
1
+ export declare const calloutsMdxTemplate = "---\ntitle: \"Callouts\"\ndescription: \"Make your content stand out by using callouts for extra emphasis.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 8\n---\n\n# Callouts\n\nMake your content stand out by using callouts for extra emphasis.\n\nYou can format them as Note, Warning, Info, Danger and Success.\n\n## Callouts Usage\n\nYou can use the Callouts component directly within your MDX files without any import. The following example shows a basic usage:\n\n```html\n<Callout type=\"note\">This is a note callout</Callout>\n<Callout type=\"warning\">This is a warning callout</Callout>\n<Callout type=\"info\">This is an info callout</Callout>\n<Callout type=\"danger\">This is a danger callout</Callout>\n<Callout type=\"success\">This is a success callout</Callout>\n```\n\n<Callout type=\"note\">\n This is a note callout\n</Callout>\n<Callout type=\"warning\">\n This is a warning callout\n</Callout>\n<Callout type=\"info\">\n This is an info callout\n</Callout>\n<Callout type=\"danger\">\n This is a danger callout\n</Callout>\n<Callout type=\"success\">\n This is a success callout\n</Callout>\n\n## Properties\n\n<Field value=\"type\" type=\"string\">\n The type of the callout: `note`, `info`, `warning`, `danger`, or `success`.\n</Field>\n\n<Field value=\"icon\" type=\"string\">\n A custom [Lucide](https://lucide.dev/icons) icon name. Overrides the default icon for the callout type.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the callout.\n</Field>";
@@ -17,34 +17,26 @@ You can format them as Note, Warning, Info, Danger and Success.
17
17
 
18
18
  You can use the Callouts component directly within your MDX files without any import. The following example shows a basic usage:
19
19
 
20
- \`\`\`mdx
20
+ \`\`\`html
21
21
  <Callout type="note">This is a note callout</Callout>
22
-
23
22
  <Callout type="warning">This is a warning callout</Callout>
24
-
25
23
  <Callout type="info">This is an info callout</Callout>
26
-
27
24
  <Callout type="danger">This is a danger callout</Callout>
28
-
29
25
  <Callout type="success">This is a success callout</Callout>
30
26
  \`\`\`
31
27
 
32
28
  <Callout type="note">
33
29
  This is a note callout
34
30
  </Callout>
35
-
36
31
  <Callout type="warning">
37
32
  This is a warning callout
38
33
  </Callout>
39
-
40
34
  <Callout type="info">
41
35
  This is an info callout
42
36
  </Callout>
43
-
44
37
  <Callout type="danger">
45
38
  This is a danger callout
46
39
  </Callout>
47
-
48
40
  <Callout type="success">
49
41
  This is a success callout
50
42
  </Callout>
@@ -1 +1 @@
1
- export declare const cardsMdxTemplate = "---\ntitle: \"Cards\"\ndescription: \"Cards act as visual containers for your content, giving you flexibility to combine text, icons, images, and links in a clean and organized way.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 6\n---\n\n# Cards\n\nDuplicate a page or section with ease, then emphasize important information or links using customizable layouts and icons.\n\nCards act as visual containers for your content, giving you flexibility to combine text, icons, images, and links in a clean and organized way.\n\n## Cards Usage\n\nYou can use the Cards component directly within your MDX files without any import. The following example shows a basic usage:\n\n```mdx\n<Card title=\"Note\" icon=\"badge-info\">\n Doccupine CLI is a command-line tool that helps you create and manage your\n Doccupine project. It provides a simple and intuitive interface for creating\n and configuring your project.\n</Card>\n```\n\n<Card title=\"Note\" icon=\"badge-info\">\n Doccupine CLI is a command-line tool that helps you create and manage your Doccupine project. It provides a simple and intuitive interface for creating and configuring your project.\n</Card>\n\n## Link Card\n\nPass a `href` prop to turn the card into a clickable link. The card will display interactive hover and focus styles automatically.\n\n```mdx\n<Card title=\"Getting Started\" icon=\"rocket\" href=\"/cards\">\n Learn how to set up Doccupine and create your first documentation site.\n</Card>\n```\n\n<Card title=\"Getting Started\" icon=\"rocket\" href=\"/cards\">\n Learn how to set up Doccupine and create your first documentation site.\n</Card>\n\n## Properties\n\n<Field value=\"title\" type=\"string\" required>\n The title of the card.\n</Field>\n\n<Field value=\"icon\" type=\"string\">\n The [Lucide](https://lucide.dev/icons) icon name to display in the card.\n</Field>\n\n<Field value=\"href\" type=\"string\">\n A URL or path to link to. When provided, the card becomes a clickable link with interactive styles.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the card.\n</Field>";
1
+ export declare const cardsMdxTemplate = "---\ntitle: \"Cards\"\ndescription: \"Cards act as visual containers for your content, giving you flexibility to combine text, icons, images, and links in a clean and organized way.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 6\n---\n\n# Cards\n\nDuplicate a page or section with ease, then emphasize important information or links using customizable layouts and icons.\n\nCards act as visual containers for your content, giving you flexibility to combine text, icons, images, and links in a clean and organized way.\n\n## Cards Usage\n\nYou can use the Cards component directly within your MDX files without any import. The following example shows a basic usage:\n\n```html\n<Card title=\"Note\" icon=\"badge-info\">\n Doccupine CLI is a command-line tool that helps you create and manage your\n Doccupine project. It provides a simple and intuitive interface for creating\n and configuring your project.\n</Card>\n```\n\n<Card title=\"Note\" icon=\"badge-info\">\n Doccupine CLI is a command-line tool that helps you create and manage your Doccupine project. It provides a simple and intuitive interface for creating and configuring your project.\n</Card>\n\n## Link Card\n\nPass a `href` prop to turn the card into a clickable link. The card will display interactive hover and focus styles automatically.\n\n```html\n<Card title=\"Getting Started\" icon=\"rocket\" href=\"/cards\">\n Learn how to set up Doccupine and create your first documentation site.\n</Card>\n```\n\n<Card title=\"Getting Started\" icon=\"rocket\" href=\"/cards\">\n Learn how to set up Doccupine and create your first documentation site.\n</Card>\n\n## Properties\n\n<Field value=\"title\" type=\"string\" required>\n The title of the card.\n</Field>\n\n<Field value=\"icon\" type=\"string\">\n The [Lucide](https://lucide.dev/icons) icon name to display in the card.\n</Field>\n\n<Field value=\"href\" type=\"string\">\n A URL or path to link to. When provided, the card becomes a clickable link with interactive styles.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the card.\n</Field>";
@@ -17,7 +17,7 @@ Cards act as visual containers for your content, giving you flexibility to combi
17
17
 
18
18
  You can use the Cards component directly within your MDX files without any import. The following example shows a basic usage:
19
19
 
20
- \`\`\`mdx
20
+ \`\`\`html
21
21
  <Card title="Note" icon="badge-info">
22
22
  Doccupine CLI is a command-line tool that helps you create and manage your
23
23
  Doccupine project. It provides a simple and intuitive interface for creating
@@ -33,7 +33,7 @@ You can use the Cards component directly within your MDX files without any impor
33
33
 
34
34
  Pass a \`href\` prop to turn the card into a clickable link. The card will display interactive hover and focus styles automatically.
35
35
 
36
- \`\`\`mdx
36
+ \`\`\`html
37
37
  <Card title="Getting Started" icon="rocket" href="/cards">
38
38
  Learn how to set up Doccupine and create your first documentation site.
39
39
  </Card>
@@ -1 +1 @@
1
- export declare const codeMdxTemplate = "---\ntitle: \"Code\"\ndescription: \"Learn how to display inline code and code blocks in documentation.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 3\n---\n\n# Code\n\nLearn how to display inline code and code blocks in documentation.\n\n## Adding Code Samples\n\nBoth inline code snippets and full code blocks are supported. Code blocks offer customization for syntax highlighting and more to improve readability and user experience.\n\n### Inline Code\n\nHighlight code within text by wrapping it with backticks:\n\n```text\nEnclose any `word` or `phrase` in backticks to format it as code.\n```\n\nEnclose any `word` or `phrase` in backticks to format it as code.\n\n## Code Blocks\n\nTo present larger code samples, use triple backticks for fenced code blocks. Each block can be copied, and\u2014if assistant features are enabled\u2014users can request explanations.\n\nYou may specify the language for highlighting:\n\n````text\n```java\nclass HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n}\n```\n````\n\n```java\nclass HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n}\n```\n\n## Highlighting Diffs\n\nShow a visual diff of added or removed lines in your code blocks. Added lines are highlighted in green and removed lines are highlighted in red. Set the language to `diff` and prefix each changed line with `+` or `-`:\n\n````text\n```diff\nfunction calculateTotal(items) {\n- return items.reduce((sum, item) => sum + item.price, 0);\n+ const total = items.reduce((sum, item) => sum + item.price, 0);\n+ return Math.round(total * 100) / 100;\n}\n```\n````\n\n```diff\nfunction calculateTotal(items) {\n- return items.reduce((sum, item) => sum + item.price, 0);\n+ const total = items.reduce((sum, item) => sum + item.price, 0);\n+ return Math.round(total * 100) / 100;\n}\n```\n\n## File Names\n\nAdd a `title` to a code block to display a file name in the window bar, styled to match the GitHub-style header. Pass it through the `<Code />` component:\n\n```text\n<Code title=\"package.json\" language=\"json\" code={`{\\n \"name\": \"my-app\",\\n \"version\": \"1.0.0\"\\n}`} />\n```\n\n<Code title=\"package.json\" language=\"json\" code={`{\\n \"name\": \"my-app\",\\n \"version\": \"1.0.0\"\\n}`} />\n\n## Tabbed Code Blocks\n\nUse `<CodeTabs />` to show several variants of the same snippet - for example the same install command across package managers. Each tab is a keyboard-accessible button, and the copy button copies whichever tab is active. Each tab may set a `language` for highlighting (defaults to `bash`).\n\n```text\n<CodeTabs tabs={[{ label: \"npm\", code: \"npm install doccupine\" }, { label: \"pnpm\", code: \"pnpm add doccupine\" }, { label: \"yarn\", code: \"yarn add doccupine\" }]} />\n```\n\n<CodeTabs tabs={[{ label: \"npm\", code: \"npm install doccupine\" }, { label: \"pnpm\", code: \"pnpm add doccupine\" }, { label: \"yarn\", code: \"yarn add doccupine\" }]} />";
1
+ export declare const codeMdxTemplate = "---\ntitle: \"Code\"\ndescription: \"Learn how to display inline code and code blocks in documentation.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 3\n---\n\n# Code\n\nLearn how to display inline code and code blocks in documentation.\n\n## Adding Code Samples\n\nBoth inline code snippets and full code blocks are supported. Code blocks offer customization for syntax highlighting and more to improve readability and user experience.\n\n### Inline Code\n\nHighlight code within text by wrapping it with backticks:\n\n```text\nEnclose any `word` or `phrase` in backticks to format it as code.\n```\n\nEnclose any `word` or `phrase` in backticks to format it as code.\n\n## Code Blocks\n\nTo present larger code samples, use triple backticks for fenced code blocks. Each block can be copied, and\u2014if assistant features are enabled\u2014users can request explanations.\n\nYou may specify the language for highlighting:\n\n````text\n```java\nclass HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n}\n```\n````\n\n```java\nclass HelloWorld {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n}\n```\n\n## Highlighting Diffs\n\nShow a visual diff of added or removed lines in your code blocks. Added lines are highlighted in green and removed lines are highlighted in red. Set the language to `diff` and prefix each changed line with `+` or `-`:\n\n````text\n```diff\nfunction calculateTotal(items) {\n- return items.reduce((sum, item) => sum + item.price, 0);\n+ const total = items.reduce((sum, item) => sum + item.price, 0);\n+ return Math.round(total * 100) / 100;\n}\n```\n````\n\n```diff\nfunction calculateTotal(items) {\n- return items.reduce((sum, item) => sum + item.price, 0);\n+ const total = items.reduce((sum, item) => sum + item.price, 0);\n+ return Math.round(total * 100) / 100;\n}\n```\n\n## File Names\n\nAdd a `title` to a code block to display a file name in the window bar, styled to match the GitHub-style header. Pass it through the `<Code />` component:\n\n```html\n<Code title=\"package.json\" language=\"json\" code={`{\\n \"name\": \"my-app\",\\n \"version\": \"1.0.0\"\\n}`} />\n```\n\n<Code title=\"package.json\" language=\"json\" code={`{\\n \"name\": \"my-app\",\\n \"version\": \"1.0.0\"\\n}`} />\n\n## Tabbed Code Blocks\n\nUse `<CodeTabs />` to show several variants of the same snippet - for example the same install command across package managers. Each tab is a keyboard-accessible button, and the copy button copies whichever tab is active. Each tab may set a `language` for highlighting (defaults to `bash`).\n\n```html\n<CodeTabs tabs={[{ label: \"npm\", code: \"npm install doccupine\" }, { label: \"pnpm\", code: \"pnpm add doccupine\" }, { label: \"yarn\", code: \"yarn add doccupine\" }]} />\n```\n\n<CodeTabs tabs={[{ label: \"npm\", code: \"npm install doccupine\" }, { label: \"pnpm\", code: \"pnpm add doccupine\" }, { label: \"yarn\", code: \"yarn add doccupine\" }]} />";
@@ -34,18 +34,18 @@ You may specify the language for highlighting:
34
34
  \`\`\`\`text
35
35
  \`\`\`java
36
36
  class HelloWorld {
37
- public static void main(String[] args) {
38
- System.out.println("Hello, World!");
39
- }
37
+ public static void main(String[] args) {
38
+ System.out.println("Hello, World!");
39
+ }
40
40
  }
41
41
  \`\`\`
42
42
  \`\`\`\`
43
43
 
44
44
  \`\`\`java
45
45
  class HelloWorld {
46
- public static void main(String[] args) {
47
- System.out.println("Hello, World!");
48
- }
46
+ public static void main(String[] args) {
47
+ System.out.println("Hello, World!");
48
+ }
49
49
  }
50
50
  \`\`\`
51
51
 
@@ -75,7 +75,7 @@ function calculateTotal(items) {
75
75
 
76
76
  Add a \`title\` to a code block to display a file name in the window bar, styled to match the GitHub-style header. Pass it through the \`<Code />\` component:
77
77
 
78
- \`\`\`text
78
+ \`\`\`html
79
79
  <Code title="package.json" language="json" code={\`{\\n "name": "my-app",\\n "version": "1.0.0"\\n}\`} />
80
80
  \`\`\`
81
81
 
@@ -85,7 +85,7 @@ Add a \`title\` to a code block to display a file name in the window bar, styled
85
85
 
86
86
  Use \`<CodeTabs />\` to show several variants of the same snippet - for example the same install command across package managers. Each tab is a keyboard-accessible button, and the copy button copies whichever tab is active. Each tab may set a \`language\` for highlighting (defaults to \`bash\`).
87
87
 
88
- \`\`\`text
88
+ \`\`\`html
89
89
  <CodeTabs tabs={[{ label: "npm", code: "npm install doccupine" }, { label: "pnpm", code: "pnpm add doccupine" }, { label: "yarn", code: "yarn add doccupine" }]} />
90
90
  \`\`\`
91
91
 
@@ -1 +1 @@
1
- export declare const colorSwatchesMdxTemplate = "---\ntitle: \"Color Swatches\"\ndescription: \"Display color palettes with labeled swatches to document your theme colors.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 15\n---\n\n# Color Swatches\n\nDisplay color palettes with labeled swatches to document your theme colors.\n\nThe `ColorSwatch` component renders a visual preview of a color alongside its token name, and `ColorSwatchGroup` arranges multiple swatches in a responsive grid.\n\n## Usage\n\nYou can use the ColorSwatch components directly within your MDX files without any import:\n\n```mdx\n<ColorSwatchGroup>\n <ColorSwatch token=\"primary\" value=\"#6366F1\" />\n <ColorSwatch token=\"secondary\" value=\"#EC4899\" />\n <ColorSwatch token=\"success\" value=\"#10B981\" />\n <ColorSwatch token=\"warning\" value=\"#F59E0B\" />\n <ColorSwatch token=\"danger\" value=\"#EF4444\" />\n <ColorSwatch token=\"info\" value=\"#3B82F6\" />\n</ColorSwatchGroup>\n```\n\n<ColorSwatchGroup>\n <ColorSwatch token=\"primary\" value=\"#6366F1\" />\n <ColorSwatch token=\"secondary\" value=\"#EC4899\" />\n <ColorSwatch token=\"success\" value=\"#10B981\" />\n <ColorSwatch token=\"warning\" value=\"#F59E0B\" />\n <ColorSwatch token=\"danger\" value=\"#EF4444\" />\n <ColorSwatch token=\"info\" value=\"#3B82F6\" />\n</ColorSwatchGroup>\n\n## Dark Colors\n\nText color automatically adapts based on the background luminance, so dark swatches display white text:\n\n```mdx\n<ColorSwatchGroup>\n <ColorSwatch token=\"dark\" value=\"#1E1E2E\" />\n <ColorSwatch token=\"grayDark\" value=\"#374151\" />\n <ColorSwatch token=\"gray\" value=\"#6B7280\" />\n <ColorSwatch token=\"grayLight\" value=\"#D1D5DB\" />\n <ColorSwatch token=\"light\" value=\"#F9FAFB\" />\n <ColorSwatch token=\"white\" value=\"#FFFFFF\" />\n</ColorSwatchGroup>\n```\n\n<ColorSwatchGroup>\n <ColorSwatch token=\"dark\" value=\"#1E1E2E\" />\n <ColorSwatch token=\"grayDark\" value=\"#374151\" />\n <ColorSwatch token=\"gray\" value=\"#6B7280\" />\n <ColorSwatch token=\"grayLight\" value=\"#D1D5DB\" />\n <ColorSwatch token=\"light\" value=\"#F9FAFB\" />\n <ColorSwatch token=\"white\" value=\"#FFFFFF\" />\n</ColorSwatchGroup>\n\n## ColorSwatch Properties\n\n<Field value=\"token\" type=\"string\" required>\n The name or label displayed below the color preview (e.g. a design token name).\n</Field>\n\n<Field value=\"value\" type=\"string\" required>\n A hex color value (e.g. `#6366F1`). Displayed inside the color preview and used as the background.\n</Field>\n\n## ColorSwatchGroup Properties\n\n<Field value=\"children\" type=\"node\" required>\n One or more `ColorSwatch` components to display in a responsive grid.\n</Field>";
1
+ export declare const colorSwatchesMdxTemplate = "---\ntitle: \"Color Swatches\"\ndescription: \"Display color palettes with labeled swatches to document your theme colors.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 15\n---\n\n# Color Swatches\n\nDisplay color palettes with labeled swatches to document your theme colors.\n\nThe `ColorSwatch` component renders a visual preview of a color alongside its token name, and `ColorSwatchGroup` arranges multiple swatches in a responsive grid.\n\n## Usage\n\nYou can use the ColorSwatch components directly within your MDX files without any import:\n\n```html\n<ColorSwatchGroup>\n <ColorSwatch token=\"primary\" value=\"#6366F1\" />\n <ColorSwatch token=\"secondary\" value=\"#EC4899\" />\n <ColorSwatch token=\"success\" value=\"#10B981\" />\n <ColorSwatch token=\"warning\" value=\"#F59E0B\" />\n <ColorSwatch token=\"danger\" value=\"#EF4444\" />\n <ColorSwatch token=\"info\" value=\"#3B82F6\" />\n</ColorSwatchGroup>\n```\n\n<ColorSwatchGroup>\n <ColorSwatch token=\"primary\" value=\"#6366F1\" />\n <ColorSwatch token=\"secondary\" value=\"#EC4899\" />\n <ColorSwatch token=\"success\" value=\"#10B981\" />\n <ColorSwatch token=\"warning\" value=\"#F59E0B\" />\n <ColorSwatch token=\"danger\" value=\"#EF4444\" />\n <ColorSwatch token=\"info\" value=\"#3B82F6\" />\n</ColorSwatchGroup>\n\n## Dark Colors\n\nText color automatically adapts based on the background luminance, so dark swatches display white text:\n\n```html\n<ColorSwatchGroup>\n <ColorSwatch token=\"dark\" value=\"#1E1E2E\" />\n <ColorSwatch token=\"grayDark\" value=\"#374151\" />\n <ColorSwatch token=\"gray\" value=\"#6B7280\" />\n <ColorSwatch token=\"grayLight\" value=\"#D1D5DB\" />\n <ColorSwatch token=\"light\" value=\"#F9FAFB\" />\n <ColorSwatch token=\"white\" value=\"#FFFFFF\" />\n</ColorSwatchGroup>\n```\n\n<ColorSwatchGroup>\n <ColorSwatch token=\"dark\" value=\"#1E1E2E\" />\n <ColorSwatch token=\"grayDark\" value=\"#374151\" />\n <ColorSwatch token=\"gray\" value=\"#6B7280\" />\n <ColorSwatch token=\"grayLight\" value=\"#D1D5DB\" />\n <ColorSwatch token=\"light\" value=\"#F9FAFB\" />\n <ColorSwatch token=\"white\" value=\"#FFFFFF\" />\n</ColorSwatchGroup>\n\n## ColorSwatch Properties\n\n<Field value=\"token\" type=\"string\" required>\n The name or label displayed below the color preview (e.g. a design token name).\n</Field>\n\n<Field value=\"value\" type=\"string\" required>\n A hex color value (e.g. `#6366F1`). Displayed inside the color preview and used as the background.\n</Field>\n\n## ColorSwatchGroup Properties\n\n<Field value=\"children\" type=\"node\" required>\n One or more `ColorSwatch` components to display in a responsive grid.\n</Field>";
@@ -17,7 +17,7 @@ The \`ColorSwatch\` component renders a visual preview of a color alongside its
17
17
 
18
18
  You can use the ColorSwatch components directly within your MDX files without any import:
19
19
 
20
- \`\`\`mdx
20
+ \`\`\`html
21
21
  <ColorSwatchGroup>
22
22
  <ColorSwatch token="primary" value="#6366F1" />
23
23
  <ColorSwatch token="secondary" value="#EC4899" />
@@ -41,7 +41,7 @@ You can use the ColorSwatch components directly within your MDX files without an
41
41
 
42
42
  Text color automatically adapts based on the background luminance, so dark swatches display white text:
43
43
 
44
- \`\`\`mdx
44
+ \`\`\`html
45
45
  <ColorSwatchGroup>
46
46
  <ColorSwatch token="dark" value="#1E1E2E" />
47
47
  <ColorSwatch token="grayDark" value="#374151" />
@@ -1 +1 @@
1
- export declare const columnsMdxTemplate = "---\ntitle: \"Columns\"\ndescription: \"Columns are used to organize content in a grid-like structure.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 13\n---\n\n# Columns\n\nArrange multiple cards neatly in a side-by-side grid layout.\n\nThe `Columns` component helps you organize several `Card` elements into a visually balanced grid. By choosing how many columns you want, you can control the layout and spacing of your cards.\n\n## Columns Usage\n\nYou can use the `Columns` component to create a grid of cards with a specified number of columns.\n\n```mdx\n<Columns cols={2}>\n <Card title=\"Getting Started\" icon=\"rocket\">\n Kick off your project using our easy quickstart guide.\n </Card>\n\n <Card title=\"API Reference\" icon=\"code\">\n Browse all endpoints, parameters, and code examples for your API integration.\n </Card>\n</Columns>\n```\n\n<Columns cols={2}>\n <Card title=\"Getting Started\" icon=\"rocket\">\n Kick off your project using our easy quickstart guide.\n </Card>\n\n <Card title=\"API Reference\" icon=\"code\">\n Browse all endpoints, parameters, and code examples for your API integration.\n </Card>\n</Columns>\n\n## Properties\n\n<Field value=\"cols\" type=\"number\">\n The number of columns in the grid. Defaults to 1.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the columns.\n</Field>";
1
+ export declare const columnsMdxTemplate = "---\ntitle: \"Columns\"\ndescription: \"Columns are used to organize content in a grid-like structure.\"\ndate: \"2026-02-19\"\ncategory: \"Components\"\ncategoryOrder: 1\norder: 13\n---\n\n# Columns\n\nArrange multiple cards neatly in a side-by-side grid layout.\n\nThe `Columns` component helps you organize several `Card` elements into a visually balanced grid. By choosing how many columns you want, you can control the layout and spacing of your cards.\n\n## Columns Usage\n\nYou can use the `Columns` component to create a grid of cards with a specified number of columns.\n\n```html\n<Columns cols={2}>\n <Card title=\"Getting Started\" icon=\"rocket\">\n Kick off your project using our easy quickstart guide.\n </Card>\n <Card title=\"API Reference\" icon=\"code\">\n Browse all endpoints, parameters, and code examples for your API integration.\n </Card>\n</Columns>\n```\n\n<Columns cols={2}>\n <Card title=\"Getting Started\" icon=\"rocket\">\n Kick off your project using our easy quickstart guide.\n </Card>\n <Card title=\"API Reference\" icon=\"code\">\n Browse all endpoints, parameters, and code examples for your API integration.\n </Card>\n</Columns>\n\n## Properties\n\n<Field value=\"cols\" type=\"number\">\n The number of columns in the grid. Defaults to 1.\n</Field>\n\n<Field value=\"children\" type=\"node\" required>\n The content of the columns.\n</Field>";