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.
- package/dist/core/create/internal-ids.d.ts +1 -0
- package/dist/core/create/internal-ids.d.ts.map +1 -1
- package/dist/core/create/internal-ids.js +1 -0
- package/dist/core/create/internal-ids.js.map +1 -1
- package/dist/domain/skills.d.ts +5 -0
- package/dist/domain/skills.d.ts.map +1 -1
- package/dist/domain/skills.js +9 -1
- package/dist/domain/skills.js.map +1 -1
- package/dist/infrastructure/create/format-project.d.ts +9 -0
- package/dist/infrastructure/create/format-project.d.ts.map +1 -0
- package/dist/infrastructure/create/format-project.js +21 -0
- package/dist/infrastructure/create/format-project.js.map +1 -0
- package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
- package/dist/infrastructure/create/lifecycle-registry.js +5 -0
- package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
- 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/index.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder/index.js +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder/index.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/dist/modules/features/cms/sanity-pagebuilder-cache/index.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/index.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/launch-ready/SKILL.md +114 -0
- package/src/agent-skills/launch-ready/references/a11y.md +74 -0
- package/src/agent-skills/launch-ready/references/content.md +65 -0
- package/src/agent-skills/launch-ready/references/crawlers.md +89 -0
- package/src/agent-skills/launch-ready/references/launch.md +44 -0
- package/src/agent-skills/launch-ready/references/metadata.md +83 -0
- package/src/agent-skills/launch-ready/references/performance.md +36 -0
- package/src/agent-skills/launch-ready/references/routing.md +47 -0
- package/src/agent-skills/launch-ready/references/security.md +39 -0
- package/src/agent-skills/page-builder-block/SKILL.md +26 -13
- package/src/modules/features/cms/sanity/files/app/layout.tsx +2 -2
- package/src/modules/features/cms/sanity/files/lib/utils/metadata.ts +2 -2
- package/src/modules/features/cms/sanity/files/lib/utils/url.ts +6 -3
- 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 +4 -2
- 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/components/redirect-import-dialog.tsx +538 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/csv.ts +88 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/breadcrumbs.ts +22 -0
- 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 +36 -49
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/presentation.ts +1 -50
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +76 -64
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/redirect-import.ts +651 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +6 -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/index.ts +1 -4
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/redirect.ts +9 -6
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/structured-data.ts +8 -0
- 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/metadata.ts +60 -6
- 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 +33 -38
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/richText.ts +0 -1
- 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 +52 -35
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/tags.ts +5 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/scripts/sanity-typegen.ts +8 -11
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/metadata.ts +109 -136
- 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 +4 -2
- 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/components/redirect-import-dialog.tsx +538 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/csv.ts +88 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/fetchers/breadcrumbs.ts +25 -0
- 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 +36 -49
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/presentation.ts +1 -50
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts +76 -64
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/redirect-import.ts +651 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/sanity.config.ts +6 -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/index.ts +1 -4
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/redirect.ts +9 -6
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/structured-data.ts +8 -0
- 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/metadata.ts +60 -6
- 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 +33 -38
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/richText.ts +0 -1
- 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 +52 -35
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/tags.ts +6 -2
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/scripts/sanity-typegen.ts +8 -11
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/metadata.ts +109 -136
- 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/.env.example +3 -1
- package/src/templates/next-default/app/layout.tsx +2 -1
- package/src/templates/next-default/app/robots.ts +9 -3
- package/src/templates/next-default/lib/utils/metadata.ts +2 -1
- package/src/templates/next-default/lib/utils/url.ts +20 -3
- package/src/templates/next-default/next.config.ts +16 -0
- package/src/templates/next-experiments/.env.example +3 -1
- package/src/templates/next-experiments/app/layout.tsx +2 -1
- package/src/templates/next-experiments/app/robots.ts +9 -3
- package/src/templates/next-experiments/lib/utils/metadata.ts +2 -1
- package/src/templates/next-experiments/lib/utils/url.ts +20 -3
- package/src/templates/next-experiments/next.config.ts +16 -0
- package/src/templates/next-pagebuilder/.env.example +3 -1
- package/src/templates/next-pagebuilder/.github/workflows/ci.yml +32 -8
- package/src/templates/next-pagebuilder/AGENTS.md +22 -7
- package/src/templates/next-pagebuilder/README.md +15 -3
- package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +45 -7
- 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/app/layout.tsx +3 -41
- package/src/templates/next-pagebuilder/app/robots.ts +9 -3
- package/src/templates/next-pagebuilder/biome.json +2 -1
- package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +1 -1
- 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 +28 -35
- package/src/templates/next-pagebuilder/lefthook.yml +1 -1
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +170 -299
- package/src/templates/next-pagebuilder/lib/utils/base-url.ts +18 -3
- package/src/templates/next-pagebuilder/lib/utils/breadcrumbs.ts +70 -0
- package/src/templates/next-pagebuilder/next.config.ts +16 -0
- package/src/templates/next-pagebuilder/package.json +1 -1
- package/src/templates/next-pagebuilder-cache/.env.example +3 -1
- package/src/templates/next-pagebuilder-cache/.github/workflows/ci.yml +32 -8
- package/src/templates/next-pagebuilder-cache/AGENTS.md +22 -7
- package/src/templates/next-pagebuilder-cache/README.md +15 -3
- package/src/templates/next-pagebuilder-cache/app/(content)/[[...slug]]/page.tsx +46 -7
- 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/app/layout.tsx +5 -46
- package/src/templates/next-pagebuilder-cache/app/robots.ts +9 -3
- package/src/templates/next-pagebuilder-cache/biome.json +2 -1
- package/src/templates/next-pagebuilder-cache/components/layout/footer/index.tsx +1 -1
- 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 +28 -35
- package/src/templates/next-pagebuilder-cache/lefthook.yml +1 -1
- package/src/templates/next-pagebuilder-cache/lib/integrations/sanity/sanity.types.ts +170 -299
- package/src/templates/next-pagebuilder-cache/lib/utils/base-url.ts +18 -3
- package/src/templates/next-pagebuilder-cache/lib/utils/breadcrumbs.ts +70 -0
- package/src/templates/next-pagebuilder-cache/next.config.ts +16 -0
- package/src/templates/next-pagebuilder-cache/package.json +1 -1
- package/src/templates/next-webgl/.env.example +3 -1
- package/src/templates/next-webgl/app/layout.tsx +2 -1
- package/src/templates/next-webgl/app/robots.ts +9 -3
- package/src/templates/next-webgl/lib/utils/metadata.ts +2 -1
- package/src/templates/next-webgl/lib/utils/url.ts +20 -3
- package/src/templates/next-webgl/next.config.ts +16 -0
- 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
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
gatedContent,
|
|
16
16
|
hero,
|
|
17
17
|
richTextBlock,
|
|
18
|
-
studioPreview,
|
|
19
18
|
} from "./components";
|
|
20
19
|
import { author } from "./content/author";
|
|
21
20
|
import { blogCategory } from "./content/blog-category";
|
|
@@ -83,7 +82,6 @@ export {
|
|
|
83
82
|
spacingSettings,
|
|
84
83
|
spacingStep,
|
|
85
84
|
structuredData,
|
|
86
|
-
studioPreview,
|
|
87
85
|
videoJsonLd,
|
|
88
86
|
};
|
|
89
87
|
|
|
@@ -121,8 +119,7 @@ export const schema: { types: SchemaTypeDefinition[] } = {
|
|
|
121
119
|
description,
|
|
122
120
|
richTextBlock,
|
|
123
121
|
gatedContent,
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
|
|
126
123
|
// Layout types (singletons for site-wide layout)
|
|
127
124
|
companyData,
|
|
128
125
|
navbar,
|
|
@@ -2,6 +2,9 @@ import { defineField, defineType } from "sanity";
|
|
|
2
2
|
import { apiVersion } from "@/lib/integrations/sanity/env";
|
|
3
3
|
import { redirectIcon } from "@/lib/integrations/sanity/icons";
|
|
4
4
|
|
|
5
|
+
export const REDIRECT_SOURCE_MAX_LENGTH = 200;
|
|
6
|
+
export const REDIRECT_PATH_PATTERN = /^[a-z0-9-/]+$/;
|
|
7
|
+
|
|
5
8
|
type RedirectValidationDocument = {
|
|
6
9
|
_id?: string;
|
|
7
10
|
source?: { current?: string };
|
|
@@ -23,14 +26,14 @@ export const redirect = defineType({
|
|
|
23
26
|
type: "slug",
|
|
24
27
|
description:
|
|
25
28
|
"Incoming route path to match, without a leading slash (e.g. old-page or blog/old-post).",
|
|
26
|
-
options: { maxLength:
|
|
29
|
+
options: { maxLength: REDIRECT_SOURCE_MAX_LENGTH },
|
|
27
30
|
validation: (Rule) =>
|
|
28
31
|
Rule.required().custom(async (slug, context) => {
|
|
29
32
|
if (!slug?.current) {
|
|
30
33
|
return "Source is required";
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
if (
|
|
36
|
+
if (!REDIRECT_PATH_PATTERN.test(slug.current)) {
|
|
34
37
|
return "Source must be lowercase with hyphens, letters, numbers, and forward slashes only";
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -63,15 +66,15 @@ export const redirect = defineType({
|
|
|
63
66
|
title: "Destination",
|
|
64
67
|
type: "string",
|
|
65
68
|
description:
|
|
66
|
-
"Where to send visitors. An internal route path without a leading slash (e.g. new-page or blog/new-post), or an absolute URL (e.g. https://example.com).",
|
|
69
|
+
"Where to send visitors. An internal route path without a leading slash (e.g. new-page or blog/new-post), / for the homepage, or an absolute URL (e.g. https://example.com).",
|
|
67
70
|
validation: (Rule) =>
|
|
68
71
|
Rule.required().custom(async (value, context) => {
|
|
69
72
|
if (typeof value !== "string") return true;
|
|
70
73
|
|
|
71
74
|
const isAbsolute = /^https?:\/\//.test(value);
|
|
72
|
-
if (isAbsolute) return true;
|
|
75
|
+
if (isAbsolute || value === "/") return true;
|
|
73
76
|
|
|
74
|
-
if (
|
|
77
|
+
if (!REDIRECT_PATH_PATTERN.test(value)) {
|
|
75
78
|
return "Destination must be a slash-free route path (lowercase, hyphens, numbers, forward slashes) or an absolute http(s) URL";
|
|
76
79
|
}
|
|
77
80
|
|
|
@@ -141,7 +144,7 @@ export const redirect = defineType({
|
|
|
141
144
|
if (destination) {
|
|
142
145
|
target = /^https?:\/\//.test(destination)
|
|
143
146
|
? destination
|
|
144
|
-
: `/${destination}`;
|
|
147
|
+
: `/${destination.replace(/^\/+/, "")}`;
|
|
145
148
|
}
|
|
146
149
|
return {
|
|
147
150
|
title: source ? `/${source}` : "Untitled redirect",
|
|
@@ -36,6 +36,14 @@ export const structuredData = defineType({
|
|
|
36
36
|
"Square or wide logo used in rich results. Min 112x112px, transparent PNG/SVG recommended.",
|
|
37
37
|
options: { hotspot: true },
|
|
38
38
|
}),
|
|
39
|
+
defineField({
|
|
40
|
+
name: "shareImage",
|
|
41
|
+
title: "Default Share Image",
|
|
42
|
+
type: "image",
|
|
43
|
+
description:
|
|
44
|
+
"Social preview (Open Graph) for any page without its own OG image. 1200x630px.",
|
|
45
|
+
options: { hotspot: true },
|
|
46
|
+
}),
|
|
39
47
|
defineField({
|
|
40
48
|
name: "description",
|
|
41
49
|
title: "Description",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type DocumentDefinition,
|
|
3
2
|
defineType,
|
|
4
3
|
type FieldDefinition,
|
|
5
4
|
type FieldGroupDefinition,
|
|
5
|
+
type ObjectDefinition,
|
|
6
6
|
} from "sanity";
|
|
7
7
|
import { presentationFields } from "./presentation";
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ const presentationGroup: FieldGroupDefinition = {
|
|
|
11
11
|
title: "Presentation",
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
type BlockDefinition = Omit<
|
|
14
|
+
type BlockDefinition = Omit<ObjectDefinition, "type" | "fields" | "groups"> & {
|
|
15
15
|
fields: FieldDefinition[];
|
|
16
16
|
groups?: FieldGroupDefinition[];
|
|
17
17
|
};
|
|
@@ -26,7 +26,7 @@ const withPresentationGroup = (groups: FieldGroupDefinition[] | undefined) => {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Defines a page-builder block — `type: "
|
|
29
|
+
* Defines a page-builder block — an inline `type: "object"` plus Anchor ID and
|
|
30
30
|
* Presentation Mode. Use instead of `defineType`.
|
|
31
31
|
*/
|
|
32
32
|
export const defineBlock = ({ fields, groups, ...rest }: BlockDefinition) => {
|
|
@@ -34,7 +34,7 @@ export const defineBlock = ({ fields, groups, ...rest }: BlockDefinition) => {
|
|
|
34
34
|
|
|
35
35
|
return defineType({
|
|
36
36
|
...rest,
|
|
37
|
-
type: "
|
|
37
|
+
type: "object",
|
|
38
38
|
...(blockGroups ? { groups: blockGroups } : {}),
|
|
39
39
|
fields: [
|
|
40
40
|
...fields,
|
|
@@ -1,6 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
defineArrayMember,
|
|
3
|
+
defineField,
|
|
4
|
+
defineType,
|
|
5
|
+
type ValidationContext,
|
|
6
|
+
} from "sanity";
|
|
7
|
+
import { apiVersion } from "@/lib/integrations/sanity/env";
|
|
2
8
|
import { pageJsonLdMembers } from "./structured-data-blocks";
|
|
3
9
|
|
|
10
|
+
const duplicateCountQuery = (
|
|
11
|
+
field: "metaTitle" | "metaDescription",
|
|
12
|
+
) => `count(*[
|
|
13
|
+
defined(metadata.${field}) &&
|
|
14
|
+
metadata.${field} == $value &&
|
|
15
|
+
!(_id in [$id, "drafts." + $id])
|
|
16
|
+
])`;
|
|
17
|
+
|
|
18
|
+
// Drafts perspective, so a duplicate that's only saved as a draft still warns.
|
|
19
|
+
const warnIfDuplicated =
|
|
20
|
+
(field: "metaTitle" | "metaDescription", label: string) =>
|
|
21
|
+
async (value: string | undefined, context: ValidationContext) => {
|
|
22
|
+
const id = context.document?._id?.replace(
|
|
23
|
+
/^(drafts|versions\.[^.]+)\./,
|
|
24
|
+
"",
|
|
25
|
+
);
|
|
26
|
+
if (!value?.trim() || !id) return true;
|
|
27
|
+
const duplicates = await context
|
|
28
|
+
.getClient({ apiVersion })
|
|
29
|
+
.withConfig({ perspective: "drafts" })
|
|
30
|
+
.fetch<number>(duplicateCountQuery(field), { value, id });
|
|
31
|
+
return duplicates > 0
|
|
32
|
+
? `Another document already uses this ${label}`
|
|
33
|
+
: true;
|
|
34
|
+
};
|
|
35
|
+
|
|
4
36
|
export const metadata = defineType({
|
|
5
37
|
name: "metadata",
|
|
6
38
|
title: "SEO & Metadata",
|
|
@@ -21,10 +53,12 @@ export const metadata = defineType({
|
|
|
21
53
|
type: "string",
|
|
22
54
|
group: "search",
|
|
23
55
|
description: "Title used by search engines and browser tabs",
|
|
24
|
-
validation: (Rule) =>
|
|
56
|
+
validation: (Rule) => [
|
|
25
57
|
Rule.max(60).warning(
|
|
26
58
|
"Title should be under 60 characters for optimal SEO",
|
|
27
59
|
),
|
|
60
|
+
Rule.custom(warnIfDuplicated("metaTitle", "meta title")).warning(),
|
|
61
|
+
],
|
|
28
62
|
}),
|
|
29
63
|
defineField({
|
|
30
64
|
name: "metaDescription",
|
|
@@ -33,10 +67,14 @@ export const metadata = defineType({
|
|
|
33
67
|
rows: 3,
|
|
34
68
|
group: "search",
|
|
35
69
|
description: "Description used by search engines",
|
|
36
|
-
validation: (Rule) =>
|
|
70
|
+
validation: (Rule) => [
|
|
37
71
|
Rule.max(160).warning(
|
|
38
72
|
"Description should be under 160 characters for optimal SEO",
|
|
39
73
|
),
|
|
74
|
+
Rule.custom(
|
|
75
|
+
warnIfDuplicated("metaDescription", "meta description"),
|
|
76
|
+
).warning(),
|
|
77
|
+
],
|
|
40
78
|
}),
|
|
41
79
|
defineField({
|
|
42
80
|
name: "keywords",
|
|
@@ -66,7 +104,9 @@ export const metadata = defineType({
|
|
|
66
104
|
description:
|
|
67
105
|
"Title shown when shared on social (Open Graph & Twitter). Falls back to Meta Title.",
|
|
68
106
|
validation: (Rule) =>
|
|
69
|
-
Rule.max(70).warning(
|
|
107
|
+
Rule.max(70).warning(
|
|
108
|
+
"Social titles are often truncated past ~70 chars",
|
|
109
|
+
),
|
|
70
110
|
}),
|
|
71
111
|
defineField({
|
|
72
112
|
name: "ogDescription",
|
|
@@ -87,9 +127,14 @@ export const metadata = defineType({
|
|
|
87
127
|
type: "url",
|
|
88
128
|
group: "advanced",
|
|
89
129
|
description:
|
|
90
|
-
"Override the canonical URL for this page. Leave blank to use the page's own URL. Use for duplicate/syndicated content.",
|
|
130
|
+
"Override the canonical URL for this page: a full URL, or a path starting with / (e.g. /blog/original-post). Leave blank to use the page's own URL. Use for duplicate/syndicated content.",
|
|
91
131
|
validation: (Rule) =>
|
|
92
|
-
Rule.uri({ scheme: ["http", "https"], allowRelative: true })
|
|
132
|
+
Rule.uri({ scheme: ["http", "https"], allowRelative: true }).custom(
|
|
133
|
+
(value) =>
|
|
134
|
+
!value || /^(https?:\/\/|\/)/i.test(value)
|
|
135
|
+
? true
|
|
136
|
+
: "Use a full URL (https://…) or a path starting with /",
|
|
137
|
+
),
|
|
93
138
|
}),
|
|
94
139
|
defineField({
|
|
95
140
|
name: "index",
|
|
@@ -99,6 +144,15 @@ export const metadata = defineType({
|
|
|
99
144
|
description: "Allow search engines to index this page",
|
|
100
145
|
initialValue: true,
|
|
101
146
|
}),
|
|
147
|
+
defineField({
|
|
148
|
+
name: "follow",
|
|
149
|
+
title: "Follow links",
|
|
150
|
+
type: "boolean",
|
|
151
|
+
group: "advanced",
|
|
152
|
+
description:
|
|
153
|
+
"Allow search engines to follow the links on this page. Independent of Index.",
|
|
154
|
+
initialValue: true,
|
|
155
|
+
}),
|
|
102
156
|
defineField({
|
|
103
157
|
name: "jsonLd",
|
|
104
158
|
title: "Structured Data (JSON-LD)",
|
|
@@ -2,8 +2,8 @@ import { defineArrayMember, defineType } from "sanity";
|
|
|
2
2
|
import { BlockActionsItem } from "@/lib/integrations/sanity/components/block-actions-item";
|
|
3
3
|
import { PageBuilderInput } from "@/lib/integrations/sanity/components/page-builder-input";
|
|
4
4
|
import {
|
|
5
|
+
pageBuilderBlockMembers,
|
|
5
6
|
pageBuilderInsertMenuGroups,
|
|
6
|
-
pageBuilderReferenceMembers,
|
|
7
7
|
} from "@/lib/integrations/sanity/page-builder-config";
|
|
8
8
|
|
|
9
9
|
export const pageBuilder = defineType({
|
|
@@ -17,27 +17,13 @@ export const pageBuilder = defineType({
|
|
|
17
17
|
groups: pageBuilderInsertMenuGroups,
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
|
-
of:
|
|
20
|
+
of: pageBuilderBlockMembers.map((member) =>
|
|
21
21
|
defineArrayMember({
|
|
22
|
-
|
|
22
|
+
type: member.documentType,
|
|
23
23
|
title: member.title,
|
|
24
|
-
type: "reference",
|
|
25
|
-
to: [{ type: member.documentType }],
|
|
26
24
|
// Per-placement Hide/Show action; hidden state lives in the owning
|
|
27
|
-
// document's `hiddenPageBuilderKeys`, not on the
|
|
25
|
+
// document's `hiddenPageBuilderKeys`, not on the block itself.
|
|
28
26
|
components: { item: BlockActionsItem },
|
|
29
|
-
...(member.documentId
|
|
30
|
-
? {
|
|
31
|
-
options: {
|
|
32
|
-
disableNew: true,
|
|
33
|
-
filter: "_id in [$documentId, $draftDocumentId]",
|
|
34
|
-
filterParams: {
|
|
35
|
-
documentId: member.documentId,
|
|
36
|
-
draftDocumentId: `drafts.${member.documentId}`,
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
}
|
|
40
|
-
: {}),
|
|
41
27
|
}),
|
|
42
28
|
),
|
|
43
29
|
});
|
|
@@ -4,8 +4,9 @@ import { SlugInput } from "@/lib/integrations/sanity/components/slug-input";
|
|
|
4
4
|
import { apiVersion } from "@/lib/integrations/sanity/env";
|
|
5
5
|
import { pageIcon } from "@/lib/integrations/sanity/icons";
|
|
6
6
|
import {
|
|
7
|
+
countPageHeadingBlocks,
|
|
7
8
|
getInvalidPageBuilderDocumentTypes,
|
|
8
|
-
|
|
9
|
+
getPageBuilderBlockMember,
|
|
9
10
|
getPageCategoryIcon,
|
|
10
11
|
type PageBuilderDocumentType,
|
|
11
12
|
type PageBuilderGroupName,
|
|
@@ -24,8 +25,8 @@ type PageValidationDocument = {
|
|
|
24
25
|
pageBuilder?: Array<{
|
|
25
26
|
_key?: string;
|
|
26
27
|
_type?: string;
|
|
27
|
-
_ref?: string;
|
|
28
28
|
}>;
|
|
29
|
+
hiddenPageBuilderKeys?: string[];
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
type PageSlugValidationContext = {
|
|
@@ -35,11 +36,6 @@ type PageSlugValidationContext = {
|
|
|
35
36
|
};
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
type ReferencedPageBuilderDocument = {
|
|
39
|
-
_id: string;
|
|
40
|
-
_type: PageBuilderDocumentType;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
39
|
const PAGE_FOLDER_QUERY = `*[_type == "pageFolder" && _id in [$publishedId, $draftId]][0].slug.current`;
|
|
44
40
|
|
|
45
41
|
async function getGeneratedPageCategoryForDocument(
|
|
@@ -107,6 +103,13 @@ export const page = defineType({
|
|
|
107
103
|
type: "string",
|
|
108
104
|
validation: (Rule) => Rule.required(),
|
|
109
105
|
}),
|
|
106
|
+
defineField({
|
|
107
|
+
name: "shortTitle",
|
|
108
|
+
title: "Short Title",
|
|
109
|
+
type: "string",
|
|
110
|
+
description:
|
|
111
|
+
"Label for this page in breadcrumbs (e.g. Blog). Falls back to the folder name for a folder's index page, then to Title.",
|
|
112
|
+
}),
|
|
110
113
|
defineField({
|
|
111
114
|
name: "type",
|
|
112
115
|
title: "Page Category",
|
|
@@ -155,7 +158,18 @@ export const page = defineType({
|
|
|
155
158
|
title: "Page Builder",
|
|
156
159
|
type: "pageBuilder",
|
|
157
160
|
description: "Composable content blocks for this page",
|
|
158
|
-
validation: (Rule) =>
|
|
161
|
+
validation: (Rule) => [
|
|
162
|
+
// Without a Heading block the page title is the H1, so only more
|
|
163
|
+
// than one is a problem.
|
|
164
|
+
Rule.custom((value, context) => {
|
|
165
|
+
const blocks = Array.isArray(value) ? value : [];
|
|
166
|
+
const hiddenKeys =
|
|
167
|
+
(context.document as PageValidationDocument | undefined)
|
|
168
|
+
?.hiddenPageBuilderKeys ?? [];
|
|
169
|
+
return countPageHeadingBlocks(blocks, hiddenKeys) > 1
|
|
170
|
+
? "More than one visible Heading block, so this page has several H1s"
|
|
171
|
+
: true;
|
|
172
|
+
}).warning(),
|
|
159
173
|
Rule.custom(async (value, context) => {
|
|
160
174
|
const document = context.document as
|
|
161
175
|
| PageValidationDocument
|
|
@@ -164,55 +178,36 @@ export const page = defineType({
|
|
|
164
178
|
document,
|
|
165
179
|
context.getClient,
|
|
166
180
|
);
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
.filter((item): item is string => typeof item === "string");
|
|
173
|
-
|
|
174
|
-
if (referenceIds.length === 0) return true;
|
|
175
|
-
|
|
176
|
-
const referencedDocuments = await context
|
|
177
|
-
.getClient({ apiVersion })
|
|
178
|
-
.fetch<ReferencedPageBuilderDocument[]>(
|
|
179
|
-
`*[
|
|
180
|
-
_id in $publishedIds || _id in $draftIds
|
|
181
|
-
]{
|
|
182
|
-
_id,
|
|
183
|
-
_type
|
|
184
|
-
}`,
|
|
185
|
-
{
|
|
186
|
-
publishedIds: referenceIds,
|
|
187
|
-
draftIds: referenceIds.map((id) => `drafts.${id}`),
|
|
188
|
-
},
|
|
181
|
+
const documentTypes = (Array.isArray(value) ? value : [])
|
|
182
|
+
.map((item) => (item as { _type?: string })?._type)
|
|
183
|
+
.filter(
|
|
184
|
+
(type): type is PageBuilderDocumentType =>
|
|
185
|
+
typeof type === "string",
|
|
189
186
|
);
|
|
190
187
|
|
|
188
|
+
if (documentTypes.length === 0) return true;
|
|
189
|
+
|
|
191
190
|
const invalidDocumentTypes = getInvalidPageBuilderDocumentTypes(
|
|
192
191
|
pageType,
|
|
193
|
-
|
|
192
|
+
documentTypes,
|
|
194
193
|
);
|
|
195
194
|
|
|
196
195
|
if (invalidDocumentTypes.length === 0) return true;
|
|
197
196
|
|
|
198
|
-
const invalidMemberTitles = invalidDocumentTypes.map(
|
|
197
|
+
const invalidMemberTitles = [...new Set(invalidDocumentTypes)].map(
|
|
199
198
|
(documentType) =>
|
|
200
|
-
|
|
201
|
-
?.title ?? documentType,
|
|
199
|
+
getPageBuilderBlockMember(documentType)?.title ?? documentType,
|
|
202
200
|
);
|
|
203
201
|
|
|
204
202
|
return `These page builder components do not belong to the "${pageType ?? "generic"}" category: ${invalidMemberTitles.join(", ")}`;
|
|
205
203
|
}),
|
|
204
|
+
],
|
|
206
205
|
}),
|
|
207
206
|
defineField({
|
|
208
207
|
name: "collectionCategory",
|
|
209
208
|
title: "Pinned Collection Category",
|
|
210
209
|
type: "reference",
|
|
211
210
|
to: [{ type: "blogCategory" }],
|
|
212
|
-
// Lives on the page because the collection block is deliberately a
|
|
213
|
-
// singleton (see `singletonComponents`) — editors reuse one block rather
|
|
214
|
-
// than creating them, so a category set there would apply site-wide. Move
|
|
215
|
-
// the block to the reusable list if you'd rather scope it per instance.
|
|
216
211
|
description:
|
|
217
212
|
"Turns this page into a category page: the content collection shows only this category. Leave empty to show everything.",
|
|
218
213
|
}),
|
|
@@ -2,22 +2,10 @@ import {
|
|
|
2
2
|
companyDataIcon,
|
|
3
3
|
footerIcon,
|
|
4
4
|
navbarIcon,
|
|
5
|
-
pageListIcon,
|
|
6
5
|
spacingSettingsIcon,
|
|
7
6
|
structuredDataIcon,
|
|
8
7
|
} from "./icons";
|
|
9
8
|
|
|
10
|
-
// `category` must be one of `componentCategories` in page-builder-config.ts.
|
|
11
|
-
export const singletonComponents = [
|
|
12
|
-
{
|
|
13
|
-
schemaType: "blogCollection",
|
|
14
|
-
documentId: "blogCollection",
|
|
15
|
-
title: "Blog Collection",
|
|
16
|
-
icon: pageListIcon,
|
|
17
|
-
category: "list",
|
|
18
|
-
},
|
|
19
|
-
] as const;
|
|
20
|
-
|
|
21
9
|
export const singletonLayout = [
|
|
22
10
|
{
|
|
23
11
|
schemaType: "companyData",
|
|
@@ -51,10 +39,6 @@ export const singletonLayout = [
|
|
|
51
39
|
},
|
|
52
40
|
] as const;
|
|
53
41
|
|
|
54
|
-
export const singletonComponentTypes: Set<string> = new Set(
|
|
55
|
-
singletonComponents.map((item) => item.schemaType),
|
|
56
|
-
);
|
|
57
|
-
|
|
58
42
|
export const singletonLayoutTypes: Set<string> = new Set(
|
|
59
43
|
singletonLayout.map((item) => item.schemaType),
|
|
60
44
|
);
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/structure.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UploadIcon } from "@sanity/icons";
|
|
1
2
|
import { from } from "rxjs";
|
|
2
3
|
import { map } from "rxjs/operators";
|
|
3
4
|
import type {
|
|
@@ -6,18 +7,21 @@ import type {
|
|
|
6
7
|
StructureResolver,
|
|
7
8
|
StructureResolverContext,
|
|
8
9
|
} from "sanity/structure";
|
|
10
|
+
import {
|
|
11
|
+
COMPONENT_LIBRARY,
|
|
12
|
+
getComponentPreviewPath,
|
|
13
|
+
} from "@/components/page-builder/library";
|
|
14
|
+
import { pageBuilderInsertMenuGroups } from "@/lib/integrations/sanity/page-builder-config";
|
|
15
|
+
import { ComponentPreviewPane } from "./components/component-preview-pane";
|
|
16
|
+
import { openRedirectImport } from "./components/redirect-import-dialog";
|
|
9
17
|
import { apiVersion } from "./env";
|
|
10
18
|
import {
|
|
11
19
|
authorIcon,
|
|
12
20
|
blogCategoryIcon,
|
|
21
|
+
componentIcon,
|
|
13
22
|
componentsFolderIcon,
|
|
14
23
|
contentFolderIcon,
|
|
15
|
-
contentIcon,
|
|
16
|
-
descriptionIcon,
|
|
17
|
-
gatedContentIcon,
|
|
18
|
-
heroIcon,
|
|
19
24
|
layoutFolderIcon,
|
|
20
|
-
pageBuilderCardIcon,
|
|
21
25
|
pageFolderIcon,
|
|
22
26
|
pageIcon,
|
|
23
27
|
pagesFolderIcon,
|
|
@@ -25,7 +29,7 @@ import {
|
|
|
25
29
|
} from "./icons";
|
|
26
30
|
import { PageTreePane } from "./page-tree-pane";
|
|
27
31
|
import { PINNED_PAGE_ENTRIES } from "./pinned-pages";
|
|
28
|
-
import {
|
|
32
|
+
import { singletonLayout } from "./singletons";
|
|
29
33
|
|
|
30
34
|
const PAGE_TREE_ITEM_ID_PREFIX = {
|
|
31
35
|
page: "page-tree-",
|
|
@@ -239,6 +243,18 @@ function buildPageTreeComponent(
|
|
|
239
243
|
.menuItems([...folderMenuItems, ...createMenuItems]);
|
|
240
244
|
}
|
|
241
245
|
|
|
246
|
+
const redirectList = (S: StructureBuilder) => {
|
|
247
|
+
const list = S.documentTypeList("redirect").title("Redirects");
|
|
248
|
+
return list.menuItems([
|
|
249
|
+
...(list.getMenuItems() ?? []),
|
|
250
|
+
S.menuItem()
|
|
251
|
+
.title("Import CSV")
|
|
252
|
+
.icon(UploadIcon)
|
|
253
|
+
.action(openRedirectImport)
|
|
254
|
+
.showAsAction(true),
|
|
255
|
+
]);
|
|
256
|
+
};
|
|
257
|
+
|
|
242
258
|
// https://www.sanity.io/docs/structure-builder-cheat-sheet
|
|
243
259
|
export const structure: StructureResolver = (S, context) =>
|
|
244
260
|
S.list()
|
|
@@ -252,7 +268,7 @@ export const structure: StructureResolver = (S, context) =>
|
|
|
252
268
|
|
|
253
269
|
S.divider(),
|
|
254
270
|
|
|
255
|
-
// GROUP 2: Content --
|
|
271
|
+
// GROUP 2: Content -- authors, blog categories
|
|
256
272
|
S.listItem()
|
|
257
273
|
.title("Content")
|
|
258
274
|
.icon(contentFolderIcon)
|
|
@@ -260,9 +276,6 @@ export const structure: StructureResolver = (S, context) =>
|
|
|
260
276
|
S.list()
|
|
261
277
|
.title("Content")
|
|
262
278
|
.items([
|
|
263
|
-
S.documentTypeListItem("blogContent")
|
|
264
|
-
.title("Blog Posts")
|
|
265
|
-
.icon(contentIcon),
|
|
266
279
|
S.documentTypeListItem("author")
|
|
267
280
|
.title("Authors")
|
|
268
281
|
.icon(authorIcon),
|
|
@@ -274,7 +287,7 @@ export const structure: StructureResolver = (S, context) =>
|
|
|
274
287
|
|
|
275
288
|
S.divider(),
|
|
276
289
|
|
|
277
|
-
// GROUP 3: Components --
|
|
290
|
+
// GROUP 3: Components -- live block previews, grouped like the insert menu
|
|
278
291
|
S.listItem()
|
|
279
292
|
.title("Components")
|
|
280
293
|
.icon(componentsFolderIcon)
|
|
@@ -282,30 +295,33 @@ export const structure: StructureResolver = (S, context) =>
|
|
|
282
295
|
S.list()
|
|
283
296
|
.title("Components")
|
|
284
297
|
.items([
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
298
|
+
...pageBuilderInsertMenuGroups.flatMap((group) => {
|
|
299
|
+
const entries = COMPONENT_LIBRARY.filter((entry) =>
|
|
300
|
+
group.of.includes(entry.documentType),
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
if (entries.length === 0) return [];
|
|
304
|
+
|
|
305
|
+
return [
|
|
306
|
+
S.divider().title(group.title),
|
|
307
|
+
...entries.map((entry) =>
|
|
308
|
+
S.listItem()
|
|
309
|
+
.title(entry.title)
|
|
310
|
+
.id(entry.documentType)
|
|
311
|
+
.icon(componentIcon)
|
|
312
|
+
.child(
|
|
313
|
+
S.component()
|
|
314
|
+
.id(`component-${entry.documentType}`)
|
|
315
|
+
.title(entry.title)
|
|
316
|
+
.component(ComponentPreviewPane)
|
|
317
|
+
.options({
|
|
318
|
+
notes: entry.notes,
|
|
319
|
+
path: getComponentPreviewPath(entry.documentType),
|
|
320
|
+
}),
|
|
321
|
+
),
|
|
295
322
|
),
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
S.documentTypeListItem("hero").title("Headings").icon(heroIcon),
|
|
299
|
-
S.documentTypeListItem("description")
|
|
300
|
-
.title("Descriptions")
|
|
301
|
-
.icon(descriptionIcon),
|
|
302
|
-
S.documentTypeListItem("gatedContent")
|
|
303
|
-
.title("Gated Content")
|
|
304
|
-
.icon(gatedContentIcon),
|
|
305
|
-
S.divider(),
|
|
306
|
-
S.documentTypeListItem("studioPreview")
|
|
307
|
-
.title("Component Previews")
|
|
308
|
-
.icon(pageBuilderCardIcon),
|
|
323
|
+
];
|
|
324
|
+
}),
|
|
309
325
|
]),
|
|
310
326
|
),
|
|
311
327
|
|
|
@@ -333,7 +349,8 @@ export const structure: StructureResolver = (S, context) =>
|
|
|
333
349
|
S.divider(),
|
|
334
350
|
S.documentTypeListItem("redirect")
|
|
335
351
|
.title("Redirects")
|
|
336
|
-
.icon(redirectIcon)
|
|
352
|
+
.icon(redirectIcon)
|
|
353
|
+
.child(redirectList(S)),
|
|
337
354
|
]),
|
|
338
355
|
),
|
|
339
356
|
]);
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/tags.ts
CHANGED
|
@@ -29,6 +29,7 @@ export const SELF_TAGGED_TYPES = new Set<string>([
|
|
|
29
29
|
// Crawler routes: broader than any per-slug tag.
|
|
30
30
|
export const SITEMAP_TAG = "sitemap";
|
|
31
31
|
export const FEED_TAG = "feed";
|
|
32
|
+
export const BREADCRUMBS_TAG = "breadcrumbs";
|
|
32
33
|
|
|
33
34
|
// The content-collection block caches each window of results separately.
|
|
34
35
|
export const BLOG_CATEGORIES_TAG = "blog-categories";
|
|
@@ -56,8 +57,9 @@ export const BLOG_COLLECTION_TYPES = new Set<string>([
|
|
|
56
57
|
export const CROSS_DOC_TAG_DEPENDENCIES: Record<string, readonly string[]> = {
|
|
57
58
|
// Redundant while LAYOUT_QUERY is merged; kept so splitting it can't lose this.
|
|
58
59
|
companyData: [SANITY_STRUCTURED_DATA_TAG],
|
|
59
|
-
// Nav links deref pages; sitemap and
|
|
60
|
-
page
|
|
60
|
+
// Nav links deref pages; sitemap, feed and breadcrumbs move whenever any
|
|
61
|
+
// page does.
|
|
62
|
+
page: [SANITY_NAVBAR_TAG, SITEMAP_TAG, FEED_TAG, BREADCRUMBS_TAG],
|
|
61
63
|
// ...plus the collections, which decide membership on the folder slug, so a
|
|
62
64
|
// rename changes which pages are articles at all.
|
|
63
65
|
pageFolder: [
|
|
@@ -65,6 +67,7 @@ export const CROSS_DOC_TAG_DEPENDENCIES: Record<string, readonly string[]> = {
|
|
|
65
67
|
...BLOG_COLLECTION_TAGS,
|
|
66
68
|
SITEMAP_TAG,
|
|
67
69
|
FEED_TAG,
|
|
70
|
+
BREADCRUMBS_TAG,
|
|
68
71
|
],
|
|
69
72
|
// The feed derefs the article's block, then its author and categories.
|
|
70
73
|
blogContent: [FEED_TAG],
|
|
@@ -88,4 +91,5 @@ export const PURGEABLE_TAGS = [
|
|
|
88
91
|
...BLOG_COLLECTION_TAGS,
|
|
89
92
|
SITEMAP_TAG,
|
|
90
93
|
FEED_TAG,
|
|
94
|
+
BREADCRUMBS_TAG,
|
|
91
95
|
];
|