@farming-labs/theme 0.0.2-beta.21 → 0.0.2-beta.23

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.
@@ -38,12 +38,14 @@ interface DocsAPIOptions {
38
38
  * Create a unified docs API route handler.
39
39
  *
40
40
  * Returns `{ GET, POST }` for use in a Next.js route handler:
41
- * - **GET** → full-text search (same as the old `createDocsSearchAPI`)
42
- * - **POST** AI-powered chat with RAG (when AI is enabled in config)
41
+ * - **GET ?query=…** → full-text search
42
+ * - **GET ?format=llms** llms.txt (concise page listing)
43
+ * - **GET ?format=llms-full** → llms-full.txt (full page content)
44
+ * - **POST** → AI-powered chat with RAG
43
45
  *
44
46
  * @example
45
47
  * ```ts
46
- * // app/api/docs/route.ts
48
+ * // app/api/docs/route.ts (auto-generated by withDocs)
47
49
  * import { createDocsAPI } from "@farming-labs/theme/api";
48
50
  * export const { GET, POST } = createDocsAPI();
49
51
  * export const revalidate = false;
@@ -53,10 +55,9 @@ interface DocsAPIOptions {
53
55
  */
54
56
  declare function createDocsAPI(options?: DocsAPIOptions): {
55
57
  /**
56
- * GET handler — full-text search.
57
- * Query: `?query=search+term`
58
+ * GET handler — search, llms.txt, or llms-full.txt depending on query params.
58
59
  */
59
- GET: (request: Request) => Promise<Response>;
60
+ GET(request: Request): Response | Promise<Response>;
60
61
  /**
61
62
  * POST handler — AI chat with RAG.
62
63
  * Body: `{ messages: [{ role: "user", content: "How do I …?" }] }`
package/dist/docs-api.mjs CHANGED
@@ -163,16 +163,64 @@ async function handleAskAI(request, indexes, searchServer, aiConfig) {
163
163
  Connection: "keep-alive"
164
164
  } });
165
165
  }
166
+ function readLlmsTxtConfig(root) {
167
+ for (const ext of FILE_EXTS) {
168
+ const configPath = path.join(root, `docs.config.${ext}`);
169
+ if (fs.existsSync(configPath)) try {
170
+ const content = fs.readFileSync(configPath, "utf-8");
171
+ if (!content.includes("llmsTxt")) return { enabled: false };
172
+ if (/llmsTxt\s*:\s*true/.test(content)) return { enabled: true };
173
+ const enabledMatch = content.match(/llmsTxt\s*:\s*\{[^}]*enabled\s*:\s*(true|false)/s);
174
+ if (enabledMatch && enabledMatch[1] === "false") return { enabled: false };
175
+ const baseUrlMatch = content.match(/llmsTxt\s*:\s*\{[^}]*baseUrl\s*:\s*["']([^"']+)["']/s);
176
+ const siteTitleMatch = content.match(/llmsTxt\s*:\s*\{[^}]*siteTitle\s*:\s*["']([^"']+)["']/s);
177
+ const siteDescMatch = content.match(/llmsTxt\s*:\s*\{[^}]*siteDescription\s*:\s*["']([^"']+)["']/s);
178
+ const navTitleMatch = content.match(/nav\s*:\s*\{[^}]*title\s*:\s*["']([^"']+)["']/s);
179
+ return {
180
+ enabled: true,
181
+ baseUrl: baseUrlMatch?.[1],
182
+ siteTitle: siteTitleMatch?.[1] ?? navTitleMatch?.[1],
183
+ siteDescription: siteDescMatch?.[1]
184
+ };
185
+ } catch {}
186
+ }
187
+ return { enabled: false };
188
+ }
189
+ function generateLlmsTxt(indexes, options) {
190
+ const { siteTitle = "Documentation", siteDescription, baseUrl = "" } = options;
191
+ let llmsTxt = `# ${siteTitle}\n\n`;
192
+ if (siteDescription) llmsTxt += `> ${siteDescription}\n\n`;
193
+ llmsTxt += `## Pages\n\n`;
194
+ for (const page of indexes) {
195
+ llmsTxt += `- [${page.title}](${baseUrl}${page.url})`;
196
+ if (page.description) llmsTxt += `: ${page.description}`;
197
+ llmsTxt += `\n`;
198
+ }
199
+ let llmsFullTxt = `# ${siteTitle}\n\n`;
200
+ if (siteDescription) llmsFullTxt += `> ${siteDescription}\n\n`;
201
+ for (const page of indexes) {
202
+ llmsFullTxt += `## ${page.title}\n\n`;
203
+ llmsFullTxt += `URL: ${baseUrl}${page.url}\n\n`;
204
+ if (page.description) llmsFullTxt += `${page.description}\n\n`;
205
+ llmsFullTxt += `${page.content}\n\n---\n\n`;
206
+ }
207
+ return {
208
+ llmsTxt,
209
+ llmsFullTxt
210
+ };
211
+ }
166
212
  /**
167
213
  * Create a unified docs API route handler.
168
214
  *
169
215
  * Returns `{ GET, POST }` for use in a Next.js route handler:
170
- * - **GET** → full-text search (same as the old `createDocsSearchAPI`)
171
- * - **POST** AI-powered chat with RAG (when AI is enabled in config)
216
+ * - **GET ?query=…** → full-text search
217
+ * - **GET ?format=llms** llms.txt (concise page listing)
218
+ * - **GET ?format=llms-full** → llms-full.txt (full page content)
219
+ * - **POST** → AI-powered chat with RAG
172
220
  *
173
221
  * @example
174
222
  * ```ts
175
- * // app/api/docs/route.ts
223
+ * // app/api/docs/route.ts (auto-generated by withDocs)
176
224
  * import { createDocsAPI } from "@farming-labs/theme/api";
177
225
  * export const { GET, POST } = createDocsAPI();
178
226
  * export const revalidate = false;
@@ -186,13 +234,34 @@ function createDocsAPI(options) {
186
234
  const docsDir = path.join(root, "app", entry);
187
235
  const language = options?.language ?? "english";
188
236
  const aiConfig = options?.ai ?? readAIConfig(root);
237
+ const llmsConfig = readLlmsTxtConfig(root);
189
238
  const indexes = scanDocsDir(docsDir, entry);
239
+ let _llmsCache = null;
240
+ function getLlmsContent() {
241
+ if (!_llmsCache) _llmsCache = generateLlmsTxt(indexes, {
242
+ siteTitle: llmsConfig.siteTitle ?? "Documentation",
243
+ siteDescription: llmsConfig.siteDescription,
244
+ baseUrl: llmsConfig.baseUrl ?? ""
245
+ });
246
+ return _llmsCache;
247
+ }
190
248
  const searchAPI = createSearchAPI("simple", {
191
249
  language,
192
250
  indexes
193
251
  });
194
252
  return {
195
- GET: searchAPI.GET,
253
+ GET(request) {
254
+ const format = new URL(request.url).searchParams.get("format");
255
+ if (format === "llms") return new Response(getLlmsContent().llmsTxt, { headers: {
256
+ "Content-Type": "text/plain; charset=utf-8",
257
+ "Cache-Control": "public, max-age=3600"
258
+ } });
259
+ if (format === "llms-full") return new Response(getLlmsContent().llmsFullTxt, { headers: {
260
+ "Content-Type": "text/plain; charset=utf-8",
261
+ "Cache-Control": "public, max-age=3600"
262
+ } });
263
+ return searchAPI.GET(request);
264
+ },
196
265
  async POST(request) {
197
266
  if (!aiConfig.enabled) return Response.json({ error: "AI is not enabled. Set `ai: { enabled: true }` in your docs.config to enable it." }, { status: 404 });
198
267
  return handleAskAI(request, indexes, searchAPI, aiConfig);
@@ -357,6 +357,7 @@ function createDocsLayout(config) {
357
357
  const lastUpdatedRaw = config.lastUpdated;
358
358
  const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
359
359
  const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
360
+ const llmsTxtEnabled = resolveBool(config.llmsTxt);
360
361
  const openDocsProviders = (typeof pageActions?.openDocs === "object" && pageActions.openDocs.providers ? pageActions.openDocs.providers : void 0)?.map((p) => ({
361
362
  name: p.name,
362
363
  urlTemplate: p.urlTemplate,
@@ -418,6 +419,7 @@ function createDocsLayout(config) {
418
419
  lastModifiedMap,
419
420
  lastUpdatedEnabled,
420
421
  lastUpdatedPosition,
422
+ llmsTxtEnabled,
421
423
  descriptionMap,
422
424
  children
423
425
  })
@@ -33,6 +33,8 @@ interface DocsPageClientProps {
33
33
  lastUpdatedEnabled?: boolean;
34
34
  /** Where to show the "Last updated" date: "footer" (next to Edit on GitHub) or "below-title" */
35
35
  lastUpdatedPosition?: "footer" | "below-title";
36
+ /** Whether llms.txt is enabled — shows links in footer */
37
+ llmsTxtEnabled?: boolean;
36
38
  /** Map of pathname → frontmatter description */
37
39
  descriptionMap?: Record<string, string>;
38
40
  /** Frontmatter description to display below the page title (overrides descriptionMap) */
@@ -55,6 +57,7 @@ declare function DocsPageClient({
55
57
  lastModifiedMap,
56
58
  lastUpdatedEnabled,
57
59
  lastUpdatedPosition,
60
+ llmsTxtEnabled,
58
61
  descriptionMap,
59
62
  description,
60
63
  children
@@ -63,7 +63,7 @@ function buildGithubFileUrl(githubUrl, branch, pathname, directory) {
63
63
  const segments = pathname.replace(/^\//, "").replace(/\/$/, "");
64
64
  return `${githubUrl}/tree/${branch}/${directory ? `${directory}/` : ""}app/${segments}/page.mdx`;
65
65
  }
66
- function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", descriptionMap, description, children }) {
66
+ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, children }) {
67
67
  const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
68
68
  const [toc, setToc] = useState([]);
69
69
  const pathname = usePathname();
@@ -109,7 +109,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
109
109
  const lastModified = lastUpdatedEnabled ? lastModifiedMap?.[normalizedPath] : void 0;
110
110
  const showLastUpdatedBelowTitle = !!lastModified && lastUpdatedPosition === "below-title";
111
111
  const showLastUpdatedInFooter = !!lastModified && lastUpdatedPosition === "footer";
112
- const showFooter = !!githubFileUrl || showLastUpdatedInFooter;
112
+ const showFooter = !!githubFileUrl || showLastUpdatedInFooter || llmsTxtEnabled;
113
113
  const needsBelowTitleBlock = showLastUpdatedBelowTitle || showActions;
114
114
  useEffect(() => {
115
115
  if (!needsBelowTitleBlock) return;
@@ -188,10 +188,29 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
188
188
  children
189
189
  }), showFooter && /* @__PURE__ */ jsxs("div", {
190
190
  className: "not-prose fd-page-footer",
191
- children: [githubFileUrl && /* @__PURE__ */ jsx(EditOnGitHub, { href: githubFileUrl }), showLastUpdatedInFooter && lastModified && /* @__PURE__ */ jsxs("span", {
192
- className: "fd-last-updated-footer",
193
- children: ["Last updated ", lastModified]
194
- })]
191
+ children: [
192
+ githubFileUrl && /* @__PURE__ */ jsx(EditOnGitHub, { href: githubFileUrl }),
193
+ llmsTxtEnabled && /* @__PURE__ */ jsxs("span", {
194
+ className: "fd-llms-txt-links",
195
+ children: [/* @__PURE__ */ jsx("a", {
196
+ href: "/api/docs?format=llms",
197
+ target: "_blank",
198
+ rel: "noopener noreferrer",
199
+ className: "fd-llms-txt-link",
200
+ children: "llms.txt"
201
+ }), /* @__PURE__ */ jsx("a", {
202
+ href: "/api/docs?format=llms-full",
203
+ target: "_blank",
204
+ rel: "noopener noreferrer",
205
+ className: "fd-llms-txt-link",
206
+ children: "llms-full.txt"
207
+ })]
208
+ }),
209
+ showLastUpdatedInFooter && lastModified && /* @__PURE__ */ jsxs("span", {
210
+ className: "fd-last-updated-footer",
211
+ children: ["Last updated ", lastModified]
212
+ })
213
+ ]
195
214
  })]
196
215
  })
197
216
  ]
package/dist/search.d.mts CHANGED
@@ -27,7 +27,7 @@ declare function createDocsSearchAPI(options?: {
27
27
  entry?: string;
28
28
  language?: string;
29
29
  }): {
30
- GET: (request: Request) => Promise<Response>;
30
+ GET(request: Request): Response | Promise<Response>;
31
31
  POST(request: Request): Promise<Response>;
32
32
  };
33
33
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.0.2-beta.21",
3
+ "version": "0.0.2-beta.23",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
+ "keywords": [
6
+ "docs",
7
+ "documentation",
8
+ "fumadocs",
9
+ "theme"
10
+ ],
11
+ "license": "MIT",
12
+ "author": "Farming Labs",
13
+ "files": [
14
+ "dist",
15
+ "styles"
16
+ ],
5
17
  "type": "module",
6
18
  "main": "./dist/index.mjs",
7
19
  "types": "./dist/index.d.mts",
@@ -74,18 +86,6 @@
74
86
  "./presets/black": "./styles/presets/black.css",
75
87
  "./presets/base": "./styles/presets/base.css"
76
88
  },
77
- "files": [
78
- "dist",
79
- "styles"
80
- ],
81
- "keywords": [
82
- "docs",
83
- "fumadocs",
84
- "theme",
85
- "documentation"
86
- ],
87
- "author": "Farming Labs",
88
- "license": "MIT",
89
89
  "dependencies": {
90
90
  "fumadocs-core": "^16.6.1",
91
91
  "fumadocs-ui": "^16.6.1",
@@ -98,7 +98,7 @@
98
98
  "next": ">=14.0.0",
99
99
  "tsdown": "^0.20.3",
100
100
  "typescript": "^5.9.3",
101
- "@farming-labs/docs": "0.0.2-beta.21"
101
+ "@farming-labs/docs": "0.0.2-beta.23"
102
102
  },
103
103
  "peerDependencies": {
104
104
  "@farming-labs/docs": ">=0.0.1",
package/styles/ai.css CHANGED
@@ -8,28 +8,58 @@
8
8
  /* ─── Animations ─────────────────────────────────────────────────── */
9
9
 
10
10
  @keyframes fd-ai-dot {
11
- 0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
12
- 40% { transform: scale(1); opacity: 1; }
11
+ 0%,
12
+ 80%,
13
+ 100% {
14
+ transform: scale(0);
15
+ opacity: 0.5;
16
+ }
17
+ 40% {
18
+ transform: scale(1);
19
+ opacity: 1;
20
+ }
13
21
  }
14
22
 
15
23
  @keyframes fd-ai-fade-in {
16
- from { opacity: 0; }
17
- to { opacity: 1; }
24
+ from {
25
+ opacity: 0;
26
+ }
27
+ to {
28
+ opacity: 1;
29
+ }
18
30
  }
19
31
 
20
32
  @keyframes fd-ai-slide-up {
21
- from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
22
- to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
33
+ from {
34
+ opacity: 0;
35
+ transform: translate(-50%, -48%) scale(0.96);
36
+ }
37
+ to {
38
+ opacity: 1;
39
+ transform: translate(-50%, -50%) scale(1);
40
+ }
23
41
  }
24
42
 
25
43
  @keyframes fd-ai-float-in {
26
- from { opacity: 0; transform: translateY(12px) scale(0.95); }
27
- to { opacity: 1; transform: translateY(0) scale(1); }
44
+ from {
45
+ opacity: 0;
46
+ transform: translateY(12px) scale(0.95);
47
+ }
48
+ to {
49
+ opacity: 1;
50
+ transform: translateY(0) scale(1);
51
+ }
28
52
  }
29
53
 
30
54
  @keyframes fd-ai-float-center-in {
31
- from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
32
- to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
55
+ from {
56
+ opacity: 0;
57
+ transform: translate(-50%, -48%) scale(0.96);
58
+ }
59
+ to {
60
+ opacity: 1;
61
+ transform: translate(-50%, -50%) scale(1);
62
+ }
33
63
  }
34
64
 
35
65
  /* ─── Overlay ────────────────────────────────────────────────────── */
@@ -254,7 +284,7 @@
254
284
  border-radius: var(--radius, 8px);
255
285
  border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.08));
256
286
  background: var(--color-fd-background, rgba(255, 255, 255, 0.01));
257
- opacity: 0.6;
287
+ opacity: 0.6;
258
288
  color: var(--color-fd-foreground, #e4e4e7);
259
289
  font-size: 13px;
260
290
  font-family: inherit;
@@ -394,8 +424,12 @@
394
424
  animation: fd-ai-dot 1.4s infinite ease-in-out both;
395
425
  }
396
426
 
397
- .fd-ai-loading-dot:nth-child(2) { animation-delay: 0.16s; }
398
- .fd-ai-loading-dot:nth-child(3) { animation-delay: 0.32s; }
427
+ .fd-ai-loading-dot:nth-child(2) {
428
+ animation-delay: 0.16s;
429
+ }
430
+ .fd-ai-loading-dot:nth-child(3) {
431
+ animation-delay: 0.32s;
432
+ }
399
433
 
400
434
  /* ─── Floating trigger button ────────────────────────────────────── */
401
435
 
@@ -416,7 +450,10 @@
416
450
  cursor: pointer;
417
451
  font-size: 14px;
418
452
  box-shadow: 0 1px 3px color-mix(in srgb, var(--color-fd-background, #000) 20%, transparent);
419
- transition: transform 150ms, background 150ms, color 150ms;
453
+ transition:
454
+ transform 150ms,
455
+ background 150ms,
456
+ color 150ms;
420
457
  animation: fd-ai-fade-in 300ms ease-out;
421
458
  }
422
459
 
@@ -536,7 +573,11 @@
536
573
 
537
574
  .fd-ai-code-copy:hover {
538
575
  color: var(--color-fd-foreground, #e4e4e7);
539
- background: color-mix(in srgb, var(--color-fd-accent, rgba(255,255,255,0.05)) 60%, transparent);
576
+ background: color-mix(
577
+ in srgb,
578
+ var(--color-fd-accent, rgba(255, 255, 255, 0.05)) 60%,
579
+ transparent
580
+ );
540
581
  }
541
582
 
542
583
  .fd-ai-code-block pre {
@@ -558,7 +599,10 @@
558
599
  }
559
600
 
560
601
  /* sugar-high: each line is a block span, min-height keeps empty lines visible */
561
- .fd-ai-code-block .sh__line { display: block; min-height: 1.2em; }
602
+ .fd-ai-code-block .sh__line {
603
+ display: block;
604
+ min-height: 1.2em;
605
+ }
562
606
 
563
607
  /* ═══════════════════════════════════════════════════════════════════
564
608
  * Full-Modal (better-auth inspired) — fd-ai-fm-*
@@ -615,8 +659,20 @@
615
659
  overflow-y: auto;
616
660
  width: min(800px, 100%);
617
661
  padding: 24px 0 120px;
618
- mask-image: linear-gradient(to bottom, transparent, white 3rem, white calc(100% - 8rem), transparent 100%);
619
- -webkit-mask-image: linear-gradient(to bottom, transparent, white 3rem, white calc(100% - 8rem), transparent 100%);
662
+ mask-image: linear-gradient(
663
+ to bottom,
664
+ transparent,
665
+ white 3rem,
666
+ white calc(100% - 8rem),
667
+ transparent 100%
668
+ );
669
+ -webkit-mask-image: linear-gradient(
670
+ to bottom,
671
+ transparent,
672
+ white 3rem,
673
+ white calc(100% - 8rem),
674
+ transparent 100%
675
+ );
620
676
  }
621
677
 
622
678
  .fd-ai-fm-messages-inner {
@@ -705,12 +761,24 @@
705
761
  animation: fd-ai-fm-bounce 1s infinite ease-in-out;
706
762
  }
707
763
 
708
- .fd-ai-fm-thinking-dot:nth-child(2) { animation-delay: 150ms; }
709
- .fd-ai-fm-thinking-dot:nth-child(3) { animation-delay: 300ms; }
764
+ .fd-ai-fm-thinking-dot:nth-child(2) {
765
+ animation-delay: 150ms;
766
+ }
767
+ .fd-ai-fm-thinking-dot:nth-child(3) {
768
+ animation-delay: 300ms;
769
+ }
710
770
 
711
771
  @keyframes fd-ai-fm-bounce {
712
- 0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }
713
- 40% { transform: scale(1); opacity: 1; }
772
+ 0%,
773
+ 80%,
774
+ 100% {
775
+ transform: scale(0.6);
776
+ opacity: 0.4;
777
+ }
778
+ 40% {
779
+ transform: scale(1);
780
+ opacity: 1;
781
+ }
714
782
  }
715
783
 
716
784
  /* ─── Bottom input bar ───────────────────────────────────────────── */
@@ -718,9 +786,10 @@
718
786
  .fd-ai-fm-input-bar {
719
787
  position: fixed;
720
788
  z-index: 9999;
721
- transition: width 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
722
- height 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
723
- transform 200ms ease-out;
789
+ transition:
790
+ width 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
791
+ height 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
792
+ transform 200ms ease-out;
724
793
  }
725
794
 
726
795
  .fd-ai-fm-input-bar--closed {
@@ -809,8 +878,20 @@
809
878
  gap: 8px;
810
879
  overflow-x: auto;
811
880
  padding-bottom: 4px;
812
- mask-image: linear-gradient(to right, transparent 0%, black 1rem, black calc(100% - 1rem), transparent 100%);
813
- -webkit-mask-image: linear-gradient(to right, transparent 0%, black 1rem, black calc(100% - 1rem), transparent 100%);
881
+ mask-image: linear-gradient(
882
+ to right,
883
+ transparent 0%,
884
+ black 1rem,
885
+ black calc(100% - 1rem),
886
+ transparent 100%
887
+ );
888
+ -webkit-mask-image: linear-gradient(
889
+ to right,
890
+ transparent 0%,
891
+ black 1rem,
892
+ black calc(100% - 1rem),
893
+ transparent 100%
894
+ );
814
895
  }
815
896
 
816
897
  .fd-ai-fm-suggestion {
@@ -820,15 +901,16 @@
820
901
  font-size: 12px;
821
902
  font-family: inherit;
822
903
  border-radius: 9999px;
823
- border: 1px solid color-mix(in srgb, var(--color-fd-border, rgba(255,255,255,0.1)) 50%, transparent);
824
- background: color-mix(in srgb, var(--color-fd-muted, rgba(255,255,255,0.04)) 30%, transparent);
904
+ border: 1px solid
905
+ color-mix(in srgb, var(--color-fd-border, rgba(255, 255, 255, 0.1)) 50%, transparent);
906
+ background: color-mix(in srgb, var(--color-fd-muted, rgba(255, 255, 255, 0.04)) 30%, transparent);
825
907
  color: var(--color-fd-muted-foreground, #71717a);
826
908
  cursor: pointer;
827
909
  transition: all 200ms;
828
910
  }
829
911
 
830
912
  .fd-ai-fm-suggestion:hover {
831
- background: color-mix(in srgb, var(--color-fd-muted, rgba(255,255,255,0.04)) 50%, transparent);
913
+ background: color-mix(in srgb, var(--color-fd-muted, rgba(255, 255, 255, 0.04)) 50%, transparent);
832
914
  color: var(--color-fd-foreground, #e4e4e7);
833
915
  border-color: var(--color-fd-border, rgba(255, 255, 255, 0.1));
834
916
  }
@@ -841,7 +923,11 @@
841
923
  gap: 4px;
842
924
  padding: 8px 16px;
843
925
  border-top: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.06));
844
- background: color-mix(in srgb, var(--color-fd-accent, rgba(255,255,255,0.03)) 40%, transparent);
926
+ background: color-mix(
927
+ in srgb,
928
+ var(--color-fd-accent, rgba(255, 255, 255, 0.03)) 40%,
929
+ transparent
930
+ );
845
931
  font-size: 12px;
846
932
  color: var(--color-fd-muted-foreground, #71717a);
847
933
  }
@@ -886,7 +972,11 @@
886
972
  gap: 4px;
887
973
  padding: 8px 16px;
888
974
  border-top: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.06));
889
- background: color-mix(in srgb, var(--color-fd-accent, rgba(255,255,255,0.03)) 40%, transparent);
975
+ background: color-mix(
976
+ in srgb,
977
+ var(--color-fd-accent, rgba(255, 255, 255, 0.03)) 40%,
978
+ transparent
979
+ );
890
980
  font-size: 12px;
891
981
  color: var(--color-fd-muted-foreground, #71717a);
892
982
  border-radius: 0 0 var(--radius, 12px) var(--radius, 12px);
@@ -915,7 +1005,10 @@
915
1005
  font-size: 14px;
916
1006
  cursor: pointer;
917
1007
  box-shadow: 0 1px 3px color-mix(in srgb, var(--color-fd-background, #000) 20%, transparent);
918
- transition: transform 150ms, background 150ms, color 150ms;
1008
+ transition:
1009
+ transform 150ms,
1010
+ background 150ms,
1011
+ color 150ms;
919
1012
  animation: fd-ai-fade-in 300ms ease-out;
920
1013
  white-space: nowrap;
921
1014
  }
package/styles/base.css CHANGED
@@ -26,34 +26,52 @@ body {
26
26
  font-family: var(--fd-font-sans, var(--font-geist-sans, ui-sans-serif, system-ui, sans-serif));
27
27
  }
28
28
 
29
- code, kbd, pre, samp {
30
- font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace));
29
+ code,
30
+ kbd,
31
+ pre,
32
+ samp {
33
+ font-family: var(
34
+ --fd-font-mono,
35
+ var(
36
+ --font-geist-mono,
37
+ ui-monospace,
38
+ "Cascadia Code",
39
+ "Source Code Pro",
40
+ Menlo,
41
+ Consolas,
42
+ monospace
43
+ )
44
+ );
31
45
  }
32
46
 
33
47
  /* ─── Prose heading typography ───────────────────────────────────────── */
34
48
 
35
- .prose h1, article h1 {
49
+ .prose h1,
50
+ article h1 {
36
51
  font-size: var(--fd-h1-size, 2.25rem);
37
52
  font-weight: var(--fd-h1-weight, 700);
38
53
  line-height: var(--fd-h1-line-height, 1.2);
39
54
  letter-spacing: var(--fd-h1-letter-spacing, -0.02em);
40
55
  }
41
56
 
42
- .prose h2, article h2 {
57
+ .prose h2,
58
+ article h2 {
43
59
  font-size: var(--fd-h2-size, 1.5rem);
44
60
  font-weight: var(--fd-h2-weight, 600);
45
61
  line-height: var(--fd-h2-line-height, 1.3);
46
62
  letter-spacing: var(--fd-h2-letter-spacing, -0.01em);
47
63
  }
48
64
 
49
- .prose h3, article h3 {
65
+ .prose h3,
66
+ article h3 {
50
67
  font-size: var(--fd-h3-size, 1.25rem);
51
68
  font-weight: var(--fd-h3-weight, 600);
52
69
  line-height: var(--fd-h3-line-height, 1.4);
53
70
  letter-spacing: var(--fd-h3-letter-spacing, normal);
54
71
  }
55
72
 
56
- .prose h4, article h4 {
73
+ .prose h4,
74
+ article h4 {
57
75
  font-size: var(--fd-h4-size, 1.125rem);
58
76
  font-weight: var(--fd-h4-weight, 600);
59
77
  line-height: var(--fd-h4-line-height, 1.4);
@@ -62,7 +80,10 @@ code, kbd, pre, samp {
62
80
 
63
81
  /* ─── Body text ──────────────────────────────────────────────────────── */
64
82
 
65
- .prose p, .prose li, .prose td, article p {
83
+ .prose p,
84
+ .prose li,
85
+ .prose td,
86
+ article p {
66
87
  font-size: var(--fd-body-size, 1rem);
67
88
  font-weight: var(--fd-body-weight, 400);
68
89
  line-height: var(--fd-body-line-height, 1.75);
@@ -70,7 +91,9 @@ code, kbd, pre, samp {
70
91
 
71
92
  /* ─── Small text (captions, metadata) ─────────────────────────────── */
72
93
 
73
- .prose small, article small, .text-sm {
94
+ .prose small,
95
+ article small,
96
+ .text-sm {
74
97
  font-size: var(--fd-small-size, 0.875rem);
75
98
  font-weight: var(--fd-small-weight, 400);
76
99
  line-height: var(--fd-small-line-height, 1.5);
@@ -133,7 +156,15 @@ figure.shiki:has(figcaption) > div:first-child::before {
133
156
  }
134
157
 
135
158
  figure.shiki:has(figcaption) figcaption {
136
- font-family: var(--fd-font-mono, ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace);
159
+ font-family: var(
160
+ --fd-font-mono,
161
+ ui-monospace,
162
+ SFMono-Regular,
163
+ "SF Mono",
164
+ Menlo,
165
+ Consolas,
166
+ monospace
167
+ );
137
168
  font-size: 0.75rem;
138
169
  letter-spacing: 0.01em;
139
170
  }
@@ -178,7 +209,9 @@ figure.shiki:has(figcaption) figcaption {
178
209
  color: inherit;
179
210
  text-decoration: none;
180
211
  cursor: pointer;
181
- transition: opacity 0.15s, color 0.15s;
212
+ transition:
213
+ opacity 0.15s,
214
+ color 0.15s;
182
215
  }
183
216
 
184
217
  .fd-breadcrumb-link:hover {
@@ -251,7 +284,10 @@ figure.shiki:has(figcaption) figcaption {
251
284
  border-radius: 0.375rem;
252
285
  cursor: pointer;
253
286
  white-space: nowrap;
254
- transition: color 0.15s, background 0.15s, border-color 0.15s;
287
+ transition:
288
+ color 0.15s,
289
+ background 0.15s,
290
+ border-color 0.15s;
255
291
  user-select: none;
256
292
  }
257
293
 
@@ -298,8 +334,14 @@ figure.shiki:has(figcaption) figcaption {
298
334
  }
299
335
 
300
336
  @keyframes fd-page-actions-fade-in {
301
- from { opacity: 0; transform: translateY(-4px); }
302
- to { opacity: 1; transform: translateY(0); }
337
+ from {
338
+ opacity: 0;
339
+ transform: translateY(-4px);
340
+ }
341
+ to {
342
+ opacity: 1;
343
+ transform: translateY(0);
344
+ }
303
345
  }
304
346
 
305
347
  .fd-page-action-menu-item {
@@ -316,7 +358,9 @@ figure.shiki:has(figcaption) figcaption {
316
358
  border-radius: 0.25rem;
317
359
  cursor: pointer;
318
360
  text-align: left;
319
- transition: background 0.1s, color 0.1s;
361
+ transition:
362
+ background 0.1s,
363
+ color 0.1s;
320
364
  }
321
365
 
322
366
  .fd-page-action-menu-item:hover {
@@ -365,6 +409,29 @@ figure.shiki:has(figcaption) figcaption {
365
409
  margin-left: auto;
366
410
  }
367
411
 
412
+ .fd-llms-txt-links {
413
+ display: inline-flex;
414
+ align-items: center;
415
+ gap: 0.5rem;
416
+ }
417
+
418
+ .fd-llms-txt-link {
419
+ color: var(--color-fd-muted-foreground, hsl(0 0% 45%));
420
+ font-size: 0.75rem;
421
+ font-family: var(--fd-font-mono, ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace);
422
+ text-decoration: none;
423
+ padding: 0.125rem 0.375rem;
424
+ border-radius: 0.25rem;
425
+ border: 1px solid var(--color-fd-border, hsl(0 0% 80% / 50%));
426
+ transition: color 150ms, border-color 150ms;
427
+ }
428
+
429
+ .fd-llms-txt-link:hover {
430
+ /* color: var(--color-fd-foreground, hsl(0 0% 10%));
431
+ border-color: var(--color-fd-foreground, hsl(0 0% 10%)); */
432
+ text-decoration: none;
433
+ }
434
+
368
435
  /* ─── Code block copy button: show on hover ────────────────────────── */
369
436
 
370
437
  figure.shiki > button,
@@ -402,7 +469,10 @@ figure.shiki:hover > div:first-child button {
402
469
  background: var(--color-fd-secondary, hsl(0 0% 96%));
403
470
  color: var(--color-fd-muted-foreground, hsl(0 0% 45%));
404
471
  cursor: pointer;
405
- transition: background-color 150ms, color 150ms, border-color 150ms;
472
+ transition:
473
+ background-color 150ms,
474
+ color 150ms,
475
+ border-color 150ms;
406
476
  }
407
477
 
408
478
  .fd-sidebar-ai-btn:hover {
@@ -44,7 +44,9 @@
44
44
 
45
45
  .fd-ai-dialog {
46
46
  border-radius: 12px;
47
- box-shadow: 0 20px 60px rgba(180, 140, 20, 0.08), 0 8px 24px rgba(0, 0, 0, 0.12);
47
+ box-shadow:
48
+ 0 20px 60px rgba(180, 140, 20, 0.08),
49
+ 0 8px 24px rgba(0, 0, 0, 0.12);
48
50
  }
49
51
 
50
52
  .fd-ai-bubble-user {
@@ -131,7 +133,9 @@
131
133
  font-size: 0.875rem;
132
134
  color: var(--color-fd-card-foreground);
133
135
  box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
134
- transition: background-color 150ms, border-color 150ms;
136
+ transition:
137
+ background-color 150ms,
138
+ border-color 150ms;
135
139
  }
136
140
 
137
141
  .fd-card:hover {
@@ -243,7 +247,9 @@
243
247
  border-radius: 0.75rem;
244
248
  border: 1px solid var(--color-fd-border);
245
249
  background: var(--color-fd-popover);
246
- box-shadow: 0 24px 60px -12px rgba(180, 140, 20, 0.12), 0 0 0 1px rgba(255, 255, 255, 0.04);
250
+ box-shadow:
251
+ 0 24px 60px -12px rgba(180, 140, 20, 0.12),
252
+ 0 0 0 1px rgba(255, 255, 255, 0.04);
247
253
  }
248
254
 
249
255
  .omni-item-active {
@@ -258,4 +264,3 @@
258
264
  .omni-search-input:focus {
259
265
  caret-color: var(--color-fd-primary);
260
266
  }
261
-
@@ -252,7 +252,9 @@ nav[class*="header"] {
252
252
  font-size: 0.875rem;
253
253
  color: var(--color-fd-card-foreground);
254
254
  box-shadow: none;
255
- transition: background-color 150ms, border-color 150ms;
255
+ transition:
256
+ background-color 150ms,
257
+ border-color 150ms;
256
258
  }
257
259
 
258
260
  .fd-card:hover {
@@ -327,7 +329,9 @@ figure.shiki {
327
329
  border-radius: 0;
328
330
  color: var(--color-fd-muted-foreground);
329
331
  border-bottom: 2px solid transparent;
330
- transition: color 150ms, border-color 150ms;
332
+ transition:
333
+ color 150ms,
334
+ border-color 150ms;
331
335
  }
332
336
 
333
337
  [role="tab"][aria-selected="true"],
@@ -56,10 +56,7 @@
56
56
  html {
57
57
  scroll-behavior: auto;
58
58
  scroll-padding-top: calc(
59
- var(--fd-nav-height, 56px) +
60
- var(--fd-banner-height, 0px) +
61
- var(--fd-tocnav-height, 0px) +
62
- 24px
59
+ var(--fd-nav-height, 56px) + var(--fd-banner-height, 0px) + var(--fd-tocnav-height, 0px) + 24px
63
60
  );
64
61
  }
65
62
 
@@ -141,7 +138,8 @@ table {
141
138
  border-radius: 0 !important;
142
139
  }
143
140
 
144
- th, td {
141
+ th,
142
+ td {
145
143
  border-color: var(--color-fd-border);
146
144
  }
147
145
 
@@ -179,7 +177,6 @@ figure button {
179
177
  border-radius: 0.1rem !important;
180
178
  }
181
179
 
182
-
183
180
  /* ─── Inline code ─────────────────────────────────────────────────── */
184
181
 
185
182
  code:not(pre code) {
@@ -19,7 +19,9 @@
19
19
 
20
20
  .fd-ai-dialog {
21
21
  border-radius: 12px;
22
- box-shadow: 0 20px 60px rgba(99, 102, 241, 0.08), 0 8px 24px rgba(0, 0, 0, 0.12);
22
+ box-shadow:
23
+ 0 20px 60px rgba(99, 102, 241, 0.08),
24
+ 0 8px 24px rgba(0, 0, 0, 0.12);
23
25
  }
24
26
 
25
27
  .fd-ai-bubble-user {
@@ -93,7 +95,9 @@
93
95
  border-radius: 0.75rem;
94
96
  border: 1px solid var(--color-fd-border, #262626);
95
97
  background: var(--color-fd-popover, hsl(0 0% 5%));
96
- box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.04);
98
+ box-shadow:
99
+ 0 24px 60px -12px rgba(0, 0, 0, 0.3),
100
+ 0 0 0 1px rgba(255, 255, 255, 0.04);
97
101
  }
98
102
 
99
103
  .omni-item {
@@ -6,43 +6,43 @@
6
6
  /* ─── GreenTree color overrides ────────────────────────────────── */
7
7
 
8
8
  :root {
9
- --color-fd-primary: #0D9373;
9
+ --color-fd-primary: #0d9373;
10
10
  --color-fd-primary-foreground: #fff;
11
- --color-fd-ring: #0D9373;
11
+ --color-fd-ring: #0d9373;
12
12
 
13
13
  --color-fd-background: #fff;
14
- --color-fd-foreground: #171A18;
14
+ --color-fd-foreground: #171a18;
15
15
  --color-fd-card: #fff;
16
- --color-fd-card-foreground: #171A18;
16
+ --color-fd-card-foreground: #171a18;
17
17
  --color-fd-popover: #fff;
18
- --color-fd-popover-foreground: #171A18;
18
+ --color-fd-popover-foreground: #171a18;
19
19
  --color-fd-secondary: #f6f8f7;
20
- --color-fd-secondary-foreground: #171A18;
20
+ --color-fd-secondary-foreground: #171a18;
21
21
  --color-fd-muted: #f6f8f7;
22
22
  --color-fd-muted-foreground: #505351;
23
23
  --color-fd-accent: #f0f5f3;
24
- --color-fd-accent-foreground: #171A18;
25
- --color-fd-border: #DFE1E0;
24
+ --color-fd-accent-foreground: #171a18;
25
+ --color-fd-border: #dfe1e0;
26
26
  }
27
27
 
28
28
  .dark {
29
- --color-fd-primary: #26BD6C;
30
- --color-fd-primary-foreground: #0A0D0D;
31
- --color-fd-ring: #26BD6C;
29
+ --color-fd-primary: #26bd6c;
30
+ --color-fd-primary-foreground: #0a0d0d;
31
+ --color-fd-ring: #26bd6c;
32
32
 
33
- --color-fd-background: #0A0D0D;
34
- --color-fd-foreground: #E5E7E6;
33
+ --color-fd-background: #0a0d0d;
34
+ --color-fd-foreground: #e5e7e6;
35
35
  --color-fd-card: #111413;
36
- --color-fd-card-foreground: #E5E7E6;
36
+ --color-fd-card-foreground: #e5e7e6;
37
37
  --color-fd-popover: #111413;
38
- --color-fd-popover-foreground: #E5E7E6;
39
- --color-fd-secondary: #1A1D1C;
40
- --color-fd-secondary-foreground: #E5E7E6;
41
- --color-fd-muted: #1A1D1C;
42
- --color-fd-muted-foreground: #8A8D8B;
43
- --color-fd-accent: #1A1D1C;
44
- --color-fd-accent-foreground: #E5E7E6;
45
- --color-fd-border: #2A2D2C;
38
+ --color-fd-popover-foreground: #e5e7e6;
39
+ --color-fd-secondary: #1a1d1c;
40
+ --color-fd-secondary-foreground: #e5e7e6;
41
+ --color-fd-muted: #1a1d1c;
42
+ --color-fd-muted-foreground: #8a8d8b;
43
+ --color-fd-accent: #1a1d1c;
44
+ --color-fd-accent-foreground: #e5e7e6;
45
+ --color-fd-border: #2a2d2c;
46
46
  }
47
47
 
48
48
  /* ─── Typography — Inter, Mintlify-style values ──────────────── */
@@ -94,7 +94,9 @@ aside a[data-active] {
94
94
  padding: 6px 10px;
95
95
  border-radius: 8px;
96
96
  color: var(--color-fd-muted-foreground);
97
- transition: color 150ms, background-color 150ms;
97
+ transition:
98
+ color 150ms,
99
+ background-color 150ms;
98
100
  }
99
101
 
100
102
  aside a[data-active]:hover {
@@ -265,7 +267,9 @@ nav[class*="header"] {
265
267
  font-size: 0.875rem;
266
268
  color: var(--color-fd-card-foreground);
267
269
  box-shadow: none;
268
- transition: background-color 150ms, border-color 150ms;
270
+ transition:
271
+ background-color 150ms,
272
+ border-color 150ms;
269
273
  }
270
274
 
271
275
  .fd-card:hover {
@@ -340,7 +344,9 @@ figure.shiki {
340
344
  border-radius: 0;
341
345
  color: var(--color-fd-muted-foreground);
342
346
  border-bottom: 2px solid transparent;
343
- transition: color 150ms, border-color 150ms;
347
+ transition:
348
+ color 150ms,
349
+ border-color 150ms;
344
350
  }
345
351
 
346
352
  [role="tab"][aria-selected="true"],
@@ -622,7 +628,10 @@ details > :not(summary) {
622
628
  background: transparent;
623
629
  color: var(--color-fd-muted-foreground);
624
630
  cursor: pointer;
625
- transition: background-color 150ms, color 150ms, border-color 150ms;
631
+ transition:
632
+ background-color 150ms,
633
+ color 150ms,
634
+ border-color 150ms;
626
635
  }
627
636
 
628
637
  .fd-sidebar-ai-btn:hover {
@@ -657,7 +666,9 @@ details > :not(summary) {
657
666
  background: transparent;
658
667
  border: 1px solid var(--color-fd-border);
659
668
  cursor: pointer;
660
- transition: background-color 150ms, color 150ms;
669
+ transition:
670
+ background-color 150ms,
671
+ color 150ms;
661
672
  white-space: nowrap;
662
673
  }
663
674
 
package/styles/omni.css CHANGED
@@ -4,25 +4,49 @@
4
4
  * ═══════════════════════════════════════════════════════════════════ */
5
5
 
6
6
  @keyframes omni-fade-in {
7
- from { opacity: 0; }
8
- to { opacity: 1; }
7
+ from {
8
+ opacity: 0;
9
+ }
10
+ to {
11
+ opacity: 1;
12
+ }
9
13
  }
10
14
  @keyframes omni-fade-out {
11
- from { opacity: 1; }
12
- to { opacity: 0; }
15
+ from {
16
+ opacity: 1;
17
+ }
18
+ to {
19
+ opacity: 0;
20
+ }
13
21
  }
14
22
  @keyframes omni-scale-in {
15
- from { opacity: 0; transform: translateX(-50%) scale(0.96) translateY(-4px); }
16
- to { opacity: 1; transform: translateX(-50%) scale(1) translateY(0); }
23
+ from {
24
+ opacity: 0;
25
+ transform: translateX(-50%) scale(0.96) translateY(-4px);
26
+ }
27
+ to {
28
+ opacity: 1;
29
+ transform: translateX(-50%) scale(1) translateY(0);
30
+ }
17
31
  }
18
32
  @keyframes omni-scale-out {
19
- from { opacity: 1; transform: translateX(-50%) scale(1) translateY(0); }
20
- to { opacity: 0; transform: translateX(-50%) scale(0.96) translateY(-4px); }
33
+ from {
34
+ opacity: 1;
35
+ transform: translateX(-50%) scale(1) translateY(0);
36
+ }
37
+ to {
38
+ opacity: 0;
39
+ transform: translateX(-50%) scale(0.96) translateY(-4px);
40
+ }
21
41
  }
22
42
 
23
43
  @keyframes omni-spin {
24
- from { transform: rotate(0deg); }
25
- to { transform: rotate(360deg); }
44
+ from {
45
+ transform: rotate(0deg);
46
+ }
47
+ to {
48
+ transform: rotate(360deg);
49
+ }
26
50
  }
27
51
 
28
52
  .omni-spin {
@@ -123,8 +147,12 @@
123
147
  overflow: auto;
124
148
  padding: 0.25rem;
125
149
  }
126
- .omni-body::-webkit-scrollbar { width: 6px; }
127
- .omni-body::-webkit-scrollbar-track { background: transparent; }
150
+ .omni-body::-webkit-scrollbar {
151
+ width: 6px;
152
+ }
153
+ .omni-body::-webkit-scrollbar-track {
154
+ background: transparent;
155
+ }
128
156
  .omni-body::-webkit-scrollbar-thumb {
129
157
  background: var(--color-fd-muted, #262626);
130
158
  border-radius: 3px;
@@ -141,7 +169,9 @@
141
169
  }
142
170
 
143
171
  /* Groups */
144
- .omni-group { padding: 0.25rem 0; }
172
+ .omni-group {
173
+ padding: 0.25rem 0;
174
+ }
145
175
  .omni-group-label {
146
176
  padding: 0.25rem 0.75rem;
147
177
  font-size: 10px;
@@ -150,7 +180,10 @@
150
180
  color: var(--color-fd-muted-foreground, #a3a3a3);
151
181
  font-weight: 500;
152
182
  }
153
- .omni-group-items { display: flex; flex-direction: column; }
183
+ .omni-group-items {
184
+ display: flex;
185
+ flex-direction: column;
186
+ }
154
187
 
155
188
  /* Items */
156
189
  .omni-item {
@@ -223,7 +256,9 @@
223
256
  border-radius: 0.25rem;
224
257
  color: var(--color-fd-muted-foreground, #a3a3a3);
225
258
  flex-shrink: 0;
226
- transition: color 100ms, background 100ms;
259
+ transition:
260
+ color 100ms,
261
+ background 100ms;
227
262
  text-decoration: none;
228
263
  }
229
264
  .omni-item-ext:hover {
@@ -238,7 +273,9 @@
238
273
  color: var(--color-fd-muted-foreground, #a3a3a3);
239
274
  }
240
275
  @media (min-width: 640px) {
241
- .omni-item-shortcuts { display: flex; }
276
+ .omni-item-shortcuts {
277
+ display: flex;
278
+ }
242
279
  }
243
280
  .omni-kbd-sm {
244
281
  border-radius: 0.25rem;
@@ -255,7 +292,9 @@
255
292
  transition: opacity 120ms;
256
293
  flex-shrink: 0;
257
294
  }
258
- .omni-item:hover .omni-item-chevron { opacity: 1; }
295
+ .omni-item:hover .omni-item-chevron {
296
+ opacity: 1;
297
+ }
259
298
 
260
299
  /* Highlight */
261
300
  .omni-highlight {
@@ -314,5 +353,7 @@
314
353
  display: none;
315
354
  }
316
355
  @media (min-width: 640px) {
317
- .omni-footer-hint-desktop { display: flex; }
356
+ .omni-footer-hint-desktop {
357
+ display: flex;
358
+ }
318
359
  }
@@ -57,7 +57,9 @@
57
57
 
58
58
  html {
59
59
  scroll-behavior: auto;
60
- scroll-padding-top: calc(var(--fd-nav-height, 56px) + var(--fd-banner-height, 0px) + var(--fd-tocnav-height, 0px) + 24px);
60
+ scroll-padding-top: calc(
61
+ var(--fd-nav-height, 56px) + var(--fd-banner-height, 0px) + var(--fd-tocnav-height, 0px) + 24px
62
+ );
61
63
  }
62
64
 
63
65
  html:not([data-anchor-scrolling]) {
@@ -156,11 +158,11 @@ code:not(pre code) {
156
158
  }
157
159
 
158
160
  /* ── Full-width border separators between top-level items ─────────── */
159
- .dark aside .overscroll-contain>div {
161
+ .dark aside .overscroll-contain > div {
160
162
  margin-top: -22px;
161
163
  }
162
164
 
163
- .dark aside .overscroll-contain>div>a[data-active] {
165
+ .dark aside .overscroll-contain > div > a[data-active] {
164
166
  border-top: 1px solid hsl(0 0% 12%);
165
167
  margin-left: -1rem;
166
168
  margin-right: -1rem;
@@ -169,20 +171,20 @@ code:not(pre code) {
169
171
  padding-bottom: 0.75rem;
170
172
  }
171
173
 
172
- .dark aside .overscroll-contain>div>div {
174
+ .dark aside .overscroll-contain > div > div {
173
175
  border-top: 1px solid hsl(0 0% 12%);
174
176
  margin-left: -1rem;
175
177
  margin-right: -1rem;
176
178
  padding: 0 !important;
177
179
  }
178
180
 
179
- .dark aside .overscroll-contain>div>a[data-active]:first-child,
180
- .dark aside .overscroll-contain>div>div:first-child {
181
+ .dark aside .overscroll-contain > div > a[data-active]:first-child,
182
+ .dark aside .overscroll-contain > div > div:first-child {
181
183
  border-top: none;
182
184
  }
183
185
 
184
- .dark aside .overscroll-contain>div>a[data-active]:last-child,
185
- .dark aside .overscroll-contain>div>div:last-child {
186
+ .dark aside .overscroll-contain > div > a[data-active]:last-child,
187
+ .dark aside .overscroll-contain > div > div:last-child {
186
188
  border-bottom: 1px solid hsl(0 0% 12%);
187
189
  }
188
190
 
@@ -262,7 +264,7 @@ code:not(pre code) {
262
264
  margin-top: -25px !important;
263
265
  }
264
266
 
265
- .dark aside div[data-state="open"]> :last-child {
267
+ .dark aside div[data-state="open"] > :last-child {
266
268
  overflow: hidden;
267
269
  }
268
270
 
@@ -334,7 +336,7 @@ figure.shiki button {
334
336
  }
335
337
 
336
338
  /* Code block title bar */
337
- figure.shiki>div:first-child {
339
+ figure.shiki > div:first-child {
338
340
  border-radius: 0 !important;
339
341
  }
340
342
 
@@ -423,6 +425,29 @@ figure.shiki>div:first-child {
423
425
  font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace));
424
426
  text-transform: uppercase;
425
427
  }
428
+ /* llms.txt links */
429
+ .fd-llms-txt-links {
430
+ display: inline-flex;
431
+ align-items: center;
432
+ gap: 0.5rem;
433
+ }
434
+
435
+ .fd-llms-txt-link {
436
+ color: var(--color-fd-muted-foreground, hsl(0 0% 45%));
437
+ font-size: 0.65rem !important;
438
+ font-family: var(--fd-font-mono, ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace);
439
+ text-decoration: none;
440
+ padding: 0.015rem 0.4rem !important;
441
+ border-radius: 0px !important;
442
+ border: 0.5px solid var(--color-fd-border, hsl(0 0% 80% / 50%));
443
+ transition: color 150ms, border-color 150ms;
444
+ }
445
+
446
+ .fd-llms-txt-link:hover {
447
+ color: var(--color-fd-foreground, hsl(0 0% 10%)) !important;
448
+ border: 0.5px solid var(--color-fd-muted-foreground, hsl(0 0% 10% / 10%)) !important;
449
+ text-decoration: none;
450
+ }
426
451
 
427
452
  /* ─── Page Actions (pixel-border overrides) ───────────────────────── */
428
453
 
@@ -663,7 +688,8 @@ figure.shiki>div:first-child {
663
688
  .omni-content {
664
689
  border-radius: 0 !important;
665
690
  border: 2px solid var(--color-fd-border, hsl(0 0% 15%));
666
- box-shadow: 3px 3px 0 0 var(--color-fd-border, hsl(0 0% 15%)),
691
+ box-shadow:
692
+ 3px 3px 0 0 var(--color-fd-border, hsl(0 0% 15%)),
667
693
  0 0 0 1px rgba(255, 255, 255, 0.02);
668
694
  }
669
695
 
@@ -701,4 +727,4 @@ figure.shiki>div:first-child {
701
727
  .omni-highlight {
702
728
  background: color-mix(in srgb, var(--color-fd-primary, #6366f1) 25%, transparent);
703
729
  border-radius: 0 !important;
704
- }
730
+ }
package/styles/shiny.css CHANGED
@@ -63,7 +63,9 @@
63
63
 
64
64
  .fd-page-action-menu {
65
65
  border-radius: 0.75rem;
66
- box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.04);
66
+ box-shadow:
67
+ 0 8px 30px rgba(0, 0, 0, 0.08),
68
+ 0 0 0 1px rgba(0, 0, 0, 0.04);
67
69
  }
68
70
 
69
71
  .fd-page-action-menu-item {
@@ -74,7 +76,9 @@
74
76
 
75
77
  .fd-ai-dialog {
76
78
  border-radius: 16px;
77
- box-shadow: 0 24px 80px rgba(0, 0, 0, 0.08), 0 8px 32px rgba(0, 0, 0, 0.1);
79
+ box-shadow:
80
+ 0 24px 80px rgba(0, 0, 0, 0.08),
81
+ 0 8px 32px rgba(0, 0, 0, 0.1);
78
82
  }
79
83
 
80
84
  .fd-ai-bubble-user {
@@ -97,13 +101,17 @@
97
101
  border-radius: 6px;
98
102
  background: hsl(240, 6%, 15%);
99
103
  color: #fff;
100
- box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.07), 0 1px 3px rgba(0, 0, 0, 0.2);
104
+ box-shadow:
105
+ inset 0 1px 0 0 rgba(255, 255, 255, 0.07),
106
+ 0 1px 3px rgba(0, 0, 0, 0.2);
101
107
  border: none;
102
108
  }
103
109
 
104
110
  .fd-ai-floating-btn:hover {
105
111
  background: hsl(240, 6%, 20%);
106
- box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.1), 0 2px 6px rgba(0, 0, 0, 0.25);
112
+ box-shadow:
113
+ inset 0 1px 0 0 rgba(255, 255, 255, 0.1),
114
+ 0 2px 6px rgba(0, 0, 0, 0.25);
107
115
  }
108
116
 
109
117
  :root .fd-ai-floating-btn {
@@ -194,8 +202,13 @@
194
202
  padding: 1.25rem;
195
203
  font-size: 0.875rem;
196
204
  color: var(--color-fd-card-foreground);
197
- box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.04), 0 1px 2px -1px rgb(0 0 0 / 0.04);
198
- transition: background-color 150ms, border-color 150ms, box-shadow 150ms;
205
+ box-shadow:
206
+ 0 1px 3px 0 rgb(0 0 0 / 0.04),
207
+ 0 1px 2px -1px rgb(0 0 0 / 0.04);
208
+ transition:
209
+ background-color 150ms,
210
+ border-color 150ms,
211
+ box-shadow 150ms;
199
212
  }
200
213
 
201
214
  .fd-card:hover {
@@ -350,7 +363,9 @@ figure.shiki {
350
363
  border-radius: 0;
351
364
  color: var(--color-fd-muted-foreground);
352
365
  border-bottom: 2px solid transparent;
353
- transition: color 150ms, border-color 150ms;
366
+ transition:
367
+ color 150ms,
368
+ border-color 150ms;
354
369
  }
355
370
 
356
371
  [role="tab"][aria-selected="true"],
@@ -430,7 +445,9 @@ details > :not(summary) {
430
445
  border-radius: 0.875rem;
431
446
  border: 1px solid var(--color-fd-border);
432
447
  background: var(--color-fd-popover);
433
- box-shadow: 0 24px 80px -12px rgba(0, 0, 0, 0.12), 0 8px 30px rgba(0, 0, 0, 0.08);
448
+ box-shadow:
449
+ 0 24px 80px -12px rgba(0, 0, 0, 0.12),
450
+ 0 8px 30px rgba(0, 0, 0, 0.08);
434
451
  }
435
452
 
436
453
  .omni-item {