@farming-labs/theme 0.1.3 → 0.1.5

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.
@@ -26,8 +26,11 @@ interface AIOptions {
26
26
  maxResults?: number;
27
27
  }
28
28
  interface DocsAPIOptions {
29
+ rootDir?: string;
29
30
  /** Docs entry folder (default: read from docs.config) */
30
31
  entry?: string;
32
+ /** Override the docs content directory when it does not live in app/<entry>. */
33
+ contentDir?: string;
31
34
  /** Search language (default: "english") */
32
35
  language?: string;
33
36
  /** AI chat configuration */
@@ -67,6 +70,10 @@ interface DocsMCPAPIOptions {
67
70
  *
68
71
  * @param options - Optional overrides (entry, language, ai config)
69
72
  */
73
+ /**
74
+ * @deprecated Prefer `createDocsAPI` from `@farming-labs/next/api` in Next.js apps.
75
+ * The `@farming-labs/theme/api` path is kept for compatibility and will be phased out.
76
+ */
70
77
  declare function createDocsAPI(options?: DocsAPIOptions): {
71
78
  /**
72
79
  * GET handler — search, llms.txt, or llms-full.txt depending on query params.
@@ -84,6 +91,10 @@ declare function createDocsAPI(options?: DocsAPIOptions): {
84
91
  *
85
92
  * Returns `{ GET, POST, DELETE }` for use in a Next.js route handler.
86
93
  */
94
+ /**
95
+ * @deprecated Prefer `createDocsMCPAPI` from `@farming-labs/next/api` in Next.js apps.
96
+ * The `@farming-labs/theme/api` path is kept for compatibility and will be phased out.
97
+ */
87
98
  declare function createDocsMCPAPI(options?: DocsMCPAPIOptions): {
88
99
  GET(request: Request): Promise<Response>;
89
100
  POST(request: Request): Promise<Response>;
package/dist/docs-api.mjs CHANGED
@@ -454,14 +454,39 @@ function generateLlmsTxt(indexes, options) {
454
454
  *
455
455
  * @param options - Optional overrides (entry, language, ai config)
456
456
  */
457
+ /**
458
+ * @deprecated Prefer `createDocsAPI` from `@farming-labs/next/api` in Next.js apps.
459
+ * The `@farming-labs/theme/api` path is kept for compatibility and will be phased out.
460
+ */
457
461
  function createDocsAPI(options) {
458
- const root = process.cwd();
462
+ const root = options?.rootDir ?? process.cwd();
459
463
  const entry = options?.entry ?? readEntry(root);
460
464
  const appDir = getNextAppDir(root);
465
+ const contentDir = options?.contentDir ?? path.join(appDir, entry);
461
466
  const i18n = resolveDocsI18n(options?.i18n ?? readI18nConfig(root));
462
467
  const aiConfig = options?.ai ?? readAIConfig(root);
463
468
  const searchConfig = options?.search;
464
469
  const llmsConfig = readLlmsTxtConfig(root);
470
+ function resolveDocsDirCandidates(locale) {
471
+ const relativeCandidates = /* @__PURE__ */ new Set();
472
+ if (path.isAbsolute(contentDir)) return [locale ? path.join(contentDir, locale) : contentDir];
473
+ relativeCandidates.add(contentDir);
474
+ relativeCandidates.add(path.join("app", entry));
475
+ relativeCandidates.add(path.join("src", "app", entry));
476
+ const rootCandidates = new Set([root]);
477
+ rootCandidates.add(process.cwd());
478
+ if (path.basename(root) === "server") rootCandidates.add(path.resolve(root, "..", ".."));
479
+ else {
480
+ rootCandidates.add(path.join(root, ".next", "server"));
481
+ rootCandidates.add(path.join(root, ".next-build", "server"));
482
+ }
483
+ const resolved = /* @__PURE__ */ new Set();
484
+ for (const base of rootCandidates) for (const relative of relativeCandidates) {
485
+ const candidate = path.join(base, relative);
486
+ resolved.add(locale ? path.join(candidate, locale) : candidate);
487
+ }
488
+ return [...resolved];
489
+ }
465
490
  function resolveLocaleFromRequest(request) {
466
491
  if (!i18n) return void 0;
467
492
  const direct = resolveDocsLocale(new URL(request.url).searchParams, i18n);
@@ -476,13 +501,13 @@ function createDocsAPI(options) {
476
501
  function resolveContextFromRequest(request) {
477
502
  if (!i18n) return {
478
503
  entryPath: entry,
479
- docsDir: path.join(root, appDir, entry)
504
+ docsDirs: resolveDocsDirCandidates()
480
505
  };
481
506
  const locale = resolveLocaleFromRequest(request) ?? i18n.defaultLocale;
482
507
  return {
483
508
  entryPath: entry,
484
509
  locale,
485
- docsDir: path.join(root, appDir, entry, locale)
510
+ docsDirs: resolveDocsDirCandidates(locale)
486
511
  };
487
512
  }
488
513
  const indexesByLocale = /* @__PURE__ */ new Map();
@@ -491,7 +516,11 @@ function createDocsAPI(options) {
491
516
  const key = ctx.locale ?? "__default__";
492
517
  const cached = indexesByLocale.get(key);
493
518
  if (cached) return cached;
494
- const next = scanDocsDir(ctx.docsDir, ctx.entryPath, ctx.locale);
519
+ let next = [];
520
+ for (const docsDir of ctx.docsDirs) {
521
+ next = scanDocsDir(docsDir, ctx.entryPath, ctx.locale);
522
+ if (next.length > 0) break;
523
+ }
495
524
  indexesByLocale.set(key, next);
496
525
  return next;
497
526
  }
@@ -543,6 +572,10 @@ function createDocsAPI(options) {
543
572
  *
544
573
  * Returns `{ GET, POST, DELETE }` for use in a Next.js route handler.
545
574
  */
575
+ /**
576
+ * @deprecated Prefer `createDocsMCPAPI` from `@farming-labs/next/api` in Next.js apps.
577
+ * The `@farming-labs/theme/api` path is kept for compatibility and will be phased out.
578
+ */
546
579
  function createDocsMCPAPI(options = {}) {
547
580
  const rootDir = options.rootDir ?? process.cwd();
548
581
  const entry = options.entry ?? readEntry(rootDir);
@@ -405,6 +405,22 @@ function DocsCommandSearch({ api = "/api/docs", locale }) {
405
405
  setActiveIndex(0);
406
406
  }
407
407
  }, [open]);
408
+ useEffect(() => {
409
+ if (!open) return;
410
+ const { body, documentElement } = document;
411
+ const previousBodyOverflow = body.style.overflow;
412
+ const previousBodyPaddingRight = body.style.paddingRight;
413
+ const previousHtmlOverflow = documentElement.style.overflow;
414
+ const scrollbarWidth = window.innerWidth - documentElement.clientWidth;
415
+ body.style.overflow = "hidden";
416
+ documentElement.style.overflow = "hidden";
417
+ if (scrollbarWidth > 0) body.style.paddingRight = `${scrollbarWidth}px`;
418
+ return () => {
419
+ body.style.overflow = previousBodyOverflow;
420
+ body.style.paddingRight = previousBodyPaddingRight;
421
+ documentElement.style.overflow = previousHtmlOverflow;
422
+ };
423
+ }, [open]);
408
424
  useEffect(() => {
409
425
  if (!open) return;
410
426
  function handler(e) {
@@ -482,6 +498,7 @@ function DocsCommandSearch({ api = "/api/docs", locale }) {
482
498
  }), /* @__PURE__ */ jsxs("div", {
483
499
  className: "omni-content",
484
500
  role: "dialog",
501
+ "aria-modal": "true",
485
502
  "aria-label": "Search documentation",
486
503
  children: [
487
504
  /* @__PURE__ */ jsx("div", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -127,7 +127,7 @@
127
127
  "tsdown": "^0.20.3",
128
128
  "typescript": "^5.9.3",
129
129
  "vitest": "^3.2.4",
130
- "@farming-labs/docs": "0.1.3"
130
+ "@farming-labs/docs": "0.1.5"
131
131
  },
132
132
  "peerDependencies": {
133
133
  "@farming-labs/docs": ">=0.0.1",
package/styles/omni.css CHANGED
@@ -80,6 +80,7 @@
80
80
  0 0 0 1px rgba(255, 255, 255, 0.04);
81
81
  outline: none;
82
82
  overflow: hidden;
83
+ overscroll-behavior: contain;
83
84
  animation: omni-scale-in 200ms cubic-bezier(0.16, 1, 0.3, 1);
84
85
  }
85
86
 
@@ -148,6 +149,7 @@
148
149
  .omni-body {
149
150
  max-height: 60vh;
150
151
  overflow: auto;
152
+ overscroll-behavior: contain;
151
153
  padding: 0.25rem;
152
154
  }
153
155
  .omni-body::-webkit-scrollbar {