@farming-labs/theme 0.1.83 → 0.1.85

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.
@@ -1,4 +1,4 @@
1
- import { ChangelogConfig, DocsAnalyticsConfig, DocsAskAIMcpConfig, DocsI18nConfig, DocsMcpConfig, DocsObservabilityConfig, DocsSearchConfig, DocsSitemapConfig, FeedbackConfig, OrderingItem } from "@farming-labs/docs";
1
+ import { ChangelogConfig, DocsAnalyticsConfig, DocsAskAIMcpConfig, DocsI18nConfig, DocsMcpConfig, DocsObservabilityConfig, DocsRobotsConfig, DocsSearchConfig, DocsSitemapConfig, FeedbackConfig, OrderingItem } from "@farming-labs/docs";
2
2
 
3
3
  //#region src/docs-api.d.ts
4
4
  interface AIProviderConfig {
@@ -56,6 +56,8 @@ interface DocsAPIOptions {
56
56
  mcp?: boolean | DocsMcpConfig;
57
57
  /** Sitemap configuration used for sitemap.xml and sitemap.md. */
58
58
  sitemap?: boolean | DocsSitemapConfig;
59
+ /** Robots.txt generation policy used for the agent discovery spec. */
60
+ robots?: boolean | DocsRobotsConfig;
59
61
  }
60
62
  interface DocsMCPAPIOptions {
61
63
  rootDir?: string;
package/dist/docs-api.mjs CHANGED
@@ -46,6 +46,7 @@ const DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms.txt";
46
46
  const DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms-full.txt";
47
47
  const DEFAULT_SKILL_MD_ROUTE = "/skill.md";
48
48
  const DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE = "/.well-known/skill.md";
49
+ const DEFAULT_ROBOTS_TXT_ROUTE = "/robots.txt";
49
50
  const DEFAULT_AGENT_FEEDBACK_ROUTE = "/api/docs/agent/feedback";
50
51
  const DEFAULT_AGENT_FEEDBACK_PAYLOAD_SCHEMA = {
51
52
  type: "object",
@@ -172,11 +173,17 @@ function isSearchEnabled(search) {
172
173
  if (search && typeof search === "object" && search.enabled === false) return false;
173
174
  return true;
174
175
  }
175
- function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, sitemap }) {
176
+ function isRobotsDiscoveryEnabled(robots) {
177
+ if (robots === false) return false;
178
+ if (robots && typeof robots === "object" && robots.enabled === false) return false;
179
+ return true;
180
+ }
181
+ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, sitemap, robots }) {
176
182
  const normalizedEntry = normalizePathSegment(entry) || "docs";
177
183
  const localesEnabled = i18n !== null;
178
184
  const searchEnabled = isSearchEnabled(search);
179
185
  const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
186
+ const robotsEnabled = isRobotsDiscoveryEnabled(robots);
180
187
  return {
181
188
  version: "1",
182
189
  name: "@farming-labs/docs",
@@ -203,6 +210,8 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
203
210
  mcp: mcp.enabled,
204
211
  search: searchEnabled,
205
212
  sitemap: sitemapConfig.enabled,
213
+ robots: robotsEnabled,
214
+ structuredData: true,
206
215
  agentFeedback: feedback.enabled,
207
216
  locales: localesEnabled
208
217
  },
@@ -252,6 +261,25 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
252
261
  api: `${DEFAULT_DOCS_API_ROUTE}?format=sitemap-md`
253
262
  }
254
263
  },
264
+ robots: {
265
+ enabled: robotsEnabled,
266
+ route: DEFAULT_ROBOTS_TXT_ROUTE,
267
+ defaultRoute: DEFAULT_ROBOTS_TXT_ROUTE
268
+ },
269
+ structuredData: {
270
+ enabled: true,
271
+ format: "application/ld+json",
272
+ schema: "https://schema.org/TechArticle",
273
+ fields: [
274
+ "headline",
275
+ "description",
276
+ "url",
277
+ "dateModified",
278
+ "breadcrumb"
279
+ ],
280
+ canonicalUrlField: "url",
281
+ breadcrumbType: "BreadcrumbList"
282
+ },
255
283
  search: {
256
284
  enabled: searchEnabled,
257
285
  endpoint: `${DEFAULT_DOCS_API_ROUTE}?query={query}`,
@@ -915,16 +943,17 @@ function renderMarkdownDocument(page) {
915
943
  lines.push("", page.agentFallbackRawContent ?? page.rawContent ?? page.content);
916
944
  return lines.join("\n");
917
945
  }
918
- function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitemap }) {
946
+ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitemap, robots }) {
919
947
  const normalizedEntry = normalizePathSegment(entry) || "docs";
920
948
  const siteTitle = compactSkillText(llms.siteTitle ?? "Documentation");
921
949
  const siteDescription = llms.siteDescription ? compactSkillText(llms.siteDescription) : void 0;
922
950
  const searchEnabled = isSearchEnabled(search);
923
951
  const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
952
+ const robotsEnabled = isRobotsDiscoveryEnabled(robots);
924
953
  const lines = [
925
954
  "---",
926
955
  "name: docs",
927
- `description: ${toYamlString(truncateSkillDescription(`Use ${siteTitle} through markdown routes, llms.txt, agent discovery, search, and MCP when available.`))}`,
956
+ `description: ${toYamlString(truncateSkillDescription(`Use ${siteTitle} through markdown routes, llms.txt, robots.txt, agent discovery, search, and MCP when available.`))}`,
928
957
  "---",
929
958
  "",
930
959
  `# ${siteTitle} Skill`,
@@ -939,9 +968,11 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
939
968
  if (sitemapConfig.xml.enabled) lines.push(`- Use ${sitemapConfig.xml.route} to check canonical page freshness.`);
940
969
  if (sitemapConfig.markdown.enabled) lines.push(`- Use ${sitemapConfig.markdown.route} for a semantic docs map.`);
941
970
  }
971
+ if (robotsEnabled) lines.push(`- Check ${DEFAULT_ROBOTS_TXT_ROUTE} for crawler and AI-agent access policy.`);
942
972
  if (mcp.enabled) lines.push(`- Use ${DEFAULT_MCP_WELL_KNOWN_ROUTE} or ${DEFAULT_MCP_PUBLIC_ROUTE} for MCP tools when your environment supports MCP.`);
943
973
  if (feedback.enabled) lines.push(`- Read ${feedback.schemaRoute} before posting agent feedback to ${feedback.route}.`);
944
974
  lines.push("", "## Routes", `- Skill document: ${DEFAULT_SKILL_MD_ROUTE}`, `- Skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Skill API format: ${DEFAULT_DOCS_API_ROUTE}?format=skill`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`, `- Markdown root: /${normalizedEntry}.md`, `- Markdown pages: /${normalizedEntry}/{slug}.md`);
975
+ if (robotsEnabled) lines.push(`- Robots policy: ${DEFAULT_ROBOTS_TXT_ROUTE}`);
945
976
  if (llms.enabled) lines.push(`- llms.txt: ${DEFAULT_LLMS_TXT_ROUTE}`, `- llms-full.txt: ${DEFAULT_LLMS_FULL_TXT_ROUTE}`, `- llms well-known aliases: ${DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE}, ${DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE}`);
946
977
  if (sitemapConfig.enabled) {
947
978
  if (sitemapConfig.xml.enabled) lines.push(`- Sitemap XML: ${sitemapConfig.xml.route}`);
@@ -1507,6 +1538,31 @@ function readSitemapConfig(root) {
1507
1538
  }
1508
1539
  }
1509
1540
  }
1541
+ function readRobotsConfig(root) {
1542
+ for (const ext of FILE_EXTS) {
1543
+ const configPath = path.join(root, `docs.config.${ext}`);
1544
+ if (!fs.existsSync(configPath)) continue;
1545
+ try {
1546
+ const content = fs.readFileSync(configPath, "utf-8");
1547
+ if (!content.includes("robots")) return void 0;
1548
+ if (/robots\s*:\s*false/.test(content)) return false;
1549
+ if (/robots\s*:\s*true/.test(content)) return true;
1550
+ const robotsBlock = content.match(/robots\s*:\s*\{([\s\S]*?)\n\s*\}/)?.[1] ?? "";
1551
+ const enabledMatch = robotsBlock.match(/enabled\s*:\s*(true|false)/);
1552
+ const pathMatch = robotsBlock.match(/path\s*:\s*["']([^"']+)["']/);
1553
+ const baseUrlMatch = robotsBlock.match(/baseUrl\s*:\s*["']([^"']+)["']/);
1554
+ const aiMatch = robotsBlock.match(/ai\s*:\s*["'](allow|disallow)["']/);
1555
+ return {
1556
+ enabled: enabledMatch ? enabledMatch[1] === "true" : true,
1557
+ path: pathMatch?.[1],
1558
+ baseUrl: baseUrlMatch?.[1],
1559
+ ai: aiMatch?.[1]
1560
+ };
1561
+ } catch {
1562
+ return;
1563
+ }
1564
+ }
1565
+ }
1510
1566
  function generateLlmsTxt(indexes, options) {
1511
1567
  const { siteTitle = "Documentation", siteDescription, baseUrl = "" } = options;
1512
1568
  let llmsTxt = `# ${siteTitle}\n\n`;
@@ -1568,6 +1624,7 @@ function createDocsAPI(options) {
1568
1624
  const searchConfig = options?.search;
1569
1625
  const llmsConfig = readLlmsTxtConfig(root);
1570
1626
  const sitemapConfig = options?.sitemap ?? readSitemapConfig(root);
1627
+ const robotsConfig = options?.robots ?? readRobotsConfig(root);
1571
1628
  const mcpConfig = resolveDocsMcpConfig(options?.mcp ?? readMcpConfig(root), { defaultName: llmsConfig.siteTitle ?? "Documentation" });
1572
1629
  function resolveDocsDirCandidates(locale) {
1573
1630
  const relativeCandidates = /* @__PURE__ */ new Set();
@@ -1708,7 +1765,8 @@ function createDocsAPI(options) {
1708
1765
  mcp: mcpConfig,
1709
1766
  feedback: agentFeedbackConfig,
1710
1767
  llms: llmsConfig,
1711
- sitemap: sitemapConfig
1768
+ sitemap: sitemapConfig,
1769
+ robots: robotsConfig
1712
1770
  }), { headers: {
1713
1771
  "Cache-Control": "public, max-age=0, s-maxage=3600",
1714
1772
  "X-Robots-Tag": "noindex"
@@ -1751,7 +1809,8 @@ function createDocsAPI(options) {
1751
1809
  mcp: mcpConfig,
1752
1810
  feedback: agentFeedbackConfig,
1753
1811
  llms: llmsConfig,
1754
- sitemap: sitemapConfig
1812
+ sitemap: sitemapConfig,
1813
+ robots: robotsConfig
1755
1814
  }), { headers: {
1756
1815
  "Content-Type": "text/markdown; charset=utf-8",
1757
1816
  "Cache-Control": "public, max-age=0, s-maxage=3600",
@@ -11,7 +11,7 @@ import path from "node:path";
11
11
  import matter from "gray-matter";
12
12
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
13
13
  import { Suspense } from "react";
14
- import { applySidebarFolderIndexBehavior, buildPageOpenGraph, buildPageTwitter, resolveChangelogConfig, resolveDocsAgentMdxContent, resolveDocsAnalyticsConfig, resolvePageSidebarFolderIndexBehavior, toDocsMarkdownUrl } from "@farming-labs/docs";
14
+ import { applySidebarFolderIndexBehavior, buildPageOpenGraph, buildPageTwitter, renderDocsPageStructuredDataJson, resolveChangelogConfig, resolveDocsAgentMdxContent, resolveDocsAnalyticsConfig, resolveDocsMetadataBaseUrl, resolvePageSidebarFolderIndexBehavior, toDocsMarkdownUrl } from "@farming-labs/docs";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
16
 
17
17
  //#region src/docs-layout.tsx
@@ -380,6 +380,41 @@ function buildReadingTimeMap(config, ctx, options) {
380
380
  scan(docsDir, []);
381
381
  return map;
382
382
  }
383
+ function findDocsPageFile(dir) {
384
+ return ["page.mdx", "page.md"].map((fileName) => path.join(dir, fileName)).find(fs.existsSync);
385
+ }
386
+ function buildStructuredDataMap(config, ctx) {
387
+ const docsDir = ctx.docsDir;
388
+ const map = {};
389
+ const excludedDirs = getExcludedDocsDirs(config, ctx);
390
+ const baseUrl = resolveDocsMetadataBaseUrl(config);
391
+ function scan(dir, slugParts) {
392
+ if (!fs.existsSync(dir)) return;
393
+ if (isExcludedDir(dir, excludedDirs)) return;
394
+ const pagePath = findDocsPageFile(dir);
395
+ if (pagePath) {
396
+ const { data } = matter(fs.readFileSync(pagePath, "utf-8"));
397
+ const route = slugParts.length === 0 ? `/${ctx.entryPath}` : `/${ctx.entryPath}/${slugParts.join("/")}`;
398
+ const title = typeof data.title === "string" ? data.title : slugParts.at(-1)?.replace(/-/g, " ") || "Documentation";
399
+ const description = typeof data.description === "string" ? data.description : void 0;
400
+ const stat = fs.statSync(pagePath);
401
+ map[route] = renderDocsPageStructuredDataJson({
402
+ title,
403
+ description,
404
+ url: withLangInUrl(route, ctx.locale),
405
+ baseUrl,
406
+ entry: ctx.entryPath,
407
+ dateModified: stat.mtime.toISOString()
408
+ });
409
+ }
410
+ for (const name of fs.readdirSync(dir)) {
411
+ const full = path.join(dir, name);
412
+ if (fs.statSync(full).isDirectory()) scan(full, [...slugParts, name]);
413
+ }
414
+ }
415
+ scan(docsDir, []);
416
+ return map;
417
+ }
383
418
  /**
384
419
  * Build a Next.js Metadata object from the docs config.
385
420
  *
@@ -638,6 +673,7 @@ function createDocsLayout(config, options) {
638
673
  enabledByDefault: readingTimeEnabledByDefault,
639
674
  wordsPerMinute: readingTimeWordsPerMinute
640
675
  });
676
+ const structuredDataMap = buildStructuredDataMap(config, localeContext);
641
677
  const readingTimeEnabled = readingTimeEnabledByDefault || Object.keys(readingTimeMap).length > 0;
642
678
  return function DocsLayoutWrapper({ children }) {
643
679
  const tree = applySidebarFolderIndexBehavior(buildTree(config, localeContext, !!sidebarFlat), {
@@ -736,6 +772,7 @@ function createDocsLayout(config, options) {
736
772
  lastUpdatedPosition,
737
773
  readingTimeEnabled,
738
774
  readingTimeMap,
775
+ structuredDataMap,
739
776
  llmsTxtEnabled,
740
777
  descriptionMap,
741
778
  feedbackEnabled: feedbackConfig.enabled,
@@ -43,6 +43,10 @@ interface DocsPageClientProps {
43
43
  readingTimeMap?: Record<string, number>;
44
44
  /** Direct reading-time override for the current page. */
45
45
  readingTime?: number | null;
46
+ /** Map of pathname → serialized Schema.org JSON-LD. */
47
+ structuredDataMap?: Record<string, string>;
48
+ /** Direct serialized Schema.org JSON-LD override for the current page. */
49
+ structuredData?: string;
46
50
  /**
47
51
  * Whether path-based reading time values should render by default.
48
52
  * Explicit `readingTime` overrides can still render when this is false.
@@ -90,6 +94,8 @@ declare function DocsPageClient({
90
94
  lastModified: lastModifiedProp,
91
95
  readingTimeMap,
92
96
  readingTime: readingTimeProp,
97
+ structuredDataMap,
98
+ structuredData: structuredDataProp,
93
99
  readingTimeEnabled,
94
100
  lastUpdatedEnabled,
95
101
  lastUpdatedPosition,
@@ -5,6 +5,7 @@ import { PageActions } from "./page-actions.mjs";
5
5
  import { useWindowSearchParams } from "./client-location.mjs";
6
6
  import { DocsFeedback } from "./docs-feedback.mjs";
7
7
  import { resolveClientLocale, withLangInUrl } from "./i18n.mjs";
8
+ import { escapeJsonLdForScript } from "./json-ld.mjs";
8
9
  import { Children, Fragment, cloneElement, isValidElement, useEffect, useState } from "react";
9
10
  import { DocsBody, DocsPage, EditOnGitHub } from "fumadocs-ui/layouts/docs/page";
10
11
  import { createPortal } from "react-dom";
@@ -163,7 +164,7 @@ function TitleDecorations({ description, belowTitle }) {
163
164
  if (!description && !belowTitle) return null;
164
165
  return /* @__PURE__ */ jsx(Fragment$1, { children: Children.toArray([description, belowTitle].filter(Boolean)) });
165
166
  }
166
- function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, changelogBasePath, entry = "docs", locale, copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, contentDir, githubBranch = "main", githubDirectory, editOnGithubUrl, lastModifiedMap, lastModified: lastModifiedProp, readingTimeMap, readingTime: readingTimeProp, readingTimeEnabled = false, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, feedbackEnabled = false, feedbackQuestion, feedbackPlaceholder, feedbackPositiveLabel, feedbackNegativeLabel, feedbackSubmitLabel, feedbackOnFeedback, analytics = false, children }) {
167
+ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, changelogBasePath, entry = "docs", locale, copyMarkdown = false, openDocs = false, openDocsProviders, 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 }) {
167
168
  const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
168
169
  const [toc, setToc] = useState([]);
169
170
  const [titlePortalHost, setTitlePortalHost] = useState(null);
@@ -175,6 +176,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
175
176
  const normalizedPath = (browserPath ?? pathname).replace(/\/$/, "") || "/";
176
177
  const isChangelogRoute = !!(changelogBasePath && (normalizedPath === changelogBasePath || normalizedPath.startsWith(`${changelogBasePath}/`)));
177
178
  const matchedReadingTime = readingTimeMap?.[normalizedPath];
179
+ const structuredDataJson = !isChangelogRoute ? structuredDataProp ?? structuredDataMap?.[normalizedPath] : void 0;
178
180
  useEffect(() => {
179
181
  if (!analytics) return;
180
182
  emitClientAnalyticsEvent({
@@ -341,7 +343,10 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
341
343
  belowTitle: belowTitleBlock
342
344
  }), titlePortalHost) : null;
343
345
  const renderedChildren = Children.toArray(decoratedChildren);
344
- return /* @__PURE__ */ jsxs(DocsPage, {
346
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [structuredDataJson && /* @__PURE__ */ jsx("script", {
347
+ type: "application/ld+json",
348
+ dangerouslySetInnerHTML: { __html: escapeJsonLdForScript(structuredDataJson) }
349
+ }), /* @__PURE__ */ jsxs(DocsPage, {
345
350
  full: false,
346
351
  toc,
347
352
  tableOfContent: {
@@ -428,7 +433,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
428
433
  ]
429
434
  })
430
435
  ]
431
- });
436
+ })] });
432
437
  }
433
438
 
434
439
  //#endregion
@@ -0,0 +1,7 @@
1
+ //#region src/json-ld.ts
2
+ function escapeJsonLdForScript(json) {
3
+ return json.replace(/</g, "\\u003c");
4
+ }
5
+
6
+ //#endregion
7
+ export { escapeJsonLdForScript };
@@ -31,6 +31,7 @@ interface TanstackDocsLayoutProps {
31
31
  description?: string;
32
32
  readingTime?: number | null;
33
33
  lastModified?: string;
34
+ structuredData?: string;
34
35
  editOnGithubUrl?: string;
35
36
  children: ReactNode;
36
37
  }
@@ -41,6 +42,7 @@ declare function TanstackDocsLayout({
41
42
  description,
42
43
  readingTime,
43
44
  lastModified,
45
+ structuredData,
44
46
  editOnGithubUrl,
45
47
  children
46
48
  }: TanstackDocsLayoutProps): react_jsx_runtime0.JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { withLangInUrl } from "./i18n.mjs";
2
+ import { escapeJsonLdForScript } from "./json-ld.mjs";
2
3
  import { DocsPageClient } from "./docs-page-client.mjs";
3
4
  import { DocsAIFeatures } from "./docs-ai-features.mjs";
4
5
  import { DocsCommandSearch } from "./docs-command-search.mjs";
@@ -8,7 +9,7 @@ import { LocaleThemeControl } from "./locale-theme-control.mjs";
8
9
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
9
10
  import { Suspense } from "react";
10
11
  import { applySidebarFolderIndexBehavior, resolveDocsAnalyticsConfig } from "@farming-labs/docs";
11
- import { jsx, jsxs } from "react/jsx-runtime";
12
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
13
 
13
14
  //#region src/tanstack-layout.tsx
14
15
  function resolveTreeIcon(icon, registry) {
@@ -207,7 +208,7 @@ function resolveFeedbackConfig(feedback) {
207
208
  function ForcedThemeScript({ theme }) {
208
209
  return /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: `document.documentElement.classList.remove('light','dark');document.documentElement.classList.add('${theme === "light" || theme === "dark" ? theme : "light"}');` } });
209
210
  }
210
- function TanstackDocsLayout({ config, tree, locale, description, readingTime, lastModified, editOnGithubUrl, children }) {
211
+ function TanstackDocsLayout({ config, tree, locale, description, readingTime, lastModified, structuredData, editOnGithubUrl, children }) {
211
212
  const tocConfig = config.theme?.ui?.layout?.toc;
212
213
  const tocEnabled = tocConfig?.enabled !== false;
213
214
  const tocStyle = tocConfig?.style;
@@ -290,7 +291,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
290
291
  collapsible: sidebarProps.collapsible !== false,
291
292
  flat: !!sidebarFlat
292
293
  });
293
- return /* @__PURE__ */ jsxs(DocsLayout, {
294
+ const layout = /* @__PURE__ */ jsxs(DocsLayout, {
294
295
  tree: resolvedTree,
295
296
  nav: {
296
297
  title: navTitle,
@@ -364,6 +365,11 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
364
365
  })
365
366
  ]
366
367
  });
368
+ if (!structuredData) return layout;
369
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("script", {
370
+ type: "application/ld+json",
371
+ dangerouslySetInnerHTML: { __html: escapeJsonLdForScript(structuredData) }
372
+ }), layout] });
367
373
  }
368
374
 
369
375
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.1.83",
3
+ "version": "0.1.85",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -139,7 +139,7 @@
139
139
  "tsdown": "^0.20.3",
140
140
  "typescript": "^5.9.3",
141
141
  "vitest": "^3.2.4",
142
- "@farming-labs/docs": "0.1.83"
142
+ "@farming-labs/docs": "0.1.85"
143
143
  },
144
144
  "peerDependencies": {
145
145
  "@farming-labs/docs": ">=0.0.1",