contentbit 0.1.0 → 0.1.1
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/dist/bin.js +293 -44
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +302 -37
- package/dist/load-registry.d.ts.map +1 -1
- package/dist/load-registry.js +10 -1
- package/dist/run.d.ts +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +293 -44
- package/package.json +6 -3
package/dist/bin.js
CHANGED
|
@@ -16154,7 +16154,17 @@ import { pathToFileURL } from "node:url";
|
|
|
16154
16154
|
async function loadRegistry(registryPath) {
|
|
16155
16155
|
const registry2 = createBlockRegistry().use(genericBlocks());
|
|
16156
16156
|
if (registryPath) {
|
|
16157
|
-
|
|
16157
|
+
let mod;
|
|
16158
|
+
try {
|
|
16159
|
+
mod = await import(pathToFileURL(registryPath).href);
|
|
16160
|
+
} catch (err) {
|
|
16161
|
+
if (err instanceof Error && "code" in err && err.code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
16162
|
+
throw new Error(
|
|
16163
|
+
`Importing a TypeScript registry needs Node 22.18+ (native type stripping): ${registryPath}`
|
|
16164
|
+
);
|
|
16165
|
+
}
|
|
16166
|
+
throw err;
|
|
16167
|
+
}
|
|
16158
16168
|
if (!Array.isArray(mod.default)) {
|
|
16159
16169
|
throw new Error(
|
|
16160
16170
|
`--registry module must default-export an array of block definitions: ${registryPath}`
|
|
@@ -16178,10 +16188,131 @@ __export(init_exports, {
|
|
|
16178
16188
|
initCommand: () => initCommand
|
|
16179
16189
|
});
|
|
16180
16190
|
import { spawn } from "node:child_process";
|
|
16191
|
+
import { existsSync } from "node:fs";
|
|
16181
16192
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
16182
16193
|
import { join } from "node:path";
|
|
16183
16194
|
import { parseArgs } from "node:util";
|
|
16184
|
-
function
|
|
16195
|
+
function blockComponentsTemplate(styled) {
|
|
16196
|
+
const body = styled ? ` return (
|
|
16197
|
+
<figure className="my-6 border-s-2 ps-4">
|
|
16198
|
+
<blockquote className="text-lg italic">{ctx.renderMarkdown(data.markdown)}</blockquote>
|
|
16199
|
+
<figcaption className="text-muted-foreground mt-2 text-sm">
|
|
16200
|
+
\u2014 {String(node.props.author)}
|
|
16201
|
+
{node.props.role ? \`, \${String(node.props.role)}\` : null}
|
|
16202
|
+
</figcaption>
|
|
16203
|
+
</figure>
|
|
16204
|
+
)` : ` return (
|
|
16205
|
+
<figure style={{ margin: '1.5rem 0', borderLeft: '2px solid #d4d4d4', paddingLeft: '1rem' }}>
|
|
16206
|
+
<blockquote style={{ fontStyle: 'italic' }}>{ctx.renderMarkdown(data.markdown)}</blockquote>
|
|
16207
|
+
<figcaption style={{ marginTop: '0.5rem', fontSize: '0.875rem', opacity: 0.7 }}>
|
|
16208
|
+
\u2014 {String(node.props.author)}
|
|
16209
|
+
{node.props.role ? \`, \${String(node.props.role)}\` : null}
|
|
16210
|
+
</figcaption>
|
|
16211
|
+
</figure>
|
|
16212
|
+
)`;
|
|
16213
|
+
return `import type { BlockComponent, BlockComponentProps } from '@contentbit/react'
|
|
16214
|
+
|
|
16215
|
+
// One React component per custom block, keyed by block name. Definitions
|
|
16216
|
+
// live in ./registry.ts \u2014 add a block there, add its component here, and
|
|
16217
|
+
// the rest of the app never changes.
|
|
16218
|
+
function QuoteBlock({ node, ctx }: BlockComponentProps) {
|
|
16219
|
+
const data = node.data as { markdown: string }
|
|
16220
|
+
${body}
|
|
16221
|
+
}
|
|
16222
|
+
|
|
16223
|
+
export const blockComponents: Record<string, BlockComponent> = {
|
|
16224
|
+
quote: QuoteBlock,
|
|
16225
|
+
}
|
|
16226
|
+
`;
|
|
16227
|
+
}
|
|
16228
|
+
function reactComponent(styled, mdWired, blocksImport) {
|
|
16229
|
+
const mdImport = mdWired ? "import ReactMarkdown from 'react-markdown'\n" : "";
|
|
16230
|
+
const mdProp = mdWired ? "\n renderMarkdown={(md) => <ReactMarkdown>{md}</ReactMarkdown>}" : `
|
|
16231
|
+
// TODO: plug your Markdown library in here, e.g. react-markdown.
|
|
16232
|
+
// One function renders all prose: https://contentbit.dev/docs/guides/markdown
|
|
16233
|
+
// renderMarkdown={(md) => <Markdown source={md} />}`;
|
|
16234
|
+
const rendererImport = styled ? `
|
|
16235
|
+
// The styled pack installed by shadcn. Yours to edit.
|
|
16236
|
+
import { ContentRenderer } from '@/components/content-blocks/content-renderer'` : "";
|
|
16237
|
+
const renderer = styled ? "ContentRenderer" : "ContentBlocks";
|
|
16238
|
+
const reactImport = styled ? "" : "import { ContentBlocks } from '@contentbit/react'\n";
|
|
16239
|
+
return `'use client'
|
|
16240
|
+
|
|
16241
|
+
import { genericBlocks } from '@contentbit/blocks'
|
|
16242
|
+
import { createBlockRegistry, parseDocument, validateDocument } from '@contentbit/core'
|
|
16243
|
+
${reactImport}${mdImport}${rendererImport}
|
|
16244
|
+
// Everything block-related lives in the blocks/ folder: definitions in
|
|
16245
|
+
// registry.ts (shared with the validate CLI), components in components.tsx.
|
|
16246
|
+
import customBlocks from '${blocksImport}/registry'
|
|
16247
|
+
import { blockComponents } from '${blocksImport}/components'
|
|
16248
|
+
|
|
16249
|
+
const registry = createBlockRegistry().use(genericBlocks()).use(customBlocks)
|
|
16250
|
+
|
|
16251
|
+
export function Content({ source }: { source: string }) {
|
|
16252
|
+
const result = validateDocument(parseDocument(source), registry)
|
|
16253
|
+
return (
|
|
16254
|
+
<${renderer}
|
|
16255
|
+
document={result.document}
|
|
16256
|
+
components={blockComponents}${mdProp}
|
|
16257
|
+
/>
|
|
16258
|
+
)
|
|
16259
|
+
}
|
|
16260
|
+
`;
|
|
16261
|
+
}
|
|
16262
|
+
function htmlRenderScript(md) {
|
|
16263
|
+
const wiring = md === "marked" ? `import { marked } from 'marked'
|
|
16264
|
+
|
|
16265
|
+
const renderMarkdown = (md) => marked.parse(md, { async: false })` : md === "markdown-it" ? `import MarkdownIt from 'markdown-it'
|
|
16266
|
+
|
|
16267
|
+
const mdIt = new MarkdownIt() // html: false by default \u2014 raw HTML stays escaped
|
|
16268
|
+
const renderMarkdown = (md) => mdIt.render(md)` : `// TODO: plug a Markdown library in here (marked, markdown-it, remark).
|
|
16269
|
+
const renderMarkdown = undefined`;
|
|
16270
|
+
return `// Render content/example.md to example.html. Run: node scripts/render-example.mjs
|
|
16271
|
+
import { genericBlocks } from '@contentbit/blocks'
|
|
16272
|
+
import { createBlockRegistry, parseDocument, validateDocument } from '@contentbit/core'
|
|
16273
|
+
import { renderToHtml } from '@contentbit/html'
|
|
16274
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
16275
|
+
${wiring}
|
|
16276
|
+
|
|
16277
|
+
const source = await readFile('content/example.md', 'utf8')
|
|
16278
|
+
const registry = createBlockRegistry().use(genericBlocks())
|
|
16279
|
+
const result = validateDocument(parseDocument(source), registry)
|
|
16280
|
+
const html = renderToHtml(result.document, { renderMarkdown })
|
|
16281
|
+
await writeFile('example.html', html, 'utf8')
|
|
16282
|
+
console.log('wrote example.html')
|
|
16283
|
+
`;
|
|
16284
|
+
}
|
|
16285
|
+
function detectFramework(cwd, deps) {
|
|
16286
|
+
if ((deps["@tanstack/react-start"] || deps["@tanstack/react-router"]) && existsSync(join(cwd, "src/routes"))) {
|
|
16287
|
+
return {
|
|
16288
|
+
framework: "tanstack",
|
|
16289
|
+
componentPath: "src/components/content-blocks.tsx",
|
|
16290
|
+
pagePath: "src/routes/example.tsx"
|
|
16291
|
+
};
|
|
16292
|
+
}
|
|
16293
|
+
if (deps.next) {
|
|
16294
|
+
const appDir = existsSync(join(cwd, "src/app")) ? "src/app" : "app";
|
|
16295
|
+
if (existsSync(join(cwd, appDir))) {
|
|
16296
|
+
return {
|
|
16297
|
+
framework: "next",
|
|
16298
|
+
componentPath: "components/content-blocks.tsx",
|
|
16299
|
+
pagePath: `${appDir}/example/page.tsx`
|
|
16300
|
+
};
|
|
16301
|
+
}
|
|
16302
|
+
}
|
|
16303
|
+
return { framework: null, componentPath: "components/content-blocks.tsx", pagePath: null };
|
|
16304
|
+
}
|
|
16305
|
+
function detectPackageManager(cwd) {
|
|
16306
|
+
const locks = [
|
|
16307
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
16308
|
+
["yarn.lock", "yarn"],
|
|
16309
|
+
["bun.lock", "bun"],
|
|
16310
|
+
["bun.lockb", "bun"],
|
|
16311
|
+
["package-lock.json", "npm"]
|
|
16312
|
+
];
|
|
16313
|
+
for (const [file2, pm] of locks) {
|
|
16314
|
+
if (existsSync(join(cwd, file2))) return pm;
|
|
16315
|
+
}
|
|
16185
16316
|
const agent = process.env.npm_config_user_agent ?? "";
|
|
16186
16317
|
for (const pm of ["pnpm", "yarn", "bun"]) {
|
|
16187
16318
|
if (agent.startsWith(pm)) return pm;
|
|
@@ -16192,6 +16323,12 @@ function installArgs(pm, dev, pkgs) {
|
|
|
16192
16323
|
const add = pm === "npm" ? "install" : "add";
|
|
16193
16324
|
return dev ? [add, "-D", ...pkgs] : [add, ...pkgs];
|
|
16194
16325
|
}
|
|
16326
|
+
function dlxCommand(pm) {
|
|
16327
|
+
if (pm === "pnpm") return ["pnpm", ["dlx"]];
|
|
16328
|
+
if (pm === "yarn") return ["yarn", ["dlx"]];
|
|
16329
|
+
if (pm === "bun") return ["bunx", []];
|
|
16330
|
+
return ["npx", ["--yes"]];
|
|
16331
|
+
}
|
|
16195
16332
|
function runInstall(pm, args, cwd) {
|
|
16196
16333
|
return new Promise((resolve) => {
|
|
16197
16334
|
const child = spawn(pm, args, { cwd, stdio: "inherit", shell: process.platform === "win32" });
|
|
@@ -16214,9 +16351,12 @@ async function initCommand(args, io) {
|
|
|
16214
16351
|
args,
|
|
16215
16352
|
options: {
|
|
16216
16353
|
target: { type: "string", short: "t" },
|
|
16354
|
+
md: { type: "string" },
|
|
16217
16355
|
yes: { type: "boolean", short: "y", default: false },
|
|
16218
16356
|
cwd: { type: "string", default: process.cwd() },
|
|
16219
|
-
"no-install": { type: "boolean", default: false }
|
|
16357
|
+
"no-install": { type: "boolean", default: false },
|
|
16358
|
+
"no-page": { type: "boolean", default: false },
|
|
16359
|
+
"no-styled": { type: "boolean", default: false }
|
|
16220
16360
|
}
|
|
16221
16361
|
});
|
|
16222
16362
|
const cwd = values.cwd;
|
|
@@ -16253,13 +16393,38 @@ async function initCommand(args, io) {
|
|
|
16253
16393
|
} else {
|
|
16254
16394
|
target = detected;
|
|
16255
16395
|
}
|
|
16256
|
-
const
|
|
16396
|
+
const choices = MD_CHOICES[target];
|
|
16397
|
+
let md;
|
|
16398
|
+
if (values.md) {
|
|
16399
|
+
if (!choices.includes(values.md)) {
|
|
16400
|
+
io.stderr(`Unknown markdown library "${values.md}". Use one of: ${choices.join(", ")}`);
|
|
16401
|
+
return 2;
|
|
16402
|
+
}
|
|
16403
|
+
md = values.md;
|
|
16404
|
+
} else if (choices.length > 1 && !values.yes && process.stdin.isTTY && process.stdout.isTTY) {
|
|
16405
|
+
const { isCancel, select } = await import("@clack/prompts");
|
|
16406
|
+
const answer = await select({
|
|
16407
|
+
message: "Markdown library for prose rendering?",
|
|
16408
|
+
initialValue: choices[0],
|
|
16409
|
+
options: choices.map((c) => ({
|
|
16410
|
+
value: c,
|
|
16411
|
+
label: c,
|
|
16412
|
+
hint: c === "none" ? "wire one yourself later" : "installed and wired for you"
|
|
16413
|
+
}))
|
|
16414
|
+
});
|
|
16415
|
+
if (isCancel(answer)) return 1;
|
|
16416
|
+
md = answer;
|
|
16417
|
+
} else {
|
|
16418
|
+
md = choices[0];
|
|
16419
|
+
}
|
|
16420
|
+
const runtime = ["@contentbit/core", "@contentbit/blocks", "zod"];
|
|
16257
16421
|
if (target === "react") runtime.push("@contentbit/react");
|
|
16258
16422
|
if (target === "html") runtime.push("@contentbit/html");
|
|
16423
|
+
if (md !== "none") runtime.push(md);
|
|
16259
16424
|
if (values["no-install"]) {
|
|
16260
16425
|
io.stdout(`skipped install: ${runtime.join(" ")} + contentbit (dev)`);
|
|
16261
16426
|
} else {
|
|
16262
|
-
const pm = detectPackageManager();
|
|
16427
|
+
const pm = detectPackageManager(cwd);
|
|
16263
16428
|
io.stdout(`installing with ${pm}: ${runtime.join(" ")}`);
|
|
16264
16429
|
if (await runInstall(pm, installArgs(pm, false, runtime), cwd) !== 0) {
|
|
16265
16430
|
io.stderr("install failed");
|
|
@@ -16271,10 +16436,54 @@ async function initCommand(args, io) {
|
|
|
16271
16436
|
}
|
|
16272
16437
|
}
|
|
16273
16438
|
const files = [
|
|
16274
|
-
["blocks/registry.
|
|
16439
|
+
["blocks/registry.ts", REGISTRY_TEMPLATE],
|
|
16275
16440
|
["content/example.md", EXAMPLE_CONTENT]
|
|
16276
16441
|
];
|
|
16277
|
-
|
|
16442
|
+
const layout = detectFramework(cwd, { ...pkg.dependencies, ...pkg.devDependencies });
|
|
16443
|
+
let styled = false;
|
|
16444
|
+
const componentsJsonPath = join(cwd, "components.json");
|
|
16445
|
+
if (target === "react" && !values["no-styled"] && existsSync(componentsJsonPath)) {
|
|
16446
|
+
const componentsJson = JSON.parse(await readFile(componentsJsonPath, "utf8"));
|
|
16447
|
+
componentsJson.registries ??= {};
|
|
16448
|
+
if (!componentsJson.registries["@contentbit"]) {
|
|
16449
|
+
componentsJson.registries["@contentbit"] = "https://contentbit.dev/r/{name}.json";
|
|
16450
|
+
await writeFile(componentsJsonPath, `${JSON.stringify(componentsJson, null, 2)}
|
|
16451
|
+
`, "utf8");
|
|
16452
|
+
io.stdout("added @contentbit registry to components.json");
|
|
16453
|
+
}
|
|
16454
|
+
if (values["no-install"]) {
|
|
16455
|
+
io.stdout("skipped: shadcn add @contentbit/generic-pack");
|
|
16456
|
+
styled = true;
|
|
16457
|
+
} else {
|
|
16458
|
+
const [bin, prefix] = dlxCommand(detectPackageManager(cwd));
|
|
16459
|
+
io.stdout("installing the styled pack: shadcn add @contentbit/generic-pack");
|
|
16460
|
+
const code2 = await runInstall(
|
|
16461
|
+
bin,
|
|
16462
|
+
[...prefix, "shadcn@latest", "add", "@contentbit/generic-pack", "--yes"],
|
|
16463
|
+
cwd
|
|
16464
|
+
);
|
|
16465
|
+
if (code2 === 0) styled = true;
|
|
16466
|
+
else io.stderr("styled pack install failed; falling back to headless defaults");
|
|
16467
|
+
}
|
|
16468
|
+
}
|
|
16469
|
+
if (target === "react") {
|
|
16470
|
+
const depth = layout.componentPath.split("/").length - 1;
|
|
16471
|
+
const blocksImport = `${"../".repeat(depth)}blocks`;
|
|
16472
|
+
files.push(["blocks/components.tsx", blockComponentsTemplate(styled)]);
|
|
16473
|
+
files.push([
|
|
16474
|
+
layout.componentPath,
|
|
16475
|
+
reactComponent(styled, md === "react-markdown", blocksImport)
|
|
16476
|
+
]);
|
|
16477
|
+
if (!values["no-page"] && layout.pagePath) {
|
|
16478
|
+
files.push([layout.pagePath, layout.framework === "tanstack" ? TANSTACK_PAGE : NEXT_PAGE]);
|
|
16479
|
+
}
|
|
16480
|
+
}
|
|
16481
|
+
if (target === "html") {
|
|
16482
|
+
files.push([
|
|
16483
|
+
"scripts/render-example.mjs",
|
|
16484
|
+
htmlRenderScript(md)
|
|
16485
|
+
]);
|
|
16486
|
+
}
|
|
16278
16487
|
for (const [rel, content] of files) {
|
|
16279
16488
|
const result = await scaffold(join(cwd, rel), content);
|
|
16280
16489
|
io.stdout(`${result}: ${rel}`);
|
|
@@ -16282,57 +16491,77 @@ async function initCommand(args, io) {
|
|
|
16282
16491
|
const fresh = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
16283
16492
|
fresh.scripts ??= {};
|
|
16284
16493
|
if (!fresh.scripts["content:check"]) {
|
|
16285
|
-
fresh.scripts["content:check"] = 'contentbit validate "content/**/*.md" --registry ./blocks/registry.
|
|
16494
|
+
fresh.scripts["content:check"] = 'contentbit validate "content/**/*.md" --registry ./blocks/registry.ts';
|
|
16286
16495
|
await writeFile(pkgPath, `${JSON.stringify(fresh, null, 2)}
|
|
16287
16496
|
`, "utf8");
|
|
16288
16497
|
io.stdout("added script: content:check");
|
|
16289
16498
|
}
|
|
16290
|
-
|
|
16499
|
+
let registry2;
|
|
16500
|
+
try {
|
|
16501
|
+
registry2 = await loadRegistry(join(cwd, "blocks/registry.ts"));
|
|
16502
|
+
} catch {
|
|
16503
|
+
registry2 = await loadRegistry();
|
|
16504
|
+
}
|
|
16291
16505
|
const guide = registry2.toAuthoringGuide({ audience: "llm", includeExamples: true });
|
|
16292
16506
|
await writeFile(join(cwd, "contentbit-guide.md"), guide, "utf8");
|
|
16293
16507
|
io.stdout("created: contentbit-guide.md (LLM authoring instructions)");
|
|
16294
16508
|
io.stdout("");
|
|
16295
16509
|
io.stdout("Done. Next steps:");
|
|
16296
|
-
io.stdout(` 1. Validate the starter content: ${detectPackageManager()} run content:check`);
|
|
16510
|
+
io.stdout(` 1. Validate the starter content: ${detectPackageManager(cwd)} run content:check`);
|
|
16297
16511
|
if (target === "react") {
|
|
16298
|
-
|
|
16512
|
+
if (!values["no-page"] && layout.pagePath) {
|
|
16513
|
+
io.stdout(" 2. Start the dev server and open /example to see the article rendered.");
|
|
16514
|
+
} else {
|
|
16515
|
+
io.stdout(' 2. Render it: import { Content } from "./components/content-blocks"');
|
|
16516
|
+
io.stdout(" <Content source={...content/example.md as a string} />");
|
|
16517
|
+
}
|
|
16299
16518
|
io.stdout(" 3. Styled components: pnpm dlx shadcn@latest add @contentbit/generic-pack");
|
|
16300
16519
|
} else if (target === "html") {
|
|
16301
|
-
io.stdout(" 2. Render it:
|
|
16520
|
+
io.stdout(" 2. Render it: node scripts/render-example.mjs && open example.html");
|
|
16302
16521
|
} else {
|
|
16303
16522
|
io.stdout(" 2. Render it: contentbit render content/example.md --target markdown");
|
|
16304
16523
|
}
|
|
16305
16524
|
io.stdout(" Docs: https://contentbit.dev/docs");
|
|
16306
16525
|
return 0;
|
|
16307
16526
|
}
|
|
16308
|
-
var TARGETS, REGISTRY_TEMPLATE, EXAMPLE_CONTENT,
|
|
16527
|
+
var TARGETS, MD_CHOICES, REGISTRY_TEMPLATE, EXAMPLE_CONTENT, TANSTACK_PAGE, NEXT_PAGE;
|
|
16309
16528
|
var init_init = __esm({
|
|
16310
16529
|
"src/commands/init.ts"() {
|
|
16311
16530
|
"use strict";
|
|
16312
16531
|
init_load_registry();
|
|
16313
16532
|
TARGETS = ["react", "html", "markdown"];
|
|
16314
|
-
|
|
16533
|
+
MD_CHOICES = {
|
|
16534
|
+
react: ["react-markdown", "none"],
|
|
16535
|
+
html: ["marked", "markdown-it", "none"],
|
|
16536
|
+
markdown: ["none"]
|
|
16537
|
+
};
|
|
16538
|
+
REGISTRY_TEMPLATE = `// Custom block definitions for this project. The CLI and your app share
|
|
16539
|
+
// this module \u2014 Node 22.18+ imports TypeScript directly:
|
|
16315
16540
|
//
|
|
16316
|
-
// contentbit validate "content/**/*.md" --registry ./blocks/registry.
|
|
16541
|
+
// contentbit validate "content/**/*.md" --registry ./blocks/registry.ts
|
|
16317
16542
|
//
|
|
16318
|
-
//
|
|
16543
|
+
// Definitions stay framework-free (the CLI and every render target use
|
|
16544
|
+
// them); React components live next door in blocks/components.tsx.
|
|
16319
16545
|
// Docs: https://contentbit.dev/docs/guides/custom-blocks
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16328
|
-
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16546
|
+
import { defineBlock, markdownBody, type BlockDefinition } from '@contentbit/core'
|
|
16547
|
+
import { z } from 'zod'
|
|
16548
|
+
|
|
16549
|
+
export const quote = defineBlock({
|
|
16550
|
+
name: 'quote',
|
|
16551
|
+
description: 'A pull quote with an author.',
|
|
16552
|
+
props: z.object({
|
|
16553
|
+
author: z.string().min(1),
|
|
16554
|
+
role: z.string().optional(),
|
|
16555
|
+
}),
|
|
16556
|
+
content: markdownBody({ minLength: 3 }),
|
|
16557
|
+
authoring: {
|
|
16558
|
+
useWhen: ['Quoting a person to support a point'],
|
|
16559
|
+
avoidWhen: ['Highlighting your own remark, use callout instead'],
|
|
16560
|
+
example: ':::quote{author="Ada Lovelace"}\\nThe Analytical Engine weaves algebraic patterns.\\n:::',
|
|
16561
|
+
},
|
|
16562
|
+
})
|
|
16334
16563
|
|
|
16335
|
-
export default []
|
|
16564
|
+
export default [quote] satisfies BlockDefinition<unknown>[]
|
|
16336
16565
|
`;
|
|
16337
16566
|
EXAMPLE_CONTENT = `# Hello, Content Blocks
|
|
16338
16567
|
|
|
@@ -16347,22 +16576,42 @@ Run the validate script and you will get file:line:col diagnostics.
|
|
|
16347
16576
|
2. Run \`contentbit validate "content/**/*.md"\`.
|
|
16348
16577
|
3. Render it with the target you picked at init.
|
|
16349
16578
|
:::
|
|
16579
|
+
|
|
16580
|
+
This one is a **custom block**, defined in \`blocks/registry.ts\` and rendered
|
|
16581
|
+
by the \`QuoteBlock\` component, in about twenty lines:
|
|
16582
|
+
|
|
16583
|
+
:::quote{author="Ada Lovelace" role="Notes on the Analytical Engine, 1843"}
|
|
16584
|
+
The Analytical Engine weaves algebraic patterns just as the Jacquard loom
|
|
16585
|
+
weaves flowers and leaves.
|
|
16586
|
+
:::
|
|
16350
16587
|
`;
|
|
16351
|
-
|
|
16352
|
-
import { createBlockRegistry, parseDocument, validateDocument } from '@contentbit/core'
|
|
16353
|
-
import { ContentBlocks } from '@contentbit/react'
|
|
16588
|
+
TANSTACK_PAGE = `import { createFileRoute } from '@tanstack/react-router'
|
|
16354
16589
|
|
|
16355
|
-
|
|
16590
|
+
import { Content } from '../components/content-blocks'
|
|
16591
|
+
// Vite's ?raw import inlines the Markdown as a string at build time.
|
|
16592
|
+
import source from '../../content/example.md?raw'
|
|
16356
16593
|
|
|
16357
|
-
export
|
|
16358
|
-
|
|
16594
|
+
export const Route = createFileRoute('/example')({ component: ExamplePage })
|
|
16595
|
+
|
|
16596
|
+
function ExamplePage() {
|
|
16359
16597
|
return (
|
|
16360
|
-
<
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16598
|
+
<main style={{ maxWidth: '42rem', margin: '0 auto', padding: '3rem 1.5rem' }}>
|
|
16599
|
+
<Content source={source} />
|
|
16600
|
+
</main>
|
|
16601
|
+
)
|
|
16602
|
+
}
|
|
16603
|
+
`;
|
|
16604
|
+
NEXT_PAGE = `import { readFile } from 'node:fs/promises'
|
|
16605
|
+
|
|
16606
|
+
// If your project has no "@/" path alias, switch to a relative import.
|
|
16607
|
+
import { Content } from '@/components/content-blocks'
|
|
16608
|
+
|
|
16609
|
+
export default async function ExamplePage() {
|
|
16610
|
+
const source = await readFile('content/example.md', 'utf8')
|
|
16611
|
+
return (
|
|
16612
|
+
<main style={{ maxWidth: '42rem', margin: '0 auto', padding: '3rem 1.5rem' }}>
|
|
16613
|
+
<Content source={source} />
|
|
16614
|
+
</main>
|
|
16366
16615
|
)
|
|
16367
16616
|
}
|
|
16368
16617
|
`;
|
|
@@ -16657,7 +16906,7 @@ import { writeFile as writeFile2 } from "node:fs/promises";
|
|
|
16657
16906
|
// src/run.ts
|
|
16658
16907
|
var USAGE = `Usage: contentbit <init|validate|render|instructions|docs> [options]
|
|
16659
16908
|
|
|
16660
|
-
init [-t react|html|markdown] [-y] [--no-install]
|
|
16909
|
+
init [-t react|html|markdown] [--md ...] [-y] [--no-install] [--no-page]
|
|
16661
16910
|
|
|
16662
16911
|
validate <globs...> [--registry <module.mjs>] [--strict-warnings]
|
|
16663
16912
|
render <file> --target html|markdown [--registry <module.mjs>] [--out <file>]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAiSnC,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyMzE"}
|