bsmnt 0.13.1 → 0.15.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 (177) hide show
  1. package/dist/core/create/internal-ids.d.ts +1 -0
  2. package/dist/core/create/internal-ids.d.ts.map +1 -1
  3. package/dist/core/create/internal-ids.js +1 -0
  4. package/dist/core/create/internal-ids.js.map +1 -1
  5. package/dist/domain/skills.d.ts +5 -0
  6. package/dist/domain/skills.d.ts.map +1 -1
  7. package/dist/domain/skills.js +9 -1
  8. package/dist/domain/skills.js.map +1 -1
  9. package/dist/infrastructure/create/format-project.d.ts +9 -0
  10. package/dist/infrastructure/create/format-project.d.ts.map +1 -0
  11. package/dist/infrastructure/create/format-project.js +21 -0
  12. package/dist/infrastructure/create/format-project.js.map +1 -0
  13. package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
  14. package/dist/infrastructure/create/lifecycle-registry.js +5 -0
  15. package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
  16. package/dist/modules/features/cms/sanity-pagebuilder/config.d.ts.map +1 -1
  17. package/dist/modules/features/cms/sanity-pagebuilder/config.js +1 -0
  18. package/dist/modules/features/cms/sanity-pagebuilder/config.js.map +1 -1
  19. package/dist/modules/features/cms/sanity-pagebuilder/index.d.ts.map +1 -1
  20. package/dist/modules/features/cms/sanity-pagebuilder/index.js +1 -0
  21. package/dist/modules/features/cms/sanity-pagebuilder/index.js.map +1 -1
  22. package/dist/modules/features/cms/sanity-pagebuilder-cache/config.d.ts.map +1 -1
  23. package/dist/modules/features/cms/sanity-pagebuilder-cache/config.js +1 -0
  24. package/dist/modules/features/cms/sanity-pagebuilder-cache/config.js.map +1 -1
  25. package/dist/modules/features/cms/sanity-pagebuilder-cache/index.d.ts.map +1 -1
  26. package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js +1 -0
  27. package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/agent-skills/ashby-pagebuilder-block/SKILL.md +29 -11
  30. package/src/agent-skills/hubspot-pagebuilder-block/SKILL.md +31 -12
  31. package/src/agent-skills/launch-ready/SKILL.md +114 -0
  32. package/src/agent-skills/launch-ready/references/a11y.md +74 -0
  33. package/src/agent-skills/launch-ready/references/content.md +65 -0
  34. package/src/agent-skills/launch-ready/references/crawlers.md +89 -0
  35. package/src/agent-skills/launch-ready/references/launch.md +44 -0
  36. package/src/agent-skills/launch-ready/references/metadata.md +83 -0
  37. package/src/agent-skills/launch-ready/references/performance.md +36 -0
  38. package/src/agent-skills/launch-ready/references/routing.md +47 -0
  39. package/src/agent-skills/launch-ready/references/security.md +39 -0
  40. package/src/agent-skills/page-builder-block/SKILL.md +26 -13
  41. package/src/modules/features/cms/sanity/files/app/layout.tsx +2 -2
  42. package/src/modules/features/cms/sanity/files/lib/utils/metadata.ts +2 -2
  43. package/src/modules/features/cms/sanity/files/lib/utils/url.ts +6 -3
  44. package/src/modules/features/cms/sanity-pagebuilder/files/app/api/revalidate/route.ts +2 -2
  45. package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/rich-text.tsx +4 -2
  46. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/block-actions-item.tsx +2 -2
  47. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/component-preview-frame.tsx +124 -0
  48. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/component-preview-pane.tsx +25 -0
  49. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-builder-input.tsx +3 -26
  50. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-builder-insert-menu.tsx +121 -93
  51. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/redirect-import-dialog.tsx +538 -0
  52. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/csv.ts +88 -0
  53. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/breadcrumbs.ts +22 -0
  54. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/icons.ts +2 -2
  55. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-builder-config.ts +36 -49
  56. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/presentation.ts +1 -50
  57. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +76 -64
  58. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/redirect-import.ts +651 -0
  59. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +6 -8
  60. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/index.ts +0 -1
  61. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +1 -4
  62. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/redirect.ts +9 -6
  63. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/structured-data.ts +8 -0
  64. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/block.ts +4 -4
  65. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/metadata.ts +60 -6
  66. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page-builder.ts +4 -18
  67. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page.ts +33 -38
  68. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/richText.ts +0 -1
  69. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/singletons.ts +0 -16
  70. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/structure.ts +52 -35
  71. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/tags.ts +5 -2
  72. package/src/modules/features/cms/sanity-pagebuilder/files/lib/scripts/sanity-typegen.ts +8 -11
  73. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/metadata.ts +109 -136
  74. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/studio-embed.ts +22 -0
  75. package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/api/revalidate/route.ts +2 -2
  76. package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/rich-text.tsx +4 -2
  77. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/block-actions-item.tsx +2 -2
  78. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/component-preview-frame.tsx +124 -0
  79. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/component-preview-pane.tsx +25 -0
  80. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/page-builder-input.tsx +3 -26
  81. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/page-builder-insert-menu.tsx +121 -93
  82. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/redirect-import-dialog.tsx +538 -0
  83. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/csv.ts +88 -0
  84. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/fetchers/breadcrumbs.ts +25 -0
  85. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/icons.ts +2 -2
  86. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/page-builder-config.ts +36 -49
  87. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/presentation.ts +1 -50
  88. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts +76 -64
  89. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/redirect-import.ts +651 -0
  90. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/sanity.config.ts +6 -8
  91. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/index.ts +0 -1
  92. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/index.ts +1 -4
  93. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/redirect.ts +9 -6
  94. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/structured-data.ts +8 -0
  95. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/block.ts +4 -4
  96. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/metadata.ts +60 -6
  97. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page-builder.ts +4 -18
  98. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page.ts +33 -38
  99. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/richText.ts +0 -1
  100. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/singletons.ts +0 -16
  101. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/structure.ts +52 -35
  102. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/tags.ts +6 -2
  103. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/scripts/sanity-typegen.ts +8 -11
  104. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/metadata.ts +109 -136
  105. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/studio-embed.ts +22 -0
  106. package/src/modules/features/forms/hubspot/files/_sanity-adapter/form-block.ts +4 -10
  107. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/README.md +10 -5
  108. package/src/modules/features/jobs/ashby/files/_sanity-adapter/job-board-block.ts +0 -7
  109. package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/README.md +11 -5
  110. package/src/templates/next-default/.env.example +3 -1
  111. package/src/templates/next-default/app/layout.tsx +2 -1
  112. package/src/templates/next-default/app/robots.ts +9 -3
  113. package/src/templates/next-default/lib/utils/metadata.ts +2 -1
  114. package/src/templates/next-default/lib/utils/url.ts +20 -3
  115. package/src/templates/next-default/next.config.ts +16 -0
  116. package/src/templates/next-experiments/.env.example +3 -1
  117. package/src/templates/next-experiments/app/layout.tsx +2 -1
  118. package/src/templates/next-experiments/app/robots.ts +9 -3
  119. package/src/templates/next-experiments/lib/utils/metadata.ts +2 -1
  120. package/src/templates/next-experiments/lib/utils/url.ts +20 -3
  121. package/src/templates/next-experiments/next.config.ts +16 -0
  122. package/src/templates/next-pagebuilder/.env.example +3 -1
  123. package/src/templates/next-pagebuilder/.github/workflows/ci.yml +32 -8
  124. package/src/templates/next-pagebuilder/AGENTS.md +22 -7
  125. package/src/templates/next-pagebuilder/README.md +15 -3
  126. package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +45 -7
  127. package/src/templates/next-pagebuilder/app/actions/unlock-gated-content.ts +5 -4
  128. package/src/templates/next-pagebuilder/app/components/page.tsx +81 -0
  129. package/src/templates/next-pagebuilder/app/layout.tsx +3 -41
  130. package/src/templates/next-pagebuilder/app/robots.ts +9 -3
  131. package/src/templates/next-pagebuilder/biome.json +2 -1
  132. package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +1 -1
  133. package/src/templates/next-pagebuilder/components/page-builder/components/gated-content/index.tsx +8 -3
  134. package/src/templates/next-pagebuilder/components/page-builder/library.ts +183 -0
  135. package/src/templates/next-pagebuilder/components/page-builder/registry.tsx +4 -1
  136. package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +3 -1
  137. package/src/templates/next-pagebuilder/components/page-builder/stage.tsx +10 -0
  138. package/src/templates/next-pagebuilder/components/page-document/index.tsx +28 -35
  139. package/src/templates/next-pagebuilder/lefthook.yml +1 -1
  140. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +170 -299
  141. package/src/templates/next-pagebuilder/lib/utils/base-url.ts +18 -3
  142. package/src/templates/next-pagebuilder/lib/utils/breadcrumbs.ts +70 -0
  143. package/src/templates/next-pagebuilder/next.config.ts +16 -0
  144. package/src/templates/next-pagebuilder/package.json +1 -1
  145. package/src/templates/next-pagebuilder-cache/.env.example +3 -1
  146. package/src/templates/next-pagebuilder-cache/.github/workflows/ci.yml +32 -8
  147. package/src/templates/next-pagebuilder-cache/AGENTS.md +22 -7
  148. package/src/templates/next-pagebuilder-cache/README.md +15 -3
  149. package/src/templates/next-pagebuilder-cache/app/(content)/[[...slug]]/page.tsx +46 -7
  150. package/src/templates/next-pagebuilder-cache/app/actions/unlock-gated-content.ts +5 -4
  151. package/src/templates/next-pagebuilder-cache/app/components/page.tsx +91 -0
  152. package/src/templates/next-pagebuilder-cache/app/layout.tsx +5 -46
  153. package/src/templates/next-pagebuilder-cache/app/robots.ts +9 -3
  154. package/src/templates/next-pagebuilder-cache/biome.json +2 -1
  155. package/src/templates/next-pagebuilder-cache/components/layout/footer/index.tsx +1 -1
  156. package/src/templates/next-pagebuilder-cache/components/page-builder/components/gated-content/index.tsx +8 -3
  157. package/src/templates/next-pagebuilder-cache/components/page-builder/library.ts +183 -0
  158. package/src/templates/next-pagebuilder-cache/components/page-builder/registry.tsx +4 -1
  159. package/src/templates/next-pagebuilder-cache/components/page-builder/renderer.tsx +3 -1
  160. package/src/templates/next-pagebuilder-cache/components/page-builder/stage.tsx +10 -0
  161. package/src/templates/next-pagebuilder-cache/components/page-document/index.tsx +28 -35
  162. package/src/templates/next-pagebuilder-cache/lefthook.yml +1 -1
  163. package/src/templates/next-pagebuilder-cache/lib/integrations/sanity/sanity.types.ts +170 -299
  164. package/src/templates/next-pagebuilder-cache/lib/utils/base-url.ts +18 -3
  165. package/src/templates/next-pagebuilder-cache/lib/utils/breadcrumbs.ts +70 -0
  166. package/src/templates/next-pagebuilder-cache/next.config.ts +16 -0
  167. package/src/templates/next-pagebuilder-cache/package.json +1 -1
  168. package/src/templates/next-webgl/.env.example +3 -1
  169. package/src/templates/next-webgl/app/layout.tsx +2 -1
  170. package/src/templates/next-webgl/app/robots.ts +9 -3
  171. package/src/templates/next-webgl/lib/utils/metadata.ts +2 -1
  172. package/src/templates/next-webgl/lib/utils/url.ts +20 -3
  173. package/src/templates/next-webgl/next.config.ts +16 -0
  174. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/use-studio-preview-urls.ts +0 -62
  175. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/studio-preview.ts +0 -37
  176. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/use-studio-preview-urls.ts +0 -62
  177. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/studio-preview.ts +0 -37
@@ -1,5 +1,4 @@
1
1
  import { contentIcon, pageIcon, type SanityStudioIcon } from "./icons";
2
- import { singletonComponents } from "./singletons";
3
2
 
4
3
  export type PageBuilderDocumentType =
5
4
  | "hero"
@@ -7,7 +6,7 @@ export type PageBuilderDocumentType =
7
6
  | "richTextBlock"
8
7
  | "gatedContent"
9
8
  | "blogContent"
10
- | (typeof singletonComponents)[number]["schemaType"];
9
+ | "blogCollection";
11
10
 
12
11
  /**
13
12
  * A block declares two orthogonal axes. `pageTypes` is which page documents may
@@ -27,18 +26,16 @@ export const componentCategories = [
27
26
 
28
27
  export type ComponentCategory = (typeof componentCategories)[number]["name"];
29
28
 
30
- type PageBuilderReferenceMember = {
29
+ type PageBuilderBlockMember = {
31
30
  documentType: PageBuilderDocumentType;
32
- name: string;
33
31
  title: string;
34
- documentId?: string;
35
32
  pageTypes: readonly PageBuilderGroupName[];
36
33
  category: ComponentCategory;
34
+ // Renders the page's H1, which replaces the title heading the page would
35
+ // otherwise render.
36
+ rendersPageHeading?: true;
37
37
  };
38
38
 
39
- export const blockPreviewKey = (schemaTypeName: string) =>
40
- `block.${schemaTypeName}`;
41
-
42
39
  export const pageBuilderPageTypes: Array<{
43
40
  title: string;
44
41
  value: PageBuilderGroupName;
@@ -56,78 +53,62 @@ export const getPageCategoryIcon = (
56
53
  pageType: PageBuilderGroupName | undefined | null,
57
54
  ) => pageCategoryIcons[pageType ?? "generic"];
58
55
 
59
- const reusablePageBuilderReferenceMembers: PageBuilderReferenceMember[] = [
56
+ export const pageBuilderBlockMembers: PageBuilderBlockMember[] = [
60
57
  {
61
58
  documentType: "hero",
62
- name: "heroReference",
63
59
  title: "Heading",
64
60
  pageTypes: ["generic"],
65
61
  category: "hero",
62
+ rendersPageHeading: true,
66
63
  },
67
64
  {
68
65
  documentType: "description",
69
- name: "descriptionReference",
70
66
  title: "Description",
71
67
  pageTypes: ["generic"],
72
68
  category: "text",
73
69
  },
74
70
  {
75
71
  documentType: "richTextBlock",
76
- name: "richTextBlockReference",
77
72
  title: "Rich Text",
78
73
  pageTypes: ["generic"],
79
74
  category: "text",
80
75
  },
81
76
  {
82
77
  documentType: "gatedContent",
83
- name: "gatedContentReference",
84
78
  title: "Gated Content",
85
79
  pageTypes: ["generic"],
86
80
  category: "misc",
87
81
  },
82
+ {
83
+ documentType: "blogCollection",
84
+ title: "Blog Collection",
85
+ pageTypes: ["generic"],
86
+ category: "list",
87
+ },
88
88
  {
89
89
  documentType: "blogContent",
90
- name: "blogContentReference",
91
90
  title: "Blog Posts",
92
91
  pageTypes: ["blogEntry"],
93
92
  category: "content",
94
93
  },
95
94
  ];
96
95
 
97
- const singletonPageBuilderReferenceMembers: PageBuilderReferenceMember[] =
98
- singletonComponents.map((component) => ({
99
- documentType: component.schemaType,
100
- name: `${component.schemaType}Reference`,
101
- title: component.title,
102
- documentId: component.documentId,
103
- pageTypes: ["generic"],
104
- category: component.category,
105
- }));
106
-
107
- export const pageBuilderReferenceMembers: PageBuilderReferenceMember[] = [
108
- ...reusablePageBuilderReferenceMembers,
109
- ...singletonPageBuilderReferenceMembers,
110
- ];
111
-
112
- export const getPageBuilderReferenceMember = (name: string) =>
113
- pageBuilderReferenceMembers.find((member) => member.name === name);
114
-
115
- export const getPageBuilderReferenceMemberByDocumentType = (
96
+ export const getPageBuilderBlockMember = (
116
97
  documentType: PageBuilderDocumentType,
117
98
  ) =>
118
- pageBuilderReferenceMembers.find(
99
+ pageBuilderBlockMembers.find(
119
100
  (member) => member.documentType === documentType,
120
101
  );
121
102
 
122
103
  const isMemberVisibleForPageType = (
123
- member: PageBuilderReferenceMember,
104
+ member: PageBuilderBlockMember,
124
105
  pageType: PageBuilderGroupName | undefined,
125
106
  ) => member.pageTypes.includes(pageType ?? "generic");
126
107
 
127
- export const getVisiblePageBuilderReferenceMembers = (
108
+ export const getVisiblePageBuilderBlockMembers = (
128
109
  pageType: PageBuilderGroupName | undefined,
129
110
  ) =>
130
- pageBuilderReferenceMembers.filter((member) =>
111
+ pageBuilderBlockMembers.filter((member) =>
131
112
  isMemberVisibleForPageType(member, pageType),
132
113
  );
133
114
 
@@ -135,7 +116,9 @@ export const getVisiblePageBuilderMemberNames = (
135
116
  pageType: PageBuilderGroupName | undefined,
136
117
  ) =>
137
118
  new Set(
138
- getVisiblePageBuilderReferenceMembers(pageType).map((member) => member.name),
119
+ getVisiblePageBuilderBlockMembers(pageType).map(
120
+ (member) => member.documentType,
121
+ ),
139
122
  );
140
123
 
141
124
  export const getVisiblePageBuilderInsertMenuGroups = (
@@ -155,28 +138,32 @@ export const getInvalidPageBuilderDocumentTypes = (
155
138
  documentTypes: PageBuilderDocumentType[],
156
139
  ) =>
157
140
  documentTypes.filter((documentType) => {
158
- const member = getPageBuilderReferenceMemberByDocumentType(documentType);
141
+ const member = getPageBuilderBlockMember(documentType);
159
142
 
160
143
  if (!member) return false;
161
144
 
162
145
  return !isMemberVisibleForPageType(member, pageType);
163
146
  });
164
147
 
148
+ export const countPageHeadingBlocks = (
149
+ blocks: ReadonlyArray<{ _key?: string; _type?: string }>,
150
+ hiddenKeys: readonly string[] = [],
151
+ ) =>
152
+ blocks.filter(
153
+ (block) =>
154
+ !(block._key && hiddenKeys.includes(block._key)) &&
155
+ getPageBuilderBlockMember(block._type as PageBuilderDocumentType)
156
+ ?.rendersPageHeading,
157
+ ).length;
158
+
165
159
  export const pageBuilderInsertMenuGroups: Array<{
166
160
  name: ComponentCategory;
167
161
  title: string;
168
- of: string[];
162
+ of: PageBuilderDocumentType[];
169
163
  }> = componentCategories.map(({ name, title }) => ({
170
164
  name,
171
165
  title,
172
- of: pageBuilderReferenceMembers
166
+ of: pageBuilderBlockMembers
173
167
  .filter((member) => member.category === name)
174
- .map((member) => member.name),
168
+ .map((member) => member.documentType),
175
169
  }));
176
-
177
- export const pageBuilderBlockPreviewOptions = pageBuilderReferenceMembers.map(
178
- (member) => ({
179
- title: `Block — ${member.title} · ${member.name}`,
180
- value: blockPreviewKey(member.name),
181
- }),
182
- );
@@ -7,7 +7,6 @@ import {
7
7
  presentationTool,
8
8
  } from "sanity/presentation";
9
9
  import { previewURL } from "./env";
10
- import { pageBuilderReferenceMembers } from "./page-builder-config";
11
10
  import { getPinnedPageById, HOMEPAGE_PINNED_PAGE } from "./pinned-pages";
12
11
 
13
12
  const MAX_FOLDER_DEPTH = 6;
@@ -44,52 +43,6 @@ const pageResolvedSlugExpression = buildNestedSlugExpression(
44
43
  "slug.current",
45
44
  );
46
45
 
47
- const PAGE_BUILDER_DOCUMENT_TYPES = new Set<string>(
48
- pageBuilderReferenceMembers.map((member) => member.documentType),
49
- );
50
-
51
- const HOST_PAGES_QUERY = `*[_type == "page" && references($id)]{
52
- _id,
53
- title,
54
- "resolvedSlug": ${pageResolvedSlugExpression}
55
- }`;
56
-
57
- type HostPage = {
58
- _id: string;
59
- title?: string;
60
- resolvedSlug?: string;
61
- };
62
-
63
- const isDraftId = (id: string) => id.startsWith("drafts.");
64
-
65
- const resolveHostPageLocations = (
66
- documentStore: DocumentStore,
67
- id: string,
68
- ): Observable<DocumentLocationsState> =>
69
- documentStore.listenQuery(HOST_PAGES_QUERY, { id }, {}).pipe(
70
- map((pages: HostPage[] | null) => {
71
- const deduped = new Map<string, HostPage>();
72
- for (const page of pages ?? []) {
73
- const publishedId = page._id.replace(/^drafts\./, "");
74
- const existing = deduped.get(publishedId);
75
- if (!existing || isDraftId(existing._id)) {
76
- deduped.set(publishedId, page);
77
- }
78
- }
79
-
80
- return {
81
- locations: [...deduped.values()].flatMap((page) => {
82
- const pinned = getPinnedPageById(page._id);
83
- const href =
84
- pinned?.path ??
85
- (page.resolvedSlug ? `/${page.resolvedSlug}` : null);
86
- if (!href) return [];
87
- return [{ title: page.title || pinned?.title || "Page", href }];
88
- }),
89
- };
90
- }),
91
- );
92
-
93
46
  const resolveSlugLocation = <T extends { title?: string }>(
94
47
  documentStore: DocumentStore,
95
48
  id: string,
@@ -136,9 +89,7 @@ export const presentation = presentationTool({
136
89
  );
137
90
  }
138
91
 
139
- if (!PAGE_BUILDER_DOCUMENT_TYPES.has(params.type)) return null;
140
-
141
- return resolveHostPageLocations(documentStore, params.id);
92
+ return null;
142
93
  },
143
94
  },
144
95
  previewUrl: {
@@ -88,58 +88,53 @@ const richTextLinkProjection = `
88
88
  const pageBuilderProjection = `
89
89
  pageBuilder[!(_key in coalesce(^.hiddenPageBuilderKeys, []))]{
90
90
  _key,
91
- ...@->{
92
- // Gated content withholds its payload from the page query — only the
93
- // teaser and gate config ship to the client. GROQ has no field exclusion,
94
- // so this branch lists safe fields explicitly rather than spreading every
95
- // field. The payload is fetched separately via GATED_CONTENT_QUERY.
96
- _type == "gatedContent" => {
97
- _id,
98
- _type,
99
- anchorId,
100
- presentation,
101
- internalTitle,
102
- teaserHeading,
103
- teaserBody[]{
91
+ // Gated content withholds its payload from the page query — only the
92
+ // teaser and gate config ship to the client. GROQ has no field exclusion,
93
+ // so this branch lists safe fields explicitly rather than spreading every
94
+ // field. The payload is fetched separately via GATED_CONTENT_QUERY.
95
+ _type == "gatedContent" => {
96
+ _type,
97
+ anchorId,
98
+ presentation,
99
+ internalTitle,
100
+ teaserHeading,
101
+ teaserBody[]{
102
+ ${richTextLinkProjection}
103
+ },
104
+ gateType,
105
+ gateHeadline,
106
+ gateDescription,
107
+ submitLabel,
108
+ successMessage,
109
+ kind
110
+ },
111
+ _type != "gatedContent" => {
112
+ ...,
113
+ _type == "richTextBlock" => {
114
+ content[]{
104
115
  ${richTextLinkProjection}
105
- },
106
- gateType,
107
- gateHeadline,
108
- gateDescription,
109
- submitLabel,
110
- successMessage,
111
- kind
116
+ }
112
117
  },
113
- _type != "gatedContent" => {
114
- ...,
115
- _type == "richTextBlock" => {
116
- ...,
117
- content[]{
118
- ${richTextLinkProjection}
119
- }
118
+ _type == "blogContent" => {
119
+ categories[]->{
120
+ _id,
121
+ title,
122
+ slug
123
+ },
124
+ author->{
125
+ _id,
126
+ name,
127
+ avatar,
128
+ role
129
+ },
130
+ body[]{
131
+ ${richTextLinkProjection}
120
132
  },
121
- _type == "blogContent" => {
122
- ...,
123
- categories[]->{
124
- _id,
125
- title,
126
- slug
127
- },
128
- author->{
129
- _id,
130
- name,
131
- avatar,
132
- role
133
- },
134
- body[]{
135
- ${richTextLinkProjection}
136
- },
137
- relatedPosts[]->{
138
- _id,
139
- title,
140
- "resolvedSlug": ${pageResolvedSlugExpression},
141
- metadata
142
- }
133
+ relatedPosts[]->{
134
+ _id,
135
+ title,
136
+ "resolvedSlug": ${pageResolvedSlugExpression},
137
+ metadata
143
138
  }
144
139
  }
145
140
  }
@@ -147,10 +142,13 @@ const pageBuilderProjection = `
147
142
  `;
148
143
 
149
144
  // Gated content payload — fetched on demand by the unlock server action, keyed
150
- // by the block's document id. Kept out of the page query so it never ships to
151
- // the client until the visitor completes the gate.
145
+ // by the hosting page plus the block's `_key`. Kept out of the page query so it
146
+ // never ships to the client until the visitor completes the gate.
152
147
  export const GATED_CONTENT_QUERY = defineQuery(`
153
- *[_type == "gatedContent" && _id == $id][0]{
148
+ *[
149
+ _type == "page" &&
150
+ (_id == $pageId || _id == "drafts." + $pageId)
151
+ ][0].pageBuilder[_key == $blockKey && _type == "gatedContent"][0]{
154
152
  kind,
155
153
  content[]{
156
154
  ${richTextLinkProjection}
@@ -231,16 +229,10 @@ export const P_REV_SLUGS_QUERY = defineQuery(`
231
229
  }
232
230
  `);
233
231
 
234
- // Pages depending on `$documentIds`, one or two hops out: one covers
235
- // `collectionCategory->`, two covers anything reached through a page-builder
236
- // block. All inline the referenced title or slug, so a change there goes stale.
237
232
  export const P_REF_DOC_PAGES_QUERY = defineQuery(`
238
233
  *[
239
234
  _type == "page" &&
240
- (
241
- references($documentIds) ||
242
- count(pageBuilder[_ref in *[references($documentIds)]._id]) > 0
243
- )
235
+ references($documentIds)
244
236
  ] | order(title asc) {
245
237
  _id,
246
238
  title,
@@ -285,6 +277,25 @@ export const P_REV_FOLDER_DESCENDANTS_QUERY = defineQuery(`
285
277
  }
286
278
  `);
287
279
 
280
+ // Path and labels of the homepage and the pages at `$paths`, for naming
281
+ // breadcrumbs. `folderTitle` is only set on a folder's index page.
282
+ export const BREADCRUMB_PAGES_QUERY = defineQuery(`
283
+ *[
284
+ _type == "page" &&
285
+ (
286
+ (!defined(pageFolder._ref) && (!defined(slug.current) || slug.current == "" || slug.current == "/")) ||
287
+ ${pageResolvedSlugExpression} in $paths
288
+ )
289
+ ]{
290
+ "path": ${pageResolvedSlugExpression},
291
+ title,
292
+ shortTitle,
293
+ "folderTitle": select(
294
+ defined(pageFolder) && (!defined(slug.current) || slug.current == "" || slug.current == "/") => pageFolder->title
295
+ )
296
+ }
297
+ `);
298
+
288
299
  export const PAGE_SITEMAP_QUERY = defineQuery(`
289
300
  *[
290
301
  _type == "page" &&
@@ -319,7 +330,7 @@ export const ALL_BLOG_ARTICLES_QUERY = defineQuery(`
319
330
  title,
320
331
  "slug": slug,
321
332
  "resolvedSlug": ${pageResolvedSlugExpression},
322
- "blogContent": pageBuilder[_ref in *[_type == "blogContent"]._id][0]->{
333
+ "blogContent": pageBuilder[_type == "blogContent"][0]{
323
334
  thumbnail{
324
335
  ...,
325
336
  alt
@@ -356,14 +367,14 @@ export const BLOG_ARTICLES_PAGINATED_QUERY = defineQuery(`
356
367
  (
357
368
  !defined($category) ||
358
369
  $category == "" ||
359
- $category in pageBuilder[_ref in *[_type == "blogContent"]._id][0]->categories[]->slug.current
370
+ $category in pageBuilder[_type == "blogContent"][0].categories[]->slug.current
360
371
  )
361
372
  ] | order(_updatedAt desc)[$offset...$end] {
362
373
  _id,
363
374
  title,
364
375
  "slug": slug,
365
376
  "resolvedSlug": ${pageResolvedSlugExpression},
366
- "blogContent": pageBuilder[_ref in *[_type == "blogContent"]._id][0]->{
377
+ "blogContent": pageBuilder[_type == "blogContent"][0]{
367
378
  thumbnail{
368
379
  ...,
369
380
  alt
@@ -395,7 +406,7 @@ export const BLOG_ARTICLES_COUNT_QUERY = defineQuery(`
395
406
  (
396
407
  !defined($category) ||
397
408
  $category == "" ||
398
- $category in pageBuilder[_ref in *[_type == "blogContent"]._id][0]->categories[]->slug.current
409
+ $category in pageBuilder[_type == "blogContent"][0].categories[]->slug.current
399
410
  )
400
411
  ])
401
412
  `);
@@ -415,7 +426,7 @@ export const ALL_BLOG_CATEGORIES_QUERY = defineQuery(`
415
426
  export const COLLECTION_PAGES_QUERY = defineQuery(`
416
427
  *[
417
428
  _type == "page" &&
418
- count(pageBuilder[!(_key in coalesce(^.hiddenPageBuilderKeys, [])) && _ref in *[_type == "blogCollection"]._id]) > 0
429
+ count(pageBuilder[!(_key in coalesce(^.hiddenPageBuilderKeys, [])) && _type == "blogCollection"]) > 0
419
430
  ] {
420
431
  "path": ${pageResolvedSlugExpression},
421
432
  "category": collectionCategory->slug.current
@@ -509,6 +520,7 @@ const structuredDataProjection = `
509
520
  description,
510
521
  url,
511
522
  "logo": logo.asset->url,
523
+ shareImage{ asset, hotspot, crop },
512
524
  contactPoint,
513
525
  address,
514
526
  "sameAs": array::unique(array::compact(