@farming-labs/theme 0.1.141 → 0.1.143

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.
@@ -28,7 +28,7 @@ interface DocsPageClientProps {
28
28
  openDocsTarget?: "markdown" | "page" | "source" | "github";
29
29
  openDocsPrompt?: string;
30
30
  /** Where to render page actions relative to the title */
31
- pageActionsPosition?: "above-title" | "below-title";
31
+ pageActionsPosition?: "above-title" | "below-title" | "toc";
32
32
  /** Horizontal alignment of page action buttons */
33
33
  pageActionsAlignment?: "left" | "right";
34
34
  /** GitHub repository URL (e.g. "https://github.com/user/repo") */
@@ -6,7 +6,7 @@ import { useWindowSearchParams } from "./client-location.mjs";
6
6
  import { DocsFeedback } from "./docs-feedback.mjs";
7
7
  import { resolveClientLocale, withLangInUrl } from "./i18n.mjs";
8
8
  import { escapeJsonLdForScript } from "./json-ld.mjs";
9
- import { Children, Fragment, cloneElement, isValidElement, useEffect, useState } from "react";
9
+ import { Children, Fragment, useEffect, useState } from "react";
10
10
  import { DocsBody, DocsPage, EditOnGitHub } from "fumadocs-ui/layouts/docs/page";
11
11
  import { createPortal } from "react-dom";
12
12
  import { usePathname, useRouter } from "fumadocs-core/framework";
@@ -53,7 +53,7 @@ function PathBreadcrumb({ pathname, publicPath, locale }) {
53
53
  },
54
54
  children: parentLabel
55
55
  })
56
- }), /* @__PURE__ */ jsxs("span", {
56
+ }, "parent"), /* @__PURE__ */ jsxs("span", {
57
57
  className: "fd-breadcrumb-item",
58
58
  children: [/* @__PURE__ */ jsx("span", {
59
59
  className: "fd-breadcrumb-sep",
@@ -62,7 +62,7 @@ function PathBreadcrumb({ pathname, publicPath, locale }) {
62
62
  className: "fd-breadcrumb-current",
63
63
  children: currentLabel
64
64
  })]
65
- })]
65
+ }, "current")]
66
66
  });
67
67
  }
68
68
  /**
@@ -214,59 +214,52 @@ function scrollToHashTarget(hash) {
214
214
  target.scrollIntoView({ block: "start" });
215
215
  return true;
216
216
  }
217
- function injectTitleDecorations(node, { description, belowTitle }) {
218
- if (!description && !belowTitle) return {
219
- node,
220
- inserted: false
221
- };
222
- let inserted = false;
223
- const extras = Children.toArray([description, belowTitle].filter(Boolean));
224
- if (extras.length === 0) return {
225
- node,
226
- inserted: false
227
- };
228
- const insertedExtras = extras.map((extra, index) => /* @__PURE__ */ jsx(Fragment, { children: extra }, `fd-title-decoration-${index}`));
229
- function visit(current) {
230
- if (current == null || typeof current === "boolean") return current;
231
- if (inserted) return current;
232
- if (Array.isArray(current)) return current.flatMap((child) => {
233
- const next = visit(child);
234
- return Array.isArray(next) ? next : [next];
235
- });
236
- if (!isValidElement(current)) return current;
237
- if (typeof current.type === "string" && current.type === "h1") {
238
- inserted = true;
239
- return /* @__PURE__ */ jsxs(Fragment, { children: [current, insertedExtras] }, "fd-title-decoration-block");
240
- }
241
- const childProps = current.props ?? null;
242
- if (childProps?.children === void 0) return current;
243
- const nextChildren = Children.toArray(childProps.children).flatMap((child) => {
244
- const next = visit(child);
245
- return Array.isArray(next) ? next : [next];
246
- });
247
- if (!inserted) return current;
248
- return cloneElement(current, void 0, nextChildren);
249
- }
250
- if (Array.isArray(node)) return {
251
- node: node.flatMap((child) => {
252
- const next = visit(child);
253
- return Array.isArray(next) ? next : [next];
254
- }),
255
- inserted
256
- };
257
- return {
258
- node: visit(node),
259
- inserted
260
- };
261
- }
262
217
  function TitleDecorations({ description, belowTitle }) {
263
218
  if (!description && !belowTitle) return null;
264
- return /* @__PURE__ */ jsx(Fragment$1, { children: Children.toArray([description, belowTitle].filter(Boolean)) });
219
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [description && /* @__PURE__ */ jsx(Fragment, { children: description }, "description"), belowTitle && /* @__PURE__ */ jsx(Fragment, { children: belowTitle }, "below-title")] });
220
+ }
221
+ function ThreadlinePageControls() {
222
+ return /* @__PURE__ */ jsxs("div", {
223
+ className: "fd-threadline-doc-controls not-prose",
224
+ "aria-label": "Page controls",
225
+ children: [/* @__PURE__ */ jsx("button", {
226
+ type: "button",
227
+ "aria-label": "Go back",
228
+ onClick: () => window.history.back(),
229
+ children: /* @__PURE__ */ jsx("span", {
230
+ "aria-hidden": "true",
231
+ children: "<"
232
+ })
233
+ }, "back"), /* @__PURE__ */ jsx("button", {
234
+ type: "button",
235
+ "aria-label": "Go forward",
236
+ onClick: () => window.history.forward(),
237
+ children: /* @__PURE__ */ jsx("span", {
238
+ "aria-hidden": "true",
239
+ children: ">"
240
+ })
241
+ }, "forward")]
242
+ });
243
+ }
244
+ function findThreadlineTocActionsContainer() {
245
+ const toc = document.getElementById("nd-toc") ?? document.querySelector(".fd-toc, [data-toc]");
246
+ if (!toc) return null;
247
+ const stickyChild = toc.querySelector(":scope > .sticky, :scope > [class*='sticky']");
248
+ if (stickyChild) return stickyChild;
249
+ if ((typeof toc.className === "string" ? toc.className : "").includes("grid-area:toc")) return toc;
250
+ let node = toc.parentElement;
251
+ while (node && node.id !== "nd-docs-layout") {
252
+ if ((typeof node.className === "string" ? node.className : "").includes("grid-area:toc") || window.getComputedStyle(node).position === "sticky") return node;
253
+ node = node.parentElement;
254
+ }
255
+ return toc.parentElement ?? toc;
265
256
  }
266
257
  function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, changelogBasePath, entry = "docs", publicPath, locale, copyMarkdown = false, openDocs = false, openDocsProviders, openDocsTarget, openDocsPrompt, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, contentDir, githubBranch = "main", githubDirectory, editOnGithubUrl, lastModifiedMap, lastModified: lastModifiedProp, readingTimeMap, readingTime: readingTimeProp, structuredDataMap, structuredData: structuredDataProp, readingTimeEnabled = false, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, feedbackEnabled = false, feedbackQuestion, feedbackPlaceholder, feedbackPositiveLabel, feedbackNegativeLabel, feedbackSubmitLabel, feedbackOnFeedback, analytics = false, children }) {
267
258
  const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
268
259
  const [toc, setToc] = useState([]);
269
260
  const [titlePortalHost, setTitlePortalHost] = useState(null);
261
+ const [titleControlsPortalHost, setTitleControlsPortalHost] = useState(null);
262
+ const [tocActionsPortalHost, setTocActionsPortalHost] = useState(null);
270
263
  const [browserPath, setBrowserPath] = useState(null);
271
264
  const pathname = usePathname();
272
265
  const activeLocale = resolveClientLocale(useWindowSearchParams(), locale);
@@ -374,10 +367,69 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
374
367
  clearTimeout(timeout);
375
368
  };
376
369
  }, [pathname, children]);
377
- const showActions = !isChangelogRoute && (copyMarkdown || openDocs);
370
+ const showActions = !isChangelogRoute && (copyMarkdown || openDocs || pageActionsPosition === "toc");
378
371
  const showActionsBelowTitle = showActions && pageActionsPosition === "below-title";
379
372
  const showActionsAboveTitle = showActions && pageActionsPosition === "above-title";
373
+ const showActionsInToc = showActions && pageActionsPosition === "toc";
380
374
  const githubFileUrl = editOnGithubUrl ?? (githubUrl ? buildGithubFileUrl(githubUrl, githubBranch, pathname, entry, activeLocale, githubDirectory, contentDir) : void 0);
375
+ useEffect(() => {
376
+ if (!showActionsInToc) {
377
+ setTocActionsPortalHost(null);
378
+ return;
379
+ }
380
+ let frame = 0;
381
+ let attempts = 0;
382
+ let host = null;
383
+ let cancelled = false;
384
+ const mountActions = () => {
385
+ if (cancelled) return;
386
+ const container = findThreadlineTocActionsContainer();
387
+ if (!container) {
388
+ if (attempts < 12) {
389
+ attempts += 1;
390
+ frame = requestAnimationFrame(mountActions);
391
+ } else setTocActionsPortalHost(null);
392
+ return;
393
+ }
394
+ host = container.querySelector(":scope > .fd-actions-toc-host");
395
+ if (!host) {
396
+ host = document.createElement("div");
397
+ host.className = "fd-actions-toc-host";
398
+ container.append(host);
399
+ }
400
+ setTocActionsPortalHost(host);
401
+ };
402
+ frame = requestAnimationFrame(mountActions);
403
+ return () => {
404
+ cancelled = true;
405
+ cancelAnimationFrame(frame);
406
+ if (host?.isConnected) host.remove();
407
+ setTocActionsPortalHost(null);
408
+ };
409
+ }, [
410
+ pathname,
411
+ showActionsInToc,
412
+ toc.length
413
+ ]);
414
+ useEffect(() => {
415
+ if (!showActionsInToc) {
416
+ setTitleControlsPortalHost(null);
417
+ return;
418
+ }
419
+ const title = document.getElementById("nd-page")?.querySelector("h1");
420
+ if (!title) {
421
+ setTitleControlsPortalHost(null);
422
+ return;
423
+ }
424
+ const host = document.createElement("div");
425
+ host.className = "fd-threadline-title-controls-host";
426
+ title.insertAdjacentElement("afterend", host);
427
+ setTitleControlsPortalHost(host);
428
+ return () => {
429
+ host.remove();
430
+ setTitleControlsPortalHost(null);
431
+ };
432
+ }, [pathname, showActionsInToc]);
381
433
  const lastModified = !isChangelogRoute && lastUpdatedEnabled ? lastModifiedProp ?? lastModifiedMap?.[normalizedPath] : void 0;
382
434
  const showLastUpdatedBelowTitle = !!lastModified && lastUpdatedPosition === "below-title";
383
435
  const showLastUpdatedInFooter = !!lastModified && lastUpdatedPosition === "footer";
@@ -392,7 +444,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
392
444
  className: "fd-page-meta-item",
393
445
  children: formatReadingTimeLabel(resolvedReadingTime)
394
446
  })]
395
- }) : void 0;
447
+ }, "reading-time") : void 0;
396
448
  const titleDescription = pageDescription ? /* @__PURE__ */ jsx("p", {
397
449
  className: "fd-page-description",
398
450
  children: pageDescription
@@ -405,8 +457,8 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
405
457
  showLastUpdatedBelowTitle && /* @__PURE__ */ jsxs("p", {
406
458
  className: "fd-last-updated-inline",
407
459
  children: ["Last updated ", lastModified]
408
- }),
409
- /* @__PURE__ */ jsx("hr", { className: "fd-title-separator" }),
460
+ }, "last-updated"),
461
+ /* @__PURE__ */ jsx("hr", { className: "fd-title-separator" }, "separator"),
410
462
  showActionsBelowTitle && /* @__PURE__ */ jsx("div", {
411
463
  className: "fd-actions-portal",
412
464
  "data-actions-alignment": pageActionsAlignment,
@@ -417,18 +469,16 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
417
469
  openDocsTarget,
418
470
  openDocsPrompt,
419
471
  alignment: pageActionsAlignment,
472
+ variant: "default",
420
473
  githubFileUrl,
421
474
  analytics
422
475
  })
423
- }),
476
+ }, "actions"),
424
477
  showReadingTimeBelowTitle && readingTimeBlock
425
478
  ]
426
- }) : void 0;
427
- const { node: decoratedChildren, inserted: titleDecorationsInserted } = injectTitleDecorations(children, {
428
- description: titleDescription,
429
- belowTitle: belowTitleBlock
430
- });
431
- const needsTitleDecorationsPortal = !titleDecorationsInserted && (!!titleDescription || !!belowTitleBlock);
479
+ }, "below-title") : void 0;
480
+ const decoratedChildren = children;
481
+ const needsTitleDecorationsPortal = !!titleDescription || !!belowTitleBlock;
432
482
  useEffect(() => {
433
483
  if (!needsTitleDecorationsPortal) {
434
484
  setTitlePortalHost(null);
@@ -451,13 +501,28 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
451
501
  const titleDecorationsPortal = needsTitleDecorationsPortal && titlePortalHost ? createPortal(/* @__PURE__ */ jsx(TitleDecorations, {
452
502
  description: titleDescription,
453
503
  belowTitle: belowTitleBlock
454
- }), titlePortalHost) : null;
455
- const renderedChildren = Children.toArray(decoratedChildren);
504
+ }), titlePortalHost, "title-decorations") : null;
505
+ const titleControlsPortal = showActionsInToc && titleControlsPortalHost ? createPortal(/* @__PURE__ */ jsx(ThreadlinePageControls, {}), titleControlsPortalHost, "title-controls") : null;
506
+ const tocActionsPortal = showActionsInToc && tocActionsPortalHost ? createPortal(/* @__PURE__ */ jsx("div", {
507
+ className: "fd-actions-toc-portal not-prose",
508
+ children: /* @__PURE__ */ jsx(PageActions, {
509
+ copyMarkdown,
510
+ openDocs,
511
+ providers: openDocsProviders,
512
+ openDocsTarget,
513
+ openDocsPrompt,
514
+ alignment: "left",
515
+ variant: "rail",
516
+ githubFileUrl,
517
+ analytics
518
+ })
519
+ }), tocActionsPortalHost, "toc-actions") : null;
520
+ const renderedChildren = Children.toArray(decoratedChildren).map((child, index) => /* @__PURE__ */ jsx(Fragment, { children: child }, `fd-rendered-child-${index}`));
456
521
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
457
522
  structuredDataJson && /* @__PURE__ */ jsx("script", {
458
523
  type: "application/ld+json",
459
524
  dangerouslySetInnerHTML: { __html: escapeJsonLdForScript(structuredDataJson) }
460
- }),
525
+ }, "structured-data"),
461
526
  llmsTxtEnabled && /* @__PURE__ */ jsx("a", {
462
527
  href: `/llms.txt${llmsLangQuery}`,
463
528
  className: "fd-agent-llms-directive",
@@ -465,7 +530,9 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
465
530
  tabIndex: -1,
466
531
  "aria-hidden": "true",
467
532
  children: "llms.txt"
468
- }),
533
+ }, "llms-txt"),
534
+ titleControlsPortal,
535
+ tocActionsPortal,
469
536
  /* @__PURE__ */ jsxs(DocsPage, {
470
537
  full: false,
471
538
  toc,
@@ -484,7 +551,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
484
551
  pathname,
485
552
  publicPath: resolvedPublicPath,
486
553
  locale: activeLocale
487
- }),
554
+ }, "breadcrumb"),
488
555
  showActionsAboveTitle && /* @__PURE__ */ jsxs("div", {
489
556
  className: "fd-below-title-block not-prose",
490
557
  children: [/* @__PURE__ */ jsx("div", {
@@ -497,11 +564,12 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
497
564
  openDocsTarget,
498
565
  openDocsPrompt,
499
566
  alignment: pageActionsAlignment,
567
+ variant: "default",
500
568
  githubFileUrl,
501
569
  analytics
502
570
  })
503
- }), readingTimeBlock]
504
- }),
571
+ }, "actions"), readingTimeBlock]
572
+ }, "actions-above-title"),
505
573
  !showReadingTimeAboveTitle && !showReadingTimeBelowTitle ? readingTimeBlock : null,
506
574
  /* @__PURE__ */ jsxs(DocsBody, {
507
575
  style: {
@@ -512,7 +580,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
512
580
  /* @__PURE__ */ jsx("div", {
513
581
  style: { flex: 1 },
514
582
  children: renderedChildren
515
- }),
583
+ }, "content"),
516
584
  titleDecorationsPortal,
517
585
  !isChangelogRoute && feedbackEnabled && /* @__PURE__ */ jsx(DocsFeedback, {
518
586
  pathname: normalizedPath,
@@ -525,11 +593,11 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
525
593
  submitLabel: feedbackSubmitLabel,
526
594
  onFeedback: feedbackOnFeedback,
527
595
  analytics
528
- }),
596
+ }, "feedback"),
529
597
  showFooter && /* @__PURE__ */ jsxs("div", {
530
598
  className: "not-prose fd-page-footer",
531
599
  children: [
532
- githubFileUrl && /* @__PURE__ */ jsx(EditOnGitHub, { href: githubFileUrl }),
600
+ githubFileUrl && /* @__PURE__ */ jsx(EditOnGitHub, { href: githubFileUrl }, "github"),
533
601
  llmsTxtEnabled && /* @__PURE__ */ jsxs("span", {
534
602
  className: "fd-llms-txt-links",
535
603
  children: [/* @__PURE__ */ jsx("a", {
@@ -545,17 +613,17 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
545
613
  className: "fd-llms-txt-link",
546
614
  children: "llms-full.txt"
547
615
  })]
548
- }),
616
+ }, "llms-links"),
549
617
  showLastUpdatedInFooter && lastModified && /* @__PURE__ */ jsxs("span", {
550
618
  className: "fd-last-updated-footer",
551
619
  children: ["Last updated ", lastModified]
552
- })
620
+ }, "last-updated")
553
621
  ]
554
- })
622
+ }, "footer")
555
623
  ]
556
- })
624
+ }, "body")
557
625
  ]
558
- })
626
+ }, "docs-page")
559
627
  ] });
560
628
  }
561
629
 
package/dist/index.d.mts CHANGED
@@ -8,6 +8,7 @@ import { DocsPageClient } from "./docs-page-client.mjs";
8
8
  import { HardlineUIDefaults, hardline } from "./hardline/index.mjs";
9
9
  import { RootProvider } from "./provider.mjs";
10
10
  import { LedgerUIDefaults, ledger } from "./ledger/index.mjs";
11
+ import { ThreadlineUIDefaults, threadline, threadlinePageActions } from "./threadline/index.mjs";
11
12
  import { DocsFeedback, DocsFeedbackProps } from "./docs-feedback.mjs";
12
13
  import { PageActions } from "./page-actions.mjs";
13
14
  import { withLangInUrl } from "./i18n.mjs";
@@ -19,4 +20,4 @@ import { AIConfig, BreadcrumbConfig, ChangelogConfig, ChangelogFrontmatter, Copy
19
20
  import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
20
21
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
21
22
  import { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, Pre } from "fumadocs-ui/components/codeblock";
22
- export { type AIConfig, Agent, type BreadcrumbConfig, type ChangelogConfig, type ChangelogFrontmatter, CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, CodeGroup, CommandGridUIDefaults, ConcreteUIDefaults, type CopyMarkdownConfig, DocsBody, DocsClientHooks, DocsCommandSearch, type DocsConfig, DocsFeedback, type DocsFeedbackData, type DocsFeedbackProps, type DocsFeedbackValue, DocsLayout, type DocsMetadata, type DocsNav, DocsPage, DocsPageClient, type DocsTheme, type FeedbackConfig, type FontStyle, DefaultUIDefaults as FumadocsUIDefaults, HardlineUIDefaults, HoverLink, type HoverLinkProps, LedgerUIDefaults, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, PageActions, type PageActionsConfig, type PageFrontmatter, Pre, Prompt, type PromptProps, RootProvider, type SidebarConfig, Tab, Tabs, type ThemeToggleConfig, type TypographyConfig, type UIConfig, commandGrid, concrete, createDocsLayout, createDocsMetadata, createPageMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs, hardline, ledger, withLangInUrl };
23
+ export { type AIConfig, Agent, type BreadcrumbConfig, type ChangelogConfig, type ChangelogFrontmatter, CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, CodeGroup, CommandGridUIDefaults, ConcreteUIDefaults, type CopyMarkdownConfig, DocsBody, DocsClientHooks, DocsCommandSearch, type DocsConfig, DocsFeedback, type DocsFeedbackData, type DocsFeedbackProps, type DocsFeedbackValue, DocsLayout, type DocsMetadata, type DocsNav, DocsPage, DocsPageClient, type DocsTheme, type FeedbackConfig, type FontStyle, DefaultUIDefaults as FumadocsUIDefaults, HardlineUIDefaults, HoverLink, type HoverLinkProps, LedgerUIDefaults, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, PageActions, type PageActionsConfig, type PageFrontmatter, Pre, Prompt, type PromptProps, RootProvider, type SidebarConfig, Tab, Tabs, type ThemeToggleConfig, ThreadlineUIDefaults, type TypographyConfig, type UIConfig, commandGrid, concrete, createDocsLayout, createDocsMetadata, createPageMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs, hardline, ledger, threadline, threadlinePageActions, withLangInUrl };
package/dist/index.mjs CHANGED
@@ -10,6 +10,7 @@ import { CommandGridUIDefaults, commandGrid } from "./command-grid/index.mjs";
10
10
  import { ConcreteUIDefaults, concrete } from "./concrete/index.mjs";
11
11
  import { HardlineUIDefaults, hardline } from "./hardline/index.mjs";
12
12
  import { LedgerUIDefaults, ledger } from "./ledger/index.mjs";
13
+ import { ThreadlineUIDefaults, threadline, threadlinePageActions } from "./threadline/index.mjs";
13
14
  import { DocsClientHooks } from "./docs-client-hooks.mjs";
14
15
  import { HoverLink } from "./hover-link.mjs";
15
16
  import { Prompt } from "./prompt.mjs";
@@ -20,4 +21,4 @@ import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
20
21
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
21
22
  import { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, Pre } from "fumadocs-ui/components/codeblock";
22
23
 
23
- export { Agent, CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, CodeGroup, CommandGridUIDefaults, ConcreteUIDefaults, DocsBody, DocsClientHooks, DocsCommandSearch, DocsFeedback, DocsLayout, DocsPage, DocsPageClient, DefaultUIDefaults as FumadocsUIDefaults, HardlineUIDefaults, HoverLink, LedgerUIDefaults, PageActions, Pre, Prompt, RootProvider, Tab, Tabs, commandGrid, concrete, createDocsLayout, createDocsMetadata, createPageMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs, hardline, ledger, withLangInUrl };
24
+ export { Agent, CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, CodeGroup, CommandGridUIDefaults, ConcreteUIDefaults, DocsBody, DocsClientHooks, DocsCommandSearch, DocsFeedback, DocsLayout, DocsPage, DocsPageClient, DefaultUIDefaults as FumadocsUIDefaults, HardlineUIDefaults, HoverLink, LedgerUIDefaults, PageActions, Pre, Prompt, RootProvider, Tab, Tabs, ThreadlineUIDefaults, commandGrid, concrete, createDocsLayout, createDocsMetadata, createPageMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs, hardline, ledger, threadline, threadlinePageActions, withLangInUrl };
@@ -236,6 +236,7 @@ function LocaleThemeControl({ locales, defaultLocale, locale, showThemeToggle =
236
236
  }), showThemeToggle && (themeMode === "light-dark" ? /* @__PURE__ */ jsxs("button", {
237
237
  type: "button",
238
238
  "aria-label": "Toggle theme",
239
+ "data-theme-toggle": true,
239
240
  onClick: () => applyTheme(resolvedTheme === "light" ? "dark" : "light"),
240
241
  style: toggleContainerStyle,
241
242
  children: [/* @__PURE__ */ jsx("span", {
@@ -251,6 +252,7 @@ function LocaleThemeControl({ locales, defaultLocale, locale, showThemeToggle =
251
252
  /* @__PURE__ */ jsx("button", {
252
253
  type: "button",
253
254
  "aria-label": "light",
255
+ "data-theme-toggle": true,
254
256
  style: getToggleItemStyle(themeValue === "light"),
255
257
  onClick: () => applyTheme("light"),
256
258
  children: /* @__PURE__ */ jsx(SunIcon, {})
@@ -258,6 +260,7 @@ function LocaleThemeControl({ locales, defaultLocale, locale, showThemeToggle =
258
260
  /* @__PURE__ */ jsx("button", {
259
261
  type: "button",
260
262
  "aria-label": "dark",
263
+ "data-theme-toggle": true,
261
264
  style: getToggleItemStyle(themeValue === "dark"),
262
265
  onClick: () => applyTheme("dark"),
263
266
  children: /* @__PURE__ */ jsx(MoonIcon, {})
@@ -265,6 +268,7 @@ function LocaleThemeControl({ locales, defaultLocale, locale, showThemeToggle =
265
268
  /* @__PURE__ */ jsx("button", {
266
269
  type: "button",
267
270
  "aria-label": "system",
271
+ "data-theme-toggle": true,
268
272
  style: getToggleItemStyle(themeValue === "system"),
269
273
  onClick: () => applyTheme("system"),
270
274
  children: /* @__PURE__ */ jsx("span", {
@@ -16,6 +16,7 @@ interface PageActionsProps {
16
16
  openDocsTarget?: "markdown" | "page" | "source" | "github";
17
17
  openDocsPrompt?: string;
18
18
  alignment?: "left" | "right";
19
+ variant?: "default" | "rail";
19
20
  /** GitHub file URL (edit view) for the current page. Used when urlTemplate contains {githubUrl}. */
20
21
  githubFileUrl?: string | null;
21
22
  analytics?: boolean;
@@ -27,6 +28,7 @@ declare function PageActions({
27
28
  openDocsTarget,
28
29
  openDocsPrompt,
29
30
  alignment,
31
+ variant,
30
32
  githubFileUrl,
31
33
  analytics
32
34
  }: PageActionsProps): react_jsx_runtime0.JSX.Element | null;
@@ -67,6 +67,46 @@ const ExternalLinkIcon = () => /* @__PURE__ */ jsxs("svg", {
67
67
  })
68
68
  ]
69
69
  });
70
+ const FileTextIcon = () => /* @__PURE__ */ jsxs("svg", {
71
+ width: "14",
72
+ height: "14",
73
+ viewBox: "0 0 24 24",
74
+ fill: "none",
75
+ stroke: "currentColor",
76
+ strokeWidth: "2",
77
+ strokeLinecap: "round",
78
+ strokeLinejoin: "round",
79
+ children: [
80
+ /* @__PURE__ */ jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
81
+ /* @__PURE__ */ jsx("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
82
+ /* @__PURE__ */ jsx("path", { d: "M10 9H8" }),
83
+ /* @__PURE__ */ jsx("path", { d: "M16 13H8" }),
84
+ /* @__PURE__ */ jsx("path", { d: "M16 17H8" })
85
+ ]
86
+ });
87
+ const GitHubIcon = () => /* @__PURE__ */ jsx("svg", {
88
+ width: "14",
89
+ height: "14",
90
+ viewBox: "0 0 24 24",
91
+ fill: "currentColor",
92
+ "aria-hidden": "true",
93
+ children: /* @__PURE__ */ jsx("path", { d: "M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.92.58.11.79-.25.79-.56v-2.02c-3.2.7-3.88-1.37-3.88-1.37-.53-1.33-1.29-1.69-1.29-1.69-1.05-.72.08-.71.08-.71 1.16.08 1.77 1.2 1.77 1.2 1.03 1.76 2.71 1.25 3.37.96.1-.75.4-1.25.73-1.54-2.56-.29-5.26-1.28-5.26-5.7 0-1.26.45-2.29 1.19-3.1-.12-.29-.52-1.47.11-3.05 0 0 .97-.31 3.18 1.18a10.9 10.9 0 0 1 5.8 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.58.23 2.76.11 3.05.74.81 1.19 1.84 1.19 3.1 0 4.43-2.7 5.41-5.27 5.7.41.36.78 1.06.78 2.14v3.03c0 .31.21.67.8.56A11.5 11.5 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5Z" })
94
+ });
95
+ const SparklesIcon = () => /* @__PURE__ */ jsxs("svg", {
96
+ width: "14",
97
+ height: "14",
98
+ viewBox: "0 0 24 24",
99
+ fill: "none",
100
+ stroke: "currentColor",
101
+ strokeWidth: "2",
102
+ strokeLinecap: "round",
103
+ strokeLinejoin: "round",
104
+ children: [
105
+ /* @__PURE__ */ jsx("path", { d: "M9.94 15.5 8.5 21l-1.44-5.5L1.5 14l5.56-1.5L8.5 7l1.44 5.5L15.5 14Z" }),
106
+ /* @__PURE__ */ jsx("path", { d: "M17.5 3 18 5l2 .5-2 .5-.5 2-.5-2-2-.5 2-.5Z" }),
107
+ /* @__PURE__ */ jsx("path", { d: "M19 11.5 20 15l3.5 1-3.5 1-1 3.5-1-3.5-3.5-1 3.5-1Z" })
108
+ ]
109
+ });
70
110
  const DEFAULT_PROVIDERS = [{
71
111
  name: "ChatGPT",
72
112
  urlTemplate: "https://chatgpt.com/?q={prompt}"
@@ -92,30 +132,39 @@ function pageUrlToMarkdownUrl(pageUrl) {
92
132
  function fillPromptTemplate(template, values) {
93
133
  return template.replace(/\{pageUrl\}/g, values.pageUrl).replace(/\{markdownUrl\}/g, values.markdownUrl).replace(/\{sourceUrl\}/g, values.sourceUrl).replace(/\{mdxUrl\}/g, values.sourceUrl).replace(/\{githubUrl\}/g, values.githubUrl).replace(/\{url\}/g, values.url);
94
134
  }
95
- function PageActions({ copyMarkdown, openDocs, providers, openDocsTarget = DEFAULT_OPEN_DOCS_TARGET, openDocsPrompt = DEFAULT_OPEN_DOCS_PROMPT, alignment = "left", githubFileUrl, analytics = false }) {
135
+ function PageActions({ copyMarkdown, openDocs, providers, openDocsTarget = DEFAULT_OPEN_DOCS_TARGET, openDocsPrompt = DEFAULT_OPEN_DOCS_PROMPT, alignment = "left", variant = "default", githubFileUrl, analytics = false }) {
96
136
  const [copied, setCopied] = useState(false);
97
137
  const [dropdownOpen, setDropdownOpen] = useState(false);
98
138
  const dropdownRef = useRef(null);
99
139
  const pathname = usePathname();
100
140
  const resolvedProviders = providers ?? DEFAULT_PROVIDERS;
141
+ const cleanedPathname = pathname.replace(/\/+$/, "") || "/";
142
+ const markdownHref = cleanedPathname === "/" ? "/index.md" : `${cleanedPathname.replace(/\.md$/, "")}.md`;
101
143
  const handleCopyMarkdown = useCallback(async () => {
102
144
  try {
103
- const article = document.querySelector("article");
104
- if (article) {
105
- const content = article.innerText || "";
106
- await navigator.clipboard.writeText(content);
107
- if (analytics) emitClientAnalyticsEvent({
108
- type: "page_action_copy_markdown",
109
- properties: {
110
- contentLength: content.length,
111
- pathname
112
- }
113
- });
114
- setCopied(true);
115
- setTimeout(() => setCopied(false), 2e3);
116
- }
145
+ let content = "";
146
+ try {
147
+ const response = await fetch(markdownHref, { headers: { Accept: "text/markdown" } });
148
+ if (response.ok) content = await response.text();
149
+ } catch {}
150
+ if (!content) content = document.querySelector("article")?.innerText || "";
151
+ if (!content) return;
152
+ await navigator.clipboard.writeText(content);
153
+ if (analytics) emitClientAnalyticsEvent({
154
+ type: "page_action_copy_markdown",
155
+ properties: {
156
+ contentLength: content.length,
157
+ pathname
158
+ }
159
+ });
160
+ setCopied(true);
161
+ setTimeout(() => setCopied(false), 2e3);
117
162
  } catch {}
118
- }, [analytics, pathname]);
163
+ }, [
164
+ analytics,
165
+ markdownHref,
166
+ pathname
167
+ ]);
119
168
  const handleOpen = useCallback((provider) => {
120
169
  const template = provider.urlTemplate;
121
170
  const githubUrl = githubFileUrl ?? "";
@@ -157,6 +206,15 @@ function PageActions({ copyMarkdown, openDocs, providers, openDocsTarget = DEFAU
157
206
  openDocsPrompt,
158
207
  openDocsTarget
159
208
  ]);
209
+ const handleAskAI = useCallback(() => {
210
+ const trigger = document.querySelector(".fd-ai-fm-trigger-btn, [data-ai-trigger], button[aria-label='Ask AI']");
211
+ if (!trigger) return;
212
+ trigger.click();
213
+ if (analytics) emitClientAnalyticsEvent({
214
+ type: "page_action_ask_ai",
215
+ properties: { pathname }
216
+ });
217
+ }, [analytics, pathname]);
160
218
  useEffect(() => {
161
219
  if (!dropdownOpen) return;
162
220
  function handleClick(e) {
@@ -169,7 +227,41 @@ function PageActions({ copyMarkdown, openDocs, providers, openDocsTarget = DEFAU
169
227
  setDropdownOpen(false);
170
228
  setCopied(false);
171
229
  }, [pathname]);
172
- if (!copyMarkdown && !openDocs) return null;
230
+ if (variant !== "rail" && !copyMarkdown && !openDocs) return null;
231
+ if (variant === "rail") return /* @__PURE__ */ jsxs("div", {
232
+ className: "fd-page-actions fd-page-actions-rail",
233
+ "data-page-actions": true,
234
+ "data-page-actions-variant": "rail",
235
+ children: [
236
+ copyMarkdown && /* @__PURE__ */ jsxs("button", {
237
+ type: "button",
238
+ onClick: handleCopyMarkdown,
239
+ className: "fd-page-action-btn",
240
+ "data-copied": copied,
241
+ children: [copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}), /* @__PURE__ */ jsx("span", { children: copied ? "Copied!" : "Copy page" })]
242
+ }),
243
+ openDocs && /* @__PURE__ */ jsxs("a", {
244
+ className: "fd-page-action-btn",
245
+ href: markdownHref,
246
+ target: "_blank",
247
+ rel: "noreferrer",
248
+ children: [/* @__PURE__ */ jsx(FileTextIcon, {}), /* @__PURE__ */ jsx("span", { children: "View as Markdown" })]
249
+ }),
250
+ githubFileUrl && /* @__PURE__ */ jsxs("a", {
251
+ className: "fd-page-action-btn",
252
+ href: githubFileUrl,
253
+ target: "_blank",
254
+ rel: "noreferrer",
255
+ children: [/* @__PURE__ */ jsx(GitHubIcon, {}), /* @__PURE__ */ jsx("span", { children: "Edit on GitHub" })]
256
+ }),
257
+ /* @__PURE__ */ jsxs("button", {
258
+ type: "button",
259
+ onClick: handleAskAI,
260
+ className: "fd-page-action-btn",
261
+ children: [/* @__PURE__ */ jsx(SparklesIcon, {}), /* @__PURE__ */ jsx("span", { children: "Ask AI" })]
262
+ })
263
+ ]
264
+ });
173
265
  return /* @__PURE__ */ jsxs("div", {
174
266
  className: "fd-page-actions",
175
267
  "data-page-actions": true,