@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.
Files changed (61) hide show
  1. package/README.md +118 -2
  2. package/dist/blog.css +227 -0
  3. package/dist/chunks/BlogEditor-VF3UAJB6.js +2527 -0
  4. package/dist/chunks/chunk-3GCZFCUK.js +51 -0
  5. package/dist/chunks/chunk-3WRTL63O.js +106 -0
  6. package/dist/chunks/chunk-AEQDRBA3.js +128 -0
  7. package/dist/chunks/chunk-AJVVTSKZ.js +90 -0
  8. package/dist/chunks/chunk-EICE5ONB.js +197 -0
  9. package/dist/chunks/chunk-HWR3R5MU.js +48 -0
  10. package/dist/chunks/chunk-QX6276YA.js +0 -0
  11. package/dist/chunks/chunk-TYX2HJZC.js +68 -0
  12. package/dist/chunks/chunk-UA243KAQ.js +104 -0
  13. package/dist/chunks/chunk-WJVZD4UI.js +114 -0
  14. package/dist/chunks/chunk-XLJBCIXI.js +93 -0
  15. package/dist/cli.js +440 -0
  16. package/dist/content-source.d.ts +31 -0
  17. package/dist/editor/BlogEditor.d.ts +37 -0
  18. package/dist/editor/BlogEditorMount.d.ts +64 -0
  19. package/dist/editor/DocumentActions.d.ts +39 -0
  20. package/dist/editor/EditDesignLink.d.ts +30 -0
  21. package/dist/editor/NewPostForm.d.ts +10 -0
  22. package/dist/editor/SlashMenu.d.ts +5 -0
  23. package/dist/editor/Toolbar.d.ts +39 -0
  24. package/dist/editor/blocks.d.ts +5 -0
  25. package/dist/editor/client.d.ts +88 -0
  26. package/dist/editor/client.js +6 -0
  27. package/dist/editor/component-node.d.ts +14 -0
  28. package/dist/editor/config.d.ts +24 -0
  29. package/dist/editor/document.d.ts +47 -0
  30. package/dist/editor/extensions.d.ts +19 -0
  31. package/dist/editor/header.d.ts +20 -0
  32. package/dist/editor/index.d.ts +11 -0
  33. package/dist/editor/index.js +209 -0
  34. package/dist/editor/paste-guard.d.ts +14 -0
  35. package/dist/editor/primitives.d.ts +17 -0
  36. package/dist/editor/props-form.d.ts +17 -0
  37. package/dist/editor/serialize.d.ts +34 -0
  38. package/dist/editor/slash-command.d.ts +21 -0
  39. package/dist/feed.d.ts +4 -0
  40. package/dist/index.d.ts +8 -0
  41. package/dist/index.js +72 -0
  42. package/dist/next/app.d.ts +34 -0
  43. package/dist/next/config.d.ts +44 -0
  44. package/dist/next/index.d.ts +2 -0
  45. package/dist/next/index.js +94 -0
  46. package/dist/next/pages.d.ts +33 -0
  47. package/dist/next/pages.js +167 -0
  48. package/dist/next/routes.d.ts +14 -0
  49. package/dist/next/routes.js +37 -0
  50. package/dist/next/views.d.ts +18 -0
  51. package/dist/react/components.d.ts +18 -0
  52. package/dist/react/index.d.ts +2 -0
  53. package/dist/react/index.js +15 -0
  54. package/dist/react/render.d.ts +7 -0
  55. package/dist/registry.d.ts +95 -0
  56. package/dist/sanitize.d.ts +33 -0
  57. package/dist/schema.d.ts +24 -0
  58. package/dist/seo.d.ts +63 -0
  59. package/dist/sitemap.d.ts +4 -0
  60. package/dist/xml.d.ts +1 -0
  61. 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
+ };