@farming-labs/theme 0.2.17 → 0.2.19

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.
@@ -12,6 +12,8 @@ interface DocsFeedbackProps {
12
12
  positiveLabel?: string;
13
13
  negativeLabel?: string;
14
14
  submitLabel?: string;
15
+ successMessage?: string;
16
+ errorMessage?: string;
15
17
  onFeedback?: (data: DocsFeedbackData) => void | Promise<void>;
16
18
  analytics?: boolean;
17
19
  }
@@ -25,6 +27,8 @@ declare function DocsFeedback({
25
27
  positiveLabel,
26
28
  negativeLabel,
27
29
  submitLabel,
30
+ successMessage,
31
+ errorMessage,
28
32
  onFeedback,
29
33
  analytics
30
34
  }: DocsFeedbackProps): react_jsx_runtime0.JSX.Element;
@@ -116,7 +116,7 @@ function CheckIcon() {
116
116
  })
117
117
  });
118
118
  }
119
- function DocsFeedback({ pathname, entry, locale, question = "How is this guide?", placeholder = "Leave your feedback...", requireComment = false, positiveLabel = "Good", negativeLabel = "Bad", submitLabel = "Submit", onFeedback, analytics = false }) {
119
+ function DocsFeedback({ pathname, entry, locale, question = "How is this guide?", placeholder = "Leave your feedback...", requireComment = false, positiveLabel = "Good", negativeLabel = "Bad", submitLabel = "Submit", successMessage = "Thanks for the feedback.", errorMessage = "Could not send feedback. Please try again.", onFeedback, analytics = false }) {
120
120
  const [selected, setSelected] = useState(null);
121
121
  const [comment, setComment] = useState("");
122
122
  const [status, setStatus] = useState("idle");
@@ -251,7 +251,7 @@ function DocsFeedback({ pathname, entry, locale, question = "How is this guide?"
251
251
  "data-status": "success",
252
252
  role: "status",
253
253
  "aria-live": "polite",
254
- children: "Thanks for the feedback."
254
+ children: successMessage
255
255
  })]
256
256
  }),
257
257
  status === "error" && /* @__PURE__ */ jsx("p", {
@@ -259,7 +259,7 @@ function DocsFeedback({ pathname, entry, locale, question = "How is this guide?"
259
259
  "data-status": "error",
260
260
  role: "status",
261
261
  "aria-live": "polite",
262
- children: "Could not send feedback. Please try again."
262
+ children: errorMessage
263
263
  })
264
264
  ]
265
265
  })]
@@ -658,11 +658,13 @@ function createDocsLayout(config, options) {
658
658
  const pageActionsAlignment = pageActions?.alignment ?? "left";
659
659
  const lastUpdatedRaw = config.lastUpdated;
660
660
  const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
661
+ const lastUpdatedLabel = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.label ?? "Last updated" : "Last updated";
661
662
  const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
662
663
  const readingTimeOptions = resolveReadingTimeOptions(config.readingTime);
663
664
  const readingTimeEnabledByDefault = readingTimeOptions.enabled;
664
665
  const readingTimeWordsPerMinute = readingTimeOptions.wordsPerMinute ?? 220;
665
666
  const readingTimeFormat = readingTimeOptions.format;
667
+ const readingTimeIncludeCode = readingTimeOptions.includeCode;
666
668
  const llmsTxtEnabled = resolveEnabledByDefault(config.llmsTxt);
667
669
  const feedbackConfig = resolveFeedbackConfig(config.feedback);
668
670
  const openDocsConfig = pageActions?.openDocs && typeof pageActions.openDocs === "object" ? pageActions.openDocs : void 0;
@@ -699,7 +701,8 @@ function createDocsLayout(config, options) {
699
701
  const descriptionMap = buildDescriptionMap(config, localeContext);
700
702
  const readingTimeMap = buildReadingTimeMap(config, localeContext, {
701
703
  enabledByDefault: readingTimeEnabledByDefault,
702
- wordsPerMinute: readingTimeWordsPerMinute
704
+ wordsPerMinute: readingTimeWordsPerMinute,
705
+ includeCode: readingTimeIncludeCode
703
706
  });
704
707
  const structuredDataMap = buildStructuredDataMap(config, localeContext);
705
708
  const readingTimeEnabled = readingTimeEnabledByDefault || Object.keys(readingTimeMap).length > 0;
@@ -792,6 +795,7 @@ function createDocsLayout(config, options) {
792
795
  locale: activeLocale,
793
796
  copyMarkdown: copyMarkdownEnabled,
794
797
  copyMarkdownFormat: copyMarkdownConfig?.format,
798
+ copyMarkdownIncludeTitle: copyMarkdownConfig?.includeTitle,
795
799
  copyMarkdownLabel: copyMarkdownConfig?.label,
796
800
  copyMarkdownCopiedLabel: copyMarkdownConfig?.copiedLabel,
797
801
  openDocs: openDocsEnabled,
@@ -806,6 +810,7 @@ function createDocsLayout(config, options) {
806
810
  githubDirectory,
807
811
  lastModifiedMap,
808
812
  lastUpdatedEnabled,
813
+ lastUpdatedLabel,
809
814
  lastUpdatedPosition,
810
815
  readingTimeEnabled,
811
816
  readingTimeFormat,
@@ -820,6 +825,8 @@ function createDocsLayout(config, options) {
820
825
  feedbackPositiveLabel: feedbackConfig.positiveLabel,
821
826
  feedbackNegativeLabel: feedbackConfig.negativeLabel,
822
827
  feedbackSubmitLabel: feedbackConfig.submitLabel,
828
+ feedbackSuccessMessage: feedbackConfig.successMessage,
829
+ feedbackErrorMessage: feedbackConfig.errorMessage,
823
830
  analytics: analyticsEnabled,
824
831
  children
825
832
  })
@@ -847,14 +854,16 @@ function resolveFeedbackConfig(feedback) {
847
854
  requireComment: false,
848
855
  positiveLabel: "Good",
849
856
  negativeLabel: "Bad",
850
- submitLabel: "Submit"
857
+ submitLabel: "Submit",
858
+ successMessage: "Thanks for the feedback.",
859
+ errorMessage: "Could not send feedback. Please try again."
851
860
  };
852
861
  if (feedback === void 0 || feedback === false) return defaults;
853
862
  if (feedback === true) return {
854
863
  ...defaults,
855
864
  enabled: true
856
865
  };
857
- const hasHumanFeedbackConfig = feedback.enabled !== void 0 || feedback.question !== void 0 || feedback.placeholder !== void 0 || feedback.requireComment !== void 0 || feedback.positiveLabel !== void 0 || feedback.negativeLabel !== void 0 || feedback.submitLabel !== void 0 || feedback.onFeedback !== void 0;
866
+ const hasHumanFeedbackConfig = feedback.enabled !== void 0 || feedback.question !== void 0 || feedback.placeholder !== void 0 || feedback.requireComment !== void 0 || feedback.positiveLabel !== void 0 || feedback.negativeLabel !== void 0 || feedback.submitLabel !== void 0 || feedback.successMessage !== void 0 || feedback.errorMessage !== void 0 || feedback.onFeedback !== void 0;
858
867
  return {
859
868
  enabled: feedback.enabled === true || feedback.enabled !== false && hasHumanFeedbackConfig,
860
869
  question: feedback.question ?? defaults.question,
@@ -862,7 +871,9 @@ function resolveFeedbackConfig(feedback) {
862
871
  requireComment: feedback.requireComment ?? defaults.requireComment,
863
872
  positiveLabel: feedback.positiveLabel ?? defaults.positiveLabel,
864
873
  negativeLabel: feedback.negativeLabel ?? defaults.negativeLabel,
865
- submitLabel: feedback.submitLabel ?? defaults.submitLabel
874
+ submitLabel: feedback.submitLabel ?? defaults.submitLabel,
875
+ successMessage: feedback.successMessage ?? defaults.successMessage,
876
+ errorMessage: feedback.errorMessage ?? defaults.errorMessage
866
877
  };
867
878
  }
868
879
  /**
@@ -24,6 +24,7 @@ interface DocsPageClientProps {
24
24
  locale?: string;
25
25
  copyMarkdown?: boolean;
26
26
  copyMarkdownFormat?: CopyMarkdownFormat;
27
+ copyMarkdownIncludeTitle?: boolean;
27
28
  copyMarkdownLabel?: string;
28
29
  copyMarkdownCopiedLabel?: string;
29
30
  openDocs?: boolean;
@@ -65,6 +66,8 @@ interface DocsPageClientProps {
65
66
  readingTimeEnabled?: boolean;
66
67
  /** Whether to show "Last updated" at all */
67
68
  lastUpdatedEnabled?: boolean;
69
+ /** Label shown before the formatted last-updated date */
70
+ lastUpdatedLabel?: string;
68
71
  /** Where to show the "Last updated" date: "footer" (next to Edit on GitHub) or "below-title" */
69
72
  lastUpdatedPosition?: "footer" | "below-title";
70
73
  /** Whether llms.txt is enabled — shows links in footer */
@@ -81,6 +84,8 @@ interface DocsPageClientProps {
81
84
  feedbackPositiveLabel?: string;
82
85
  feedbackNegativeLabel?: string;
83
86
  feedbackSubmitLabel?: string;
87
+ feedbackSuccessMessage?: string;
88
+ feedbackErrorMessage?: string;
84
89
  feedbackOnFeedback?: (data: DocsFeedbackData) => void | Promise<void>;
85
90
  analytics?: boolean;
86
91
  children: ReactNode;
@@ -95,6 +100,7 @@ declare function DocsPageClient({
95
100
  locale,
96
101
  copyMarkdown,
97
102
  copyMarkdownFormat,
103
+ copyMarkdownIncludeTitle,
98
104
  copyMarkdownLabel,
99
105
  copyMarkdownCopiedLabel,
100
106
  openDocs,
@@ -117,6 +123,7 @@ declare function DocsPageClient({
117
123
  structuredData: structuredDataProp,
118
124
  readingTimeEnabled,
119
125
  lastUpdatedEnabled,
126
+ lastUpdatedLabel,
120
127
  lastUpdatedPosition,
121
128
  llmsTxtEnabled,
122
129
  descriptionMap,
@@ -128,6 +135,8 @@ declare function DocsPageClient({
128
135
  feedbackPositiveLabel,
129
136
  feedbackNegativeLabel,
130
137
  feedbackSubmitLabel,
138
+ feedbackSuccessMessage,
139
+ feedbackErrorMessage,
131
140
  feedbackOnFeedback,
132
141
  analytics,
133
142
  children
@@ -255,7 +255,7 @@ function findThreadlineTocActionsContainer() {
255
255
  }
256
256
  return toc.parentElement ?? toc;
257
257
  }
258
- function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, changelogBasePath, entry = "docs", publicPath, locale, copyMarkdown = false, copyMarkdownFormat, copyMarkdownLabel, copyMarkdownCopiedLabel, openDocs = false, openDocsProviders, openDocsTarget, openDocsPrompt, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, contentDir, githubBranch = "main", githubDirectory, editOnGithubUrl, lastModifiedMap, lastModified: lastModifiedProp, readingTimeMap, readingTime: readingTimeProp, readingTimeFormat = "long", structuredDataMap, structuredData: structuredDataProp, readingTimeEnabled = false, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, feedbackEnabled = false, feedbackQuestion, feedbackPlaceholder, feedbackRequireComment, feedbackPositiveLabel, feedbackNegativeLabel, feedbackSubmitLabel, feedbackOnFeedback, analytics = false, children }) {
258
+ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, changelogBasePath, entry = "docs", publicPath, locale, copyMarkdown = false, copyMarkdownFormat, copyMarkdownIncludeTitle, copyMarkdownLabel, copyMarkdownCopiedLabel, openDocs = false, openDocsProviders, openDocsTarget, openDocsPrompt, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, contentDir, githubBranch = "main", githubDirectory, editOnGithubUrl, lastModifiedMap, lastModified: lastModifiedProp, readingTimeMap, readingTime: readingTimeProp, readingTimeFormat = "long", structuredDataMap, structuredData: structuredDataProp, readingTimeEnabled = false, lastUpdatedEnabled = true, lastUpdatedLabel = "Last updated", lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, feedbackEnabled = false, feedbackQuestion, feedbackPlaceholder, feedbackRequireComment, feedbackPositiveLabel, feedbackNegativeLabel, feedbackSubmitLabel, feedbackSuccessMessage, feedbackErrorMessage, feedbackOnFeedback, analytics = false, children }) {
259
259
  const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
260
260
  const [toc, setToc] = useState([]);
261
261
  const [titlePortalHost, setTitlePortalHost] = useState(null);
@@ -434,6 +434,8 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
434
434
  const lastModified = !isChangelogRoute && lastUpdatedEnabled ? lastModifiedProp ?? lastModifiedMap?.[normalizedPath] : void 0;
435
435
  const showLastUpdatedBelowTitle = !!lastModified && lastUpdatedPosition === "below-title";
436
436
  const showLastUpdatedInFooter = !!lastModified && lastUpdatedPosition === "footer";
437
+ const lastUpdatedLabelText = lastUpdatedLabel.trim();
438
+ const lastUpdatedText = lastUpdatedLabelText && lastModified ? `${lastUpdatedLabelText} ${lastModified}` : lastModified;
437
439
  const showFooter = !isChangelogRoute && (!!githubFileUrl || showLastUpdatedInFooter || llmsTxtEnabled);
438
440
  const readingTimeBlock = typeof resolvedReadingTime === "number" ? /* @__PURE__ */ jsxs("div", {
439
441
  className: "fd-page-meta not-prose",
@@ -455,9 +457,9 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
455
457
  const belowTitleBlock = showLastUpdatedBelowTitle || showActionsBelowTitle || showReadingTimeBelowTitle ? /* @__PURE__ */ jsxs("div", {
456
458
  className: "fd-below-title-block not-prose",
457
459
  children: [
458
- showLastUpdatedBelowTitle && /* @__PURE__ */ jsxs("p", {
460
+ showLastUpdatedBelowTitle && /* @__PURE__ */ jsx("p", {
459
461
  className: "fd-last-updated-inline",
460
- children: ["Last updated ", lastModified]
462
+ children: lastUpdatedText
461
463
  }, "last-updated"),
462
464
  /* @__PURE__ */ jsx("hr", { className: "fd-title-separator" }, "separator"),
463
465
  showActionsBelowTitle && /* @__PURE__ */ jsx("div", {
@@ -466,6 +468,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
466
468
  children: /* @__PURE__ */ jsx(PageActions, {
467
469
  copyMarkdown,
468
470
  copyMarkdownFormat,
471
+ copyMarkdownIncludeTitle,
469
472
  copyMarkdownLabel,
470
473
  copyMarkdownCopiedLabel,
471
474
  openDocs,
@@ -512,6 +515,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
512
515
  children: /* @__PURE__ */ jsx(PageActions, {
513
516
  copyMarkdown,
514
517
  copyMarkdownFormat,
518
+ copyMarkdownIncludeTitle,
515
519
  copyMarkdownLabel,
516
520
  copyMarkdownCopiedLabel,
517
521
  openDocs,
@@ -567,6 +571,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
567
571
  children: /* @__PURE__ */ jsx(PageActions, {
568
572
  copyMarkdown,
569
573
  copyMarkdownFormat,
574
+ copyMarkdownIncludeTitle,
570
575
  copyMarkdownLabel,
571
576
  copyMarkdownCopiedLabel,
572
577
  openDocs,
@@ -602,6 +607,8 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
602
607
  positiveLabel: feedbackPositiveLabel,
603
608
  negativeLabel: feedbackNegativeLabel,
604
609
  submitLabel: feedbackSubmitLabel,
610
+ successMessage: feedbackSuccessMessage,
611
+ errorMessage: feedbackErrorMessage,
605
612
  onFeedback: feedbackOnFeedback,
606
613
  analytics
607
614
  }, "feedback"),
@@ -625,9 +632,9 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
625
632
  children: "llms-full.txt"
626
633
  })]
627
634
  }, "llms-links"),
628
- showLastUpdatedInFooter && lastModified && /* @__PURE__ */ jsxs("span", {
635
+ showLastUpdatedInFooter && lastModified && /* @__PURE__ */ jsx("span", {
629
636
  className: "fd-last-updated-footer",
630
- children: ["Last updated ", lastModified]
637
+ children: lastUpdatedText
631
638
  }, "last-updated")
632
639
  ]
633
640
  }, "footer")
@@ -13,6 +13,7 @@ interface SerializedProvider {
13
13
  interface PageActionsProps {
14
14
  copyMarkdown?: boolean;
15
15
  copyMarkdownFormat?: CopyMarkdownFormat;
16
+ copyMarkdownIncludeTitle?: boolean;
16
17
  copyMarkdownLabel?: string;
17
18
  copyMarkdownCopiedLabel?: string;
18
19
  openDocs?: boolean;
@@ -25,9 +26,16 @@ interface PageActionsProps {
25
26
  githubFileUrl?: string | null;
26
27
  analytics?: boolean;
27
28
  }
29
+ declare function formatCopyMarkdownContent(params: {
30
+ content: string;
31
+ format: CopyMarkdownFormat;
32
+ includeTitle?: boolean;
33
+ title?: string | null;
34
+ }): string;
28
35
  declare function PageActions({
29
36
  copyMarkdown,
30
37
  copyMarkdownFormat,
38
+ copyMarkdownIncludeTitle,
31
39
  copyMarkdownLabel,
32
40
  copyMarkdownCopiedLabel,
33
41
  openDocs,
@@ -40,4 +48,4 @@ declare function PageActions({
40
48
  analytics
41
49
  }: PageActionsProps): react_jsx_runtime0.JSX.Element | null;
42
50
  //#endregion
43
- export { PageActions };
51
+ export { PageActions, formatCopyMarkdownContent };
@@ -132,7 +132,26 @@ function pageUrlToMarkdownUrl(pageUrl) {
132
132
  function fillPromptTemplate(template, values) {
133
133
  return template.replace(/\{pageUrl\}/g, values.pageUrl).replace(/\{markdownUrl\}/g, values.markdownUrl).replace(/\{sourceUrl\}/g, values.sourceUrl).replace(/\{mdxUrl\}/g, values.sourceUrl).replace(/\{githubUrl\}/g, values.githubUrl).replace(/\{url\}/g, values.url);
134
134
  }
135
- function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdownLabel = "Copy page", copyMarkdownCopiedLabel = "Copied!", openDocs, providers, openDocsTarget = DEFAULT_OPEN_DOCS_TARGET, openDocsPrompt = DEFAULT_OPEN_DOCS_PROMPT, alignment = "left", variant = "default", githubFileUrl, analytics = false }) {
135
+ function firstContentLine(content) {
136
+ return content.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
137
+ }
138
+ function formatCopyMarkdownContent(params) {
139
+ const title = params.title?.trim();
140
+ if (!params.includeTitle || !title) return params.content;
141
+ const firstLine = firstContentLine(params.content);
142
+ if (params.format === "markdown") {
143
+ const heading = `# ${title}`;
144
+ if (firstLine === heading || firstLine === title) return params.content;
145
+ return `${heading}\n\n${params.content.trimStart()}`;
146
+ }
147
+ if (firstLine === title) return params.content;
148
+ return `${title}\n\n${params.content.trimStart()}`;
149
+ }
150
+ function currentPageTitle() {
151
+ const title = document.querySelector("#nd-page h1") ?? document.querySelector("article h1") ?? document.querySelector("h1");
152
+ return title?.innerText?.trim() || title?.textContent?.trim() || "";
153
+ }
154
+ function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdownIncludeTitle = false, copyMarkdownLabel = "Copy page", copyMarkdownCopiedLabel = "Copied!", openDocs, providers, openDocsTarget = DEFAULT_OPEN_DOCS_TARGET, openDocsPrompt = DEFAULT_OPEN_DOCS_PROMPT, alignment = "left", variant = "default", githubFileUrl, analytics = false }) {
136
155
  const [copied, setCopied] = useState(false);
137
156
  const [dropdownOpen, setDropdownOpen] = useState(false);
138
157
  const dropdownRef = useRef(null);
@@ -149,12 +168,19 @@ function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdo
149
168
  } catch {}
150
169
  if (!content) content = document.querySelector("article")?.innerText || "";
151
170
  if (!content) return;
171
+ content = formatCopyMarkdownContent({
172
+ content,
173
+ format: copyMarkdownFormat,
174
+ includeTitle: copyMarkdownIncludeTitle,
175
+ title: currentPageTitle()
176
+ });
152
177
  await navigator.clipboard.writeText(content);
153
178
  if (analytics) emitClientAnalyticsEvent({
154
179
  type: "page_action_copy_markdown",
155
180
  properties: {
156
181
  contentLength: content.length,
157
182
  format: copyMarkdownFormat,
183
+ includeTitle: copyMarkdownIncludeTitle,
158
184
  pathname
159
185
  }
160
186
  });
@@ -164,6 +190,7 @@ function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdo
164
190
  }, [
165
191
  analytics,
166
192
  copyMarkdownFormat,
193
+ copyMarkdownIncludeTitle,
167
194
  markdownHref,
168
195
  pathname
169
196
  ]);
@@ -241,6 +268,7 @@ function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdo
241
268
  className: "fd-page-action-btn",
242
269
  "data-copied": copied,
243
270
  "data-copy-markdown-format": copyMarkdownFormat,
271
+ "data-copy-markdown-include-title": copyMarkdownIncludeTitle || void 0,
244
272
  children: [copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}), /* @__PURE__ */ jsx("span", { children: copied ? copyMarkdownCopiedLabel : copyMarkdownLabel })]
245
273
  }),
246
274
  openDocs && /* @__PURE__ */ jsxs("a", {
@@ -275,6 +303,7 @@ function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdo
275
303
  className: "fd-page-action-btn",
276
304
  "data-copied": copied,
277
305
  "data-copy-markdown-format": copyMarkdownFormat,
306
+ "data-copy-markdown-include-title": copyMarkdownIncludeTitle || void 0,
278
307
  children: [copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}), /* @__PURE__ */ jsx("span", { children: copied ? copyMarkdownCopiedLabel : copyMarkdownLabel })]
279
308
  }), openDocs && resolvedProviders.length > 0 && /* @__PURE__ */ jsxs("div", {
280
309
  ref: dropdownRef,
@@ -324,4 +353,4 @@ function PageActions({ copyMarkdown, copyMarkdownFormat = "markdown", copyMarkdo
324
353
  }
325
354
 
326
355
  //#endregion
327
- export { PageActions };
356
+ export { PageActions, formatCopyMarkdownContent };
@@ -8,41 +8,46 @@ function normalizeWordsPerMinute(wordsPerMinute) {
8
8
  if (typeof wordsPerMinute !== "number" || !Number.isFinite(wordsPerMinute)) return 220;
9
9
  return Math.max(1, Math.floor(wordsPerMinute));
10
10
  }
11
- function stripNonReadingContent(content) {
12
- return content.replace(/(`{3,})[^\n]*\n[\s\S]*?\1/g, " ").replace(/(~{3,})[^\n]*\n[\s\S]*?\1/g, " ").replace(/`[^`\n]+`/g, " ").replace(/!\[[^\]]*\]\([^)]+\)/g, " ").replace(/\[([^\]]+)\]\([^)]+\)/g, " $1 ").replace(/<[^>]+>/g, " ").replace(/\{[^{}]*\}/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/[#>*_~|]/g, " ");
11
+ function stripNonReadingContent(content, options) {
12
+ const includeCode = options?.includeCode === true;
13
+ return (includeCode ? content.replace(/^(`{3,}|~{3,})[^\n]*$/gm, " ").replace(/`([^`\n]+)`/g, " $1 ") : content.replace(/(`{3,})[^\n]*\n[\s\S]*?\1/g, " ").replace(/(~{3,})[^\n]*\n[\s\S]*?\1/g, " ").replace(/`[^`\n]+`/g, " ")).replace(/!\[[^\]]*\]\([^)]+\)/g, " ").replace(/\[([^\]]+)\]\([^)]+\)/g, " $1 ").replace(/<[^>]+>/g, " ").replace(includeCode ? /[{}]/g : /\{[^{}]*\}/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/[#>*_~|]/g, " ");
13
14
  }
14
- function estimateReadingTimeMinutes(content, wordsPerMinute) {
15
- const wordCount = stripNonReadingContent(content).match(/\b[\p{L}\p{N}][\p{L}\p{N}'’-]*\b/gu)?.length ?? 0;
15
+ function estimateReadingTimeMinutes(content, wordsPerMinute, options) {
16
+ const wordCount = stripNonReadingContent(content, options).match(/\b[\p{L}\p{N}][\p{L}\p{N}'’-]*\b/gu)?.length ?? 0;
16
17
  return Math.max(1, Math.ceil(wordCount / normalizeWordsPerMinute(wordsPerMinute)));
17
18
  }
18
19
  function resolveReadingTimeOptions(readingTime) {
19
20
  if (readingTime === true) return {
20
21
  enabled: true,
21
- format: "long"
22
+ format: "long",
23
+ includeCode: false
22
24
  };
23
25
  if (readingTime === false || readingTime === void 0 || readingTime === null) return {
24
26
  enabled: false,
25
- format: "long"
27
+ format: "long",
28
+ includeCode: false
26
29
  };
27
30
  if (typeof readingTime !== "object") return {
28
31
  enabled: false,
29
- format: "long"
32
+ format: "long",
33
+ includeCode: false
30
34
  };
31
35
  return {
32
36
  enabled: readingTime.enabled !== false,
33
37
  wordsPerMinute: typeof readingTime.wordsPerMinute === "number" && Number.isFinite(readingTime.wordsPerMinute) ? readingTime.wordsPerMinute : void 0,
34
- format: readingTime.format === "short" ? "short" : "long"
38
+ format: readingTime.format === "short" ? "short" : "long",
39
+ includeCode: readingTime.includeCode === true
35
40
  };
36
41
  }
37
- function resolveReadingTimeFromContent(frontmatter, content, wordsPerMinute) {
42
+ function resolveReadingTimeFromContent(frontmatter, content, wordsPerMinute, options) {
38
43
  const pageData = frontmatter ?? {};
39
44
  if (pageData.readingTime === false) return null;
40
45
  if (typeof pageData.readingTime === "number" && Number.isFinite(pageData.readingTime)) return Math.max(1, Math.ceil(pageData.readingTime));
41
- return estimateReadingTimeMinutes(content, wordsPerMinute);
46
+ return estimateReadingTimeMinutes(content, wordsPerMinute, options);
42
47
  }
43
48
  function resolvePageReadingTime(frontmatter, content, options) {
44
49
  if (!(options?.enabledByDefault ?? false) && !hasExplicitReadingTime(frontmatter)) return;
45
- return resolveReadingTimeFromContent(frontmatter, content, options?.wordsPerMinute);
50
+ return resolveReadingTimeFromContent(frontmatter, content, options?.wordsPerMinute, { includeCode: options?.includeCode });
46
51
  }
47
52
 
48
53
  //#endregion
@@ -196,14 +196,16 @@ function resolveFeedbackConfig(feedback) {
196
196
  requireComment: false,
197
197
  positiveLabel: "Good",
198
198
  negativeLabel: "Bad",
199
- submitLabel: "Submit"
199
+ submitLabel: "Submit",
200
+ successMessage: "Thanks for the feedback.",
201
+ errorMessage: "Could not send feedback. Please try again."
200
202
  };
201
203
  if (feedback === void 0 || feedback === false) return defaults;
202
204
  if (feedback === true) return {
203
205
  ...defaults,
204
206
  enabled: true
205
207
  };
206
- const hasHumanFeedbackConfig = feedback.enabled !== void 0 || feedback.question !== void 0 || feedback.placeholder !== void 0 || feedback.requireComment !== void 0 || feedback.positiveLabel !== void 0 || feedback.negativeLabel !== void 0 || feedback.submitLabel !== void 0 || feedback.onFeedback !== void 0;
208
+ const hasHumanFeedbackConfig = feedback.enabled !== void 0 || feedback.question !== void 0 || feedback.placeholder !== void 0 || feedback.requireComment !== void 0 || feedback.positiveLabel !== void 0 || feedback.negativeLabel !== void 0 || feedback.submitLabel !== void 0 || feedback.successMessage !== void 0 || feedback.errorMessage !== void 0 || feedback.onFeedback !== void 0;
207
209
  return {
208
210
  enabled: feedback.enabled === true || feedback.enabled !== false && hasHumanFeedbackConfig,
209
211
  question: feedback.question ?? defaults.question,
@@ -211,7 +213,9 @@ function resolveFeedbackConfig(feedback) {
211
213
  requireComment: feedback.requireComment ?? defaults.requireComment,
212
214
  positiveLabel: feedback.positiveLabel ?? defaults.positiveLabel,
213
215
  negativeLabel: feedback.negativeLabel ?? defaults.negativeLabel,
214
- submitLabel: feedback.submitLabel ?? defaults.submitLabel
216
+ submitLabel: feedback.submitLabel ?? defaults.submitLabel,
217
+ successMessage: feedback.successMessage ?? defaults.successMessage,
218
+ errorMessage: feedback.errorMessage ?? defaults.errorMessage
215
219
  };
216
220
  }
217
221
  function ForcedThemeScript({ theme }) {
@@ -246,6 +250,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
246
250
  const pageActionsAlignment = pageActions?.alignment ?? "left";
247
251
  const lastUpdatedRaw = config.lastUpdated;
248
252
  const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
253
+ const lastUpdatedLabel = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.label ?? "Last updated" : "Last updated";
249
254
  const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
250
255
  const readingTimeOptions = resolveReadingTimeOptions(config.readingTime);
251
256
  const readingTimeEnabled = readingTimeOptions.enabled;
@@ -357,6 +362,8 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
357
362
  entry: config.entry ?? "docs",
358
363
  locale,
359
364
  copyMarkdown: copyMarkdownEnabled,
365
+ copyMarkdownFormat: copyMarkdownConfig?.format,
366
+ copyMarkdownIncludeTitle: copyMarkdownConfig?.includeTitle,
360
367
  copyMarkdownLabel: copyMarkdownConfig?.label,
361
368
  copyMarkdownCopiedLabel: copyMarkdownConfig?.copiedLabel,
362
369
  openDocs: openDocsEnabled,
@@ -367,6 +374,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
367
374
  pageActionsAlignment,
368
375
  editOnGithubUrl,
369
376
  lastUpdatedEnabled,
377
+ lastUpdatedLabel,
370
378
  lastUpdatedPosition,
371
379
  lastModified,
372
380
  readingTimeEnabled,
@@ -381,6 +389,8 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
381
389
  feedbackPositiveLabel: feedbackConfig.positiveLabel,
382
390
  feedbackNegativeLabel: feedbackConfig.negativeLabel,
383
391
  feedbackSubmitLabel: feedbackConfig.submitLabel,
392
+ feedbackSuccessMessage: feedbackConfig.successMessage,
393
+ feedbackErrorMessage: feedbackConfig.errorMessage,
384
394
  analytics: analyticsEnabled,
385
395
  children
386
396
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -145,7 +145,7 @@
145
145
  "tsdown": "^0.20.3",
146
146
  "typescript": "^5.9.3",
147
147
  "vitest": "^4.1.8",
148
- "@farming-labs/docs": "0.2.17"
148
+ "@farming-labs/docs": "0.2.19"
149
149
  },
150
150
  "peerDependencies": {
151
151
  "@farming-labs/docs": ">=0.0.1",