@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 +43 -2
- package/dist/BlogIndex.d.ts +9 -1
- package/dist/BlogIndex.d.ts.map +1 -1
- package/dist/BlogIndex.js +14 -6
- package/dist/BlogIndex.js.map +1 -1
- package/dist/BlogPost.d.ts.map +1 -1
- package/dist/BlogPost.js +6 -3
- package/dist/BlogPost.js.map +1 -1
- package/dist/components/Chart.js +1 -1
- package/dist/config.d.ts +11 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/data.d.ts +2 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +10 -0
- package/dist/data.js.map +1 -1
- package/dist/headless.d.ts +14 -0
- package/dist/headless.d.ts.map +1 -0
- package/dist/headless.js +20 -0
- package/dist/headless.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/theme.d.ts +12 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +48 -0
- package/dist/theme.js.map +1 -0
- package/dist/validate.d.ts +18 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +101 -0
- package/dist/validate.js.map +1 -0
- package/package.json +3 -3
- package/styles.css +245 -172
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` (
|
|
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
|
package/dist/BlogIndex.d.ts
CHANGED
|
@@ -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
|
package/dist/BlogIndex.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlogIndex.d.ts","sourceRoot":"","sources":["../src/BlogIndex.tsx"],"names":[],"mappings":"
|
|
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
|
-
|
|
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
|
|
19
|
-
|
|
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
|
package/dist/BlogIndex.js.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/BlogPost.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
package/dist/BlogPost.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlogPost.js","sourceRoot":"","sources":["../src/BlogPost.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"BlogPost.js","sourceRoot":"","sources":["../src/BlogPost.tsx"],"names":[],"mappings":"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"}
|
package/dist/components/Chart.js
CHANGED
|
@@ -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, #
|
|
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
|
-
/**
|
|
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
|
package/dist/config.d.ts.map
CHANGED
|
@@ -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
|
|
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) {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
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
|
package/dist/data.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/headless.js
ADDED
|
@@ -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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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;
|
|
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"}
|
package/dist/theme.d.ts
ADDED
|
@@ -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"}
|
package/dist/validate.js
ADDED
|
@@ -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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GAGtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,SAAS,MAAM,YAAY,CAAC;AAiBnC,SAAS,kBAAkB,CAAC,IAAoB,EAAE,GAAqB;IACrE,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QAC3E,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACxC,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAUD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,UAA8B,EAAE;IAEhC,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAe,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,qBAAqB,EAAE,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAEtC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CAAC,IAAoB,EAAE,EAAE;QAC/C,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAA4E,CAAC;QAC7F,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC;YACzD,GAAG,CAAC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;QACrB,wEAAwE;QACxE,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QAElE,MAAM,QAAQ,GAAG;YACf,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnF,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1F,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,mBAAmB;gBACzB,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,IAAI,IAAI,+LAA+L,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACnP,GAAG,QAAQ;aACZ,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG;YAAE,SAAS,CAAC,sDAAsD;QAE1E,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC;QAClC,qEAAqE;QACrE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,2BAA2B,CAAC,CAAC;QAC5E,MAAM,SAAS,GAAG,KAAK;aACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;aACzE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAc,CAAC,CAAC;QAEhC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,SAAS;oBACnB,IAAI,EAAE,cAAc;oBACpB,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,IAAI,IAAI,aAAa,IAAI,wBAAwB,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,GAAG;oBAChH,GAAG,QAAQ;iBACZ,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC7B,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpD,MAAM,CAAC,IAAI,CAAC;wBACV,QAAQ,EAAE,OAAO;wBACjB,IAAI,EAAE,uBAAuB;wBAC7B,SAAS,EAAE,IAAI;wBACf,OAAO,EAAE,IAAI,IAAI,8BAA8B,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,IAAI,4BAA4B;wBACxG,GAAG,QAAQ;qBACZ,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,MAAM;QACN,QAAQ;QACR,eAAe,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC"}
|