@farming-labs/theme 0.0.9 → 0.0.11

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.
@@ -0,0 +1,13 @@
1
+ import * as React$1 from "react";
2
+ import { CodeBlockCopyData } from "@farming-labs/docs";
3
+
4
+ //#region src/code-block-copy-wrapper.d.ts
5
+ type PreProps = React$1.ComponentPropsWithoutRef<"pre">;
6
+ /**
7
+ * Creates a wrapper around the default MDX `pre` component that calls
8
+ * `onCopyClick` when the user clicks the code block's copy button.
9
+ * The actual copy-to-clipboard is still done by the default component.
10
+ */
11
+ declare function createPreWithCopyCallback(DefaultPre: React$1.ComponentType<PreProps> | "pre", onCopyClick?: (data: CodeBlockCopyData) => void): React$1.ComponentType<PreProps>;
12
+ //#endregion
13
+ export { createPreWithCopyCallback };
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import * as React$1 from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+
6
+ //#region src/code-block-copy-wrapper.tsx
7
+ /**
8
+ * Creates a wrapper around the default MDX `pre` component that calls
9
+ * `onCopyClick` when the user clicks the code block's copy button.
10
+ * The actual copy-to-clipboard is still done by the default component.
11
+ */
12
+ function createPreWithCopyCallback(DefaultPre, onCopyClick) {
13
+ if (!onCopyClick) return typeof DefaultPre === "string" ? DefaultPre : DefaultPre;
14
+ function PreWithCopyCallback(props) {
15
+ const ref = React$1.useRef(null);
16
+ React$1.useEffect(() => {
17
+ const wrapper = ref.current;
18
+ if (!wrapper) return;
19
+ const figure = wrapper.closest("figure");
20
+ if (!figure) return;
21
+ const handleClick = (e) => {
22
+ if (!e.target.closest?.("button")) return;
23
+ const code = figure.querySelector("pre")?.querySelector("code");
24
+ if (!code) return;
25
+ const content = code.textContent ?? "";
26
+ const url = typeof window !== "undefined" ? window.location.href : "";
27
+ const language = code.getAttribute("data-language") ?? figure.getAttribute("data-language") ?? void 0;
28
+ onCopyClick({
29
+ title: figure.querySelector("[data-title]")?.textContent?.trim() ?? figure.querySelector(".fd-codeblock-title-text")?.textContent?.trim() ?? void 0,
30
+ content,
31
+ url,
32
+ language
33
+ });
34
+ };
35
+ figure.addEventListener("click", handleClick, true);
36
+ return () => figure.removeEventListener("click", handleClick, true);
37
+ }, [onCopyClick]);
38
+ const Pre = DefaultPre;
39
+ return /* @__PURE__ */ jsx("div", {
40
+ ref,
41
+ "data-fd-copy-wrapper": true,
42
+ style: { display: "contents" },
43
+ children: typeof Pre === "string" ? /* @__PURE__ */ jsx("pre", { ...props }) : /* @__PURE__ */ jsx(Pre, { ...props })
44
+ });
45
+ }
46
+ return PreWithCopyCallback;
47
+ }
48
+
49
+ //#endregion
50
+ export { createPreWithCopyCallback };
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from "react";
2
2
  import * as react_jsx_runtime0 from "react/jsx-runtime";
3
- import { DocsConfig } from "@farming-labs/docs";
3
+ import { DocsConfig, PageFrontmatter } from "@farming-labs/docs";
4
4
 
5
5
  //#region src/docs-layout.d.ts
6
6
  /**
@@ -16,23 +16,19 @@ import { DocsConfig } from "@farming-labs/docs";
16
16
  */
17
17
  declare function createDocsMetadata(config: DocsConfig): Record<string, unknown>;
18
18
  /**
19
- * Generate page-level metadata with dynamic OG images.
19
+ * Generate page-level metadata with dynamic or static OG/twitter.
20
+ * When the page has `openGraph` or `twitter` in frontmatter, those are used (static OG).
21
+ * Otherwise uses `ogImage` or the config dynamic endpoint.
20
22
  *
21
23
  * Usage in a docs page or [[...slug]] route:
22
24
  * ```ts
23
25
  * export function generateMetadata({ params }) {
24
26
  * const page = getPage(params.slug);
25
- * return createPageMetadata(docsConfig, {
26
- * title: page.data.title,
27
- * description: page.data.description,
28
- * });
27
+ * return createPageMetadata(docsConfig, page.data);
29
28
  * }
30
29
  * ```
31
30
  */
32
- declare function createPageMetadata(config: DocsConfig, page: {
33
- title: string;
34
- description?: string;
35
- }): Record<string, unknown>;
31
+ declare function createPageMetadata(config: DocsConfig, page: Pick<PageFrontmatter, "title" | "description" | "ogImage" | "openGraph" | "twitter">, baseUrl?: string): Record<string, unknown>;
36
32
  declare function createDocsLayout(config: DocsConfig): ({
37
33
  children
38
34
  }: {
@@ -8,6 +8,7 @@ import fs from "node:fs";
8
8
  import path from "node:path";
9
9
  import matter from "gray-matter";
10
10
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
11
+ import { buildPageOpenGraph, buildPageTwitter } from "@farming-labs/docs";
11
12
 
12
13
  //#region src/docs-layout.tsx
13
14
  /** Resolve a frontmatter `icon` string to a ReactNode via the icon registry. */
@@ -231,42 +232,28 @@ function createDocsMetadata(config) {
231
232
  return result;
232
233
  }
233
234
  /**
234
- * Generate page-level metadata with dynamic OG images.
235
+ * Generate page-level metadata with dynamic or static OG/twitter.
236
+ * When the page has `openGraph` or `twitter` in frontmatter, those are used (static OG).
237
+ * Otherwise uses `ogImage` or the config dynamic endpoint.
235
238
  *
236
239
  * Usage in a docs page or [[...slug]] route:
237
240
  * ```ts
238
241
  * export function generateMetadata({ params }) {
239
242
  * const page = getPage(params.slug);
240
- * return createPageMetadata(docsConfig, {
241
- * title: page.data.title,
242
- * description: page.data.description,
243
- * });
243
+ * return createPageMetadata(docsConfig, page.data);
244
244
  * }
245
245
  * ```
246
246
  */
247
- function createPageMetadata(config, page) {
248
- const og = config.og;
247
+ function createPageMetadata(config, page, baseUrl) {
249
248
  const result = {
250
249
  title: page.title,
251
250
  ...page.description ? { description: page.description } : {}
252
251
  };
253
- if (og?.enabled !== false && og?.endpoint) {
254
- const ogUrl = `${og.endpoint}?title=${encodeURIComponent(page.title)}${page.description ? `&description=${encodeURIComponent(page.description)}` : ""}`;
255
- result.openGraph = {
256
- title: page.title,
257
- description: page.description,
258
- images: [{
259
- url: ogUrl,
260
- width: 1200,
261
- height: 630
262
- }]
263
- };
264
- result.twitter = {
265
- card: "summary_large_image",
266
- title: page.title,
267
- description: page.description,
268
- images: [ogUrl]
269
- };
252
+ if (config.og?.enabled !== false) {
253
+ const openGraph = buildPageOpenGraph(page, config.og, baseUrl);
254
+ if (openGraph) result.openGraph = openGraph;
255
+ const twitter = buildPageTwitter(page, config.og, baseUrl);
256
+ if (twitter) result.twitter = twitter;
270
257
  }
271
258
  return result;
272
259
  }
package/dist/index.d.mts CHANGED
@@ -5,8 +5,8 @@ import { DocsPageClient } from "./docs-page-client.mjs";
5
5
  import { RootProvider } from "./provider.mjs";
6
6
  import { PageActions } from "./page-actions.mjs";
7
7
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
8
- import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
9
8
  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
+ import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
10
10
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
11
11
  import { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, Pre } from "fumadocs-ui/components/codeblock";
12
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, createPageMetadata, createTheme, deepMerge, defineDocs, extendTheme, fumadocs };
package/dist/index.mjs CHANGED
@@ -5,8 +5,8 @@ import { createDocsLayout, createDocsMetadata, createPageMetadata } from "./docs
5
5
  import { RootProvider } from "./provider.mjs";
6
6
  import { DefaultUIDefaults, fumadocs } from "./default/index.mjs";
7
7
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
8
- import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
9
8
  import { createTheme, deepMerge, defineDocs, extendTheme } from "@farming-labs/docs";
9
+ import { DocsBody, DocsPage } from "fumadocs-ui/layouts/docs/page";
10
10
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
11
11
  import { CodeBlock, CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, Pre } from "fumadocs-ui/components/codeblock";
12
12
 
package/dist/mdx.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { MDXImg } from "./mdx-img.mjs";
2
- import * as react from "react";
2
+ import React from "react";
3
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+ import { CodeBlockCopyData } from "@farming-labs/docs";
4
5
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
5
6
  import * as fumadocs_ui_components_codeblock0 from "fumadocs-ui/components/codeblock";
6
7
  import defaultMdxComponents from "fumadocs-ui/mdx";
@@ -16,22 +17,26 @@ declare const extendedMdxComponents: {
16
17
  CodeBlockTabs: typeof fumadocs_ui_components_codeblock0.CodeBlockTabs;
17
18
  CodeBlockTabsList: typeof fumadocs_ui_components_codeblock0.CodeBlockTabsList;
18
19
  CodeBlockTabsTrigger: typeof fumadocs_ui_components_codeblock0.CodeBlockTabsTrigger;
19
- pre: (props: react.HTMLAttributes<HTMLPreElement>) => react_jsx_runtime0.JSX.Element;
20
+ pre: (props: React.HTMLAttributes<HTMLPreElement>) => react_jsx_runtime0.JSX.Element;
20
21
  Card: typeof fumadocs_ui_components_card0.Card;
21
22
  Cards: typeof fumadocs_ui_components_card0.Cards;
22
- a: react.FC<react.AnchorHTMLAttributes<HTMLAnchorElement>>;
23
- h1: (props: react.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
24
- h2: (props: react.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
25
- h3: (props: react.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
26
- h4: (props: react.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
27
- h5: (props: react.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
28
- h6: (props: react.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
29
- table: (props: react.TableHTMLAttributes<HTMLTableElement>) => react_jsx_runtime0.JSX.Element;
23
+ a: React.FC<React.AnchorHTMLAttributes<HTMLAnchorElement>>;
24
+ h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
25
+ h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
26
+ h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
27
+ h4: (props: React.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
28
+ h5: (props: React.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
29
+ h6: (props: React.HTMLAttributes<HTMLHeadingElement>) => react_jsx_runtime0.JSX.Element;
30
+ table: (props: React.TableHTMLAttributes<HTMLTableElement>) => react_jsx_runtime0.JSX.Element;
30
31
  Callout: typeof fumadocs_ui_components_callout0.Callout;
31
32
  CalloutContainer: typeof fumadocs_ui_components_callout0.CalloutContainer;
32
33
  CalloutTitle: typeof fumadocs_ui_components_callout0.CalloutTitle;
33
34
  CalloutDescription: typeof fumadocs_ui_components_callout0.CalloutDescription;
34
35
  };
35
- declare function getMDXComponents<T extends Record<string, unknown> = Record<string, unknown>>(overrides?: T): typeof extendedMdxComponents & T;
36
+ interface GetMDXComponentsOptions {
37
+ /** Called when the user clicks the copy button on a code block (in addition to the default copy). */
38
+ onCopyClick?: (data: CodeBlockCopyData) => void;
39
+ }
40
+ declare function getMDXComponents<T extends Record<string, unknown> = Record<string, unknown>>(overrides?: T, options?: GetMDXComponentsOptions): typeof extendedMdxComponents & T;
36
41
  //#endregion
37
- export { Tab, Tabs, defaultMdxComponents, extendedMdxComponents, getMDXComponents };
42
+ export { GetMDXComponentsOptions, Tab, Tabs, defaultMdxComponents, extendedMdxComponents, getMDXComponents };
package/dist/mdx.mjs CHANGED
@@ -1,30 +1,25 @@
1
+ import { createPreWithCopyCallback } from "./code-block-copy-wrapper.mjs";
1
2
  import { MDXImg } from "./mdx-img.mjs";
2
3
  import { Tab, Tabs } from "fumadocs-ui/components/tabs";
3
4
  import defaultMdxComponents from "fumadocs-ui/mdx";
4
5
 
5
6
  //#region src/mdx.ts
6
- /**
7
- * Re-export fumadocs-ui MDX components.
8
- *
9
- * Includes all default MDX components (headings, code blocks, callouts, cards)
10
- * plus Tabs/Tab for tabbed content and InstallTabs for package manager tabs.
11
- * Overrides `img` so that ![alt](url) in markdown works without width/height
12
- * (uses Next Image with unoptimized + default dimensions for external URLs).
13
- *
14
- * Usage in mdx-components.tsx:
15
- * import { getMDXComponents } from "@farming-labs/theme/mdx";
16
- */
17
7
  const extendedMdxComponents = {
18
8
  ...defaultMdxComponents,
19
9
  img: MDXImg,
20
10
  Tab,
21
11
  Tabs
22
12
  };
23
- function getMDXComponents(overrides) {
24
- return {
13
+ function getMDXComponents(overrides, options) {
14
+ const base = {
25
15
  ...extendedMdxComponents,
26
16
  ...overrides
27
17
  };
18
+ if (options?.onCopyClick) {
19
+ const DefaultPre = defaultMdxComponents.pre;
20
+ if (DefaultPre) base.pre = createPreWithCopyCallback(DefaultPre, options.onCopyClick);
21
+ }
22
+ return base;
28
23
  }
29
24
 
30
25
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -103,7 +103,7 @@
103
103
  "next": ">=14.0.0",
104
104
  "tsdown": "^0.20.3",
105
105
  "typescript": "^5.9.3",
106
- "@farming-labs/docs": "0.0.9"
106
+ "@farming-labs/docs": "0.0.11"
107
107
  },
108
108
  "peerDependencies": {
109
109
  "@farming-labs/docs": ">=0.0.1",