@farming-labs/theme 0.1.47 → 0.1.49

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.
@@ -3,7 +3,7 @@ import { withLangInUrl } from "./i18n.mjs";
3
3
  import { DocsPageClient } from "./docs-page-client.mjs";
4
4
  import { DocsAIFeatures } from "./docs-ai-features.mjs";
5
5
  import { DocsCommandSearch } from "./docs-command-search.mjs";
6
- import { resolveReadingTimeFromContent, resolveReadingTimeOptions } from "./reading-time.mjs";
6
+ import { resolvePageReadingTime, resolveReadingTimeOptions } from "./reading-time.mjs";
7
7
  import { SidebarSearchWithAI } from "./sidebar-search-ai.mjs";
8
8
  import { LocaleThemeControl } from "./locale-theme-control.mjs";
9
9
  import fs from "node:fs";
@@ -341,7 +341,7 @@ function buildDescriptionMap(config, ctx) {
341
341
  scan(docsDir, []);
342
342
  return map;
343
343
  }
344
- function buildReadingTimeMap(config, ctx, wordsPerMinute) {
344
+ function buildReadingTimeMap(config, ctx, options) {
345
345
  const docsDir = ctx.docsDir;
346
346
  const map = {};
347
347
  const excludedDirs = getExcludedDocsDirs(config, ctx);
@@ -351,8 +351,8 @@ function buildReadingTimeMap(config, ctx, wordsPerMinute) {
351
351
  const pagePath = path.join(dir, "page.mdx");
352
352
  if (fs.existsSync(pagePath)) {
353
353
  const { data, content } = matter(fs.readFileSync(pagePath, "utf-8"));
354
- const minutes = resolveReadingTimeFromContent(data, resolveDocsAgentMdxContent(content, "human"), wordsPerMinute);
355
- if (minutes !== null) {
354
+ const minutes = resolvePageReadingTime(data, resolveDocsAgentMdxContent(content, "human"), options);
355
+ if (typeof minutes === "number") {
356
356
  const url = slugParts.length === 0 ? `/${ctx.entryPath}` : `/${ctx.entryPath}/${slugParts.join("/")}`;
357
357
  map[url] = minutes;
358
358
  }
@@ -582,7 +582,7 @@ function createDocsLayout(config, options) {
582
582
  const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
583
583
  const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
584
584
  const readingTimeOptions = resolveReadingTimeOptions(config.readingTime);
585
- const readingTimeEnabled = readingTimeOptions.enabled;
585
+ const readingTimeEnabledByDefault = readingTimeOptions.enabled;
586
586
  const readingTimeWordsPerMinute = readingTimeOptions.wordsPerMinute ?? 220;
587
587
  const llmsTxtEnabled = resolveBool(config.llmsTxt);
588
588
  const feedbackConfig = resolveFeedbackConfig(config.feedback);
@@ -616,7 +616,11 @@ function createDocsLayout(config, options) {
616
616
  }
617
617
  const lastModifiedMap = buildLastModifiedMap(config, localeContext);
618
618
  const descriptionMap = buildDescriptionMap(config, localeContext);
619
- const readingTimeMap = readingTimeEnabled ? buildReadingTimeMap(config, localeContext, readingTimeWordsPerMinute) : {};
619
+ const readingTimeMap = buildReadingTimeMap(config, localeContext, {
620
+ enabledByDefault: readingTimeEnabledByDefault,
621
+ wordsPerMinute: readingTimeWordsPerMinute
622
+ });
623
+ const readingTimeEnabled = readingTimeEnabledByDefault || Object.keys(readingTimeMap).length > 0;
620
624
  return function DocsLayoutWrapper({ children }) {
621
625
  const tree = buildTree(config, localeContext, !!sidebarFlat);
622
626
  const localizedTree = i18n ? localizeTreeUrls(tree, activeLocale) : tree;
@@ -42,8 +42,11 @@ interface DocsPageClientProps {
42
42
  /** Map of pathname → reading time in minutes */
43
43
  readingTimeMap?: Record<string, number>;
44
44
  /** Direct reading-time override for the current page. */
45
- readingTime?: number;
46
- /** Whether to show estimated reading time at the top of the page. */
45
+ readingTime?: number | null;
46
+ /**
47
+ * Whether path-based reading time values should render by default.
48
+ * Explicit `readingTime` overrides can still render when this is false.
49
+ */
47
50
  readingTimeEnabled?: boolean;
48
51
  /** Whether to show "Last updated" at all */
49
52
  lastUpdatedEnabled?: boolean;
@@ -172,7 +172,8 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
172
172
  const pageDescription = description ?? descriptionMap?.[pathname.replace(/\/$/, "") || "/"];
173
173
  const normalizedPath = (browserPath ?? pathname).replace(/\/$/, "") || "/";
174
174
  const isChangelogRoute = !!(changelogBasePath && (normalizedPath === changelogBasePath || normalizedPath.startsWith(`${changelogBasePath}/`)));
175
- const resolvedReadingTime = !isChangelogRoute && readingTimeEnabled ? readingTimeProp ?? readingTimeMap?.[normalizedPath] : void 0;
175
+ const matchedReadingTime = readingTimeMap?.[normalizedPath];
176
+ const resolvedReadingTime = !isChangelogRoute ? readingTimeProp !== void 0 ? readingTimeProp : readingTimeEnabled ? matchedReadingTime : void 0 : void 0;
176
177
  const effectiveTocEnabled = isChangelogRoute ? false : tocEnabled;
177
178
  const effectiveBreadcrumbEnabled = isChangelogRoute ? false : breadcrumbEnabled;
178
179
  useEffect(() => {
@@ -1,6 +1,9 @@
1
1
  import matter from "gray-matter";
2
2
 
3
3
  //#region src/reading-time.ts
4
+ function hasExplicitReadingTime(frontmatter) {
5
+ return Object.prototype.hasOwnProperty.call(frontmatter ?? {}, "readingTime");
6
+ }
4
7
  function normalizeWordsPerMinute(wordsPerMinute) {
5
8
  if (typeof wordsPerMinute !== "number" || !Number.isFinite(wordsPerMinute)) return 220;
6
9
  return Math.max(1, Math.floor(wordsPerMinute));
@@ -27,6 +30,10 @@ function resolveReadingTimeFromContent(frontmatter, content, wordsPerMinute) {
27
30
  if (typeof pageData.readingTime === "number" && Number.isFinite(pageData.readingTime)) return Math.max(1, Math.ceil(pageData.readingTime));
28
31
  return estimateReadingTimeMinutes(content, wordsPerMinute);
29
32
  }
33
+ function resolvePageReadingTime(frontmatter, content, options) {
34
+ if (!(options?.enabledByDefault ?? false) && !hasExplicitReadingTime(frontmatter)) return;
35
+ return resolveReadingTimeFromContent(frontmatter, content, options?.wordsPerMinute);
36
+ }
30
37
 
31
38
  //#endregion
32
- export { resolveReadingTimeFromContent, resolveReadingTimeOptions };
39
+ export { resolvePageReadingTime, resolveReadingTimeOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -133,7 +133,7 @@
133
133
  "tsdown": "^0.20.3",
134
134
  "typescript": "^5.9.3",
135
135
  "vitest": "^3.2.4",
136
- "@farming-labs/docs": "0.1.47"
136
+ "@farming-labs/docs": "0.1.49"
137
137
  },
138
138
  "peerDependencies": {
139
139
  "@farming-labs/docs": ">=0.0.1",