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
|
@@ -1,36 +1,13 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
|
+
import { stegaClean } from "next-sanity";
|
|
2
3
|
import { urlForImage } from "@/lib/integrations/sanity/utils/image";
|
|
3
4
|
import { getBaseUrl } from "./base-url";
|
|
4
5
|
|
|
5
|
-
interface GenerateMetadataOptions {
|
|
6
|
-
title?: string | undefined;
|
|
7
|
-
description?: string | undefined;
|
|
8
|
-
keywords?: string[] | undefined;
|
|
9
|
-
ogTitle?: string | undefined;
|
|
10
|
-
ogDescription?: string | undefined;
|
|
11
|
-
canonicalUrl?: string | undefined;
|
|
12
|
-
image?:
|
|
13
|
-
| {
|
|
14
|
-
url?: string | undefined;
|
|
15
|
-
width?: number | undefined;
|
|
16
|
-
height?: number | undefined;
|
|
17
|
-
}
|
|
18
|
-
| undefined;
|
|
19
|
-
url?: string | undefined;
|
|
20
|
-
siteName?: string | undefined;
|
|
21
|
-
index?: boolean | undefined;
|
|
22
|
-
noIndex?: boolean | undefined;
|
|
23
|
-
type?: "website" | "article";
|
|
24
|
-
publishedTime?: string | undefined;
|
|
25
|
-
modifiedTime?: string | undefined;
|
|
26
|
-
authors?: string[] | undefined;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
6
|
interface SanityMetadataImage {
|
|
30
7
|
asset?: {
|
|
31
8
|
_ref?: string;
|
|
32
9
|
_type?: "reference";
|
|
33
|
-
};
|
|
10
|
+
} | null;
|
|
34
11
|
}
|
|
35
12
|
|
|
36
13
|
interface SanityPageMetadata {
|
|
@@ -44,6 +21,7 @@ interface SanityPageMetadata {
|
|
|
44
21
|
image?: SanityMetadataImage | null;
|
|
45
22
|
} | null;
|
|
46
23
|
index?: boolean | null;
|
|
24
|
+
follow?: boolean | null;
|
|
47
25
|
title?: string | null;
|
|
48
26
|
description?: string | null;
|
|
49
27
|
image?: SanityMetadataImage | null;
|
|
@@ -52,138 +30,133 @@ interface SanityPageMetadata {
|
|
|
52
30
|
|
|
53
31
|
interface SanityMetadataDocument {
|
|
54
32
|
title?: string | null;
|
|
55
|
-
subtitle?: string | null;
|
|
56
33
|
metadata?: SanityPageMetadata | null;
|
|
57
34
|
}
|
|
58
35
|
|
|
36
|
+
// The Structured Data singleton: its name is the og:site_name and its share
|
|
37
|
+
// image covers any page without an OG image of its own.
|
|
38
|
+
interface SiteMetadata {
|
|
39
|
+
name?: string | null;
|
|
40
|
+
shareImage?: SanityMetadataImage | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ArticleMetadata {
|
|
44
|
+
publishedTime?: string | null | undefined;
|
|
45
|
+
modifiedTime?: string | null | undefined;
|
|
46
|
+
authors?: readonly (string | null | undefined)[] | null | undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
59
49
|
interface GenerateSanityMetadataOptions {
|
|
60
50
|
document: SanityMetadataDocument;
|
|
61
51
|
url?: string;
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
site?: SiteMetadata | null | undefined;
|
|
53
|
+
fallbackDescription?: string | null | undefined;
|
|
54
|
+
fallbackImage?: SanityMetadataImage | null | undefined;
|
|
55
|
+
article?: ArticleMetadata | undefined;
|
|
64
56
|
}
|
|
65
57
|
|
|
58
|
+
const OG_WIDTH = 1200;
|
|
59
|
+
const OG_HEIGHT = 630;
|
|
60
|
+
const DESCRIPTION_LENGTH = 160;
|
|
61
|
+
|
|
66
62
|
const APP_BASE_URL = getBaseUrl();
|
|
67
63
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
url
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
const
|
|
64
|
+
// A relative override is rooted, so "blog/post" can't resolve against the
|
|
65
|
+
// current path.
|
|
66
|
+
const resolveCanonical = (
|
|
67
|
+
override: string | null | undefined,
|
|
68
|
+
ownPath: string,
|
|
69
|
+
) => {
|
|
70
|
+
const value = override?.trim();
|
|
71
|
+
if (!value) return ownPath;
|
|
72
|
+
if (/^https?:\/\//i.test(value)) return value;
|
|
73
|
+
return `/${value.replace(/^\/+/, "")}`;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Trims body copy to a meta description, cut at a word boundary.
|
|
77
|
+
const summarize = (
|
|
78
|
+
text: string | null | undefined,
|
|
79
|
+
maxLength = DESCRIPTION_LENGTH,
|
|
80
|
+
) => {
|
|
81
|
+
const clean = text?.replace(/\s+/g, " ").trim();
|
|
82
|
+
if (!clean) return undefined;
|
|
83
|
+
if (clean.length <= maxLength) return clean;
|
|
84
|
+
const cut = clean.slice(0, maxLength - 1);
|
|
85
|
+
const lastSpace = cut.lastIndexOf(" ");
|
|
86
|
+
return `${(lastSpace > 0 ? cut.slice(0, lastSpace) : cut).replace(/[\s,;:.–—-]+$/, "")}…`;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const socialImage = (source: SanityMetadataImage | null | undefined) =>
|
|
90
|
+
source?.asset
|
|
91
|
+
? urlForImage(source).width(OG_WIDTH).height(OG_HEIGHT).url()
|
|
92
|
+
: undefined;
|
|
93
|
+
|
|
94
|
+
export const generateSanityMetadata = ({
|
|
95
|
+
document,
|
|
96
|
+
url = "/",
|
|
97
|
+
site,
|
|
98
|
+
fallbackDescription,
|
|
99
|
+
fallbackImage,
|
|
100
|
+
article,
|
|
101
|
+
}: GenerateSanityMetadataOptions): Metadata => {
|
|
102
|
+
const { name, shareImage } = stegaClean(site) ?? {};
|
|
103
|
+
const siteName = name?.trim() || undefined;
|
|
104
|
+
|
|
105
|
+
const seo = document.metadata;
|
|
106
|
+
const title = seo?.metaTitle || seo?.title || document.title || siteName;
|
|
107
|
+
const description =
|
|
108
|
+
seo?.metaDescription || seo?.description || summarize(fallbackDescription);
|
|
109
|
+
const socialTitle = seo?.ogTitle || title;
|
|
110
|
+
const socialDescription = seo?.ogDescription || description;
|
|
111
|
+
const imageUrl =
|
|
112
|
+
socialImage(seo?.image) ||
|
|
113
|
+
socialImage(seo?.og?.image) ||
|
|
114
|
+
socialImage(fallbackImage) ||
|
|
115
|
+
socialImage(shareImage);
|
|
116
|
+
const images = imageUrl
|
|
117
|
+
? [{ url: imageUrl, width: OG_WIDTH, height: OG_HEIGHT }]
|
|
118
|
+
: undefined;
|
|
119
|
+
|
|
120
|
+
const canonical = resolveCanonical(seo?.canonicalUrl, url);
|
|
121
|
+
|
|
122
|
+
const index = seo?.index ?? (seo?.noIndex != null ? !seo.noIndex : true);
|
|
123
|
+
// Unset on pages that predate the toggle, which were `nofollow` whenever
|
|
124
|
+
// they were `noindex`.
|
|
125
|
+
const follow = seo?.follow ?? index;
|
|
126
|
+
const authors = article?.authors?.filter((author): author is string =>
|
|
127
|
+
Boolean(author),
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return {
|
|
116
131
|
metadataBase: new URL(APP_BASE_URL),
|
|
117
132
|
title,
|
|
118
133
|
description,
|
|
119
|
-
keywords,
|
|
120
|
-
alternates: { canonical
|
|
134
|
+
keywords: seo?.keywords?.length ? seo.keywords : undefined,
|
|
135
|
+
alternates: { canonical },
|
|
121
136
|
openGraph: {
|
|
137
|
+
title: socialTitle,
|
|
122
138
|
description: socialDescription,
|
|
123
|
-
url
|
|
139
|
+
// Follows the canonical, so an override doesn't leave og:url pointing
|
|
140
|
+
// at the duplicate.
|
|
141
|
+
url: new URL(canonical, APP_BASE_URL).toString(),
|
|
124
142
|
siteName,
|
|
125
143
|
locale: "en_US",
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
144
|
+
images,
|
|
145
|
+
...(article
|
|
146
|
+
? {
|
|
147
|
+
type: "article",
|
|
148
|
+
publishedTime: article.publishedTime || undefined,
|
|
149
|
+
modifiedTime: article.modifiedTime || undefined,
|
|
150
|
+
authors: authors?.length ? authors : undefined,
|
|
151
|
+
}
|
|
152
|
+
: { type: "website" }),
|
|
132
153
|
},
|
|
133
154
|
twitter: {
|
|
134
155
|
card: "summary_large_image",
|
|
156
|
+
title: socialTitle,
|
|
135
157
|
description: socialDescription,
|
|
136
|
-
images
|
|
137
|
-
...(socialTitle && { title: socialTitle }),
|
|
158
|
+
images,
|
|
138
159
|
},
|
|
139
|
-
|
|
160
|
+
...(index && follow ? {} : { robots: { index, follow } }),
|
|
140
161
|
};
|
|
141
|
-
|
|
142
|
-
if (!shouldIndex) metadata.robots = { index: false, follow: false };
|
|
143
|
-
|
|
144
|
-
return metadata;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
export const generateSanityMetadata = ({
|
|
148
|
-
document,
|
|
149
|
-
url,
|
|
150
|
-
siteName,
|
|
151
|
-
type = "website",
|
|
152
|
-
}: GenerateSanityMetadataOptions): Metadata => {
|
|
153
|
-
const pageMetadata = document.metadata;
|
|
154
|
-
const title =
|
|
155
|
-
pageMetadata?.metaTitle ||
|
|
156
|
-
pageMetadata?.title ||
|
|
157
|
-
document.title ||
|
|
158
|
-
undefined;
|
|
159
|
-
const description =
|
|
160
|
-
pageMetadata?.metaDescription ||
|
|
161
|
-
pageMetadata?.description ||
|
|
162
|
-
document.subtitle ||
|
|
163
|
-
undefined;
|
|
164
|
-
const socialImageSource = pageMetadata?.image || pageMetadata?.og?.image;
|
|
165
|
-
const imageUrl = socialImageSource
|
|
166
|
-
? urlForImage(socialImageSource).width(1200).height(630).url()
|
|
167
|
-
: undefined;
|
|
168
|
-
const index =
|
|
169
|
-
pageMetadata?.index ??
|
|
170
|
-
(pageMetadata?.noIndex != null ? !pageMetadata.noIndex : true);
|
|
171
|
-
|
|
172
|
-
const keywords = pageMetadata?.keywords?.length
|
|
173
|
-
? pageMetadata.keywords
|
|
174
|
-
: undefined;
|
|
175
|
-
|
|
176
|
-
return generatePageMetadata({
|
|
177
|
-
title,
|
|
178
|
-
description,
|
|
179
|
-
keywords,
|
|
180
|
-
ogTitle: pageMetadata?.ogTitle || undefined,
|
|
181
|
-
ogDescription: pageMetadata?.ogDescription || undefined,
|
|
182
|
-
canonicalUrl: pageMetadata?.canonicalUrl || undefined,
|
|
183
|
-
image: imageUrl ? { url: imageUrl, width: 1200, height: 630 } : undefined,
|
|
184
|
-
url,
|
|
185
|
-
siteName,
|
|
186
|
-
index,
|
|
187
|
-
type,
|
|
188
|
-
});
|
|
189
162
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { headers } from "next/headers";
|
|
2
|
+
|
|
3
|
+
const STUDIO_PATH = "/studio";
|
|
4
|
+
|
|
5
|
+
const isStudioReferer = (referer: string | null) => {
|
|
6
|
+
if (!referer) return false;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
return new URL(referer).pathname.startsWith(STUDIO_PATH);
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const isStudioEmbed = async () => {
|
|
16
|
+
const headerList = await headers();
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
headerList.get("sec-fetch-dest") === "iframe" ||
|
|
20
|
+
isStudioReferer(headerList.get("referer"))
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -4,7 +4,7 @@ import { parseBody } from "next-sanity/webhook";
|
|
|
4
4
|
// `directClient`, never `client`: a CDN hit returns the pre-mutation slug, which
|
|
5
5
|
// purges the old path twice and never the new one.
|
|
6
6
|
import { directClient } from "@/lib/integrations/sanity/client";
|
|
7
|
-
import {
|
|
7
|
+
import { pageBuilderBlockMembers } from "@/lib/integrations/sanity/page-builder-config";
|
|
8
8
|
import {
|
|
9
9
|
ALL_PAGE_SLUGS_QUERY,
|
|
10
10
|
FOLDER_PATH_QUERY,
|
|
@@ -64,7 +64,7 @@ type RevalidateWebhookBody = WebhookDocument & {
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
const referenceableTypes = new Set<string>([
|
|
67
|
-
...
|
|
67
|
+
...pageBuilderBlockMembers.map((member) => member.documentType),
|
|
68
68
|
...REFERENCEABLE_TYPES,
|
|
69
69
|
]);
|
|
70
70
|
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/rich-text.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { SanityImage } from "@/components/ui/sanity-image";
|
|
|
4
4
|
import {
|
|
5
5
|
getLinkAttributes,
|
|
6
6
|
urlForReference,
|
|
7
|
-
} from "
|
|
7
|
+
} from "@/lib/integrations/sanity/utils/link";
|
|
8
8
|
|
|
9
9
|
interface RichTextProps {
|
|
10
10
|
content: PortableTextProps["value"];
|
|
@@ -80,7 +80,9 @@ export const RichText = ({ content }: RichTextProps) => {
|
|
|
80
80
|
externalLink: LinkMark,
|
|
81
81
|
},
|
|
82
82
|
block: {
|
|
83
|
-
h1:
|
|
83
|
+
// The h1 style is retired: the page owns its H1, so legacy content
|
|
84
|
+
// drops a level.
|
|
85
|
+
h1: ({ children }) => <h2 className="h2">{children}</h2>,
|
|
84
86
|
h2: ({ children }) => <h2 className="h2">{children}</h2>,
|
|
85
87
|
h3: ({ children }) => <h3 className="h3">{children}</h3>,
|
|
86
88
|
h4: ({ children }) => <h4 className="h4">{children}</h4>,
|
|
@@ -6,7 +6,7 @@ import { apiVersion } from "@/lib/integrations/sanity/env";
|
|
|
6
6
|
|
|
7
7
|
const HIDDEN_KEYS_FIELD = "hiddenPageBuilderKeys";
|
|
8
8
|
|
|
9
|
-
type
|
|
9
|
+
type BlockItem = { _key: string; _type?: string };
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Eye-icon toggle for a page builder placement's per-page visibility. Adds the
|
|
@@ -14,7 +14,7 @@ type ReferenceItem = { _key: string; _ref: string; _type: string };
|
|
|
14
14
|
* filters those keys out at query time. Standalone control because Sanity's
|
|
15
15
|
* built-in item menu isn't extensible via public props.
|
|
16
16
|
*/
|
|
17
|
-
export function BlockActionsItem(props: ObjectItemProps<
|
|
17
|
+
export function BlockActionsItem(props: ObjectItemProps<BlockItem>) {
|
|
18
18
|
const { value, renderDefault } = props;
|
|
19
19
|
const client = useClient({ apiVersion });
|
|
20
20
|
const toast = useToast();
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Box, Button, Card, Code, Flex, Text } from "@sanity/ui";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
const VIEWPORTS = [
|
|
5
|
+
{ id: "desktop", label: "Desktop", width: 1440 },
|
|
6
|
+
{ id: "tablet", label: "Tablet", width: 834 },
|
|
7
|
+
{ id: "mobile", label: "Mobile", width: 390 },
|
|
8
|
+
] as const;
|
|
9
|
+
|
|
10
|
+
type ViewportId = (typeof VIEWPORTS)[number]["id"];
|
|
11
|
+
|
|
12
|
+
interface ComponentPreviewFrameProps {
|
|
13
|
+
notes?: string | undefined;
|
|
14
|
+
path: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const ComponentPreviewFrame = ({
|
|
18
|
+
notes,
|
|
19
|
+
path,
|
|
20
|
+
}: ComponentPreviewFrameProps) => {
|
|
21
|
+
const stage = useRef<HTMLDivElement>(null);
|
|
22
|
+
const [box, setBox] = useState({ height: 0, width: 0 });
|
|
23
|
+
const [viewport, setViewport] = useState<ViewportId>("desktop");
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const element = stage.current;
|
|
27
|
+
if (!element) return;
|
|
28
|
+
|
|
29
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
30
|
+
if (!entry) return;
|
|
31
|
+
const { height, width } = entry.contentRect;
|
|
32
|
+
setBox({ height, width });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
observer.observe(element);
|
|
36
|
+
return () => observer.disconnect();
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const width = VIEWPORTS.find((item) => item.id === viewport)?.width ?? 1440;
|
|
40
|
+
|
|
41
|
+
const scale = box.width > 0 ? Math.min(1, box.width / width) : 1;
|
|
42
|
+
const height = box.height > 0 ? box.height / scale : 0;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Flex direction="column" height="fill">
|
|
46
|
+
<Card borderBottom padding={2} tone="transparent">
|
|
47
|
+
<Flex align="center" gap={2}>
|
|
48
|
+
<Flex gap={1}>
|
|
49
|
+
{VIEWPORTS.map((item) => (
|
|
50
|
+
<Button
|
|
51
|
+
fontSize={0}
|
|
52
|
+
key={item.id}
|
|
53
|
+
mode={item.id === viewport ? "default" : "bleed"}
|
|
54
|
+
onClick={() => setViewport(item.id)}
|
|
55
|
+
padding={2}
|
|
56
|
+
text={item.label}
|
|
57
|
+
tone={item.id === viewport ? "primary" : "default"}
|
|
58
|
+
/>
|
|
59
|
+
))}
|
|
60
|
+
</Flex>
|
|
61
|
+
<Box flex={1} />
|
|
62
|
+
<Code size={0}>
|
|
63
|
+
{width} × {Math.round(height)} · {Math.round(scale * 100)}%
|
|
64
|
+
</Code>
|
|
65
|
+
</Flex>
|
|
66
|
+
</Card>
|
|
67
|
+
|
|
68
|
+
{notes ? (
|
|
69
|
+
<Card borderBottom padding={3} tone="transparent">
|
|
70
|
+
<Text muted size={0}>
|
|
71
|
+
{notes}
|
|
72
|
+
</Text>
|
|
73
|
+
</Card>
|
|
74
|
+
) : null}
|
|
75
|
+
|
|
76
|
+
<Box
|
|
77
|
+
flex={1}
|
|
78
|
+
style={{
|
|
79
|
+
background: "var(--card-muted-bg-color)",
|
|
80
|
+
overflow: "hidden",
|
|
81
|
+
position: "relative",
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
<div
|
|
85
|
+
ref={stage}
|
|
86
|
+
style={{
|
|
87
|
+
display: "flex",
|
|
88
|
+
height: "100%",
|
|
89
|
+
justifyContent: "center",
|
|
90
|
+
width: "100%",
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
{height > 0 ? (
|
|
94
|
+
<div
|
|
95
|
+
style={{
|
|
96
|
+
background: "var(--card-bg-color)",
|
|
97
|
+
border: "1px solid var(--card-border-color)",
|
|
98
|
+
borderRadius: 4,
|
|
99
|
+
boxShadow: "0 1px 12px rgb(0 0 0 / 0.12)",
|
|
100
|
+
flex: "none",
|
|
101
|
+
height: box.height,
|
|
102
|
+
overflow: "hidden",
|
|
103
|
+
width: width * scale,
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<iframe
|
|
107
|
+
src={path}
|
|
108
|
+
style={{
|
|
109
|
+
border: 0,
|
|
110
|
+
display: "block",
|
|
111
|
+
height,
|
|
112
|
+
transform: `scale(${scale})`,
|
|
113
|
+
transformOrigin: "top left",
|
|
114
|
+
width,
|
|
115
|
+
}}
|
|
116
|
+
title="Component preview"
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
) : null}
|
|
120
|
+
</div>
|
|
121
|
+
</Box>
|
|
122
|
+
</Flex>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Card, Text } from "@sanity/ui";
|
|
2
|
+
import { ComponentPreviewFrame } from "./component-preview-frame";
|
|
3
|
+
|
|
4
|
+
interface ComponentPreviewPaneProps {
|
|
5
|
+
options?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const ComponentPreviewPane = ({
|
|
9
|
+
options,
|
|
10
|
+
}: ComponentPreviewPaneProps) => {
|
|
11
|
+
const path = options?.path as string | undefined;
|
|
12
|
+
const notes = options?.notes as string | undefined;
|
|
13
|
+
|
|
14
|
+
if (!path) {
|
|
15
|
+
return (
|
|
16
|
+
<Card padding={4}>
|
|
17
|
+
<Text muted size={1}>
|
|
18
|
+
This component has no preview route.
|
|
19
|
+
</Text>
|
|
20
|
+
</Card>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <ComponentPreviewFrame notes={notes} path={path} />;
|
|
25
|
+
};
|
|
@@ -1,38 +1,18 @@
|
|
|
1
1
|
import { type ArrayOfObjectsInputProps, useFormValue } from "sanity";
|
|
2
2
|
import { PageBuilderInsertMenu } from "@/lib/integrations/sanity/components/page-builder-insert-menu";
|
|
3
|
-
import { useStudioPreviewUrls } from "@/lib/integrations/sanity/components/use-studio-preview-urls";
|
|
4
3
|
import {
|
|
5
|
-
blockPreviewKey,
|
|
6
4
|
getVisiblePageBuilderInsertMenuGroups,
|
|
7
5
|
getVisiblePageBuilderMemberNames,
|
|
6
|
+
type PageBuilderDocumentType,
|
|
8
7
|
type PageBuilderGroupName,
|
|
9
|
-
pageBuilderReferenceMembers,
|
|
10
8
|
} from "@/lib/integrations/sanity/page-builder-config";
|
|
11
9
|
|
|
12
|
-
const BLOCK_PREVIEW_KEYS = pageBuilderReferenceMembers.map((member) =>
|
|
13
|
-
blockPreviewKey(member.name),
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
function useInsertMenuViews() {
|
|
17
|
-
const previewUrls = useStudioPreviewUrls(BLOCK_PREVIEW_KEYS);
|
|
18
|
-
|
|
19
|
-
return [
|
|
20
|
-
{
|
|
21
|
-
name: "grid" as const,
|
|
22
|
-
previewImageUrl: (schemaTypeName: string) =>
|
|
23
|
-
previewUrls?.[blockPreviewKey(schemaTypeName)],
|
|
24
|
-
},
|
|
25
|
-
{ name: "list" as const },
|
|
26
|
-
];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
10
|
export function PageBuilderInput(props: ArrayOfObjectsInputProps) {
|
|
30
11
|
const pageTypeValue = useFormValue(["type"]);
|
|
31
12
|
const pageType =
|
|
32
13
|
typeof pageTypeValue === "string"
|
|
33
14
|
? (pageTypeValue as PageBuilderGroupName)
|
|
34
15
|
: undefined;
|
|
35
|
-
const views = useInsertMenuViews();
|
|
36
16
|
const visibleMemberNames = getVisiblePageBuilderMemberNames(pageType);
|
|
37
17
|
|
|
38
18
|
return props.renderDefault({
|
|
@@ -40,17 +20,14 @@ export function PageBuilderInput(props: ArrayOfObjectsInputProps) {
|
|
|
40
20
|
arrayFunctions: PageBuilderInsertMenu,
|
|
41
21
|
schemaType: {
|
|
42
22
|
...props.schemaType,
|
|
43
|
-
of: props.schemaType.of.filter(
|
|
44
|
-
(member)
|
|
45
|
-
typeof member.name === "string" &&
|
|
46
|
-
visibleMemberNames.has(member.name),
|
|
23
|
+
of: props.schemaType.of.filter((member) =>
|
|
24
|
+
visibleMemberNames.has(member.name as PageBuilderDocumentType),
|
|
47
25
|
),
|
|
48
26
|
options: {
|
|
49
27
|
...props.schemaType.options,
|
|
50
28
|
insertMenu: {
|
|
51
29
|
...props.schemaType.options?.insertMenu,
|
|
52
30
|
groups: getVisiblePageBuilderInsertMenuGroups(pageType),
|
|
53
|
-
views,
|
|
54
31
|
},
|
|
55
32
|
},
|
|
56
33
|
},
|