@usezanin/blog 0.1.0 → 0.3.0

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.
package/README.md CHANGED
@@ -8,7 +8,7 @@ npm install @usezanin/blog
8
8
 
9
9
  ## Setup
10
10
 
11
- Env vars: `ZANIN_BASE_URL`, `ZANIN_SITE_ID`, `ZANIN_SITE_KEY` (from the Zanin dashboard), optionally `ZANIN_SITE_URL` (your site's public origin, for canonical URLs/RSS) and `ZANIN_REVALIDATE_SECRET`.
11
+ Env vars: `ZANIN_BASE_URL`, `ZANIN_SITE_ID`, `ZANIN_SITE_KEY` (from the Zanin dashboard), optionally `ZANIN_SITE_URL` (your site's public origin, for canonical URLs/RSS) and `ZANIN_REVALIDATE_SECRET`. Rendering only reads, so make `ZANIN_SITE_KEY` a **read-only key scoped to this site** (Settings → API keys) rather than a full-write workspace credential.
12
12
 
13
13
  ```tsx
14
14
  // app/layout.tsx — import the themable styles once
@@ -57,9 +57,50 @@ import { createRevalidateHandler } from "@usezanin/blog";
57
57
  export const POST = createRevalidateHandler();
58
58
  ```
59
59
 
60
+ ### Static export (`output: "export"`)
61
+
62
+ Statically exported sites have no server at runtime, so:
63
+
64
+ ```ts
65
+ // app/blog/rss.xml/route.ts — add force-static so the file is emitted at build time
66
+ import { createRssHandler } from "@usezanin/blog";
67
+ export const dynamic = "force-static";
68
+ export const GET = createRssHandler();
69
+ // same for app/blog/sitemap.xml/route.ts
70
+ ```
71
+
72
+ Skip `createRevalidateHandler` entirely — there is no ISR cache to bust. Instead point the site's revalidate webhook URL (Zanin dashboard → Settings → Sites) at a [Vercel Deploy Hook](https://vercel.com/docs/deploy-hooks) (or your CI's equivalent): publishing a post then triggers a rebuild that pulls fresh content through `generateStaticParams`. The build environment needs `ZANIN_SITE_KEY` — use a read-only site-scoped key.
73
+
74
+ ## Theming — fully customizable
75
+
76
+ Blogs are themable end to end: colors, fonts, sizes, spacing, radius, content width, and index layout.
77
+
78
+ 1. **Dashboard / agents (recommended)** — set the theme per site in the Zanin dashboard ("Customize theme") or let agents call the `update_site_theme` MCP tool. The SDK fetches it with the content and re-renders instantly via the revalidation webhook. No deploy.
79
+ 2. **Host code overrides** — pass `theme` in the config (wins over the dashboard theme):
80
+
81
+ ```ts
82
+ const config = {
83
+ theme: {
84
+ accent: "#0a7d54",
85
+ fontHeading: "'Playfair Display', Georgia, serif", // load the font in your layout
86
+ fontBody: "Inter, sans-serif",
87
+ measure: "680px",
88
+ radius: "16px",
89
+ spacing: "relaxed", // compact | comfortable | relaxed
90
+ indexLayout: "grid", // list | grid
91
+ },
92
+ } satisfies ZaninBlogConfig;
93
+ ```
94
+
95
+ 3. **Plain CSS** — every value is a `--zanin-*` CSS variable on `.zanin-blog`; override any of them (or restyle `.zanin-*` component classes) in your own stylesheet.
96
+ 4. **Fully headless** — build your own layouts with the exported data helpers and pieces: `getBlogPosts()`, `getBlogPost(slug)`, `getBlogSite()` (includes the theme), `PostCard`, `renderMdx`, `builtinComponents`, `themeToStyle`.
97
+
98
+ Custom fonts: load them however you like (`next/font`, `<link>` tags) and reference the family name in `fontHeading` / `fontBody` / `fontMono`.
99
+
60
100
  ## What you get
61
101
 
62
- - Server-rendered MDX with built-in components: `Callout`, `Figure`, `Chart` (bar/line/area/pie from inline data), `CTA`, `YouTube`, `Tweet`, `ComparisonTable`, `FAQ` (with FAQPage JSON-LD), styled code blocks
102
+ - Server-rendered MDX with built-in components: `Callout`, `Figure`, `Chart` (bar/line/area/pie from inline data), `CTA`, `YouTube`, `Tweet`, `ComparisonTable`, `FAQ` (takes `items={[{ q, a }]}` and emits FAQPage JSON-LD), styled code blocks — exact prop tables live in `builtinComponentDocs` (re-exported here), the `get_builtin_components` MCP tool, and the deployed `/docs` page
103
+ - `validateMdx(source, { knownComponents })` — the same compiler `BlogPost` uses, as a linter: MDX errors, unknown component tags, unknown/missing props on built-ins
63
104
  - Per-site custom components: agents upload TSX to the CMS; the SDK loads the compiled result at render time — no redeploy
64
105
  - SEO: canonical/OG/Twitter metadata, JSON-LD Article schema, static params for SSG, RSS + sitemap
65
106
  - ISR with instant, webhook-driven revalidation on publish
@@ -1,9 +1,17 @@
1
+ import type { Post } from "@usezanin/client";
1
2
  import { type ZaninBlogConfig } from "./config.js";
3
+ /** One entry in the blog index; exported for fully custom index layouts. */
4
+ export declare function PostCard({ post, basePath }: {
5
+ post: Post;
6
+ basePath?: string;
7
+ }): import("react").JSX.Element;
2
8
  export interface BlogIndexProps {
3
9
  config?: ZaninBlogConfig;
4
10
  title?: string;
5
11
  description?: string;
12
+ /** Overrides the themed index layout for this page only. */
13
+ layout?: "list" | "grid";
6
14
  }
7
15
  /** Server component: renders the list of published posts. */
8
- export declare function BlogIndex({ config, title, description }: BlogIndexProps): Promise<import("react").JSX.Element>;
16
+ export declare function BlogIndex({ config, title, description, layout }: BlogIndexProps): Promise<import("react").JSX.Element>;
9
17
  //# sourceMappingURL=BlogIndex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlogIndex.d.ts","sourceRoot":"","sources":["../src/BlogIndex.tsx"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAiClE,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,6DAA6D;AAC7D,wBAAsB,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,cAAc,wCAqB7E"}
1
+ {"version":3,"file":"BlogIndex.d.ts","sourceRoot":"","sources":["../src/BlogIndex.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAYlE,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAkB,EAAE,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,+BAuBvF;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED,6DAA6D;AAC7D,wBAAsB,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,cAAc,wCA2BrF"}
package/dist/BlogIndex.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { resolveConfig } from "./config.js";
3
- import { fetchPublishedPosts } from "./data.js";
3
+ import { fetchPublishedPosts, fetchSite } from "./data.js";
4
+ import { indexLayoutClass, mergeThemes, themeToStyle } from "./theme.js";
4
5
  function formatDate(iso) {
5
6
  return new Date(iso).toLocaleDateString("en-US", {
6
7
  year: "numeric",
@@ -8,14 +9,21 @@ function formatDate(iso) {
8
9
  day: "numeric",
9
10
  });
10
11
  }
11
- function PostCard({ post, basePath }) {
12
+ /** One entry in the blog index; exported for fully custom index layouts. */
13
+ export function PostCard({ post, basePath = "/blog" }) {
12
14
  const href = `${basePath}/${post.slug}`.replace(/\/{2,}/g, "/");
13
- return (_jsx("article", { className: "zanin-index-item", children: _jsxs("a", { href: href, children: [_jsxs("div", { className: "zanin-index-meta", children: [_jsx("time", { dateTime: post.publishedAt ?? undefined, children: formatDate(post.publishedAt ?? post.createdAt) }), post.tags.slice(0, 3).map((tag) => (_jsx("span", { className: "zanin-tag", children: tag }, tag)))] }), _jsx("h2", { children: post.title }), post.description && _jsx("p", { children: post.description })] }) }));
15
+ return (_jsx("article", { className: "zanin-index-item", children: _jsxs("a", { href: href, children: [_jsxs("div", { className: "zanin-index-meta", children: [_jsx("time", { dateTime: post.publishedAt ?? undefined, children: formatDate(post.publishedAt ?? post.createdAt) }), post.tags.slice(0, 3).map((tag) => (_jsx("span", { className: "zanin-tag", children: tag }, tag)))] }), _jsx("h2", { children: post.title }), post.description && _jsx("p", { children: post.description }), _jsx("span", { className: "zanin-index-more", "aria-hidden": true, children: "Read more \u2192" })] }) }));
14
16
  }
15
17
  /** Server component: renders the list of published posts. */
16
- export async function BlogIndex({ config, title, description }) {
18
+ export async function BlogIndex({ config, title, description, layout }) {
17
19
  const resolved = resolveConfig(config);
18
- const posts = await fetchPublishedPosts(resolved);
19
- return (_jsxs("div", { className: "zanin-blog zanin-index", children: [_jsxs("header", { className: "zanin-index-header", children: [_jsx("h1", { children: title ?? "Blog" }), description && _jsx("p", { children: description })] }), posts.length === 0 ? (_jsx("p", { className: "zanin-index-empty", children: "No posts yet." })) : (_jsx("div", { className: "zanin-index-list", children: posts.map((post) => (_jsx(PostCard, { post: post, basePath: resolved.basePath }, post.id))) }))] }));
20
+ const [posts, site] = await Promise.all([
21
+ fetchPublishedPosts(resolved),
22
+ fetchSite(resolved),
23
+ ]);
24
+ const theme = mergeThemes(site?.theme, resolved.theme);
25
+ if (layout)
26
+ theme.indexLayout = layout;
27
+ return (_jsxs("div", { className: `zanin-blog zanin-index ${indexLayoutClass(theme)}`, style: themeToStyle(theme), children: [_jsxs("header", { className: "zanin-index-header", children: [_jsx("h1", { children: title ?? "Blog" }), description && _jsx("p", { children: description })] }), posts.length === 0 ? (_jsx("p", { className: "zanin-index-empty", children: "No posts yet." })) : (_jsx("div", { className: "zanin-index-list", children: posts.map((post) => (_jsx(PostCard, { post: post, basePath: resolved.basePath }, post.id))) }))] }));
20
28
  }
21
29
  //# sourceMappingURL=BlogIndex.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlogIndex.js","sourceRoot":"","sources":["../src/BlogIndex.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC/C,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;KACf,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAoC;IACpE,MAAM,IAAI,GAAG,GAAG,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChE,OAAO,CACL,kBAAS,SAAS,EAAC,kBAAkB,YACnC,aAAG,IAAI,EAAE,IAAI,aACX,eAAK,SAAS,EAAC,kBAAkB,aAC/B,eAAM,QAAQ,EAAE,IAAI,CAAC,WAAW,IAAI,SAAS,YAC1C,UAAU,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,GAC1C,EACN,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAClC,eAAgB,SAAS,EAAC,WAAW,YAClC,GAAG,IADK,GAAG,CAEP,CACR,CAAC,IACE,EACN,uBAAK,IAAI,CAAC,KAAK,GAAM,EACpB,IAAI,CAAC,WAAW,IAAI,sBAAI,IAAI,CAAC,WAAW,GAAK,IAC5C,GACI,CACX,CAAC;AACJ,CAAC;AAQD,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAkB;IAC5E,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAElD,OAAO,CACL,eAAK,SAAS,EAAC,wBAAwB,aACrC,kBAAQ,SAAS,EAAC,oBAAoB,aACpC,uBAAK,KAAK,IAAI,MAAM,GAAM,EACzB,WAAW,IAAI,sBAAI,WAAW,GAAK,IAC7B,EACR,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACpB,YAAG,SAAS,EAAC,mBAAmB,8BAAkB,CACnD,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,kBAAkB,YAC9B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,QAAQ,IAAe,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAhD,IAAI,CAAC,EAAE,CAA6C,CACpE,CAAC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"BlogIndex.js","sourceRoot":"","sources":["../src/BlogIndex.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzE,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC/C,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;KACf,CAAC,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,EAAqC;IACtF,MAAM,IAAI,GAAG,GAAG,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChE,OAAO,CACL,kBAAS,SAAS,EAAC,kBAAkB,YACnC,aAAG,IAAI,EAAE,IAAI,aACX,eAAK,SAAS,EAAC,kBAAkB,aAC/B,eAAM,QAAQ,EAAE,IAAI,CAAC,WAAW,IAAI,SAAS,YAC1C,UAAU,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,GAC1C,EACN,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAClC,eAAgB,SAAS,EAAC,WAAW,YAClC,GAAG,IADK,GAAG,CAEP,CACR,CAAC,IACE,EACN,uBAAK,IAAI,CAAC,KAAK,GAAM,EACpB,IAAI,CAAC,WAAW,IAAI,sBAAI,IAAI,CAAC,WAAW,GAAK,EAC9C,eAAM,SAAS,EAAC,kBAAkB,sDAE3B,IACL,GACI,CACX,CAAC;AACJ,CAAC;AAUD,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAkB;IACpF,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtC,mBAAmB,CAAC,QAAQ,CAAC;QAC7B,SAAS,CAAC,QAAQ,CAAC;KACpB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,MAAM;QAAE,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC;IAEvC,OAAO,CACL,eAAK,SAAS,EAAE,0BAA0B,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,aAC7F,kBAAQ,SAAS,EAAC,oBAAoB,aACpC,uBAAK,KAAK,IAAI,MAAM,GAAM,EACzB,WAAW,IAAI,sBAAI,WAAW,GAAK,IAC7B,EACR,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACpB,YAAG,SAAS,EAAC,mBAAmB,8BAAkB,CACnD,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,kBAAkB,YAC9B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,QAAQ,IAAe,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAhD,IAAI,CAAC,EAAE,CAA6C,CACpE,CAAC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"BlogPost.d.ts","sourceRoot":"","sources":["../src/BlogPost.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAiBlE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,aAAa,wCAyDzE"}
1
+ {"version":3,"file":"BlogPost.d.ts","sourceRoot":"","sources":["../src/BlogPost.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAkBlE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,aAAa,wCA4DzE"}
package/dist/BlogPost.js CHANGED
@@ -2,8 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { notFound } from "next/navigation";
3
3
  import { resolveConfig } from "./config.js";
4
4
  import { fetchCustomComponents } from "./custom-components.js";
5
- import { fetchPublishedPost, postUrl } from "./data.js";
5
+ import { fetchPublishedPost, fetchSite, postUrl } from "./data.js";
6
6
  import { renderMdx } from "./mdx.js";
7
+ import { mergeThemes, themeToStyle } from "./theme.js";
7
8
  function formatDate(iso) {
8
9
  return new Date(iso).toLocaleDateString("en-US", {
9
10
  year: "numeric",
@@ -20,12 +21,14 @@ function readingTime(body) {
20
21
  */
21
22
  export async function BlogPost({ slug, config, components }) {
22
23
  const resolved = resolveConfig(config);
23
- const [post, customComponents] = await Promise.all([
24
+ const [post, customComponents, site] = await Promise.all([
24
25
  fetchPublishedPost(resolved, slug),
25
26
  fetchCustomComponents(resolved),
27
+ fetchSite(resolved),
26
28
  ]);
27
29
  if (!post)
28
30
  notFound();
31
+ const theme = mergeThemes(site?.theme, resolved.theme);
29
32
  // Precedence: built-ins < site custom components < host overrides.
30
33
  const content = await renderMdx(post.body ?? "", {
31
34
  ...customComponents,
@@ -48,6 +51,6 @@ export async function BlogPost({ slug, config, components }) {
48
51
  }
49
52
  : {}),
50
53
  };
51
- return (_jsxs("article", { className: "zanin-blog zanin-post", children: [_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(jsonLd) } }), _jsxs("header", { className: "zanin-post-header", children: [_jsxs("div", { className: "zanin-post-meta", children: [_jsx("time", { dateTime: post.publishedAt ?? undefined, children: formatDate(post.publishedAt ?? post.createdAt) }), _jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsxs("span", { children: [readingTime(post.body ?? ""), " min read"] }), post.tags.slice(0, 3).map((tag) => (_jsx("span", { className: "zanin-tag", children: tag }, tag)))] }), _jsx("h1", { children: post.title }), post.description && _jsx("p", { className: "zanin-post-lede", children: post.description })] }), _jsx("div", { className: "zanin-prose", children: content })] }));
54
+ return (_jsxs("article", { className: "zanin-blog zanin-post", style: themeToStyle(theme), children: [_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(jsonLd) } }), _jsxs("header", { className: "zanin-post-header", children: [_jsxs("div", { className: "zanin-post-meta", children: [_jsx("time", { dateTime: post.publishedAt ?? undefined, children: formatDate(post.publishedAt ?? post.createdAt) }), _jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsxs("span", { children: [readingTime(post.body ?? ""), " min read"] }), post.tags.slice(0, 3).map((tag) => (_jsx("span", { className: "zanin-tag", children: tag }, tag)))] }), _jsx("h1", { children: post.title }), post.description && _jsx("p", { className: "zanin-post-lede", children: post.description })] }), _jsx("div", { className: "zanin-prose", children: content })] }));
52
55
  }
53
56
  //# sourceMappingURL=BlogPost.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlogPost.js","sourceRoot":"","sources":["../src/BlogPost.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BlogPost.js","sourceRoot":"","sources":["../src/BlogPost.tsx"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, Legend, Line, LineChart, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from "recharts";
4
4
  const DEFAULT_COLORS = [
5
- "var(--zanin-accent, #2563eb)",
5
+ "var(--zanin-accent, #005bd3)",
6
6
  "#0ea5e9",
7
7
  "#8b5cf6",
8
8
  "#f59e0b",
package/dist/config.d.ts CHANGED
@@ -1,9 +1,18 @@
1
+ import type { ZaninTheme } from "@usezanin/client";
1
2
  export interface ZaninBlogConfig {
3
+ /**
4
+ * Theme overrides applied on top of the theme configured in the Zanin
5
+ * dashboard (colors, fonts, layout). Highest precedence.
6
+ */
7
+ theme?: ZaninTheme;
2
8
  /** Base URL of the Zanin CMS deployment. Falls back to ZANIN_BASE_URL. */
3
9
  baseUrl?: string;
4
10
  /** Site id from the Zanin dashboard. Falls back to ZANIN_SITE_ID. */
5
11
  siteId?: string;
6
- /** Workspace API key ("zn_..."). Falls back to ZANIN_SITE_KEY / ZANIN_API_KEY. */
12
+ /**
13
+ * API key ("zn_..."). Falls back to ZANIN_SITE_KEY / ZANIN_API_KEY.
14
+ * Rendering only reads, so use a read-only key scoped to this site.
15
+ */
7
16
  apiKey?: string;
8
17
  /** Path the blog is mounted at in the host site. Default "/blog". */
9
18
  basePath?: string;
@@ -25,6 +34,7 @@ export interface ResolvedZaninBlogConfig {
25
34
  siteName?: string;
26
35
  revalidate: number | false;
27
36
  revalidateSecret?: string;
37
+ theme?: ZaninTheme;
28
38
  }
29
39
  export declare function resolveConfig(config?: ZaninBlogConfig): ResolvedZaninBlogConfig;
30
40
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wIAAwI;IACxI,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,kHAAkH;IAClH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,aAAa,CAAC,MAAM,GAAE,eAAoB,GAAG,uBAAuB,CAsBnF"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wIAAwI;IACxI,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B,kHAAkH;IAClH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,MAAM,GAAE,eAAoB,GAAG,uBAAuB,CAuBnF"}
package/dist/config.js CHANGED
@@ -18,6 +18,7 @@ export function resolveConfig(config = {}) {
18
18
  siteName: config.siteName,
19
19
  revalidate: config.revalidate ?? 300,
20
20
  revalidateSecret: config.revalidateSecret ?? process.env.ZANIN_REVALIDATE_SECRET,
21
+ theme: config.theme,
21
22
  };
22
23
  }
23
24
  function normalizeBasePath(path) {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA8BA,MAAM,UAAU,aAAa,CAAC,SAA0B,EAAE;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC1D,MAAM,MAAM,GACV,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAE3E,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACzF,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACtF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,MAAM;QACN,MAAM;QACN,QAAQ,EAAE,iBAAiB,CAAC,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC;QACvD,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5E,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,GAAG;QACpC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB;KACjF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7D,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAyCA,MAAM,UAAU,aAAa,CAAC,SAA0B,EAAE;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC1D,MAAM,MAAM,GACV,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAE3E,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACzF,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACtF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,MAAM;QACN,MAAM;QACN,QAAQ,EAAE,iBAAiB,CAAC,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC;QACvD,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5E,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,GAAG;QACpC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB;QAChF,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7D,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAChD,CAAC"}
package/dist/data.d.ts CHANGED
@@ -5,5 +5,7 @@ export declare const ZANIN_CACHE_TAG = "zanin-blog";
5
5
  export declare function createClient(config: ResolvedZaninBlogConfig): ZaninClient;
6
6
  export declare function fetchPublishedPosts(config: ResolvedZaninBlogConfig): Promise<Post[]>;
7
7
  export declare function fetchPublishedPost(config: ResolvedZaninBlogConfig, slug: string): Promise<Post | null>;
8
+ /** The site record carries the dashboard-configured theme. */
9
+ export declare function fetchSite(config: ResolvedZaninBlogConfig): Promise<import("@usezanin/client").Site | null>;
8
10
  export declare function postUrl(config: ResolvedZaninBlogConfig, slug: string): string;
9
11
  //# sourceMappingURL=data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,qFAAqF;AACrF,eAAO,MAAM,eAAe,eAAe,CAAC;AAY5C,wBAAgB,YAAY,CAAC,MAAM,EAAE,uBAAuB,GAAG,WAAW,CAMzE;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,IAAI,EAAE,CAAC,CAUjB;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,uBAAuB,EAC/B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAItB;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7E"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,qFAAqF;AACrF,eAAO,MAAM,eAAe,eAAe,CAAC;AAY5C,wBAAgB,YAAY,CAAC,MAAM,EAAE,uBAAuB,GAAG,WAAW,CAMzE;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,IAAI,EAAE,CAAC,CAUjB;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,uBAAuB,EAC/B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAItB;AAED,8DAA8D;AAC9D,wBAAsB,SAAS,CAAC,MAAM,EAAE,uBAAuB,mDAO9D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7E"}
package/dist/data.js CHANGED
@@ -29,6 +29,16 @@ export async function fetchPublishedPost(config, slug) {
29
29
  status: "published",
30
30
  });
31
31
  }
32
+ /** The site record carries the dashboard-configured theme. */
33
+ export async function fetchSite(config) {
34
+ try {
35
+ return await createClient(config).getSite(config.siteId);
36
+ }
37
+ catch (err) {
38
+ console.error("[@usezanin/blog] Failed to fetch site (theme falls back to defaults):", err);
39
+ return null;
40
+ }
41
+ }
32
42
  export function postUrl(config, slug) {
33
43
  const path = `${config.basePath}/${slug}`.replace(/\/{2,}/g, "/");
34
44
  return config.siteUrl ? `${config.siteUrl}${path}` : path;
package/dist/data.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAa,MAAM,kBAAkB,CAAC;AAG1D,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC;AAE5C,SAAS,WAAW,CAAC,MAA+B;IAClD,yEAAyE;IACzE,qEAAqE;IACrE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CACrB,KAAK,CAAC,KAAK,EAAE;QACX,GAAG,IAAI;QACP,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,EAAE;KAClD,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAA+B;IAC1D,OAAO,IAAI,WAAW,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;KAC3B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAA+B;IAE/B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE;QAChE,MAAM,EAAE,WAAW;QACnB,KAAK,EAAE,GAAG;KACX,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CACpB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;QAChD,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CACnD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAA+B,EAC/B,IAAY;IAEZ,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE;QAC7D,MAAM,EAAE,WAAW;KACpB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAA+B,EAAE,IAAY;IACnE,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5D,CAAC"}
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAa,MAAM,kBAAkB,CAAC;AAG1D,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC;AAE5C,SAAS,WAAW,CAAC,MAA+B;IAClD,yEAAyE;IACzE,qEAAqE;IACrE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CACrB,KAAK,CAAC,KAAK,EAAE;QACX,GAAG,IAAI;QACP,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,EAAE;KAClD,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAA+B;IAC1D,OAAO,IAAI,WAAW,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;KAC3B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAA+B;IAE/B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE;QAChE,MAAM,EAAE,WAAW;QACnB,KAAK,EAAE,GAAG;KACX,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CACpB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;QAChD,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CACnD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAA+B,EAC/B,IAAY;IAEZ,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE;QAC7D,MAAM,EAAE,WAAW;KACpB,CAAC,CAAC;AACL,CAAC;AAED,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAA+B;IAC7D,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,uEAAuE,EAAE,GAAG,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAA+B,EAAE,IAAY;IACnE,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Post, Site } from "@usezanin/client";
2
+ import { type ZaninBlogConfig } from "./config.js";
3
+ /**
4
+ * Headless data helpers for fully custom blog UIs: fetch the content with
5
+ * these, render however you like (renderMdx + builtinComponents are exported
6
+ * too). All requests share the SDK's ISR caching and revalidation webhook.
7
+ */
8
+ /** All published posts (sorted newest first, bodies excluded). */
9
+ export declare function getBlogPosts(config?: ZaninBlogConfig): Promise<Post[]>;
10
+ /** One published post by slug, including its MDX body; null when not found. */
11
+ export declare function getBlogPost(slug: string, config?: ZaninBlogConfig): Promise<Post | null>;
12
+ /** The site record, including the dashboard-configured theme. */
13
+ export declare function getBlogSite(config?: ZaninBlogConfig): Promise<Site | null>;
14
+ //# sourceMappingURL=headless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../src/headless.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAGlE;;;;GAIG;AAEH,kEAAkE;AAClE,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAE5E;AAED,+EAA+E;AAC/E,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAEtB;AAED,iEAAiE;AACjE,wBAAsB,WAAW,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAEhF"}
@@ -0,0 +1,20 @@
1
+ import { resolveConfig } from "./config.js";
2
+ import { fetchPublishedPost, fetchPublishedPosts, fetchSite } from "./data.js";
3
+ /**
4
+ * Headless data helpers for fully custom blog UIs: fetch the content with
5
+ * these, render however you like (renderMdx + builtinComponents are exported
6
+ * too). All requests share the SDK's ISR caching and revalidation webhook.
7
+ */
8
+ /** All published posts (sorted newest first, bodies excluded). */
9
+ export async function getBlogPosts(config) {
10
+ return fetchPublishedPosts(resolveConfig(config));
11
+ }
12
+ /** One published post by slug, including its MDX body; null when not found. */
13
+ export async function getBlogPost(slug, config) {
14
+ return fetchPublishedPost(resolveConfig(config), slug);
15
+ }
16
+ /** The site record, including the dashboard-configured theme. */
17
+ export async function getBlogSite(config) {
18
+ return fetchSite(resolveConfig(config));
19
+ }
20
+ //# sourceMappingURL=headless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.js","sourceRoot":"","sources":["../src/headless.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE/E;;;;GAIG;AAEH,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAwB;IACzD,OAAO,mBAAmB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,MAAwB;IAExB,OAAO,kBAAkB,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAwB;IACxD,OAAO,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,14 @@
1
- export { BlogIndex, type BlogIndexProps } from "./BlogIndex.js";
1
+ export { BlogIndex, PostCard, type BlogIndexProps } from "./BlogIndex.js";
2
2
  export { BlogPost, type BlogPostProps } from "./BlogPost.js";
3
3
  export { resolveConfig, type ZaninBlogConfig } from "./config.js";
4
4
  export { ZANIN_CACHE_TAG } from "./data.js";
5
+ export { getBlogPost, getBlogPosts, getBlogSite } from "./headless.js";
6
+ export { indexLayoutClass, mergeThemes, themeToStyle, type ZaninTheme } from "./theme.js";
5
7
  export { createRevalidateHandler, createRssHandler, createSitemapHandler, } from "./handlers.js";
6
8
  export { fetchCustomComponents } from "./custom-components.js";
7
9
  export { builtinComponents, renderMdx } from "./mdx.js";
10
+ export { validateMdx, type MdxIssue, type MdxValidation, type ValidateMdxOptions, } from "./validate.js";
11
+ export { builtinComponentDocs, builtinComponentNames, type BuiltinComponentDoc, type BuiltinComponentProp, } from "@usezanin/client";
8
12
  export { generateBlogMetadata, generateBlogStaticParams } from "./seo.js";
9
13
  export { Callout } from "./components/Callout.js";
10
14
  export { Chart, type ChartProps } from "./components/Chart.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1F,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EACL,WAAW,EACX,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
- export { BlogIndex } from "./BlogIndex.js";
1
+ export { BlogIndex, PostCard } from "./BlogIndex.js";
2
2
  export { BlogPost } from "./BlogPost.js";
3
3
  export { resolveConfig } from "./config.js";
4
4
  export { ZANIN_CACHE_TAG } from "./data.js";
5
+ export { getBlogPost, getBlogPosts, getBlogSite } from "./headless.js";
6
+ export { indexLayoutClass, mergeThemes, themeToStyle } from "./theme.js";
5
7
  export { createRevalidateHandler, createRssHandler, createSitemapHandler, } from "./handlers.js";
6
8
  export { fetchCustomComponents } from "./custom-components.js";
7
9
  export { builtinComponents, renderMdx } from "./mdx.js";
10
+ export { validateMdx, } from "./validate.js";
11
+ export { builtinComponentDocs, builtinComponentNames, } from "@usezanin/client";
8
12
  export { generateBlogMetadata, generateBlogStaticParams } from "./seo.js";
9
13
  export { Callout } from "./components/Callout.js";
10
14
  export { Chart } from "./components/Chart.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAuB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAsB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAgB,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAuB,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAsB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAmB,MAAM,YAAY,CAAC;AAC1F,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EACL,WAAW,GAIZ,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GAGtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAgB,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ZaninTheme } from "@usezanin/client";
2
+ export type { ZaninTheme };
3
+ /** Host theme wins over the CMS theme; both win over stylesheet defaults. */
4
+ export declare function mergeThemes(cmsTheme: ZaninTheme | null | undefined, hostTheme: ZaninTheme | undefined): ZaninTheme;
5
+ /**
6
+ * Converts a theme to inline CSS-variable overrides for the .zanin-blog
7
+ * wrapper. Every value lands in a CSS custom property (never a property),
8
+ * so arbitrary values cannot escape the declaration.
9
+ */
10
+ export declare function themeToStyle(theme: ZaninTheme): Record<string, string>;
11
+ export declare function indexLayoutClass(theme: ZaninTheme): string;
12
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,YAAY,EAAE,UAAU,EAAE,CAAC;AA0B3B,6EAA6E;AAC7E,wBAAgB,WAAW,CACzB,QAAQ,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACvC,SAAS,EAAE,UAAU,GAAG,SAAS,GAChC,UAAU,CAEZ;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYtE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAE1D"}
package/dist/theme.js ADDED
@@ -0,0 +1,48 @@
1
+ /** Direct theme-field → CSS-variable mappings. */
2
+ const VAR_MAP = {
3
+ "--zanin-accent": "accent",
4
+ "--zanin-canvas": "background",
5
+ "--zanin-surface": "surface",
6
+ "--zanin-ink": "text",
7
+ "--zanin-ink-muted": "textMuted",
8
+ "--zanin-ink-faint": "textFaint",
9
+ "--zanin-hairline": "border",
10
+ "--zanin-font-body": "fontBody",
11
+ "--zanin-font-heading": "fontHeading",
12
+ "--zanin-font-mono": "fontMono",
13
+ "--zanin-base-size": "baseFontSize",
14
+ "--zanin-heading-weight": "headingWeight",
15
+ "--zanin-measure": "measure",
16
+ "--zanin-radius": "radius",
17
+ };
18
+ const SPACING_SCALE = {
19
+ compact: "0.8",
20
+ comfortable: "1",
21
+ relaxed: "1.3",
22
+ };
23
+ /** Host theme wins over the CMS theme; both win over stylesheet defaults. */
24
+ export function mergeThemes(cmsTheme, hostTheme) {
25
+ return { ...(cmsTheme ?? {}), ...(hostTheme ?? {}) };
26
+ }
27
+ /**
28
+ * Converts a theme to inline CSS-variable overrides for the .zanin-blog
29
+ * wrapper. Every value lands in a CSS custom property (never a property),
30
+ * so arbitrary values cannot escape the declaration.
31
+ */
32
+ export function themeToStyle(theme) {
33
+ const style = {};
34
+ for (const [cssVar, field] of Object.entries(VAR_MAP)) {
35
+ const value = theme[field];
36
+ if (typeof value === "string" && value.trim()) {
37
+ style[cssVar] = value.trim().replace(/[{};]/g, "");
38
+ }
39
+ }
40
+ if (theme.spacing) {
41
+ style["--zanin-space"] = SPACING_SCALE[theme.spacing];
42
+ }
43
+ return style;
44
+ }
45
+ export function indexLayoutClass(theme) {
46
+ return theme.indexLayout === "grid" ? "zanin-index--grid" : "zanin-index--list";
47
+ }
48
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAIA,kDAAkD;AAClD,MAAM,OAAO,GAAqC;IAChD,gBAAgB,EAAE,QAAQ;IAC1B,gBAAgB,EAAE,YAAY;IAC9B,iBAAiB,EAAE,SAAS;IAC5B,aAAa,EAAE,MAAM;IACrB,mBAAmB,EAAE,WAAW;IAChC,mBAAmB,EAAE,WAAW;IAChC,kBAAkB,EAAE,QAAQ;IAC5B,mBAAmB,EAAE,UAAU;IAC/B,sBAAsB,EAAE,aAAa;IACrC,mBAAmB,EAAE,UAAU;IAC/B,mBAAmB,EAAE,cAAc;IACnC,wBAAwB,EAAE,eAAe;IACzC,iBAAiB,EAAE,SAAS;IAC5B,gBAAgB,EAAE,QAAQ;CAC3B,CAAC;AAEF,MAAM,aAAa,GAAuD;IACxE,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,GAAG;IAChB,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CACzB,QAAuC,EACvC,SAAiC;IAEjC,OAAO,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAiB;IAC5C,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAC9C,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,KAAK,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,OAAO,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAAC;AAClF,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type MdxIssue, type MdxValidation } from "@usezanin/client";
2
+ export type { MdxIssue, MdxValidation };
3
+ export interface ValidateMdxOptions {
4
+ /**
5
+ * Component tags available besides the built-ins (per-site custom
6
+ * components and/or host-provided components).
7
+ */
8
+ knownComponents?: string[];
9
+ }
10
+ /**
11
+ * Validates an MDX post body with the exact pipeline the SDK uses to render
12
+ * it (@mdx-js/mdx + remark-gfm), then lints component usage:
13
+ *
14
+ * - errors: MDX syntax/compile failures, missing required props on built-ins
15
+ * - warnings: unknown component tags, unknown props on built-in components
16
+ */
17
+ export declare function validateMdx(source: string, options?: ValidateMdxOptions): Promise<MdxValidation>;
18
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;AAwBxC,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,aAAa,CAAC,CAwFxB"}
@@ -0,0 +1,101 @@
1
+ import { compile } from "@mdx-js/mdx";
2
+ import { builtinComponentDocs, builtinComponentNames, } from "@usezanin/client";
3
+ import remarkGfm from "remark-gfm";
4
+ function collectJsxElements(tree, out) {
5
+ if (tree.type === "mdxJsxFlowElement" || tree.type === "mdxJsxTextElement") {
6
+ out.push(tree);
7
+ }
8
+ for (const child of tree.children ?? []) {
9
+ collectJsxElements(child, out);
10
+ }
11
+ }
12
+ /**
13
+ * Validates an MDX post body with the exact pipeline the SDK uses to render
14
+ * it (@mdx-js/mdx + remark-gfm), then lints component usage:
15
+ *
16
+ * - errors: MDX syntax/compile failures, missing required props on built-ins
17
+ * - warnings: unknown component tags, unknown props on built-in components
18
+ */
19
+ export async function validateMdx(source, options = {}) {
20
+ const errors = [];
21
+ const warnings = [];
22
+ const known = new Set([...builtinComponentNames, ...(options.knownComponents ?? [])]);
23
+ const elements = [];
24
+ const collector = () => (tree) => {
25
+ collectJsxElements(tree, elements);
26
+ };
27
+ try {
28
+ await compile(source, { remarkPlugins: [remarkGfm, collector] });
29
+ }
30
+ catch (err) {
31
+ const message = err;
32
+ errors.push({
33
+ severity: "error",
34
+ rule: "mdx-syntax",
35
+ message: message.reason ?? message.message ?? String(err),
36
+ ...(typeof message.line === "number" ? { line: message.line } : {}),
37
+ ...(typeof message.column === "number" ? { column: message.column } : {}),
38
+ });
39
+ }
40
+ for (const el of elements) {
41
+ const name = el.name;
42
+ // Skip fragments, lowercase HTML tags and member expressions (Foo.Bar).
43
+ if (!name || !/^[A-Z]/.test(name) || name.includes("."))
44
+ continue;
45
+ const position = {
46
+ ...(el.position?.start?.line !== undefined ? { line: el.position.start.line } : {}),
47
+ ...(el.position?.start?.column !== undefined ? { column: el.position.start.column } : {}),
48
+ };
49
+ if (!known.has(name)) {
50
+ warnings.push({
51
+ severity: "warning",
52
+ rule: "unknown-component",
53
+ component: name,
54
+ message: `<${name}> is not a built-in component and no custom component with that name exists on this site. The post will fail to render unless the host site supplies it via the components prop. Built-ins: ${builtinComponentNames.join(", ")}.`,
55
+ ...position,
56
+ });
57
+ continue;
58
+ }
59
+ const doc = builtinComponentDocs.find((d) => d.name === name);
60
+ if (!doc)
61
+ continue; // custom component — no prop metadata to lint against
62
+ const attrs = el.attributes ?? [];
63
+ // A spread ({...props}) can supply anything; skip prop-level checks.
64
+ const hasSpread = attrs.some((a) => a.type === "mdxJsxExpressionAttribute");
65
+ const attrNames = attrs
66
+ .filter((a) => a.type === "mdxJsxAttribute" && typeof a.name === "string")
67
+ .map((a) => a.name);
68
+ const validProps = new Set(doc.props.map((p) => p.name));
69
+ for (const attr of attrNames) {
70
+ if (!validProps.has(attr)) {
71
+ warnings.push({
72
+ severity: "warning",
73
+ rule: "unknown-prop",
74
+ component: name,
75
+ message: `<${name}> has no "${attr}" prop. Valid props: ${doc.props.map((p) => p.name).join(", ") || "(none)"}.`,
76
+ ...position,
77
+ });
78
+ }
79
+ }
80
+ if (!hasSpread) {
81
+ for (const prop of doc.props) {
82
+ if (prop.required && !attrNames.includes(prop.name)) {
83
+ errors.push({
84
+ severity: "error",
85
+ rule: "missing-required-prop",
86
+ component: name,
87
+ message: `<${name}> is missing its required "${prop.name}" prop (${prop.type}) and will fail to render.`,
88
+ ...position,
89
+ });
90
+ }
91
+ }
92
+ }
93
+ }
94
+ return {
95
+ valid: errors.length === 0,
96
+ errors,
97
+ warnings,
98
+ knownComponents: [...known].sort(),
99
+ };
100
+ }
101
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}