@farming-labs/theme 0.0.2-beta.15 → 0.0.2-beta.17

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,5 @@
1
1
  import { DocsAIFeatures } from "./docs-ai-features.mjs";
2
+ import { DocsCommandSearch } from "./docs-command-search.mjs";
2
3
  import { serializeIcon } from "./serialize-icon.mjs";
3
4
  import { DocsPageClient } from "./docs-page-client.mjs";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -161,6 +162,31 @@ function buildLastModifiedMap(entry) {
161
162
  return map;
162
163
  }
163
164
  /**
165
+ * Scan all page.mdx files and build a map of URL pathname → description
166
+ * from the frontmatter `description` field.
167
+ */
168
+ function buildDescriptionMap(entry) {
169
+ const docsDir = path.join(process.cwd(), "app", entry);
170
+ const map = {};
171
+ function scan(dir, slugParts) {
172
+ if (!fs.existsSync(dir)) return;
173
+ const pagePath = path.join(dir, "page.mdx");
174
+ if (fs.existsSync(pagePath)) {
175
+ const desc = readFrontmatter(pagePath).description;
176
+ if (desc) {
177
+ const url = slugParts.length === 0 ? `/${entry}` : `/${entry}/${slugParts.join("/")}`;
178
+ map[url] = desc;
179
+ }
180
+ }
181
+ for (const name of fs.readdirSync(dir)) {
182
+ const full = path.join(dir, name);
183
+ if (fs.statSync(full).isDirectory()) scan(full, [...slugParts, name]);
184
+ }
185
+ }
186
+ scan(docsDir, []);
187
+ return map;
188
+ }
189
+ /**
164
190
  * Build a Next.js Metadata object from the docs config.
165
191
  *
166
192
  * Returns layout-level metadata including `title.template` so each page's
@@ -230,7 +256,7 @@ function buildColorsCSS(colors) {
230
256
  vars.push(`${COLOR_MAP[key]}: ${value};`);
231
257
  }
232
258
  if (vars.length === 0) return "";
233
- return `:root, .dark {\n ${vars.join("\n ")}\n}`;
259
+ return `.dark {\n ${vars.join("\n ")}\n}`;
234
260
  }
235
261
  function ColorStyle({ colors }) {
236
262
  const css = buildColorsCSS(colors);
@@ -275,7 +301,9 @@ function TypographyStyle({ typography }) {
275
301
  return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } });
276
302
  }
277
303
  function createDocsLayout(config) {
278
- const tocEnabled = (config.theme?.ui?.layout?.toc)?.enabled !== false;
304
+ const tocConfig = config.theme?.ui?.layout?.toc;
305
+ const tocEnabled = tocConfig?.enabled !== false;
306
+ const tocStyle = tocConfig?.style;
279
307
  const navTitle = config.nav?.title ?? "Docs";
280
308
  const navUrl = config.nav?.url ?? `/${config.entry}`;
281
309
  const themeSwitch = resolveThemeSwitch(config.themeToggle);
@@ -309,6 +337,7 @@ function createDocsLayout(config) {
309
337
  const aiLabel = aiConfig?.aiLabel;
310
338
  const aiLoadingComponentHtml = typeof aiConfig?.loadingComponent === "function" ? serializeIcon(aiConfig.loadingComponent({ name: aiLabel || "AI" })) : void 0;
311
339
  const lastModifiedMap = buildLastModifiedMap(config.entry);
340
+ const descriptionMap = buildDescriptionMap(config.entry);
312
341
  return function DocsLayoutWrapper({ children }) {
313
342
  return /* @__PURE__ */ jsxs(DocsLayout, {
314
343
  tree: buildTree(config),
@@ -322,6 +351,7 @@ function createDocsLayout(config) {
322
351
  /* @__PURE__ */ jsx(ColorStyle, { colors }),
323
352
  /* @__PURE__ */ jsx(TypographyStyle, { typography }),
324
353
  forcedTheme && /* @__PURE__ */ jsx(ForcedThemeScript, { theme: forcedTheme }),
354
+ /* @__PURE__ */ jsx(DocsCommandSearch, {}),
325
355
  aiEnabled && /* @__PURE__ */ jsx(DocsAIFeatures, {
326
356
  mode: aiMode,
327
357
  position: aiPosition,
@@ -333,6 +363,7 @@ function createDocsLayout(config) {
333
363
  }),
334
364
  /* @__PURE__ */ jsx(DocsPageClient, {
335
365
  tocEnabled,
366
+ tocStyle,
336
367
  breadcrumbEnabled,
337
368
  entry: config.entry,
338
369
  copyMarkdown: copyMarkdownEnabled,
@@ -343,6 +374,7 @@ function createDocsLayout(config) {
343
374
  githubBranch,
344
375
  githubDirectory,
345
376
  lastModifiedMap,
377
+ descriptionMap,
346
378
  children
347
379
  })
348
380
  ]
@@ -10,6 +10,7 @@ interface SerializedProvider {
10
10
  }
11
11
  interface DocsPageClientProps {
12
12
  tocEnabled: boolean;
13
+ tocStyle?: "default" | "directional";
13
14
  breadcrumbEnabled?: boolean;
14
15
  /** The docs entry folder name (e.g. "docs") — used to strip from breadcrumb */
15
16
  entry?: string;
@@ -26,10 +27,15 @@ interface DocsPageClientProps {
26
27
  githubDirectory?: string;
27
28
  /** Map of pathname → formatted last-modified date string */
28
29
  lastModifiedMap?: Record<string, string>;
30
+ /** Map of pathname → frontmatter description */
31
+ descriptionMap?: Record<string, string>;
32
+ /** Frontmatter description to display below the page title (overrides descriptionMap) */
33
+ description?: string;
29
34
  children: ReactNode;
30
35
  }
31
36
  declare function DocsPageClient({
32
37
  tocEnabled,
38
+ tocStyle,
33
39
  breadcrumbEnabled,
34
40
  entry,
35
41
  copyMarkdown,
@@ -40,6 +46,8 @@ declare function DocsPageClient({
40
46
  githubBranch,
41
47
  githubDirectory,
42
48
  lastModifiedMap,
49
+ descriptionMap,
50
+ description,
43
51
  children
44
52
  }: DocsPageClientProps): react_jsx_runtime0.JSX.Element;
45
53
  //#endregion
@@ -13,15 +13,13 @@ import { usePathname, useRouter } from "next/navigation";
13
13
  */
14
14
  function PathBreadcrumb({ pathname, entry }) {
15
15
  const router = useRouter();
16
- const allSegments = pathname.split("/").filter(Boolean);
17
- const segments = allSegments.filter((s) => s.toLowerCase() !== entry.toLowerCase());
16
+ const segments = pathname.split("/").filter(Boolean);
18
17
  if (segments.length < 2) return null;
19
18
  const parentSegment = segments[segments.length - 2];
20
19
  const currentSegment = segments[segments.length - 1];
21
20
  const parentLabel = parentSegment.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
22
21
  const currentLabel = currentSegment.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
23
- const parentIndex = allSegments.indexOf(parentSegment);
24
- const parentUrl = "/" + allSegments.slice(0, parentIndex + 1).join("/");
22
+ const parentUrl = "/" + segments.slice(0, segments.length - 1).join("/");
25
23
  return /* @__PURE__ */ jsxs("nav", {
26
24
  className: "fd-breadcrumb",
27
25
  "aria-label": "Breadcrumb",
@@ -64,9 +62,11 @@ function buildGithubFileUrl(githubUrl, branch, pathname, directory) {
64
62
  const segments = pathname.replace(/^\//, "").replace(/\/$/, "");
65
63
  return `${githubUrl}/tree/${branch}/${directory ? `${directory}/` : ""}app/${segments}/page.mdx`;
66
64
  }
67
- function DocsPageClient({ tocEnabled, breadcrumbEnabled = true, entry = "docs", copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, children }) {
65
+ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, descriptionMap, description, children }) {
66
+ const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
68
67
  const [toc, setToc] = useState([]);
69
68
  const pathname = usePathname();
69
+ const pageDescription = description ?? descriptionMap?.[pathname.replace(/\/$/, "") || "/"];
70
70
  useEffect(() => {
71
71
  if (!tocEnabled) return;
72
72
  const timer = requestAnimationFrame(() => {
@@ -81,6 +81,26 @@ function DocsPageClient({ tocEnabled, breadcrumbEnabled = true, entry = "docs",
81
81
  });
82
82
  return () => cancelAnimationFrame(timer);
83
83
  }, [tocEnabled, pathname]);
84
+ useEffect(() => {
85
+ if (!pageDescription) return;
86
+ const timer = requestAnimationFrame(() => {
87
+ const container = document.getElementById("nd-page");
88
+ if (!container) return;
89
+ const existingDesc = container.querySelector(".fd-page-description");
90
+ if (existingDesc) existingDesc.remove();
91
+ const h1 = container.querySelector("h1");
92
+ if (!h1) return;
93
+ const descEl = document.createElement("p");
94
+ descEl.className = "fd-page-description";
95
+ descEl.textContent = pageDescription;
96
+ h1.insertAdjacentElement("afterend", descEl);
97
+ });
98
+ return () => {
99
+ cancelAnimationFrame(timer);
100
+ const desc = document.querySelector("#nd-page .fd-page-description");
101
+ if (desc) desc.remove();
102
+ };
103
+ }, [pageDescription, pathname]);
84
104
  const showActions = copyMarkdown || openDocs;
85
105
  const githubFileUrl = githubUrl ? buildGithubFileUrl(githubUrl, githubBranch, pathname, githubDirectory) : void 0;
86
106
  const normalizedPath = pathname.replace(/\/$/, "") || "/";
@@ -88,8 +108,14 @@ function DocsPageClient({ tocEnabled, breadcrumbEnabled = true, entry = "docs",
88
108
  const showFooter = githubFileUrl || lastModified;
89
109
  return /* @__PURE__ */ jsxs(DocsPage, {
90
110
  toc,
91
- tableOfContent: { enabled: tocEnabled },
92
- tableOfContentPopover: { enabled: tocEnabled },
111
+ tableOfContent: {
112
+ enabled: tocEnabled,
113
+ style: fdTocStyle
114
+ },
115
+ tableOfContentPopover: {
116
+ enabled: tocEnabled,
117
+ style: fdTocStyle
118
+ },
93
119
  breadcrumb: { enabled: false },
94
120
  children: [
95
121
  breadcrumbEnabled && /* @__PURE__ */ jsx(PathBreadcrumb, {
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { DefaultUIDefaults, fumadocs } from "./default/index.mjs";
2
+ import { DocsCommandSearch } from "./docs-command-search.mjs";
2
3
  import { createDocsLayout, createDocsMetadata } from "./docs-layout.mjs";
3
4
  import { DocsPageClient } from "./docs-page-client.mjs";
4
5
  import { RootProvider } from "./provider.mjs";
@@ -8,4 +9,4 @@ import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
8
9
  import { AIConfig, BreadcrumbConfig, CopyMarkdownConfig, DocsConfig, DocsMetadata, DocsNav, DocsTheme, FontStyle, OGConfig, OpenDocsConfig, OpenDocsProvider, PageActionsConfig, PageFrontmatter, SidebarConfig, ThemeToggleConfig, TypographyConfig, UIConfig, createTheme, deepMerge, defineDocs, extendTheme } from "@farming-labs/docs";
9
10
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
10
11
  import { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, Pre } from "fumadocs-ui/components/codeblock";
11
- export { type AIConfig, type BreadcrumbConfig, CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, type CopyMarkdownConfig, DocsBody, type DocsConfig, DocsLayout, type DocsMetadata, type DocsNav, DocsPage, DocsPageClient, type DocsTheme, type FontStyle, DefaultUIDefaults as FumadocsUIDefaults, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, PageActions, type PageActionsConfig, type PageFrontmatter, Pre, RootProvider, type SidebarConfig, Tab, Tabs, type ThemeToggleConfig, type TypographyConfig, type UIConfig, createDocsLayout, createDocsMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs };
12
+ export { type AIConfig, type BreadcrumbConfig, CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, type CopyMarkdownConfig, DocsBody, DocsCommandSearch, type DocsConfig, DocsLayout, type DocsMetadata, type DocsNav, DocsPage, DocsPageClient, type DocsTheme, type FontStyle, DefaultUIDefaults as FumadocsUIDefaults, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, PageActions, type PageActionsConfig, type PageFrontmatter, Pre, RootProvider, type SidebarConfig, Tab, Tabs, type ThemeToggleConfig, type TypographyConfig, type UIConfig, createDocsLayout, createDocsMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs };
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { DocsCommandSearch } from "./docs-command-search.mjs";
1
2
  import { PageActions } from "./page-actions.mjs";
2
3
  import { DocsPageClient } from "./docs-page-client.mjs";
3
4
  import { createDocsLayout, createDocsMetadata } from "./docs-layout.mjs";
@@ -9,4 +10,4 @@ import { createTheme, deepMerge, defineDocs, extendTheme } from "@farming-labs/d
9
10
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
10
11
  import { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, Pre } from "fumadocs-ui/components/codeblock";
11
12
 
12
- export { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, DocsBody, DocsLayout, DocsPage, DocsPageClient, DefaultUIDefaults as FumadocsUIDefaults, PageActions, Pre, RootProvider, Tab, Tabs, createDocsLayout, createDocsMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs };
13
+ export { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, DocsBody, DocsCommandSearch, DocsLayout, DocsPage, DocsPageClient, DefaultUIDefaults as FumadocsUIDefaults, PageActions, Pre, RootProvider, Tab, Tabs, createDocsLayout, createDocsMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.0.2-beta.15",
3
+ "version": "0.0.2-beta.17",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -31,6 +31,11 @@
31
31
  "import": "./dist/pixel-border/index.mjs",
32
32
  "default": "./dist/pixel-border/index.mjs"
33
33
  },
34
+ "./colorful": {
35
+ "types": "./dist/colorful/index.d.mts",
36
+ "import": "./dist/colorful/index.mjs",
37
+ "default": "./dist/colorful/index.mjs"
38
+ },
34
39
  "./search": {
35
40
  "types": "./dist/search.d.mts",
36
41
  "import": "./dist/search.mjs",
@@ -46,6 +51,7 @@
46
51
  "./default/css": "./styles/default.css",
47
52
  "./darksharp/css": "./styles/darksharp.css",
48
53
  "./pixel-border/css": "./styles/pixel-border.css",
54
+ "./colorful/css": "./styles/colorful.css",
49
55
  "./presets/neutral": "./styles/presets/neutral.css",
50
56
  "./presets/black": "./styles/presets/black.css",
51
57
  "./presets/base": "./styles/presets/base.css"
@@ -74,7 +80,7 @@
74
80
  "next": ">=14.0.0",
75
81
  "tsdown": "^0.20.3",
76
82
  "typescript": "^5.9.3",
77
- "@farming-labs/docs": "0.0.2-beta.15"
83
+ "@farming-labs/docs": "0.0.2-beta.17"
78
84
  },
79
85
  "peerDependencies": {
80
86
  "@farming-labs/docs": ">=0.0.1",
package/styles/ai.css CHANGED
@@ -402,24 +402,32 @@
402
402
  .fd-ai-floating-btn {
403
403
  position: fixed;
404
404
  z-index: 9997;
405
- width: 52px;
406
- height: 52px;
407
- border-radius: var(--radius, 26px);
408
- border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
409
- background: var(--color-fd-primary, #6366f1);
410
- color: var(--color-fd-primary-foreground, #fff);
411
- cursor: pointer;
412
405
  display: flex;
413
406
  align-items: center;
414
407
  justify-content: center;
415
- box-shadow: 0 8px 32px color-mix(in srgb, var(--color-fd-primary, #6366f1) 30%, transparent);
416
- transition: all 200ms;
408
+ gap: 8px;
409
+ padding: 8px 12px;
410
+ height: 40px;
411
+ border-radius: 16px;
412
+ border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
413
+ background: color-mix(in srgb, var(--color-fd-secondary, #f4f4f5) 80%, transparent);
414
+ backdrop-filter: blur(4px);
415
+ color: var(--color-fd-muted-foreground, #71717a);
416
+ cursor: pointer;
417
+ font-size: 14px;
418
+ box-shadow: 0 1px 3px color-mix(in srgb, var(--color-fd-background, #000) 20%, transparent);
419
+ transition: transform 150ms, background 150ms, color 150ms;
417
420
  animation: fd-ai-fade-in 300ms ease-out;
418
421
  }
419
422
 
420
423
  .fd-ai-floating-btn:hover {
421
- transform: scale(1.05);
422
- box-shadow: 0 10px 40px color-mix(in srgb, var(--color-fd-primary, #6366f1) 40%, transparent);
424
+ background: var(--color-fd-accent);
425
+ color: var(--color-fd-accent-foreground);
426
+ transform: scale(1.03);
427
+ }
428
+
429
+ .fd-ai-floating-btn:active {
430
+ transform: scale(0.97);
423
431
  }
424
432
 
425
433
  .fd-ai-floating-trigger {
@@ -492,7 +500,7 @@
492
500
  margin: 10px 0;
493
501
  border-radius: var(--radius, 8px);
494
502
  border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
495
- /* background: var(--color-fd-muted, #1a1a2e); */
503
+ background: var(--color-fd-muted, #1a1a2e);
496
504
  overflow: hidden;
497
505
  }
498
506
 
@@ -722,6 +730,7 @@
722
730
  .fd-ai-fm-input-bar--open {
723
731
  bottom: 16px;
724
732
  left: 50%;
733
+ right: auto;
725
734
  transform: translateX(-50%);
726
735
  width: min(800px, calc(100vw - 32px));
727
736
  }
@@ -871,24 +880,28 @@
871
880
  align-items: center;
872
881
  justify-content: center;
873
882
  gap: 8px;
874
- padding: 8px 16px;
883
+ padding: 8px 12px;
875
884
  height: 40px;
876
- border-radius: var(--radius, 16px);
885
+ border-radius: 16px;
877
886
  border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
878
- background: var(--color-fd-secondary, rgba(255, 255, 255, 0.06));
887
+ background: color-mix(in srgb, var(--color-fd-secondary, #f4f4f5) 80%, transparent);
888
+ backdrop-filter: blur(4px);
879
889
  color: var(--color-fd-muted-foreground, #71717a);
880
890
  font-family: inherit;
881
891
  font-size: 14px;
882
892
  cursor: pointer;
883
- backdrop-filter: blur(8px);
884
- box-shadow: 0 8px 32px color-mix(in srgb, var(--color-fd-background, #000) 40%, transparent);
885
- transition: all 200ms;
893
+ box-shadow: 0 1px 3px color-mix(in srgb, var(--color-fd-background, #000) 20%, transparent);
894
+ transition: transform 150ms, background 150ms, color 150ms;
886
895
  animation: fd-ai-fade-in 300ms ease-out;
887
896
  white-space: nowrap;
888
897
  }
889
898
 
890
899
  .fd-ai-fm-trigger-btn:hover {
891
- background: var(--color-fd-accent, rgba(255, 255, 255, 0.1));
892
- color: var(--color-fd-accent-foreground, #fff);
900
+ background: var(--color-fd-accent);
901
+ color: var(--color-fd-accent-foreground);
893
902
  transform: scale(1.03);
894
903
  }
904
+
905
+ .fd-ai-fm-trigger-btn:active {
906
+ transform: scale(0.97);
907
+ }
package/styles/base.css CHANGED
@@ -1,6 +1,9 @@
1
1
  /* AI Chat & Search Dialog styles */
2
2
  @import "./ai.css";
3
3
 
4
+ /* Omni Command Palette — built-in search */
5
+ @import "./omni.css";
6
+
4
7
  /* Shared base styles for all @farming-labs/theme themes.
5
8
  *
6
9
  * Typography CSS custom properties:
@@ -105,6 +108,15 @@ figure.shiki pre > code > [data-line] {
105
108
  padding: 0 0.25rem;
106
109
  }
107
110
 
111
+ /* ─── Page description (frontmatter) ─────────────────────────────────── */
112
+
113
+ .fd-page-description {
114
+ margin-bottom: 1rem;
115
+ font-size: 1.125rem;
116
+ line-height: 1.75;
117
+ color: var(--color-fd-muted-foreground);
118
+ }
119
+
108
120
  /* ─── Breadcrumb ─────────────────────────────────────────────────────── */
109
121
 
110
122
  .fd-breadcrumb {
@@ -0,0 +1,261 @@
1
+ /* @farming-labs/theme — colorful theme CSS
2
+ * Fumadocs-inspired theme with warm yellow/amber accent colors.
3
+ */
4
+ @import "./presets/neutral.css";
5
+
6
+ /* ─── Colorful yellow accent overrides ────────────────────────────── */
7
+
8
+ :root {
9
+ --color-fd-primary: hsl(40, 96%, 40%);
10
+ --color-fd-primary-foreground: hsl(0, 0%, 100%);
11
+ --color-fd-ring: hsl(40, 80%, 50%);
12
+ }
13
+
14
+ .dark {
15
+ --color-fd-primary: hsl(45, 100%, 60%);
16
+ --color-fd-primary-foreground: hsl(0, 0%, 5%);
17
+ --color-fd-ring: hsl(45, 90%, 55%);
18
+ }
19
+
20
+ /* ─── Description under title ──────────────────────────────────────── */
21
+
22
+ .fd-page-description {
23
+ margin-bottom: 1rem;
24
+ font-size: 1.125rem;
25
+ line-height: 1.75;
26
+ color: var(--color-fd-muted-foreground);
27
+ }
28
+
29
+ /* ─── Page Actions (colorful theme) ─────────────────────────────────── */
30
+
31
+ .fd-page-action-btn {
32
+ border-radius: 0.375rem;
33
+ }
34
+
35
+ .fd-page-action-menu {
36
+ border-radius: 0.5rem;
37
+ }
38
+
39
+ .fd-page-action-menu-item {
40
+ border-radius: 0.25rem;
41
+ }
42
+
43
+ /* ─── AI Chat (colorful theme) ───────────────────────────────────────── */
44
+
45
+ .fd-ai-dialog {
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);
48
+ }
49
+
50
+ .fd-ai-bubble-user {
51
+ border-radius: 16px 16px 4px 16px;
52
+ }
53
+
54
+ .fd-ai-bubble-ai {
55
+ border-radius: 16px 16px 16px 4px;
56
+ }
57
+
58
+ .fd-ai-input-wrap {
59
+ border-radius: 10px;
60
+ }
61
+
62
+ .fd-ai-send-btn {
63
+ border-radius: 8px;
64
+ }
65
+
66
+ .fd-ai-floating-btn {
67
+ border-radius: 26px;
68
+ box-shadow: 0 8px 32px rgba(180, 140, 20, 0.3);
69
+ }
70
+
71
+ .fd-ai-floating-btn:hover {
72
+ box-shadow: 0 10px 40px rgba(180, 140, 20, 0.4);
73
+ }
74
+
75
+ .fd-ai-suggestion {
76
+ border-radius: 8px;
77
+ }
78
+
79
+ .fd-ai-result {
80
+ border-radius: 8px;
81
+ }
82
+
83
+ /* ─── Full-Modal ────────────────────────────────────────────────────── */
84
+
85
+ .fd-ai-fm-input-container {
86
+ border-radius: 12px;
87
+ }
88
+
89
+ .fd-ai-fm-send-btn {
90
+ border-radius: 9999px;
91
+ }
92
+
93
+ .fd-ai-fm-suggestion {
94
+ border-radius: 9999px;
95
+ }
96
+
97
+ .fd-ai-fm-trigger-btn {
98
+ border-radius: 16px;
99
+ }
100
+
101
+ .fd-ai-fm-close-btn {
102
+ border-radius: 9999px;
103
+ }
104
+
105
+ /* ─── Code blocks ───────────────────────────────────────────────────── */
106
+
107
+ .fd-ai-code-block {
108
+ border-radius: 8px;
109
+ }
110
+
111
+ .fd-ai-code-copy {
112
+ border-radius: 4px;
113
+ }
114
+
115
+ /* ─── Sidebar colorful overrides ────────────────────────────────────── */
116
+
117
+ .dark .fd-sidebar {
118
+ --color-fd-muted: hsl(0, 0%, 16%);
119
+ --color-fd-secondary: hsl(0, 0%, 18%);
120
+ --color-fd-muted-foreground: hsl(0, 0%, 72%);
121
+ }
122
+
123
+ /* ─── Cards (fumadocs style) ────────────────────────────────────────── */
124
+
125
+ .fd-card {
126
+ display: block;
127
+ border-radius: 0.75rem;
128
+ border: 1px solid var(--color-fd-border);
129
+ background: var(--color-fd-card);
130
+ padding: 1rem;
131
+ font-size: 0.875rem;
132
+ color: var(--color-fd-card-foreground);
133
+ box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
134
+ transition: background-color 150ms, border-color 150ms;
135
+ }
136
+
137
+ .fd-card:hover {
138
+ background: var(--color-fd-accent);
139
+ }
140
+
141
+ .fd-card-icon {
142
+ margin-bottom: 0.5rem;
143
+ width: fit-content;
144
+ border-radius: 0.375rem;
145
+ border: 1px solid var(--color-fd-border);
146
+ padding: 0.375rem;
147
+ color: var(--color-fd-muted-foreground);
148
+ }
149
+
150
+ .fd-card-title {
151
+ font-weight: 500;
152
+ }
153
+
154
+ .fd-card-description {
155
+ color: var(--color-fd-muted-foreground);
156
+ margin-top: 0.25rem;
157
+ }
158
+
159
+ /* ─── Cards grid ──────────────────────────────────────────────────── */
160
+
161
+ .fd-cards {
162
+ display: grid;
163
+ grid-template-columns: 1fr;
164
+ gap: 1rem;
165
+ }
166
+
167
+ @media (min-width: 640px) {
168
+ .fd-cards {
169
+ grid-template-columns: repeat(2, 1fr);
170
+ }
171
+ }
172
+
173
+ /* ─── Page nav cards (fumadocs style) ──────────────────────────────── */
174
+
175
+ .fd-page-nav-card {
176
+ border-radius: 0.75rem;
177
+ }
178
+
179
+ /* ─── Inline code ──────────────────────────────────────────────────── */
180
+
181
+ .fd-docs-content :not(pre) > code {
182
+ padding: 3px;
183
+ border: 1px solid var(--color-fd-border);
184
+ font-size: 13px;
185
+ border-radius: 5px;
186
+ background: var(--color-fd-muted);
187
+ }
188
+
189
+ /* ─── Links in prose ───────────────────────────────────────────────── */
190
+
191
+ .fd-docs-content a:not(.fd-page-nav-card):not([class]) {
192
+ text-decoration: underline;
193
+ text-underline-offset: 3.5px;
194
+ text-decoration-color: var(--color-fd-primary);
195
+ text-decoration-thickness: 1.5px;
196
+ font-weight: 500;
197
+ }
198
+
199
+ /* ─── Tables (rounded style) ───────────────────────────────────────── */
200
+
201
+ .fd-docs-content table {
202
+ border-collapse: separate;
203
+ border-spacing: 0;
204
+ background: var(--color-fd-card);
205
+ border-radius: 0.75rem;
206
+ border: 1px solid var(--color-fd-border);
207
+ overflow: hidden;
208
+ }
209
+
210
+ .fd-docs-content th {
211
+ background: var(--color-fd-muted);
212
+ font-weight: 600;
213
+ }
214
+
215
+ .fd-docs-content th,
216
+ .fd-docs-content td {
217
+ padding: 0.625rem;
218
+ border-bottom: 1px solid var(--color-fd-border);
219
+ }
220
+
221
+ .fd-docs-content tr:last-child td {
222
+ border-bottom: none;
223
+ }
224
+
225
+ /* ─── Blockquotes ──────────────────────────────────────────────────── */
226
+
227
+ .fd-docs-content blockquote {
228
+ border-left: 2px solid var(--color-fd-primary);
229
+ padding-left: 1rem;
230
+ color: var(--color-fd-foreground);
231
+ font-style: normal;
232
+ }
233
+
234
+ /* ─── Horizontal rule ──────────────────────────────────────────────── */
235
+
236
+ .fd-docs-content hr {
237
+ border-color: var(--color-fd-border);
238
+ }
239
+
240
+ /* ─── Omni Command Palette (colorful theme) ─────────────────────── */
241
+
242
+ .omni-content {
243
+ border-radius: 0.75rem;
244
+ border: 1px solid var(--color-fd-border);
245
+ 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);
247
+ }
248
+
249
+ .omni-item-active {
250
+ background: color-mix(in srgb, var(--color-fd-primary) 15%, transparent);
251
+ }
252
+
253
+ .omni-highlight {
254
+ background: color-mix(in srgb, var(--color-fd-primary) 30%, transparent);
255
+ color: var(--color-fd-primary-foreground);
256
+ }
257
+
258
+ .omni-search-input:focus {
259
+ caret-color: var(--color-fd-primary);
260
+ }
261
+
@@ -113,19 +113,19 @@ code:not(pre code) {
113
113
  }
114
114
 
115
115
  /* ═══════════════════════════════════════════════════════════════════
116
- * Global sharp radius — override all rounded Tailwind utilities
116
+ * Sharp radius — scoped to docs layout only
117
117
  * ═══════════════════════════════════════════════════════════════════ */
118
118
 
119
- [class*="rounded-lg"] {
119
+ #nd-docs-layout [class*="rounded-lg"] {
120
120
  border-radius: 0.2rem !important;
121
121
  }
122
122
 
123
- [class*="rounded-md"] {
123
+ #nd-docs-layout [class*="rounded-md"] {
124
124
  border-radius: 0.1rem !important;
125
125
  }
126
126
 
127
- [class*="rounded-xl"],
128
- [class*="rounded-2xl"] {
127
+ #nd-docs-layout [class*="rounded-xl"],
128
+ #nd-docs-layout [class*="rounded-2xl"] {
129
129
  border-radius: 0.2rem !important;
130
130
  }
131
131
 
@@ -431,3 +431,20 @@ article a[class*="text-fd-muted-foreground"] {
431
431
  .fd-ai-code-copy {
432
432
  border-radius: 2px;
433
433
  }
434
+
435
+ /* ─── Omni Command Palette (darksharp theme) ────────────────────── */
436
+
437
+ .omni-content {
438
+ border-radius: 0.5rem;
439
+ border: 1px solid var(--color-fd-border);
440
+ background: var(--color-fd-popover);
441
+ box-shadow: 0 4px 24px hsl(0 0% 0% / 0.4);
442
+ }
443
+
444
+ .omni-item {
445
+ border-radius: 0.25rem;
446
+ }
447
+
448
+ .omni-highlight {
449
+ background: color-mix(in srgb, var(--color-fd-primary) 30%, transparent);
450
+ }