bsmnt 0.13.0 → 0.14.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/dist/modules/features/cms/sanity-pagebuilder/config.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder/config.js +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder/config.js.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.js +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-skills/ashby-pagebuilder-block/SKILL.md +29 -11
- package/src/agent-skills/hubspot-pagebuilder-block/SKILL.md +31 -12
- package/src/agent-skills/page-builder-block/SKILL.md +26 -13
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/revalidate/route.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/rich-text.tsx +1 -1
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/block-actions-item.tsx +2 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/component-preview-frame.tsx +124 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/component-preview-pane.tsx +25 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-builder-input.tsx +3 -26
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-builder-insert-menu.tsx +121 -93
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/icons.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-builder-config.ts +22 -50
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/presentation.ts +1 -18
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +56 -64
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +4 -8
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/index.ts +0 -1
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +1 -4
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/block.ts +4 -4
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page-builder.ts +4 -18
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page.ts +11 -37
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/singletons.ts +0 -16
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/structure.ts +35 -33
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/studio-embed.ts +22 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/api/revalidate/route.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/rich-text.tsx +1 -1
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/block-actions-item.tsx +2 -2
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/component-preview-frame.tsx +124 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/component-preview-pane.tsx +25 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/page-builder-input.tsx +3 -26
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/page-builder-insert-menu.tsx +121 -93
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/icons.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/page-builder-config.ts +22 -50
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/presentation.ts +1 -18
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts +56 -64
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/sanity.config.ts +4 -8
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/index.ts +0 -1
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/index.ts +1 -4
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/block.ts +4 -4
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page-builder.ts +4 -18
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page.ts +11 -37
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/singletons.ts +0 -16
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/structure.ts +35 -33
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/studio-embed.ts +22 -0
- package/src/modules/features/forms/hubspot/files/_sanity-adapter/form-block.ts +4 -10
- package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/README.md +10 -5
- package/src/modules/features/jobs/ashby/files/_sanity-adapter/job-board-block.ts +0 -7
- package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/README.md +11 -5
- package/src/templates/next-default/lib/utils/README.md +1 -0
- package/src/templates/next-default/lib/utils/image-sizes.ts +64 -25
- package/src/templates/next-experiments/lib/utils/README.md +1 -0
- package/src/templates/next-experiments/lib/utils/image-sizes.ts +64 -25
- package/src/templates/next-pagebuilder/AGENTS.md +19 -7
- package/src/templates/next-pagebuilder/README.md +15 -3
- package/src/templates/next-pagebuilder/app/actions/unlock-gated-content.ts +5 -4
- package/src/templates/next-pagebuilder/app/components/page.tsx +81 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/gated-content/index.tsx +8 -3
- package/src/templates/next-pagebuilder/components/page-builder/library.ts +183 -0
- package/src/templates/next-pagebuilder/components/page-builder/registry.tsx +4 -1
- package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +3 -1
- package/src/templates/next-pagebuilder/components/page-builder/stage.tsx +10 -0
- package/src/templates/next-pagebuilder/components/page-document/index.tsx +2 -1
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +139 -271
- package/src/templates/next-pagebuilder/lib/utils/image-sizes.ts +64 -25
- package/src/templates/next-pagebuilder-cache/AGENTS.md +19 -7
- package/src/templates/next-pagebuilder-cache/README.md +15 -3
- package/src/templates/next-pagebuilder-cache/app/actions/unlock-gated-content.ts +5 -4
- package/src/templates/next-pagebuilder-cache/app/components/page.tsx +91 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/gated-content/index.tsx +8 -3
- package/src/templates/next-pagebuilder-cache/components/page-builder/library.ts +183 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/registry.tsx +4 -1
- package/src/templates/next-pagebuilder-cache/components/page-builder/renderer.tsx +3 -1
- package/src/templates/next-pagebuilder-cache/components/page-builder/stage.tsx +10 -0
- package/src/templates/next-pagebuilder-cache/components/page-document/index.tsx +2 -1
- package/src/templates/next-pagebuilder-cache/lib/integrations/sanity/sanity.types.ts +139 -271
- package/src/templates/next-pagebuilder-cache/lib/utils/image-sizes.ts +64 -25
- package/src/templates/next-webgl/lib/utils/README.md +1 -0
- package/src/templates/next-webgl/lib/utils/image-sizes.ts +64 -25
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/use-studio-preview-urls.ts +0 -62
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/studio-preview.ts +0 -37
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/use-studio-preview-urls.ts +0 -62
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/studio-preview.ts +0 -37
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { PageBuilderDocumentType } from "@/lib/integrations/sanity/page-builder-config"
|
|
2
|
+
import type { PageBuilderBlock } from "./types"
|
|
3
|
+
|
|
4
|
+
/** One block's stand-in value, rendered by `/components` through `Renderer`. */
|
|
5
|
+
export type LibraryEntry = {
|
|
6
|
+
documentType: PageBuilderDocumentType
|
|
7
|
+
title: string
|
|
8
|
+
notes: string
|
|
9
|
+
background: string
|
|
10
|
+
block: PageBuilderBlock
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type BlockOf<T extends PageBuilderDocumentType> = Extract<
|
|
14
|
+
PageBuilderBlock,
|
|
15
|
+
{ _type: T }
|
|
16
|
+
>
|
|
17
|
+
|
|
18
|
+
const span = (key: string, text: string) => ({
|
|
19
|
+
_type: "span" as const,
|
|
20
|
+
_key: key,
|
|
21
|
+
text,
|
|
22
|
+
marks: [],
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const paragraph = (key: string, text: string) => ({
|
|
26
|
+
_type: "block" as const,
|
|
27
|
+
_key: key,
|
|
28
|
+
style: "normal" as const,
|
|
29
|
+
markDefs: [],
|
|
30
|
+
children: [span(`${key}-span`, text)],
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const heading = (key: string, text: string) => ({
|
|
34
|
+
...paragraph(key, text),
|
|
35
|
+
style: "h2" as const,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const PLACEHOLDER_KEY = "placeholder"
|
|
39
|
+
|
|
40
|
+
const hero: BlockOf<"hero"> = {
|
|
41
|
+
_key: PLACEHOLDER_KEY,
|
|
42
|
+
_type: "hero",
|
|
43
|
+
headline: "A heading that says what this page is for.",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const description: BlockOf<"description"> = {
|
|
47
|
+
_key: PLACEHOLDER_KEY,
|
|
48
|
+
_type: "description",
|
|
49
|
+
description:
|
|
50
|
+
"One paragraph of standfirst copy under a heading — long enough to set up the page, short enough that nobody skips it.",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const richTextBlock: BlockOf<"richTextBlock"> = {
|
|
54
|
+
_key: PLACEHOLDER_KEY,
|
|
55
|
+
_type: "richTextBlock",
|
|
56
|
+
content: [
|
|
57
|
+
heading("rt-head", "What long-form copy looks like here"),
|
|
58
|
+
paragraph(
|
|
59
|
+
"rt-one",
|
|
60
|
+
"Rich Text is the block for body copy: headings, paragraphs, lists, links and quotes, all authored in the Studio and rendered with the site's own typography."
|
|
61
|
+
),
|
|
62
|
+
paragraph(
|
|
63
|
+
"rt-two",
|
|
64
|
+
"Because it is Portable Text rather than HTML, the same content renders in the page, in the markdown route and in the feed without a second template."
|
|
65
|
+
),
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const gatedContent: BlockOf<"gatedContent"> = {
|
|
70
|
+
_key: PLACEHOLDER_KEY,
|
|
71
|
+
_type: "gatedContent",
|
|
72
|
+
internalTitle: "Gated guide",
|
|
73
|
+
teaserHeading: "A guide worth an email address",
|
|
74
|
+
teaserBody: [
|
|
75
|
+
paragraph(
|
|
76
|
+
"gc-teaser",
|
|
77
|
+
"The teaser is public. The payload — rich text, a file or a video — is withheld from the page query until a visitor submits the form."
|
|
78
|
+
),
|
|
79
|
+
],
|
|
80
|
+
gateType: "form",
|
|
81
|
+
gateHeadline: "Read the full guide",
|
|
82
|
+
gateDescription: "We'll email you a copy as well.",
|
|
83
|
+
submitLabel: "Get the guide",
|
|
84
|
+
successMessage: "Sent — it's on its way.",
|
|
85
|
+
kind: "richText",
|
|
86
|
+
anchorId: null,
|
|
87
|
+
presentation: null,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const blogCollection: BlockOf<"blogCollection"> = {
|
|
91
|
+
_key: PLACEHOLDER_KEY,
|
|
92
|
+
_type: "blogCollection",
|
|
93
|
+
subtitle: "Everything else we've written",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const blogContent: BlockOf<"blogContent"> = {
|
|
97
|
+
_key: PLACEHOLDER_KEY,
|
|
98
|
+
_type: "blogContent",
|
|
99
|
+
title: "How this starter renders a blog post",
|
|
100
|
+
categories: [],
|
|
101
|
+
date: "2026-02-11",
|
|
102
|
+
author: {
|
|
103
|
+
_id: "placeholder-author",
|
|
104
|
+
name: "Jane Doe",
|
|
105
|
+
avatar: null,
|
|
106
|
+
role: "Engineer",
|
|
107
|
+
},
|
|
108
|
+
body: [
|
|
109
|
+
paragraph(
|
|
110
|
+
"bc-one",
|
|
111
|
+
"A blog post is an ordinary page whose page builder holds a Blog Posts block: byline, date, categories and body all live on the block."
|
|
112
|
+
),
|
|
113
|
+
heading("bc-head", "One block, one article"),
|
|
114
|
+
paragraph(
|
|
115
|
+
"bc-two",
|
|
116
|
+
"The collection block reads the same fields, so an article added in the Studio shows up in the index without touching code."
|
|
117
|
+
),
|
|
118
|
+
],
|
|
119
|
+
relatedPosts: [],
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const COMPONENT_LIBRARY: LibraryEntry[] = [
|
|
123
|
+
{
|
|
124
|
+
documentType: "hero",
|
|
125
|
+
title: "Heading",
|
|
126
|
+
notes: "The page's opening statement. Headline only, no media.",
|
|
127
|
+
background: "bg-white",
|
|
128
|
+
block: hero,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
documentType: "description",
|
|
132
|
+
title: "Description",
|
|
133
|
+
notes: "A single paragraph of standfirst copy under a heading.",
|
|
134
|
+
background: "bg-white",
|
|
135
|
+
block: description,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
documentType: "richTextBlock",
|
|
139
|
+
title: "Rich Text",
|
|
140
|
+
notes: "Long-form body copy — headings, lists, links and quotes.",
|
|
141
|
+
background: "bg-white",
|
|
142
|
+
block: richTextBlock,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
documentType: "gatedContent",
|
|
146
|
+
title: "Gated Content",
|
|
147
|
+
notes:
|
|
148
|
+
"A teaser with an email gate. The payload is withheld until a visitor submits, so the preview shows the locked state.",
|
|
149
|
+
background: "bg-white",
|
|
150
|
+
block: gatedContent,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
documentType: "blogCollection",
|
|
154
|
+
title: "Blog Collection",
|
|
155
|
+
notes:
|
|
156
|
+
"The full article index with search and category filters. Reads real posts.",
|
|
157
|
+
background: "bg-white",
|
|
158
|
+
block: blogCollection,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
documentType: "blogContent",
|
|
162
|
+
title: "Blog Posts",
|
|
163
|
+
notes:
|
|
164
|
+
"The body of an article — byline, date, categories and rich text. Only valid on a blog entry page.",
|
|
165
|
+
background: "bg-white",
|
|
166
|
+
block: blogContent,
|
|
167
|
+
},
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
export const getLibraryEntry = (documentType: string | undefined) =>
|
|
171
|
+
documentType
|
|
172
|
+
? (COMPONENT_LIBRARY.find((entry) => entry.documentType === documentType) ??
|
|
173
|
+
null)
|
|
174
|
+
: null
|
|
175
|
+
|
|
176
|
+
export const COMPONENT_PREVIEW_PATH = "/components"
|
|
177
|
+
|
|
178
|
+
export const COMPONENT_PREVIEW_PARAM = "component"
|
|
179
|
+
|
|
180
|
+
export const getComponentPreviewPath = (documentType?: string) =>
|
|
181
|
+
documentType
|
|
182
|
+
? `${COMPONENT_PREVIEW_PATH}?${COMPONENT_PREVIEW_PARAM}=${encodeURIComponent(documentType)}`
|
|
183
|
+
: COMPONENT_PREVIEW_PATH
|
|
@@ -13,6 +13,7 @@ import { RichTextBlock } from "./components/rich-text-block"
|
|
|
13
13
|
import type { PageBuilderBlock } from "./types"
|
|
14
14
|
|
|
15
15
|
export type BlockContext = {
|
|
16
|
+
pageId: string
|
|
16
17
|
searchParams: ContentCollectionSearchParams
|
|
17
18
|
pinnedCategory: PinnedCollectionCategory
|
|
18
19
|
}
|
|
@@ -48,7 +49,9 @@ const blockRegistry: {
|
|
|
48
49
|
isEmpty: (block) => !block.description,
|
|
49
50
|
},
|
|
50
51
|
gatedContent: {
|
|
51
|
-
render: (block
|
|
52
|
+
render: (block, { pageId }) => (
|
|
53
|
+
<GatedContent block={block} pageId={pageId} />
|
|
54
|
+
),
|
|
52
55
|
},
|
|
53
56
|
hero: {
|
|
54
57
|
render: (block) => <Hero block={block} />,
|
|
@@ -12,18 +12,20 @@ import type { PageBuilderBlock, PageBuilderBlocks } from "./types"
|
|
|
12
12
|
|
|
13
13
|
type RendererProps = {
|
|
14
14
|
blocks: PageBuilderBlocks
|
|
15
|
+
pageId: string
|
|
15
16
|
searchParams: ContentCollectionSearchParams
|
|
16
17
|
pinnedCategory: PinnedCollectionCategory
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export function Renderer({
|
|
20
21
|
blocks,
|
|
22
|
+
pageId,
|
|
21
23
|
searchParams,
|
|
22
24
|
pinnedCategory,
|
|
23
25
|
}: RendererProps) {
|
|
24
26
|
if (!blocks?.length) return null
|
|
25
27
|
|
|
26
|
-
const context: BlockContext = { searchParams, pinnedCategory }
|
|
28
|
+
const context: BlockContext = { pageId, searchParams, pinnedCategory }
|
|
27
29
|
|
|
28
30
|
const reservedAnchorIds = reserveAnchorIds(blocks)
|
|
29
31
|
const takenAnchorIds = new Set<string>()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PropsWithChildren } from "react"
|
|
2
|
+
import { cn } from "@/lib/styles/cn"
|
|
3
|
+
|
|
4
|
+
type StageProps = PropsWithChildren<{ background?: string }>
|
|
5
|
+
|
|
6
|
+
export const Stage = ({ background, children }: StageProps) => (
|
|
7
|
+
<div className={cn("grid min-h-svh content-center", background)}>
|
|
8
|
+
{children}
|
|
9
|
+
</div>
|
|
10
|
+
)
|
|
@@ -31,6 +31,7 @@ export const getPageSections = (
|
|
|
31
31
|
<Renderer
|
|
32
32
|
key="page-builder"
|
|
33
33
|
blocks={page.pageBuilder}
|
|
34
|
+
pageId={page._id}
|
|
34
35
|
searchParams={searchParams}
|
|
35
36
|
pinnedCategory={stegaClean(page.collectionCategory)}
|
|
36
37
|
/>,
|
|
@@ -90,7 +91,7 @@ export const PageDocument = ({
|
|
|
90
91
|
// Editor-selected page-level structured data (FAQ, Event, custom, etc.).
|
|
91
92
|
const pageJsonLd = buildPageJsonLd(page.metadata?.jsonLd)
|
|
92
93
|
|
|
93
|
-
// Blog posts (pages with a Blog
|
|
94
|
+
// Blog posts (pages with a Blog Posts block) emit Article JSON-LD with
|
|
94
95
|
// fields derived from the post — no Custom block needed. Skipped when the
|
|
95
96
|
// editor already supplied an Article (via a Custom block) to avoid duplicates.
|
|
96
97
|
const blogBlock = page.pageBuilder?.find(
|