@codepress/blog 0.0.0-stage → 0.1.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 +118 -2
- package/dist/blog.css +227 -0
- package/dist/chunks/BlogEditor-VF3UAJB6.js +2527 -0
- package/dist/chunks/chunk-3GCZFCUK.js +51 -0
- package/dist/chunks/chunk-3WRTL63O.js +106 -0
- package/dist/chunks/chunk-AEQDRBA3.js +128 -0
- package/dist/chunks/chunk-AJVVTSKZ.js +90 -0
- package/dist/chunks/chunk-EICE5ONB.js +197 -0
- package/dist/chunks/chunk-HWR3R5MU.js +48 -0
- package/dist/chunks/chunk-QX6276YA.js +0 -0
- package/dist/chunks/chunk-TYX2HJZC.js +68 -0
- package/dist/chunks/chunk-UA243KAQ.js +104 -0
- package/dist/chunks/chunk-WJVZD4UI.js +114 -0
- package/dist/chunks/chunk-XLJBCIXI.js +93 -0
- package/dist/cli.js +440 -0
- package/dist/content-source.d.ts +31 -0
- package/dist/editor/BlogEditor.d.ts +37 -0
- package/dist/editor/BlogEditorMount.d.ts +64 -0
- package/dist/editor/DocumentActions.d.ts +39 -0
- package/dist/editor/EditDesignLink.d.ts +30 -0
- package/dist/editor/NewPostForm.d.ts +10 -0
- package/dist/editor/SlashMenu.d.ts +5 -0
- package/dist/editor/Toolbar.d.ts +39 -0
- package/dist/editor/blocks.d.ts +5 -0
- package/dist/editor/client.d.ts +88 -0
- package/dist/editor/client.js +6 -0
- package/dist/editor/component-node.d.ts +14 -0
- package/dist/editor/config.d.ts +24 -0
- package/dist/editor/document.d.ts +47 -0
- package/dist/editor/extensions.d.ts +19 -0
- package/dist/editor/header.d.ts +20 -0
- package/dist/editor/index.d.ts +11 -0
- package/dist/editor/index.js +209 -0
- package/dist/editor/paste-guard.d.ts +14 -0
- package/dist/editor/primitives.d.ts +17 -0
- package/dist/editor/props-form.d.ts +17 -0
- package/dist/editor/serialize.d.ts +34 -0
- package/dist/editor/slash-command.d.ts +21 -0
- package/dist/feed.d.ts +4 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +72 -0
- package/dist/next/app.d.ts +34 -0
- package/dist/next/config.d.ts +44 -0
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +94 -0
- package/dist/next/pages.d.ts +33 -0
- package/dist/next/pages.js +167 -0
- package/dist/next/routes.d.ts +14 -0
- package/dist/next/routes.js +37 -0
- package/dist/next/views.d.ts +18 -0
- package/dist/react/components.d.ts +18 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +15 -0
- package/dist/react/render.d.ts +7 -0
- package/dist/registry.d.ts +95 -0
- package/dist/sanitize.d.ts +33 -0
- package/dist/schema.d.ts +24 -0
- package/dist/seo.d.ts +63 -0
- package/dist/sitemap.d.ts +4 -0
- package/dist/xml.d.ts +1 -0
- package/package.json +92 -4
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// src/editor/config.ts
|
|
2
|
+
var DEFAULT_TIMINGS = {
|
|
3
|
+
autosaveMs: 2e3,
|
|
4
|
+
draftPollMs: 1e4,
|
|
5
|
+
publishReloadMs: 4e3
|
|
6
|
+
};
|
|
7
|
+
function resolveTimings(timings) {
|
|
8
|
+
const pick = (key) => {
|
|
9
|
+
const value = timings?.[key];
|
|
10
|
+
return typeof value === "number" && value > 0 ? value : DEFAULT_TIMINGS[key];
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
autosaveMs: pick("autosaveMs"),
|
|
14
|
+
draftPollMs: pick("draftPollMs"),
|
|
15
|
+
publishReloadMs: pick("publishReloadMs")
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
var DEFAULT_COLUMN = "mx-auto w-full max-w-[720px] px-5 sm:px-8";
|
|
19
|
+
var DEFAULT_APP_URL = "https://codepress.dev";
|
|
20
|
+
var BLOG_TOOLBAR_BOTTOM_VAR = "--blog-toolbar-bottom";
|
|
21
|
+
|
|
22
|
+
// src/editor/EditDesignLink.tsx
|
|
23
|
+
import { jsx } from "react/jsx-runtime";
|
|
24
|
+
function designTargetOf(capabilities) {
|
|
25
|
+
const {
|
|
26
|
+
organization_slug: organizationSlug,
|
|
27
|
+
repository_full_name: repository
|
|
28
|
+
} = capabilities;
|
|
29
|
+
return organizationSlug && repository ? { organizationSlug, repository } : null;
|
|
30
|
+
}
|
|
31
|
+
function designUrl({ organizationSlug, repository }, slug, appUrl = "") {
|
|
32
|
+
const query = new URLSearchParams({
|
|
33
|
+
repo: repository,
|
|
34
|
+
path: `/blog/${slug}`
|
|
35
|
+
});
|
|
36
|
+
return `${appUrl}/dashboard/${encodeURIComponent(organizationSlug)}/design?${query.toString()}`;
|
|
37
|
+
}
|
|
38
|
+
function EditDesignLink({
|
|
39
|
+
href,
|
|
40
|
+
children = "Edit design",
|
|
41
|
+
...rest
|
|
42
|
+
}) {
|
|
43
|
+
if (!href) return null;
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
"a",
|
|
46
|
+
{
|
|
47
|
+
...rest,
|
|
48
|
+
href,
|
|
49
|
+
target: "_blank",
|
|
50
|
+
rel: "noopener noreferrer",
|
|
51
|
+
"data-testid": "blog-edit-design",
|
|
52
|
+
children
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/editor/header.ts
|
|
58
|
+
import { useLayoutEffect, useState } from "react";
|
|
59
|
+
var DEFAULT_HEADER_SELECTOR = "[data-blog-header]";
|
|
60
|
+
function findHostHeader(selector, editorRoot) {
|
|
61
|
+
const matched = document.querySelector(
|
|
62
|
+
selector ?? DEFAULT_HEADER_SELECTOR
|
|
63
|
+
);
|
|
64
|
+
if (matched) return matched;
|
|
65
|
+
return Array.from(document.querySelectorAll("header")).find(
|
|
66
|
+
(element) => !editorRoot?.contains(element)
|
|
67
|
+
) ?? null;
|
|
68
|
+
}
|
|
69
|
+
function useHeaderOffset(header, own) {
|
|
70
|
+
const selector = header?.selector;
|
|
71
|
+
const offset = header?.offset;
|
|
72
|
+
const [height, setHeight] = useState(0);
|
|
73
|
+
useLayoutEffect(() => {
|
|
74
|
+
if (offset !== void 0) return;
|
|
75
|
+
const element = findHostHeader(
|
|
76
|
+
selector,
|
|
77
|
+
own.current?.closest('[data-testid="blog-editor"]') ?? own.current
|
|
78
|
+
);
|
|
79
|
+
if (!element) {
|
|
80
|
+
setHeight(0);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const update = () => setHeight(element.offsetHeight);
|
|
84
|
+
update();
|
|
85
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
86
|
+
const observer = new ResizeObserver(update);
|
|
87
|
+
observer.observe(element);
|
|
88
|
+
return () => observer.disconnect();
|
|
89
|
+
}, [selector, offset, own]);
|
|
90
|
+
return offset ?? height;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
DEFAULT_TIMINGS,
|
|
95
|
+
resolveTimings,
|
|
96
|
+
DEFAULT_COLUMN,
|
|
97
|
+
DEFAULT_APP_URL,
|
|
98
|
+
BLOG_TOOLBAR_BOTTOM_VAR,
|
|
99
|
+
designTargetOf,
|
|
100
|
+
designUrl,
|
|
101
|
+
EditDesignLink,
|
|
102
|
+
DEFAULT_HEADER_SELECTOR,
|
|
103
|
+
useHeaderOffset
|
|
104
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderPostBody
|
|
3
|
+
} from "./chunk-AJVVTSKZ.js";
|
|
4
|
+
import {
|
|
5
|
+
absoluteImage,
|
|
6
|
+
blogPostingJsonLd,
|
|
7
|
+
blogUrl,
|
|
8
|
+
breadcrumbJsonLd,
|
|
9
|
+
jsonLd,
|
|
10
|
+
postUrl
|
|
11
|
+
} from "./chunk-AEQDRBA3.js";
|
|
12
|
+
|
|
13
|
+
// src/next/views.tsx
|
|
14
|
+
import Link from "next/link.js";
|
|
15
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var PAGE_STYLE = {
|
|
17
|
+
maxWidth: "var(--cp-blog-page-width, 720px)",
|
|
18
|
+
margin: "0 auto",
|
|
19
|
+
padding: "var(--cp-blog-page-padding, 3rem 1.25rem 5rem)",
|
|
20
|
+
color: "var(--cp-blog-text)",
|
|
21
|
+
fontFamily: "var(--cp-blog-font)"
|
|
22
|
+
};
|
|
23
|
+
var MUTED_STYLE = { color: "var(--cp-blog-muted)" };
|
|
24
|
+
var dateFormat = new Intl.DateTimeFormat("en-US", {
|
|
25
|
+
dateStyle: "long",
|
|
26
|
+
timeZone: "UTC"
|
|
27
|
+
});
|
|
28
|
+
function formatDate(date) {
|
|
29
|
+
return dateFormat.format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
|
|
30
|
+
}
|
|
31
|
+
function shareImage(site, ogImage) {
|
|
32
|
+
return absoluteImage(site, ogImage) || void 0;
|
|
33
|
+
}
|
|
34
|
+
function indexJsonLd(site, posts) {
|
|
35
|
+
return jsonLd({
|
|
36
|
+
"@context": "https://schema.org",
|
|
37
|
+
"@type": "Blog",
|
|
38
|
+
name: site.title,
|
|
39
|
+
description: site.description,
|
|
40
|
+
url: blogUrl(site),
|
|
41
|
+
blogPost: posts.map(({ slug, meta }) => ({
|
|
42
|
+
"@type": "BlogPosting",
|
|
43
|
+
headline: meta.title,
|
|
44
|
+
url: postUrl(site, slug),
|
|
45
|
+
datePublished: meta.date
|
|
46
|
+
}))
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function postJsonLd(site, post) {
|
|
50
|
+
const { image, ...posting } = blogPostingJsonLd(site, post.slug, post.meta);
|
|
51
|
+
return [
|
|
52
|
+
jsonLd(image ? { ...posting, image } : posting),
|
|
53
|
+
jsonLd(breadcrumbJsonLd(site, post.slug, post.meta.title))
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
function JsonLd({ data }) {
|
|
57
|
+
return /* @__PURE__ */ jsx(
|
|
58
|
+
"script",
|
|
59
|
+
{
|
|
60
|
+
type: "application/ld+json",
|
|
61
|
+
dangerouslySetInnerHTML: { __html: data }
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
function BlogIndexView({
|
|
66
|
+
blog,
|
|
67
|
+
posts,
|
|
68
|
+
structuredData = true
|
|
69
|
+
}) {
|
|
70
|
+
const { site, basePath } = blog;
|
|
71
|
+
return /* @__PURE__ */ jsxs("main", { className: "cp-blog-index", style: PAGE_STYLE, children: [
|
|
72
|
+
structuredData ? /* @__PURE__ */ jsx(JsonLd, { data: indexJsonLd(site, posts) }) : null,
|
|
73
|
+
/* @__PURE__ */ jsx("h1", { children: site.title }),
|
|
74
|
+
/* @__PURE__ */ jsx("p", { style: MUTED_STYLE, children: site.description }),
|
|
75
|
+
posts.length === 0 ? /* @__PURE__ */ jsx("p", { className: "cp-blog-empty", style: MUTED_STYLE, children: "No posts yet." }) : /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", padding: 0 }, children: posts.map(({ slug, meta }) => /* @__PURE__ */ jsx("li", { style: { padding: "1.5rem 0" }, children: /* @__PURE__ */ jsxs(Link, { href: `${basePath}/${slug}`, children: [
|
|
76
|
+
/* @__PURE__ */ jsx("p", { style: MUTED_STYLE, children: /* @__PURE__ */ jsx("time", { dateTime: meta.date, children: formatDate(meta.date) }) }),
|
|
77
|
+
/* @__PURE__ */ jsx("h2", { children: meta.title }),
|
|
78
|
+
/* @__PURE__ */ jsx("p", { children: meta.description })
|
|
79
|
+
] }) }, slug)) })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
function BlogPostView({
|
|
83
|
+
blog,
|
|
84
|
+
post,
|
|
85
|
+
structuredData = true
|
|
86
|
+
}) {
|
|
87
|
+
const { meta, html } = post;
|
|
88
|
+
return /* @__PURE__ */ jsxs("main", { className: "cp-blog-post", style: PAGE_STYLE, children: [
|
|
89
|
+
structuredData ? postJsonLd(blog.site, post).map((data) => /* @__PURE__ */ jsx(JsonLd, { data }, data)) : null,
|
|
90
|
+
/* @__PURE__ */ jsxs(Link, { href: blog.basePath, style: MUTED_STYLE, children: [
|
|
91
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u2190" }),
|
|
92
|
+
" All posts"
|
|
93
|
+
] }),
|
|
94
|
+
/* @__PURE__ */ jsxs("header", { children: [
|
|
95
|
+
/* @__PURE__ */ jsx("h1", { children: meta.title }),
|
|
96
|
+
/* @__PURE__ */ jsxs("p", { style: MUTED_STYLE, children: [
|
|
97
|
+
/* @__PURE__ */ jsx("time", { dateTime: meta.date, children: formatDate(meta.date) }),
|
|
98
|
+
meta.authors?.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
+
" \xB7 ",
|
|
100
|
+
meta.authors.join(", ")
|
|
101
|
+
] }) : null
|
|
102
|
+
] })
|
|
103
|
+
] }),
|
|
104
|
+
/* @__PURE__ */ jsx("article", { className: "cp-blog-prose", children: renderPostBody(html) })
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export {
|
|
109
|
+
shareImage,
|
|
110
|
+
indexJsonLd,
|
|
111
|
+
postJsonLd,
|
|
112
|
+
BlogIndexView,
|
|
113
|
+
BlogPostView
|
|
114
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/registry.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4
|
+
var BLOCK_ID_ATTRIBUTE = "data-cp-id";
|
|
5
|
+
var PROPS_ATTRIBUTE = "data-props";
|
|
6
|
+
var URL_SCHEMES = ["https", "http", "mailto"];
|
|
7
|
+
var withBlockId = (attributes = [], urlAttributes) => ({
|
|
8
|
+
attributes: [BLOCK_ID_ATTRIBUTE, ...attributes],
|
|
9
|
+
...urlAttributes ? { urlAttributes } : {}
|
|
10
|
+
});
|
|
11
|
+
var ELEMENTS = {
|
|
12
|
+
p: withBlockId(),
|
|
13
|
+
h2: withBlockId(["id"]),
|
|
14
|
+
h3: withBlockId(["id"]),
|
|
15
|
+
h4: withBlockId(["id"]),
|
|
16
|
+
ul: withBlockId(),
|
|
17
|
+
ol: withBlockId(),
|
|
18
|
+
li: withBlockId(),
|
|
19
|
+
a: withBlockId(["href", "title", "rel", "target"], ["href"]),
|
|
20
|
+
strong: withBlockId(),
|
|
21
|
+
em: withBlockId(),
|
|
22
|
+
code: withBlockId(),
|
|
23
|
+
pre: withBlockId(),
|
|
24
|
+
blockquote: withBlockId(),
|
|
25
|
+
hr: withBlockId(),
|
|
26
|
+
br: withBlockId(),
|
|
27
|
+
figure: withBlockId(),
|
|
28
|
+
figcaption: withBlockId(),
|
|
29
|
+
img: withBlockId(["src", "alt", "width", "height", "loading"], ["src"]),
|
|
30
|
+
table: withBlockId(),
|
|
31
|
+
thead: withBlockId(),
|
|
32
|
+
tbody: withBlockId(),
|
|
33
|
+
tr: withBlockId(),
|
|
34
|
+
th: withBlockId(),
|
|
35
|
+
td: withBlockId()
|
|
36
|
+
};
|
|
37
|
+
var urlProp = z.string().regex(/^(https?:\/\/|\/(?!\/))/);
|
|
38
|
+
var CALLOUT_TYPES = ["info", "warn", "tip"];
|
|
39
|
+
var calloutProps = z.object({ type: z.enum(CALLOUT_TYPES) }).strict();
|
|
40
|
+
var figureProps = z.object({
|
|
41
|
+
src: urlProp,
|
|
42
|
+
alt: z.string(),
|
|
43
|
+
caption: z.string().optional(),
|
|
44
|
+
width: z.number().int().positive().max(1e4).optional(),
|
|
45
|
+
height: z.number().int().positive().max(1e4).optional()
|
|
46
|
+
}).strict();
|
|
47
|
+
var COMPONENTS = {
|
|
48
|
+
"cp-callout": {
|
|
49
|
+
attributes: [BLOCK_ID_ATTRIBUTE, PROPS_ATTRIBUTE],
|
|
50
|
+
content: "block",
|
|
51
|
+
props: calloutProps
|
|
52
|
+
},
|
|
53
|
+
"cp-figure": {
|
|
54
|
+
attributes: [BLOCK_ID_ATTRIBUTE, PROPS_ATTRIBUTE],
|
|
55
|
+
content: "none",
|
|
56
|
+
props: figureProps
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function isComponentTag(tag) {
|
|
60
|
+
return Object.prototype.hasOwnProperty.call(COMPONENTS, tag);
|
|
61
|
+
}
|
|
62
|
+
function isElementTag(tag) {
|
|
63
|
+
return Object.prototype.hasOwnProperty.call(ELEMENTS, tag);
|
|
64
|
+
}
|
|
65
|
+
var isoDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/).refine((value) => {
|
|
66
|
+
const time = Date.parse(`${value}T00:00:00Z`);
|
|
67
|
+
return !Number.isNaN(time) && new Date(time).toISOString().slice(0, 10) === value;
|
|
68
|
+
}, "must be a real calendar date").meta({ format: "date" });
|
|
69
|
+
var postMetaSchema = z.looseObject({
|
|
70
|
+
title: z.string().min(1),
|
|
71
|
+
description: z.string().min(1),
|
|
72
|
+
date: isoDate,
|
|
73
|
+
updated: isoDate.optional(),
|
|
74
|
+
authors: z.array(z.string()).optional(),
|
|
75
|
+
tags: z.array(z.string()).optional(),
|
|
76
|
+
ogImage: z.string().optional(),
|
|
77
|
+
status: z.enum(["published", "draft"]).optional()
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
export {
|
|
81
|
+
SLUG_PATTERN,
|
|
82
|
+
BLOCK_ID_ATTRIBUTE,
|
|
83
|
+
PROPS_ATTRIBUTE,
|
|
84
|
+
URL_SCHEMES,
|
|
85
|
+
ELEMENTS,
|
|
86
|
+
CALLOUT_TYPES,
|
|
87
|
+
calloutProps,
|
|
88
|
+
figureProps,
|
|
89
|
+
COMPONENTS,
|
|
90
|
+
isComponentTag,
|
|
91
|
+
isElementTag,
|
|
92
|
+
postMetaSchema
|
|
93
|
+
};
|