bsmnt 0.12.0 → 0.13.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/application/add-integration/index.d.ts.map +1 -1
- package/dist/application/add-integration/index.js +23 -0
- package/dist/application/add-integration/index.js.map +1 -1
- package/dist/domain/consent.d.ts +17 -0
- package/dist/domain/consent.d.ts.map +1 -0
- package/dist/domain/consent.js +13 -0
- package/dist/domain/consent.js.map +1 -0
- package/dist/domain/integration.d.ts +19 -2
- package/dist/domain/integration.d.ts.map +1 -1
- package/dist/domain/integration.js +10 -1
- package/dist/domain/integration.js.map +1 -1
- package/dist/domain/jobs.d.ts +17 -0
- package/dist/domain/jobs.d.ts.map +1 -0
- package/dist/domain/jobs.js +13 -0
- package/dist/domain/jobs.js.map +1 -0
- package/dist/domain/skills.d.ts +23 -2
- package/dist/domain/skills.d.ts.map +1 -1
- package/dist/domain/skills.js +23 -2
- package/dist/domain/skills.js.map +1 -1
- package/dist/domain/templates.d.ts +7 -1
- package/dist/domain/templates.d.ts.map +1 -1
- package/dist/domain/templates.js +2 -0
- package/dist/domain/templates.js.map +1 -1
- package/dist/index.js +34 -9
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/create/setup-agent.d.ts.map +1 -1
- package/dist/infrastructure/create/setup-agent.js +11 -4
- package/dist/infrastructure/create/setup-agent.js.map +1 -1
- package/dist/infrastructure/integrations/inject-integration.d.ts.map +1 -1
- package/dist/infrastructure/integrations/inject-integration.js +36 -2
- package/dist/infrastructure/integrations/inject-integration.js.map +1 -1
- package/dist/modules/features/consent/ketch/config.d.ts +18 -0
- package/dist/modules/features/consent/ketch/config.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/config.js +24 -0
- package/dist/modules/features/consent/ketch/config.js.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/biome.d.ts +16 -0
- package/dist/modules/features/consent/ketch/mergers/biome.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/biome.js +31 -0
- package/dist/modules/features/consent/ketch/mergers/biome.js.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/check-integration.d.ts +13 -0
- package/dist/modules/features/consent/ketch/mergers/check-integration.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/check-integration.js +64 -0
- package/dist/modules/features/consent/ketch/mergers/check-integration.js.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/env-example.d.ts +12 -0
- package/dist/modules/features/consent/ketch/mergers/env-example.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/env-example.js +28 -0
- package/dist/modules/features/consent/ketch/mergers/env-example.js.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/footer.d.ts +17 -0
- package/dist/modules/features/consent/ketch/mergers/footer.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/footer.js +40 -0
- package/dist/modules/features/consent/ketch/mergers/footer.js.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/knip.d.ts +18 -0
- package/dist/modules/features/consent/ketch/mergers/knip.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/knip.js +37 -0
- package/dist/modules/features/consent/ketch/mergers/knip.js.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/layout.d.ts +25 -0
- package/dist/modules/features/consent/ketch/mergers/layout.d.ts.map +1 -0
- package/dist/modules/features/consent/ketch/mergers/layout.js +55 -0
- package/dist/modules/features/consent/ketch/mergers/layout.js.map +1 -0
- package/dist/modules/features/jobs/ashby/config.d.ts +19 -0
- package/dist/modules/features/jobs/ashby/config.d.ts.map +1 -0
- package/dist/modules/features/jobs/ashby/config.js +29 -0
- package/dist/modules/features/jobs/ashby/config.js.map +1 -0
- package/dist/modules/features/jobs/ashby/mergers/check-integration.d.ts +14 -0
- package/dist/modules/features/jobs/ashby/mergers/check-integration.d.ts.map +1 -0
- package/dist/modules/features/jobs/ashby/mergers/check-integration.js +78 -0
- package/dist/modules/features/jobs/ashby/mergers/check-integration.js.map +1 -0
- package/dist/modules/features/jobs/ashby/mergers/env-example.d.ts +12 -0
- package/dist/modules/features/jobs/ashby/mergers/env-example.d.ts.map +1 -0
- package/dist/modules/features/jobs/ashby/mergers/env-example.js +27 -0
- package/dist/modules/features/jobs/ashby/mergers/env-example.js.map +1 -0
- package/dist/modules/features/jobs/ashby/mergers/knip.d.ts +18 -0
- package/dist/modules/features/jobs/ashby/mergers/knip.d.ts.map +1 -0
- package/dist/modules/features/jobs/ashby/mergers/knip.js +41 -0
- package/dist/modules/features/jobs/ashby/mergers/knip.js.map +1 -0
- package/dist/paths.d.ts +12 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +12 -0
- package/dist/paths.js.map +1 -1
- package/package.json +3 -1
- package/src/agent-skills/ashby-pagebuilder-block/SKILL.md +277 -0
- package/src/agent-skills/hubspot-pagebuilder-block/SKILL.md +58 -25
- package/src/agent-skills/ketch-consent-check/SKILL.md +197 -0
- package/src/agent-skills/ketch-consent-setup/SKILL.md +326 -0
- package/src/agent-skills/ketch-consent-setup/references/ui-customization.md +329 -0
- package/src/agent-skills/page-builder-block/SKILL.md +150 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/anchor-id-input.tsx +17 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/presentation-input.tsx +146 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/spacing-steps-input.tsx +84 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/layout.ts +6 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/icons.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +12 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/description.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/gated-content.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/hero.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/rich-text-block.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/spacing-settings.ts +120 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/anchor.ts +75 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/block.ts +46 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/presentation.ts +44 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/spacing.ts +164 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/singletons.ts +7 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/anchor-id-input.tsx +17 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/presentation-input.tsx +146 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/spacing-steps-input.tsx +84 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/fetchers/layout.ts +4 -2
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/icons.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts +12 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/description.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/gated-content.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/hero.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/rich-text-block.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +3 -3
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/index.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/spacing-settings.ts +120 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/anchor.ts +75 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/block.ts +46 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/presentation.ts +44 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/spacing.ts +164 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/singletons.ts +7 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/tags.ts +2 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/check-integration.ts +25 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/README.md +70 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/categories.ts +20 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/consent-store.ts +107 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/env.ts +20 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/ketch-experience.css +136 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/preferences-button.tsx +51 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/script.tsx +8 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/types.ts +15 -0
- package/src/modules/features/consent/ketch/files/lib/integrations/ketch/use-consent.ts +26 -0
- package/src/modules/features/jobs/ashby/files/_sanity-adapter/job-board-block.ts +53 -0
- package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/README.md +134 -0
- package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/env.ts +3 -0
- package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/index.ts +40 -0
- package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/normalize.ts +124 -0
- package/src/modules/features/jobs/ashby/files/lib/integrations/ashby/types.ts +20 -0
- package/src/modules/features/jobs/ashby/files/lib/integrations/check-integration.ts +25 -0
- package/src/templates/next-pagebuilder/AGENTS.md +129 -0
- package/src/templates/next-pagebuilder/CLAUDE.md +3 -0
- package/src/templates/next-pagebuilder/README.md +70 -0
- package/src/templates/next-pagebuilder/app/(content)/layout.tsx +2 -0
- package/src/templates/next-pagebuilder/components/layout/spacing-scale/index.tsx +18 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/article-content/index.tsx +1 -1
- package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/index.tsx +2 -2
- package/src/templates/next-pagebuilder/components/page-builder/components/description.tsx +3 -7
- package/src/templates/next-pagebuilder/components/page-builder/components/gated-content/index.tsx +2 -2
- package/src/templates/next-pagebuilder/components/page-builder/components/hero.tsx +3 -7
- package/src/templates/next-pagebuilder/components/page-builder/components/rich-text-block.tsx +3 -5
- package/src/templates/next-pagebuilder/components/page-builder/registry.tsx +70 -0
- package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +33 -49
- package/src/templates/next-pagebuilder/components/page-builder/section.tsx +35 -0
- package/src/templates/next-pagebuilder/components/page-document/index.tsx +1 -1
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +92 -4
- package/src/templates/next-pagebuilder-cache/AGENTS.md +136 -0
- package/src/templates/next-pagebuilder-cache/CLAUDE.md +3 -0
- package/src/templates/next-pagebuilder-cache/README.md +75 -0
- package/src/templates/next-pagebuilder-cache/app/(content)/layout.tsx +2 -0
- package/src/templates/next-pagebuilder-cache/components/layout/spacing-scale/index.tsx +46 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/article-content/index.tsx +1 -1
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/index.tsx +2 -2
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/description.tsx +3 -7
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/gated-content/index.tsx +2 -2
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/hero.tsx +3 -7
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/rich-text-block.tsx +3 -5
- package/src/templates/next-pagebuilder-cache/components/page-builder/registry.tsx +70 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/renderer.tsx +33 -49
- package/src/templates/next-pagebuilder-cache/components/page-builder/section.tsx +35 -0
- package/src/templates/next-pagebuilder-cache/components/page-document/index.tsx +1 -1
- package/src/templates/next-pagebuilder-cache/lib/integrations/sanity/sanity.types.ts +92 -4
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Button, Card, Stack, Text } from "@sanity/ui";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { type ArrayOfObjectsInputProps, set } from "sanity";
|
|
4
|
+
import { defaultSpacingSteps } from "@/lib/integrations/sanity/schemas/shared/spacing";
|
|
5
|
+
|
|
6
|
+
type StepValue = { _key?: string; isDefault?: boolean };
|
|
7
|
+
|
|
8
|
+
const defaultKeysOf = (value: StepValue[] | undefined) =>
|
|
9
|
+
(value ?? [])
|
|
10
|
+
.filter((step) => step?.isDefault === true)
|
|
11
|
+
.flatMap((step) => (step._key ? [step._key] : []));
|
|
12
|
+
|
|
13
|
+
export function SpacingStepsInput(props: ArrayOfObjectsInputProps) {
|
|
14
|
+
const value = props.value as StepValue[] | undefined;
|
|
15
|
+
const { onChange } = props;
|
|
16
|
+
|
|
17
|
+
const defaultKeys = defaultKeysOf(value);
|
|
18
|
+
const defaultKeysId = defaultKeys.join(",");
|
|
19
|
+
const lastSingleDefault = useRef<string | undefined>(defaultKeys[0]);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const keys = defaultKeysId ? defaultKeysId.split(",") : [];
|
|
23
|
+
|
|
24
|
+
if (keys.length < 2) {
|
|
25
|
+
lastSingleDefault.current = keys[0];
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const keep = keys.find((key) => key !== lastSingleDefault.current) ?? keys[0];
|
|
30
|
+
lastSingleDefault.current = keep;
|
|
31
|
+
|
|
32
|
+
onChange(
|
|
33
|
+
keys
|
|
34
|
+
.filter((key) => key !== keep)
|
|
35
|
+
.map((key) => set(false, [{ _key: key }, "isDefault"])),
|
|
36
|
+
);
|
|
37
|
+
}, [defaultKeysId, onChange]);
|
|
38
|
+
|
|
39
|
+
const seed = () => {
|
|
40
|
+
onChange(
|
|
41
|
+
set(
|
|
42
|
+
defaultSpacingSteps.map((step) => ({
|
|
43
|
+
_key: step.key,
|
|
44
|
+
_type: "spacingStep",
|
|
45
|
+
name: step.name,
|
|
46
|
+
mobile: step.mobile,
|
|
47
|
+
tablet: step.tablet,
|
|
48
|
+
desktop: step.desktop,
|
|
49
|
+
isDefault: step.isDefault,
|
|
50
|
+
})),
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Stack space={3}>
|
|
57
|
+
{props.renderDefault(props)}
|
|
58
|
+
{value?.length ? null : (
|
|
59
|
+
<Card padding={3} radius={2} border tone="primary">
|
|
60
|
+
<Stack space={3}>
|
|
61
|
+
<Text size={1}>
|
|
62
|
+
No steps yet, so blocks fall back to the built-in scale:{" "}
|
|
63
|
+
{defaultSpacingSteps
|
|
64
|
+
.map(
|
|
65
|
+
(step) =>
|
|
66
|
+
`${step.name} ${step.desktop}px${
|
|
67
|
+
step.isDefault ? " (default)" : ""
|
|
68
|
+
}`,
|
|
69
|
+
)
|
|
70
|
+
.join(" · ")}
|
|
71
|
+
.
|
|
72
|
+
</Text>
|
|
73
|
+
<Button
|
|
74
|
+
text="Add the built-in steps"
|
|
75
|
+
tone="primary"
|
|
76
|
+
mode="ghost"
|
|
77
|
+
onClick={seed}
|
|
78
|
+
/>
|
|
79
|
+
</Stack>
|
|
80
|
+
</Card>
|
|
81
|
+
)}
|
|
82
|
+
</Stack>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -12,16 +12,18 @@ export type NavbarData = NonNullable<LayoutData["navbar"]>
|
|
|
12
12
|
export type FooterData = NonNullable<LayoutData["footer"]>
|
|
13
13
|
export type CompanyData = NonNullable<LayoutData["companyData"]>
|
|
14
14
|
export type StructuredData = NonNullable<LayoutData["structuredData"]>
|
|
15
|
+
export type SpacingSettings = NonNullable<LayoutData["spacingSettings"]>
|
|
15
16
|
|
|
16
17
|
const EMPTY_LAYOUT: LayoutData = {
|
|
17
18
|
navbar: null,
|
|
18
19
|
footer: null,
|
|
19
20
|
companyData: null,
|
|
20
21
|
structuredData: null,
|
|
22
|
+
spacingSettings: null,
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
// One entry for
|
|
24
|
-
// with the same options, so they share one fetch
|
|
25
|
+
// One entry for every layout singleton: header, footer, json-ld and the spacing
|
|
26
|
+
// scale call this with the same options, so they share one fetch.
|
|
25
27
|
//
|
|
26
28
|
// Don't cap the empty branch — this renders in every route's shell, and a nested
|
|
27
29
|
// lifetime propagates upwards as a min().
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/icons.ts
CHANGED
|
@@ -2,6 +2,9 @@ import type { Icon, IconProps } from "@phosphor-icons/react";
|
|
|
2
2
|
import {
|
|
3
3
|
AppWindowIcon,
|
|
4
4
|
ArrowBendUpRightIcon,
|
|
5
|
+
ArrowLineDownIcon,
|
|
6
|
+
ArrowLineUpIcon,
|
|
7
|
+
ArrowsOutLineVerticalIcon,
|
|
5
8
|
ArticleNyTimesIcon,
|
|
6
9
|
BracketsCurlyIcon,
|
|
7
10
|
BriefcaseIcon,
|
|
@@ -75,6 +78,11 @@ export const richTextIcon = asDuotoneIcon(TextTIcon);
|
|
|
75
78
|
export const contentIcon = asDuotoneIcon(ArticleNyTimesIcon);
|
|
76
79
|
export const gatedContentIcon = asDuotoneIcon(LockKeyIcon);
|
|
77
80
|
|
|
81
|
+
export const spacingSettingsIcon = asDuotoneIcon(ArrowsOutLineVerticalIcon);
|
|
82
|
+
|
|
83
|
+
export const paddingTopIcon = asDuotoneIcon(ArrowLineUpIcon);
|
|
84
|
+
export const paddingBottomIcon = asDuotoneIcon(ArrowLineDownIcon);
|
|
85
|
+
|
|
78
86
|
export const pageIcon = asDuotoneIcon(FileTextIcon);
|
|
79
87
|
export const pagesFolderIcon = asDuotoneIcon(BrowsersIcon);
|
|
80
88
|
export const pageFolderIcon = asDuotoneIcon(FolderOpenIcon);
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts
CHANGED
|
@@ -96,6 +96,8 @@ const pageBuilderProjection = `
|
|
|
96
96
|
_type == "gatedContent" => {
|
|
97
97
|
_id,
|
|
98
98
|
_type,
|
|
99
|
+
anchorId,
|
|
100
|
+
presentation,
|
|
99
101
|
internalTitle,
|
|
100
102
|
teaserHeading,
|
|
101
103
|
teaserBody[]{
|
|
@@ -533,6 +535,16 @@ export const LAYOUT_QUERY = defineQuery(`
|
|
|
533
535
|
},
|
|
534
536
|
"structuredData": *[_type == "structuredData"][0]{
|
|
535
537
|
${structuredDataProjection}
|
|
538
|
+
},
|
|
539
|
+
"spacingSettings": *[_type == "spacingSettings"][0]{
|
|
540
|
+
steps[]{
|
|
541
|
+
_key,
|
|
542
|
+
name,
|
|
543
|
+
mobile,
|
|
544
|
+
tablet,
|
|
545
|
+
desktop,
|
|
546
|
+
isDefault
|
|
547
|
+
}
|
|
536
548
|
}
|
|
537
549
|
}
|
|
538
550
|
`);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineField
|
|
1
|
+
import { defineField } from "sanity";
|
|
2
2
|
import { contentIcon } from "@/lib/integrations/sanity/icons";
|
|
3
|
+
import { defineBlock } from "@/lib/integrations/sanity/schemas/shared/block";
|
|
3
4
|
|
|
4
|
-
export const blogContent =
|
|
5
|
+
export const blogContent = defineBlock({
|
|
5
6
|
name: "blogContent",
|
|
6
7
|
title: "Blog Content",
|
|
7
|
-
type: "document",
|
|
8
8
|
icon: contentIcon,
|
|
9
9
|
fields: [
|
|
10
10
|
defineField({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineField
|
|
1
|
+
import { defineField } from "sanity";
|
|
2
2
|
import { descriptionIcon } from "@/lib/integrations/sanity/icons";
|
|
3
|
+
import { defineBlock } from "@/lib/integrations/sanity/schemas/shared/block";
|
|
3
4
|
|
|
4
|
-
export const description =
|
|
5
|
+
export const description = defineBlock({
|
|
5
6
|
name: "description",
|
|
6
7
|
title: "Description",
|
|
7
|
-
type: "document",
|
|
8
8
|
icon: descriptionIcon,
|
|
9
9
|
fields: [
|
|
10
10
|
defineField({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { defineField
|
|
1
|
+
import { defineField } from "sanity";
|
|
2
2
|
import { gatedContentIcon } from "@/lib/integrations/sanity/icons";
|
|
3
|
+
import { defineBlock } from "@/lib/integrations/sanity/schemas/shared/block";
|
|
3
4
|
|
|
4
5
|
type GatedContentParent = { kind?: string };
|
|
5
6
|
|
|
@@ -19,10 +20,9 @@ const requiredForKind =
|
|
|
19
20
|
return isEmpty ? message : true;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
export const gatedContent =
|
|
23
|
+
export const gatedContent = defineBlock({
|
|
23
24
|
name: "gatedContent",
|
|
24
25
|
title: "Gated Content",
|
|
25
|
-
type: "document",
|
|
26
26
|
icon: gatedContentIcon,
|
|
27
27
|
description:
|
|
28
28
|
"Content hidden behind a lead-capture gate. Everyone sees the teaser; the payload is withheld from the page until the visitor submits the form.",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineField
|
|
1
|
+
import { defineField } from "sanity";
|
|
2
2
|
import { heroIcon } from "@/lib/integrations/sanity/icons";
|
|
3
|
+
import { defineBlock } from "@/lib/integrations/sanity/schemas/shared/block";
|
|
3
4
|
|
|
4
|
-
export const hero =
|
|
5
|
+
export const hero = defineBlock({
|
|
5
6
|
name: "hero",
|
|
6
7
|
title: "Heading",
|
|
7
|
-
type: "document",
|
|
8
8
|
icon: heroIcon,
|
|
9
9
|
fields: [
|
|
10
10
|
defineField({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineField
|
|
1
|
+
import { defineField } from "sanity";
|
|
2
2
|
import { richTextIcon } from "@/lib/integrations/sanity/icons";
|
|
3
|
+
import { defineBlock } from "@/lib/integrations/sanity/schemas/shared/block";
|
|
3
4
|
|
|
4
|
-
export const richTextBlock =
|
|
5
|
+
export const richTextBlock = defineBlock({
|
|
5
6
|
name: "richTextBlock",
|
|
6
7
|
title: "Rich Text",
|
|
7
|
-
type: "document",
|
|
8
8
|
icon: richTextIcon,
|
|
9
9
|
fields: [
|
|
10
10
|
defineField({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { defineField
|
|
1
|
+
import { defineField } from "sanity";
|
|
2
2
|
import type { SanityStudioIcon } from "@/lib/integrations/sanity/icons";
|
|
3
3
|
import { pageListIcon } from "@/lib/integrations/sanity/icons";
|
|
4
|
+
import { defineBlock } from "@/lib/integrations/sanity/schemas/shared/block";
|
|
4
5
|
|
|
5
6
|
function createContentCollection(config: {
|
|
6
7
|
name: string;
|
|
@@ -8,10 +9,9 @@ function createContentCollection(config: {
|
|
|
8
9
|
icon: SanityStudioIcon;
|
|
9
10
|
label: string;
|
|
10
11
|
}) {
|
|
11
|
-
return
|
|
12
|
+
return defineBlock({
|
|
12
13
|
name: config.name,
|
|
13
14
|
title: config.title,
|
|
14
|
-
type: "document",
|
|
15
15
|
icon: config.icon,
|
|
16
16
|
description: `This component contains all the ${config.label}`,
|
|
17
17
|
fields: [
|
|
@@ -23,6 +23,7 @@ import { companyData } from "./layout/company-data";
|
|
|
23
23
|
import { footer } from "./layout/footer";
|
|
24
24
|
import { navbar } from "./layout/navbar";
|
|
25
25
|
import { redirect } from "./layout/redirect";
|
|
26
|
+
import { spacingSettings, spacingStep } from "./layout/spacing-settings";
|
|
26
27
|
import { structuredData } from "./layout/structured-data";
|
|
27
28
|
import { externalLink, link, pageReference } from "./shared/link";
|
|
28
29
|
import { metadata } from "./shared/metadata";
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
35
36
|
import { page } from "./shared/page";
|
|
36
37
|
import { pageBuilder } from "./shared/page-builder";
|
|
37
38
|
import { pageFolder } from "./shared/page-folder";
|
|
39
|
+
import { presentation } from "./shared/presentation";
|
|
38
40
|
import { richText } from "./shared/richText";
|
|
39
41
|
import {
|
|
40
42
|
customJsonLd,
|
|
@@ -74,9 +76,12 @@ export {
|
|
|
74
76
|
pageBuilder,
|
|
75
77
|
pageFolder,
|
|
76
78
|
pageReference,
|
|
79
|
+
presentation,
|
|
77
80
|
redirect,
|
|
78
81
|
richText,
|
|
79
82
|
softwareApplicationJsonLd,
|
|
83
|
+
spacingSettings,
|
|
84
|
+
spacingStep,
|
|
80
85
|
structuredData,
|
|
81
86
|
studioPreview,
|
|
82
87
|
videoJsonLd,
|
|
@@ -91,6 +96,7 @@ export const schema: { types: SchemaTypeDefinition[] } = {
|
|
|
91
96
|
link,
|
|
92
97
|
metadata,
|
|
93
98
|
pageBuilder,
|
|
99
|
+
presentation,
|
|
94
100
|
richText,
|
|
95
101
|
|
|
96
102
|
// Page-level JSON-LD blocks (selectable in metadata)
|
|
@@ -122,6 +128,8 @@ export const schema: { types: SchemaTypeDefinition[] } = {
|
|
|
122
128
|
navbar,
|
|
123
129
|
footer,
|
|
124
130
|
structuredData,
|
|
131
|
+
spacingStep,
|
|
132
|
+
spacingSettings,
|
|
125
133
|
|
|
126
134
|
// Layout collections (managed lists, not singletons)
|
|
127
135
|
redirect,
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { defineArrayMember, defineField, defineType } from "sanity";
|
|
2
|
+
import { SpacingStepsInput } from "@/lib/integrations/sanity/components/spacing-steps-input";
|
|
3
|
+
import { spacingSettingsIcon } from "@/lib/integrations/sanity/icons";
|
|
4
|
+
import { defaultSpacingSteps } from "@/lib/integrations/sanity/schemas/shared/spacing";
|
|
5
|
+
|
|
6
|
+
const pxField = (
|
|
7
|
+
name: "mobile" | "tablet" | "desktop",
|
|
8
|
+
title: string,
|
|
9
|
+
description: string,
|
|
10
|
+
isRequired = false,
|
|
11
|
+
) =>
|
|
12
|
+
defineField({
|
|
13
|
+
name,
|
|
14
|
+
title,
|
|
15
|
+
type: "number",
|
|
16
|
+
description,
|
|
17
|
+
validation: (Rule) => {
|
|
18
|
+
const range = Rule.min(0).max(400).integer();
|
|
19
|
+
return isRequired ? range.required() : range;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const spacingStep = defineType({
|
|
24
|
+
name: "spacingStep",
|
|
25
|
+
title: "Spacing step",
|
|
26
|
+
type: "object",
|
|
27
|
+
fields: [
|
|
28
|
+
defineField({
|
|
29
|
+
name: "name",
|
|
30
|
+
title: "Name",
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Shown in the Presentation Mode dropdown on every block.",
|
|
33
|
+
validation: (Rule) => Rule.required().max(24),
|
|
34
|
+
}),
|
|
35
|
+
pxField("desktop", "Desktop", "From 1440px up. Required.", true),
|
|
36
|
+
pxField("tablet", "Tablet", "From 768px up. Empty reuses Desktop."),
|
|
37
|
+
pxField("mobile", "Mobile", "Below 768px. Empty reuses Desktop."),
|
|
38
|
+
defineField({
|
|
39
|
+
name: "isDefault",
|
|
40
|
+
title: "Use as default",
|
|
41
|
+
type: "boolean",
|
|
42
|
+
description:
|
|
43
|
+
"Blocks that never touch Presentation Mode use this step. Exactly one step can be the default.",
|
|
44
|
+
initialValue: false,
|
|
45
|
+
}),
|
|
46
|
+
],
|
|
47
|
+
preview: {
|
|
48
|
+
select: {
|
|
49
|
+
name: "name",
|
|
50
|
+
mobile: "mobile",
|
|
51
|
+
tablet: "tablet",
|
|
52
|
+
desktop: "desktop",
|
|
53
|
+
isDefault: "isDefault",
|
|
54
|
+
},
|
|
55
|
+
prepare({ name, mobile, tablet, desktop, isDefault }) {
|
|
56
|
+
const px = [mobile ?? desktop, tablet ?? desktop, desktop]
|
|
57
|
+
.map((value) => (typeof value === "number" ? `${value}px` : "—"))
|
|
58
|
+
.join(" / ");
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
title: `${name || "Untitled"}${isDefault ? " · default" : ""}`,
|
|
62
|
+
subtitle: `${px} (mobile / tablet / desktop)`,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const spacingSettings = defineType({
|
|
69
|
+
name: "spacingSettings",
|
|
70
|
+
title: "Spacing Scale",
|
|
71
|
+
type: "document",
|
|
72
|
+
icon: spacingSettingsIcon,
|
|
73
|
+
fields: [
|
|
74
|
+
defineField({
|
|
75
|
+
name: "steps",
|
|
76
|
+
title: "Spacing steps",
|
|
77
|
+
description:
|
|
78
|
+
"The vertical spacing every block can pick from. Add as many as you need and mark one as the default. Left empty, the built-in scale is used.",
|
|
79
|
+
type: "array",
|
|
80
|
+
components: { input: SpacingStepsInput },
|
|
81
|
+
of: [defineArrayMember({ type: "spacingStep" })],
|
|
82
|
+
initialValue: defaultSpacingSteps.map((step) => ({
|
|
83
|
+
_key: step.key,
|
|
84
|
+
_type: "spacingStep",
|
|
85
|
+
name: step.name,
|
|
86
|
+
mobile: step.mobile,
|
|
87
|
+
tablet: step.tablet,
|
|
88
|
+
desktop: step.desktop,
|
|
89
|
+
isDefault: step.isDefault,
|
|
90
|
+
})),
|
|
91
|
+
validation: (Rule) =>
|
|
92
|
+
Rule.custom((steps: unknown) => {
|
|
93
|
+
if (!Array.isArray(steps) || steps.length === 0) return true;
|
|
94
|
+
|
|
95
|
+
const defaults = steps.filter(
|
|
96
|
+
(step) => (step as { isDefault?: boolean })?.isDefault === true,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (defaults.length === 0) return "Mark one step as the default";
|
|
100
|
+
if (defaults.length > 1) return "Only one step can be the default";
|
|
101
|
+
|
|
102
|
+
const names = steps.map((step) =>
|
|
103
|
+
(step as { name?: string })?.name?.trim().toLowerCase(),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return new Set(names).size === names.length
|
|
107
|
+
? true
|
|
108
|
+
: "Two steps share the same name";
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
],
|
|
112
|
+
preview: {
|
|
113
|
+
prepare() {
|
|
114
|
+
return {
|
|
115
|
+
title: "Spacing Scale",
|
|
116
|
+
subtitle: "Section padding steps per breakpoint",
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const anchorSourceFields = [
|
|
2
|
+
"headline",
|
|
3
|
+
"heading",
|
|
4
|
+
"teaserHeading",
|
|
5
|
+
"title",
|
|
6
|
+
"label",
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
9
|
+
const ANCHOR_MAX_LENGTH = 60;
|
|
10
|
+
|
|
11
|
+
export const slugifyAnchor = (raw: string) =>
|
|
12
|
+
raw
|
|
13
|
+
.normalize("NFKD")
|
|
14
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
17
|
+
.replace(/^-+|-+$/g, "")
|
|
18
|
+
.slice(0, ANCHOR_MAX_LENGTH)
|
|
19
|
+
.replace(/-+$/g, "");
|
|
20
|
+
|
|
21
|
+
export const deriveAnchorId = (block: Record<string, unknown>) => {
|
|
22
|
+
for (const field of anchorSourceFields) {
|
|
23
|
+
const value = block[field];
|
|
24
|
+
if (typeof value === "string" && value.trim()) {
|
|
25
|
+
const slug = slugifyAnchor(value);
|
|
26
|
+
if (slug) return slug;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return "";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const explicitAnchorId = (block: Record<string, unknown>) =>
|
|
34
|
+
typeof block.anchorId === "string" ? slugifyAnchor(block.anchorId) : "";
|
|
35
|
+
|
|
36
|
+
const NO_RESERVED_IDS: ReadonlySet<string> = new Set();
|
|
37
|
+
|
|
38
|
+
export const reserveAnchorIds = (
|
|
39
|
+
blocks: readonly Record<string, unknown>[],
|
|
40
|
+
): ReadonlySet<string> => {
|
|
41
|
+
const reserved = new Set<string>();
|
|
42
|
+
|
|
43
|
+
for (const block of blocks) {
|
|
44
|
+
const explicit = explicitAnchorId(block);
|
|
45
|
+
if (explicit) reserved.add(explicit);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return reserved;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const resolveAnchorId = (
|
|
52
|
+
block: Record<string, unknown>,
|
|
53
|
+
taken: Set<string>,
|
|
54
|
+
reserved: ReadonlySet<string> = NO_RESERVED_IDS,
|
|
55
|
+
) => {
|
|
56
|
+
const explicit = explicitAnchorId(block);
|
|
57
|
+
const base = explicit || deriveAnchorId(block);
|
|
58
|
+
|
|
59
|
+
if (!base) return "";
|
|
60
|
+
|
|
61
|
+
const isBlocked = (candidate: string) =>
|
|
62
|
+
taken.has(candidate) || (!explicit && reserved.has(candidate));
|
|
63
|
+
|
|
64
|
+
let candidate = base;
|
|
65
|
+
let suffix = 2;
|
|
66
|
+
|
|
67
|
+
while (isBlocked(candidate)) {
|
|
68
|
+
candidate = `${base}-${suffix}`;
|
|
69
|
+
suffix += 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
taken.add(candidate);
|
|
73
|
+
|
|
74
|
+
return candidate;
|
|
75
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type DocumentDefinition,
|
|
3
|
+
defineType,
|
|
4
|
+
type FieldDefinition,
|
|
5
|
+
type FieldGroupDefinition,
|
|
6
|
+
} from "sanity";
|
|
7
|
+
import { presentationFields } from "./presentation";
|
|
8
|
+
|
|
9
|
+
const presentationGroup: FieldGroupDefinition = {
|
|
10
|
+
name: "presentation",
|
|
11
|
+
title: "Presentation",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type BlockDefinition = Omit<DocumentDefinition, "type" | "fields" | "groups"> & {
|
|
15
|
+
fields: FieldDefinition[];
|
|
16
|
+
groups?: FieldGroupDefinition[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const withPresentationGroup = (groups: FieldGroupDefinition[] | undefined) => {
|
|
20
|
+
if (!groups?.length) return undefined;
|
|
21
|
+
if (groups.some((group) => group.name === presentationGroup.name)) {
|
|
22
|
+
return groups;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return [...groups, presentationGroup];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Defines a page-builder block — `type: "document"` plus Anchor ID and
|
|
30
|
+
* Presentation Mode. Use instead of `defineType`.
|
|
31
|
+
*/
|
|
32
|
+
export const defineBlock = ({ fields, groups, ...rest }: BlockDefinition) => {
|
|
33
|
+
const blockGroups = withPresentationGroup(groups);
|
|
34
|
+
|
|
35
|
+
return defineType({
|
|
36
|
+
...rest,
|
|
37
|
+
type: "document",
|
|
38
|
+
...(blockGroups ? { groups: blockGroups } : {}),
|
|
39
|
+
fields: [
|
|
40
|
+
...fields,
|
|
41
|
+
...presentationFields(
|
|
42
|
+
blockGroups ? { group: presentationGroup.name } : undefined,
|
|
43
|
+
),
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineField, defineType } from "sanity";
|
|
2
|
+
import { AnchorIdInput } from "@/lib/integrations/sanity/components/anchor-id-input";
|
|
3
|
+
import { PresentationInput } from "@/lib/integrations/sanity/components/presentation-input";
|
|
4
|
+
|
|
5
|
+
export const presentation = defineType({
|
|
6
|
+
name: "presentation",
|
|
7
|
+
title: "Presentation Mode",
|
|
8
|
+
type: "object",
|
|
9
|
+
components: { input: PresentationInput },
|
|
10
|
+
fields: [
|
|
11
|
+
defineField({
|
|
12
|
+
name: "paddingTop",
|
|
13
|
+
title: "Padding top",
|
|
14
|
+
type: "string",
|
|
15
|
+
}),
|
|
16
|
+
defineField({
|
|
17
|
+
name: "paddingBottom",
|
|
18
|
+
title: "Padding bottom",
|
|
19
|
+
type: "string",
|
|
20
|
+
}),
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const presentationFields = (options?: { group?: string }) => [
|
|
25
|
+
defineField({
|
|
26
|
+
name: "anchorId",
|
|
27
|
+
title: "Anchor ID",
|
|
28
|
+
type: "string",
|
|
29
|
+
...(options?.group ? { group: options.group } : {}),
|
|
30
|
+
components: { input: AnchorIdInput },
|
|
31
|
+
description:
|
|
32
|
+
"Links to this block as /page#your-anchor-id. Leave empty to generate it from the block title.",
|
|
33
|
+
validation: (Rule) =>
|
|
34
|
+
Rule.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, { name: "anchor id" }).error(
|
|
35
|
+
"Use lowercase letters, numbers and dashes only (e.g. how-it-works)",
|
|
36
|
+
),
|
|
37
|
+
}),
|
|
38
|
+
defineField({
|
|
39
|
+
name: "presentation",
|
|
40
|
+
title: "Presentation Mode",
|
|
41
|
+
type: "presentation",
|
|
42
|
+
...(options?.group ? { group: options.group } : {}),
|
|
43
|
+
}),
|
|
44
|
+
];
|