bsmnt 0.9.0 → 0.11.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 +19 -2
- package/dist/application/add-integration/index.js.map +1 -1
- package/dist/application/shared/node-version.js.map +1 -1
- package/dist/core/create/internal-ids.d.ts +3 -0
- package/dist/core/create/internal-ids.d.ts.map +1 -1
- package/dist/core/create/internal-ids.js +4 -0
- package/dist/core/create/internal-ids.js.map +1 -1
- package/dist/domain/agents.d.ts.map +1 -1
- package/dist/domain/animations.d.ts.map +1 -1
- package/dist/domain/cms.d.ts.map +1 -1
- package/dist/domain/forms.d.ts.map +1 -1
- package/dist/domain/hooks.d.ts.map +1 -1
- package/dist/domain/skills.d.ts.map +1 -1
- package/dist/domain/templates.d.ts +10 -0
- package/dist/domain/templates.d.ts.map +1 -1
- package/dist/domain/templates.js +5 -0
- package/dist/domain/templates.js.map +1 -1
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/agents/register-sanity-mcp.js +3 -8
- package/dist/infrastructure/agents/register-sanity-mcp.js.map +1 -1
- package/dist/infrastructure/agents/register-storybook-mcp.d.ts +18 -0
- package/dist/infrastructure/agents/register-storybook-mcp.d.ts.map +1 -0
- package/dist/infrastructure/agents/register-storybook-mcp.js +157 -0
- package/dist/infrastructure/agents/register-storybook-mcp.js.map +1 -0
- package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
- package/dist/infrastructure/create/lifecycle-registry.js +39 -1
- package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
- package/dist/infrastructure/create/merge-registry.d.ts.map +1 -1
- package/dist/infrastructure/create/merge-registry.js +4 -0
- package/dist/infrastructure/create/merge-registry.js.map +1 -1
- package/dist/infrastructure/create/sanity-auth.js.map +1 -1
- package/dist/infrastructure/create/setup-agent.d.ts +6 -1
- package/dist/infrastructure/create/setup-agent.d.ts.map +1 -1
- package/dist/infrastructure/create/setup-agent.js +23 -21
- package/dist/infrastructure/create/setup-agent.js.map +1 -1
- package/dist/infrastructure/create/setup-dotenvx.js.map +1 -1
- package/dist/infrastructure/create/setup-remote.js.map +1 -1
- package/dist/infrastructure/create/setup-sanity.d.ts.map +1 -1
- package/dist/infrastructure/create/setup-sanity.js +12 -1
- package/dist/infrastructure/create/setup-sanity.js.map +1 -1
- package/dist/infrastructure/integrations/ensure-studio-headers.d.ts +6 -0
- package/dist/infrastructure/integrations/ensure-studio-headers.d.ts.map +1 -0
- package/dist/infrastructure/integrations/ensure-studio-headers.js +153 -0
- package/dist/infrastructure/integrations/ensure-studio-headers.js.map +1 -0
- package/dist/infrastructure/integrations/inject-integration.d.ts.map +1 -1
- package/dist/infrastructure/integrations/inject-integration.js +2 -0
- package/dist/infrastructure/integrations/inject-integration.js.map +1 -1
- package/dist/infrastructure/update/notifier.js.map +1 -1
- package/dist/modules/features/cms/index.d.ts.map +1 -1
- package/dist/modules/features/cms/index.js +2 -0
- package/dist/modules/features/cms/index.js.map +1 -1
- package/dist/modules/features/cms/sanity/config.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/config.js +3 -1
- package/dist/modules/features/cms/sanity/config.js.map +1 -1
- package/dist/modules/features/cms/sanity/index.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/index.js +10 -1
- package/dist/modules/features/cms/sanity/index.js.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/check-integration.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/check-integration.js +15 -6
- package/dist/modules/features/cms/sanity/mergers/check-integration.js.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/knip.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/knip.js +1 -0
- package/dist/modules/features/cms/sanity/mergers/knip.js.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/layout.js.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/package-json.d.ts +12 -0
- package/dist/modules/features/cms/sanity/mergers/package-json.d.ts.map +1 -0
- package/dist/modules/features/cms/sanity/mergers/package-json.js +19 -0
- package/dist/modules/features/cms/sanity/mergers/package-json.js.map +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder/config.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder/config.js +2 -1
- 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 +7 -1
- package/dist/modules/features/cms/sanity-pagebuilder/index.js.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.d.ts +14 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.d.ts.map +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.js +50 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/config.js.map +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/index.d.ts +3 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/index.d.ts.map +1 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js +55 -0
- package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js.map +1 -0
- package/dist/modules/presets/index.d.ts.map +1 -1
- package/dist/modules/presets/index.js +2 -0
- package/dist/modules/presets/index.js.map +1 -1
- package/dist/modules/presets/next-pagebuilder-cache.d.ts +3 -0
- package/dist/modules/presets/next-pagebuilder-cache.d.ts.map +1 -0
- package/dist/modules/presets/next-pagebuilder-cache.js +10 -0
- package/dist/modules/presets/next-pagebuilder-cache.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +6 -0
- package/dist/paths.js.map +1 -1
- package/package.json +6 -3
- package/src/modules/features/cms/sanity/files/app/api/blog/[slug]/route.ts +4 -1
- package/src/modules/features/cms/sanity/files/app/sitemap.md/route.ts +2 -1
- package/src/modules/features/cms/sanity/files/components/ui/sanity-image/index.tsx +19 -5
- package/src/modules/features/cms/sanity/files/lib/integrations/check-integration.ts +7 -6
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/README.md +32 -1
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/components/rich-text.tsx +1 -0
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/env.ts +2 -2
- package/src/modules/features/cms/sanity/files/proxy.ts +9 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/[[...slug]]/route.ts +12 -3
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/revalidate/route.ts +172 -24
- package/src/modules/features/cms/sanity-pagebuilder/files/app/feed.xml/route.ts +14 -7
- package/src/modules/features/cms/sanity-pagebuilder/files/app/sitemap.md/route.ts +8 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/app/studio/[[...tool]]/page.tsx +16 -1
- package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/rich-text.tsx +1 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/visual-editing.tsx +2 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/components/ui/sanity-image/index.tsx +15 -5
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/check-integration.ts +6 -5
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/client.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/slug-field.tsx +13 -7
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/slug-notices.tsx +125 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/env.ts +2 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/layout.ts +22 -52
- 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/live/index.tsx +4 -2
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/markdown-proxy.config.ts +1 -1
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-builder-config.ts +7 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-tree-pane.tsx +70 -57
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +119 -29
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/revalidate-paths.ts +70 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/index.ts +1 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/rich-text-block.ts +39 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +2 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/redirect.ts +35 -4
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page.ts +12 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/tags.ts +56 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/page-builder-markdown.ts +12 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/sitemap.ts +11 -8
- package/src/modules/features/cms/sanity-pagebuilder/files/proxy.ts +9 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/.knip.json +8 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/api/[[...slug]]/route.ts +112 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/api/draft-mode/disable/route.ts +7 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/api/draft-mode/enable/route.ts +20 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/api/revalidate/route.ts +292 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/feed.xml/route.ts +66 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/sitemap.md/route.ts +132 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/studio/[[...tool]]/layout.tsx +26 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/studio/[[...tool]]/page.tsx +23 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/draft-mode-toggle.tsx +27 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/rich-text.tsx +88 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/visual-editing.tsx +11 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/ui/sanity-image/index.tsx +51 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/check-integration.ts +6 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/client.ts +37 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/block-actions-item.tsx +81 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/disable-draft-mode.tsx +23 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/page-builder-input.tsx +39 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/page-category-input.tsx +50 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/same-as-input.tsx +66 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/slug-field.tsx +24 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/slug-input.tsx +14 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/slug-notices.tsx +125 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/confirm-publish-action.ts +40 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/env.ts +34 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/fetchers/layout.ts +39 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/fetchers/redirects.ts +22 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/icons.ts +81 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/live/index.tsx +140 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/markdown-proxy.config.ts +50 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/page-builder-config.ts +144 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/page-category.ts +28 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/page-tree-pane.tsx +431 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/pinned-pages.ts +54 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/presentation.ts +119 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts +548 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/revalidate-paths.ts +70 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/sanity.cli.ts +29 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/sanity.config.ts +116 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/index.ts +6 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +89 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/description.ts +29 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/gated-content.ts +178 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/hero.ts +28 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/reusable/rich-text-block.ts +39 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +45 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/content/author.ts +70 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/content/blog-category.ts +55 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/index.ts +134 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/company-data.ts +70 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/footer.ts +79 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/navbar.ts +75 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/redirect.ts +152 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/structured-data.ts +124 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/link.ts +125 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/logo-field.ts +9 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/metadata.ts +132 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/nav-objects.ts +192 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page-builder.ts +43 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page-folder.ts +124 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page.ts +265 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/richText.ts +63 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/structured-data-blocks.ts +436 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/singletons.ts +51 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/structure.ts +334 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/tags.ts +89 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/utils/image.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/utils/link.ts +140 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/utils/page-builder-markdown.ts +113 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/scripts/sanity-typegen.ts +36 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/check-redirect.ts +30 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/json-ld.tsx +522 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/metadata.ts +189 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/rss.ts +96 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/sitemap.ts +58 -0
- package/src/modules/features/cms/sanity-pagebuilder-cache/files/proxy.ts +90 -0
- package/src/modules/features/env/dotenvx/files/vercelignore +5 -0
- package/src/templates/next-default/.env.example +4 -2
- package/src/templates/next-default/.github/workflows/ci.yml +1 -1
- package/src/templates/next-default/.vscode/settings.json +0 -2
- package/src/templates/next-default/app/robots.ts +2 -3
- package/src/templates/next-default/components/ui/image/index.tsx +2 -4
- package/src/templates/next-default/knip.json +1 -1
- package/src/templates/next-default/lefthook.yml +1 -1
- package/src/templates/next-default/lib/utils/README.md +18 -5
- package/src/templates/next-default/lib/utils/image-sizes.ts +72 -0
- package/src/templates/next-default/lib/utils/merge-refs.ts +56 -0
- package/src/templates/next-default/lib/utils/strings.ts +1 -51
- package/src/templates/next-default/next.config.ts +38 -5
- package/src/templates/next-default/package.json +9 -12
- package/src/templates/next-experiments/.env.example +4 -2
- package/src/templates/next-experiments/.github/workflows/ci.yml +1 -1
- package/src/templates/next-experiments/.vscode/settings.json +0 -2
- package/src/templates/next-experiments/app/page.tsx +1 -1
- package/src/templates/next-experiments/app/robots.ts +2 -3
- package/src/templates/next-experiments/components/ui/image/index.tsx +2 -4
- package/src/templates/next-experiments/knip.json +1 -1
- package/src/templates/next-experiments/lefthook.yml +1 -1
- package/src/templates/next-experiments/lib/utils/README.md +18 -5
- package/src/templates/next-experiments/lib/utils/image-sizes.ts +72 -0
- package/src/templates/next-experiments/lib/utils/merge-refs.ts +56 -0
- package/src/templates/next-experiments/lib/utils/strings.ts +1 -51
- package/src/templates/next-experiments/next.config.ts +38 -5
- package/src/templates/next-experiments/package.json +9 -12
- package/src/templates/next-pagebuilder/.env.example +3 -0
- package/src/templates/next-pagebuilder/.github/workflows/ci.yml +1 -1
- package/src/templates/next-pagebuilder/.vscode/settings.json +0 -2
- package/src/templates/next-pagebuilder/README.md +95 -0
- package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +24 -9
- package/src/templates/next-pagebuilder/app/robots.ts +2 -3
- package/src/templates/next-pagebuilder/app/sitemap.xml/route.ts +9 -4
- package/src/templates/next-pagebuilder/biome.json +2 -1
- package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +3 -6
- package/src/templates/next-pagebuilder/components/layout/header/index.tsx +3 -2
- package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +3 -8
- package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/content-filters.tsx +23 -40
- package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/index.tsx +88 -58
- package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/skeleton.tsx +41 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/types.ts +14 -1
- package/src/templates/next-pagebuilder/components/page-builder/components/rich-text-block.tsx +16 -0
- package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +23 -3
- package/src/templates/next-pagebuilder/components/page-document/index.tsx +1 -0
- package/src/templates/next-pagebuilder/components/ui/image/index.tsx +2 -1
- package/src/templates/next-pagebuilder/knip.json +3 -2
- package/src/templates/next-pagebuilder/lefthook.yml +1 -1
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +1221 -977
- package/src/templates/next-pagebuilder/lib/utils/image-sizes.ts +72 -0
- package/src/templates/next-pagebuilder/lib/utils/merge-refs.ts +56 -0
- package/src/templates/next-pagebuilder/next.config.ts +35 -5
- package/src/templates/next-pagebuilder/package.json +8 -10
- package/src/templates/next-pagebuilder-cache/.biome/plugins/README.md +21 -0
- package/src/templates/next-pagebuilder-cache/.biome/plugins/no-anchor-element.grit +12 -0
- package/src/templates/next-pagebuilder-cache/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/src/templates/next-pagebuilder-cache/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/src/templates/next-pagebuilder-cache/.env.example +40 -0
- package/src/templates/next-pagebuilder-cache/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- package/src/templates/next-pagebuilder-cache/.github/workflows/ci.yml +105 -0
- package/src/templates/next-pagebuilder-cache/.vscode/extensions.json +19 -0
- package/src/templates/next-pagebuilder-cache/.vscode/settings.json +103 -0
- package/src/templates/next-pagebuilder-cache/.zed/settings.json +47 -0
- package/src/templates/next-pagebuilder-cache/README.md +212 -0
- package/src/templates/next-pagebuilder-cache/_gitignore +65 -0
- package/src/templates/next-pagebuilder-cache/app/(content)/[[...slug]]/page.tsx +124 -0
- package/src/templates/next-pagebuilder-cache/app/(content)/layout.tsx +28 -0
- package/src/templates/next-pagebuilder-cache/app/actions/unlock-gated-content.ts +53 -0
- package/src/templates/next-pagebuilder-cache/app/favicon.ico +0 -0
- package/src/templates/next-pagebuilder-cache/app/layout.tsx +83 -0
- package/src/templates/next-pagebuilder-cache/app/robots.ts +13 -0
- package/src/templates/next-pagebuilder-cache/app/sitemap.xml/route.ts +84 -0
- package/src/templates/next-pagebuilder-cache/biome.json +257 -0
- package/src/templates/next-pagebuilder-cache/components/layout/footer/index.tsx +127 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/components/cta-button.tsx +28 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/components/mega-menu-panel.tsx +90 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/components/nav-item-renderer.tsx +98 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/components/nav-leaf-item.tsx +33 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/components/types.ts +7 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/header-client.tsx +110 -0
- package/src/templates/next-pagebuilder-cache/components/layout/header/index.tsx +32 -0
- package/src/templates/next-pagebuilder-cache/components/layout/json-ld/index.tsx +79 -0
- package/src/templates/next-pagebuilder-cache/components/layout/wrapper/index.tsx +33 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/article-content/index.tsx +78 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/article-content/related-post-item.tsx +27 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/content-card.tsx +66 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/content-filters.tsx +76 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/content-grid.tsx +40 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/content-pagination-nav.tsx +71 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/index.tsx +306 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/skeleton.tsx +41 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/content-collection/types.ts +32 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/description.tsx +17 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/gated-content/index.tsx +169 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/hero.tsx +17 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/components/rich-text-block.tsx +16 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/renderer.tsx +71 -0
- package/src/templates/next-pagebuilder-cache/components/page-builder/types.ts +25 -0
- package/src/templates/next-pagebuilder-cache/components/page-document/index.tsx +147 -0
- package/src/templates/next-pagebuilder-cache/components/ui/image/index.tsx +216 -0
- package/src/templates/next-pagebuilder-cache/components/ui/link/index.tsx +152 -0
- package/src/templates/next-pagebuilder-cache/components.json +24 -0
- package/src/templates/next-pagebuilder-cache/knip.json +35 -0
- package/src/templates/next-pagebuilder-cache/lefthook.yml +25 -0
- package/src/templates/next-pagebuilder-cache/lib/integrations/sanity/sanity.types.ts +1588 -0
- package/src/templates/next-pagebuilder-cache/lib/scripts/setup-ci-secrets.ts +117 -0
- package/src/templates/next-pagebuilder-cache/lib/styles/cn.ts +5 -0
- package/src/templates/next-pagebuilder-cache/lib/styles/global.css +69 -0
- package/src/templates/next-pagebuilder-cache/lib/utils/base-url.ts +17 -0
- package/src/templates/next-pagebuilder-cache/lib/utils/format-date.ts +8 -0
- package/src/templates/next-pagebuilder-cache/lib/utils/slug-tag.ts +6 -0
- package/src/templates/next-pagebuilder-cache/next.config.ts +176 -0
- package/src/templates/next-pagebuilder-cache/package.json +62 -0
- package/src/templates/next-pagebuilder-cache/postcss.config.mjs +65 -0
- package/src/templates/next-pagebuilder-cache/svg.d.ts +6 -0
- package/src/templates/next-pagebuilder-cache/tsconfig.json +38 -0
- package/src/templates/next-webgl/.env.example +4 -2
- package/src/templates/next-webgl/.github/workflows/ci.yml +1 -1
- package/src/templates/next-webgl/.vscode/settings.json +0 -2
- package/src/templates/next-webgl/app/robots.ts +2 -3
- package/src/templates/next-webgl/components/ui/image/index.tsx +2 -4
- package/src/templates/next-webgl/knip.json +1 -1
- package/src/templates/next-webgl/lefthook.yml +1 -1
- package/src/templates/next-webgl/lib/utils/README.md +18 -5
- package/src/templates/next-webgl/lib/utils/image-sizes.ts +72 -0
- package/src/templates/next-webgl/lib/utils/merge-refs.ts +56 -0
- package/src/templates/next-webgl/lib/utils/strings.ts +1 -51
- package/src/templates/next-webgl/next.config.ts +38 -5
- package/src/templates/next-webgl/package.json +11 -14
- package/src/templates/next-experiments/tsconfig.tsbuildinfo +0 -1
- package/src/templates/next-pagebuilder/app/actions/refresh.ts +0 -5
- package/src/templates/next-webgl/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { cacheLife, cacheTag } from "next/cache";
|
|
2
|
+
import { ALL_BLOG_ARTICLES_QUERY } from "@/lib/integrations/sanity/queries";
|
|
3
|
+
import type { ALL_BLOG_ARTICLES_QUERY_RESULT } from "@/lib/integrations/sanity/sanity.types";
|
|
4
|
+
import { FEED_TAG } from "@/lib/integrations/sanity/tags";
|
|
5
|
+
import { generateRssFeed, rssErrorResponse } from "@/lib/utils/rss";
|
|
6
|
+
import { getPageUrl, getSitemapBaseUrl } from "@/lib/utils/sitemap";
|
|
7
|
+
|
|
8
|
+
// Cached and tagged rather than read per request: feed readers poll.
|
|
9
|
+
const getArticles = async () => {
|
|
10
|
+
"use cache";
|
|
11
|
+
const sanityModule = await import("@/lib/integrations/sanity/client");
|
|
12
|
+
const client = sanityModule?.client;
|
|
13
|
+
|
|
14
|
+
if (!client) return null;
|
|
15
|
+
|
|
16
|
+
// Explicit generic: next-sanity 13.3 doesn't infer it for a dynamic import.
|
|
17
|
+
const articles = await client
|
|
18
|
+
.fetch<ALL_BLOG_ARTICLES_QUERY_RESULT>(ALL_BLOG_ARTICLES_QUERY)
|
|
19
|
+
.catch((error) => {
|
|
20
|
+
console.error("Error fetching articles for the feed:", error);
|
|
21
|
+
return null;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (articles) {
|
|
25
|
+
cacheTag(FEED_TAG);
|
|
26
|
+
} else {
|
|
27
|
+
// No publish clears a failed read, and this prerenders — otherwise a build-time
|
|
28
|
+
// outage would serve an error feed for the full ~1y cacheLife.
|
|
29
|
+
cacheLife("hours");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return articles;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// No `Cache-Control`: a CDN copy is a second cache the webhook can't purge.
|
|
36
|
+
export async function GET() {
|
|
37
|
+
const baseUrl = getSitemapBaseUrl();
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const articles = await getArticles();
|
|
41
|
+
if (!articles) return rssErrorResponse();
|
|
42
|
+
|
|
43
|
+
const items = articles
|
|
44
|
+
.filter((article) => article.resolvedSlug && !article.noIndex)
|
|
45
|
+
.map((article) => ({
|
|
46
|
+
title: article.title ?? "Untitled",
|
|
47
|
+
link: getPageUrl(baseUrl, article.resolvedSlug),
|
|
48
|
+
description: article.metadata?.metaDescription ?? undefined,
|
|
49
|
+
pubDate: article.blogContent?.date ?? undefined,
|
|
50
|
+
authors: article.blogContent?.author?.name
|
|
51
|
+
? [article.blogContent.author.name]
|
|
52
|
+
: undefined,
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
return generateRssFeed({
|
|
56
|
+
title: `${new URL(baseUrl).hostname} Blog`,
|
|
57
|
+
link: `${baseUrl}/blog`,
|
|
58
|
+
description: "Latest articles",
|
|
59
|
+
feedUrl: `${baseUrl}/feed.xml`,
|
|
60
|
+
items,
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error("Error generating RSS feed:", error);
|
|
64
|
+
return rssErrorResponse();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { isSanityConfigured } from "@/lib/integrations/check-integration";
|
|
3
|
+
import type { PAGE_SITEMAP_QUERY_RESULT } from "@/lib/integrations/sanity/sanity.types";
|
|
4
|
+
import {
|
|
5
|
+
getMarkdownPath,
|
|
6
|
+
getSitemap,
|
|
7
|
+
getSitemapBaseUrl,
|
|
8
|
+
} from "@/lib/utils/sitemap";
|
|
9
|
+
|
|
10
|
+
type PageDoc = PAGE_SITEMAP_QUERY_RESULT[number];
|
|
11
|
+
|
|
12
|
+
const ROOT_GROUP = "__root__";
|
|
13
|
+
|
|
14
|
+
const getFolderGroup = (slug: string | null) => {
|
|
15
|
+
if (!slug) return ROOT_GROUP;
|
|
16
|
+
|
|
17
|
+
const segments = slug.split("/").filter(Boolean);
|
|
18
|
+
|
|
19
|
+
if (segments.length <= 1) return ROOT_GROUP;
|
|
20
|
+
|
|
21
|
+
return segments.slice(0, -1).join("/");
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const getGroupHeading = (group: string) => {
|
|
25
|
+
if (group === ROOT_GROUP) return "### Root Pages";
|
|
26
|
+
|
|
27
|
+
return `### /${group}`;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const sortPages = (left: PageDoc, right: PageDoc) => {
|
|
31
|
+
const leftLabel = left.title || left.slug || "Homepage";
|
|
32
|
+
const rightLabel = right.title || right.slug || "Homepage";
|
|
33
|
+
|
|
34
|
+
return leftLabel.localeCompare(rightLabel);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Cached, not per-request: this bills itself as being for AI agents, so its
|
|
38
|
+
// traffic is crawler-driven. `getSitemap` tags the read; the webhook busts it.
|
|
39
|
+
export const GET = async () => {
|
|
40
|
+
const baseUrl = getSitemapBaseUrl();
|
|
41
|
+
|
|
42
|
+
if (!isSanityConfigured()) {
|
|
43
|
+
return new NextResponse(
|
|
44
|
+
[
|
|
45
|
+
"# Sitemap",
|
|
46
|
+
"",
|
|
47
|
+
"## Pages",
|
|
48
|
+
"",
|
|
49
|
+
`- [Homepage](${baseUrl}/index.md)`,
|
|
50
|
+
"",
|
|
51
|
+
"CMS not configured. No additional content available.",
|
|
52
|
+
].join("\n"),
|
|
53
|
+
{
|
|
54
|
+
headers: { "Content-Type": "text/markdown; charset=utf-8" },
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const allPages = await getSitemap();
|
|
61
|
+
|
|
62
|
+
if (!allPages) {
|
|
63
|
+
return new NextResponse("# Sitemap\n\nUnable to connect to CMS.", {
|
|
64
|
+
status: 503,
|
|
65
|
+
headers: { "Content-Type": "text/markdown; charset=utf-8" },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const pages = (allPages ?? []).filter((page) => !page.noIndex);
|
|
70
|
+
const pageGroups = new Map<string, PageDoc[]>();
|
|
71
|
+
|
|
72
|
+
for (const page of pages) {
|
|
73
|
+
const group = getFolderGroup(page.slug ?? null);
|
|
74
|
+
const groupedPages = pageGroups.get(group) ?? [];
|
|
75
|
+
|
|
76
|
+
groupedPages.push(page);
|
|
77
|
+
pageGroups.set(group, groupedPages);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const sortedGroupNames = [...pageGroups.keys()].sort((left, right) => {
|
|
81
|
+
if (left === ROOT_GROUP) return -1;
|
|
82
|
+
if (right === ROOT_GROUP) return 1;
|
|
83
|
+
|
|
84
|
+
return left.localeCompare(right);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const parts = [
|
|
88
|
+
`# ${new URL(baseUrl).hostname} - Content Sitemap`,
|
|
89
|
+
"",
|
|
90
|
+
"> This sitemap lists all available markdown content for AI agents.",
|
|
91
|
+
"",
|
|
92
|
+
"## Pages",
|
|
93
|
+
"",
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
if (pages.length > 0) {
|
|
97
|
+
for (const groupName of sortedGroupNames) {
|
|
98
|
+
const groupedPages = (pageGroups.get(groupName) ?? []).sort(sortPages);
|
|
99
|
+
|
|
100
|
+
if (groupedPages.length === 0) continue;
|
|
101
|
+
|
|
102
|
+
parts.push(getGroupHeading(groupName), "");
|
|
103
|
+
|
|
104
|
+
for (const page of groupedPages) {
|
|
105
|
+
parts.push(
|
|
106
|
+
`- [${page.title || page.slug || "Homepage"}](${getMarkdownPath(baseUrl, page.slug ?? null)})`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
parts.push("");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (pages.length === 0) parts.push("No content published yet.", "");
|
|
115
|
+
|
|
116
|
+
// No `Cache-Control`: an `s-maxage` would be a second cache the webhook can't
|
|
117
|
+
// purge, so a publish would clear this entry and the CDN would serve the old
|
|
118
|
+
// markdown for another hour regardless.
|
|
119
|
+
return new NextResponse(parts.join("\n"), {
|
|
120
|
+
headers: {
|
|
121
|
+
"Content-Type": "text/markdown; charset=utf-8",
|
|
122
|
+
"X-Content-Type-Options": "nosniff",
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error("Error generating sitemap.md:", error);
|
|
127
|
+
return new NextResponse("# Sitemap\n\nError fetching content.", {
|
|
128
|
+
status: 500,
|
|
129
|
+
headers: { "Content-Type": "text/markdown; charset=utf-8" },
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
};
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/studio/[[...tool]]/layout.tsx
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { connection } from "next/server";
|
|
2
|
+
import { type ReactNode, Suspense } from "react";
|
|
3
|
+
|
|
4
|
+
// Re-export next-sanity's static metadata (incl. robots: noindex) — the
|
|
5
|
+
// "use client" Studio page can't export metadata itself.
|
|
6
|
+
export { metadata, viewport } from "next-sanity/studio";
|
|
7
|
+
|
|
8
|
+
// File-based metadata on a catch-all depends on the route param, so the Studio's
|
|
9
|
+
// metadata is dynamic while its body is static — which Cache Components rejects.
|
|
10
|
+
// It's an interactive SPA with no SEO value, so mark it dynamic behind its own
|
|
11
|
+
// boundary and let the rest of the shell prerender.
|
|
12
|
+
async function DynamicMarker() {
|
|
13
|
+
await connection();
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function StudioLayout({ children }: { children: ReactNode }) {
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
{children}
|
|
21
|
+
<Suspense>
|
|
22
|
+
<DynamicMarker />
|
|
23
|
+
</Suspense>
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
}
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/app/studio/[[...tool]]/page.tsx
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { NextStudio } from "next-sanity/studio";
|
|
4
|
+
import { isSanityConfigured } from "@/lib/integrations/check-integration";
|
|
5
|
+
import config from "@/lib/integrations/sanity/sanity.config";
|
|
6
|
+
|
|
7
|
+
// The Studio throws on an empty `projectId`, which `env.ts` falls back to when
|
|
8
|
+
// Sanity isn't configured — so this route would fail `next build`.
|
|
9
|
+
const StudioPage = () =>
|
|
10
|
+
isSanityConfigured() ? (
|
|
11
|
+
<NextStudio config={config} />
|
|
12
|
+
) : (
|
|
13
|
+
<main style={{ padding: "2rem", fontFamily: "system-ui, sans-serif" }}>
|
|
14
|
+
<h1>Studio unavailable</h1>
|
|
15
|
+
<p>
|
|
16
|
+
Set <code>NEXT_PUBLIC_SANITY_PROJECT_ID</code> and{" "}
|
|
17
|
+
<code>NEXT_PUBLIC_SANITY_DATASET</code>, then restart, to load the
|
|
18
|
+
embedded Studio.
|
|
19
|
+
</p>
|
|
20
|
+
</main>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export default StudioPage;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRouter } from "next/navigation";
|
|
4
|
+
import { useTransition } from "react";
|
|
5
|
+
|
|
6
|
+
export function DraftModeToggle() {
|
|
7
|
+
const router = useRouter();
|
|
8
|
+
const [isPending, startTransition] = useTransition();
|
|
9
|
+
|
|
10
|
+
const handleDisable = () => {
|
|
11
|
+
startTransition(async () => {
|
|
12
|
+
await fetch("/api/draft-mode/disable");
|
|
13
|
+
router.refresh();
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<button
|
|
19
|
+
type="button"
|
|
20
|
+
onClick={handleDisable}
|
|
21
|
+
disabled={isPending}
|
|
22
|
+
className="fixed bottom-4 left-1/2 z-50 -translate-x-1/2 rounded-full border border-white/10 bg-black/80 px-2 py-1 font-medium text-sm text-white shadow-lg backdrop-blur-sm transition-colors hover:bg-black/90 disabled:opacity-50"
|
|
23
|
+
>
|
|
24
|
+
{isPending ? "Disabling..." : "Disable Draft Mode"}
|
|
25
|
+
</button>
|
|
26
|
+
);
|
|
27
|
+
}
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/rich-text.tsx
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { PortableText, type PortableTextProps } from "@portabletext/react";
|
|
2
|
+
import { Link } from "@/components/ui/link";
|
|
3
|
+
import { SanityImage } from "@/components/ui/sanity-image";
|
|
4
|
+
import {
|
|
5
|
+
getLinkAttributes,
|
|
6
|
+
urlForReference,
|
|
7
|
+
} from "../../lib/integrations/sanity/utils/link";
|
|
8
|
+
|
|
9
|
+
interface RichTextProps {
|
|
10
|
+
content: PortableTextProps["value"];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type LinkMarkProps = {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
value?: unknown;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const LinkMark = ({ children, value }: LinkMarkProps) => {
|
|
19
|
+
const href = urlForReference(value as Parameters<typeof urlForReference>[0]);
|
|
20
|
+
const attrs = getLinkAttributes(
|
|
21
|
+
value as Parameters<typeof getLinkAttributes>[0],
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Link
|
|
26
|
+
href={href}
|
|
27
|
+
target={attrs.target}
|
|
28
|
+
rel={attrs.rel}
|
|
29
|
+
className="text-blue underline underline-offset-2 transition-opacity hover:opacity-70"
|
|
30
|
+
data-sanity-edit-target
|
|
31
|
+
>
|
|
32
|
+
{children}
|
|
33
|
+
</Link>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const RichText = ({ content }: RichTextProps) => {
|
|
38
|
+
if (!content) return null;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<PortableText
|
|
42
|
+
value={content}
|
|
43
|
+
components={{
|
|
44
|
+
types: {
|
|
45
|
+
image: ({ value }) => <SanityImage image={value} maxWidth={1920} />,
|
|
46
|
+
table: ({ value }) => {
|
|
47
|
+
const rows = value?.rows as
|
|
48
|
+
| Array<{ _key?: string; cells?: string[] }>
|
|
49
|
+
| undefined;
|
|
50
|
+
if (!rows?.length) return null;
|
|
51
|
+
return (
|
|
52
|
+
<table>
|
|
53
|
+
<tbody>
|
|
54
|
+
{rows.map((row, i) => (
|
|
55
|
+
<tr key={row._key ?? `row-${i}`}>
|
|
56
|
+
{row.cells?.map((cell) => {
|
|
57
|
+
const cellKey = `${row._key}-${cell}`;
|
|
58
|
+
return i === 0 ? (
|
|
59
|
+
<th key={cellKey}>{cell}</th>
|
|
60
|
+
) : (
|
|
61
|
+
<td key={cellKey}>{cell}</td>
|
|
62
|
+
);
|
|
63
|
+
})}
|
|
64
|
+
</tr>
|
|
65
|
+
))}
|
|
66
|
+
</tbody>
|
|
67
|
+
</table>
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
marks: {
|
|
72
|
+
link: LinkMark,
|
|
73
|
+
pageReference: LinkMark,
|
|
74
|
+
externalLink: LinkMark,
|
|
75
|
+
},
|
|
76
|
+
block: {
|
|
77
|
+
h1: ({ children }) => <h1 className="h1">{children}</h1>,
|
|
78
|
+
h2: ({ children }) => <h2 className="h2">{children}</h2>,
|
|
79
|
+
h3: ({ children }) => <h3 className="h3">{children}</h3>,
|
|
80
|
+
h4: ({ children }) => <h4 className="h4">{children}</h4>,
|
|
81
|
+
h5: ({ children }) => <h5 className="h5">{children}</h5>,
|
|
82
|
+
h6: ({ children }) => <h6 className="h6">{children}</h6>,
|
|
83
|
+
normal: ({ children }) => <p className="p">{children}</p>,
|
|
84
|
+
},
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
};
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/visual-editing.tsx
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { VisualEditing } from "next-sanity/visual-editing";
|
|
2
|
+
import { DraftModeToggle } from "@/components/sanity/draft-mode-toggle";
|
|
3
|
+
|
|
4
|
+
// Rendered by the content layout only when draft mode is enabled. <SanityLive>
|
|
5
|
+
// lives in the layout so there is exactly one of each across the tree.
|
|
6
|
+
export const SanityVisualEditing = () => (
|
|
7
|
+
<>
|
|
8
|
+
<DraftModeToggle />
|
|
9
|
+
<VisualEditing />
|
|
10
|
+
</>
|
|
11
|
+
);
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/ui/sanity-image/index.tsx
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getImageDimensions } from "@sanity/asset-utils";
|
|
2
|
+
import { Image, type ImageProps } from "@/components/ui/image";
|
|
3
|
+
import { urlForImage } from "@/lib/integrations/sanity/utils/image";
|
|
4
|
+
|
|
5
|
+
interface SanityImageProps extends Omit<ImageProps, "src" | "aspectRatio"> {
|
|
6
|
+
image: {
|
|
7
|
+
asset?: {
|
|
8
|
+
_ref: string;
|
|
9
|
+
_type: "reference";
|
|
10
|
+
};
|
|
11
|
+
alt?: string;
|
|
12
|
+
hotspot?: object;
|
|
13
|
+
crop?: { left?: number; right?: number; top?: number; bottom?: number };
|
|
14
|
+
};
|
|
15
|
+
maxWidth?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function SanityImage({
|
|
19
|
+
image,
|
|
20
|
+
maxWidth = 1920,
|
|
21
|
+
alt,
|
|
22
|
+
fill,
|
|
23
|
+
...props
|
|
24
|
+
}: SanityImageProps) {
|
|
25
|
+
if (!image?.asset) return null;
|
|
26
|
+
|
|
27
|
+
// getImageDimensions is uncropped; the URL builder applies the crop.
|
|
28
|
+
// Rounding order must match @sanity/image-url: origin first, then subtract.
|
|
29
|
+
const { width, height } = getImageDimensions(image.asset);
|
|
30
|
+
const { left = 0, right = 0, top = 0, bottom = 0 } = image.crop ?? {};
|
|
31
|
+
const cropLeft = Math.round(left * width);
|
|
32
|
+
const cropTop = Math.round(top * height);
|
|
33
|
+
const sourceWidth = Math.round(width - right * width - cropLeft);
|
|
34
|
+
const sourceHeight = Math.round(height - bottom * height - cropTop);
|
|
35
|
+
|
|
36
|
+
const imageProps = fill
|
|
37
|
+
? { fill: true }
|
|
38
|
+
: { width: sourceWidth, height: sourceHeight };
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Image
|
|
42
|
+
src={urlForImage(image)
|
|
43
|
+
.width(Math.min(maxWidth, sourceWidth))
|
|
44
|
+
.url()}
|
|
45
|
+
alt={alt || image.alt || ""}
|
|
46
|
+
aspectRatio={sourceWidth / sourceHeight}
|
|
47
|
+
{...imageProps}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { dataset, projectId } from "@/lib/integrations/sanity/env";
|
|
2
|
+
|
|
3
|
+
// Derived from env.ts, not a second read of `process.env`. Read directly these
|
|
4
|
+
// disagreed — env.ts also accepts `SANITY_STUDIO_PROJECT_ID` and defaults the
|
|
5
|
+
// dataset — so a resolvable project reported itself unconfigured.
|
|
6
|
+
export const isSanityConfigured = () => Boolean(projectId && dataset);
|
package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/client.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createClient, type SanityClient } from "next-sanity";
|
|
2
|
+
import { isSanityConfigured } from "@/lib/integrations/check-integration";
|
|
3
|
+
import { apiVersion, dataset, projectId, sanityToken, studioUrl } from "./env";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sanity client instance
|
|
7
|
+
*
|
|
8
|
+
* Returns null if Sanity is not configured (missing env vars).
|
|
9
|
+
* Always check with isSanityConfigured() before using.
|
|
10
|
+
*/
|
|
11
|
+
export const client: SanityClient | null = isSanityConfigured()
|
|
12
|
+
? createClient({
|
|
13
|
+
projectId,
|
|
14
|
+
dataset,
|
|
15
|
+
apiVersion,
|
|
16
|
+
useCdn: true,
|
|
17
|
+
perspective: "published",
|
|
18
|
+
token: sanityToken,
|
|
19
|
+
stega: {
|
|
20
|
+
studioUrl,
|
|
21
|
+
filter: (props) => {
|
|
22
|
+
if (props.sourcePath.at(-1) === "title") return true;
|
|
23
|
+
return props.filterDefault(props);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
: null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Non-CDN clone for the publish webhook, and only for it: a CDN hit would return
|
|
31
|
+
* the pre-mutation slug, so it would invalidate the old path and miss the new one.
|
|
32
|
+
*
|
|
33
|
+
* Elsewhere outside a `'use cache'` scope, use plain `client.fetch` — bypassing
|
|
34
|
+
* the CDN costs uncached-API quota for no freshness anyone needs.
|
|
35
|
+
*/
|
|
36
|
+
export const directClient: SanityClient | null =
|
|
37
|
+
client?.withConfig({ useCdn: false }) ?? null;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { EyeClosedIcon, EyeOpenIcon } from "@sanity/icons";
|
|
2
|
+
import { Badge, Box, Button, Flex, Text, Tooltip, useToast } from "@sanity/ui";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { type ObjectItemProps, useClient, useFormValue } from "sanity";
|
|
5
|
+
import { apiVersion } from "@/lib/integrations/sanity/env";
|
|
6
|
+
|
|
7
|
+
const HIDDEN_KEYS_FIELD = "hiddenPageBuilderKeys";
|
|
8
|
+
|
|
9
|
+
type ReferenceItem = { _key: string; _ref: string; _type: string };
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Eye-icon toggle for a page builder placement's per-page visibility. Adds the
|
|
13
|
+
* placement's `_key` to the owning document's `hiddenPageBuilderKeys`; GROQ
|
|
14
|
+
* filters those keys out at query time. Standalone control because Sanity's
|
|
15
|
+
* built-in item menu isn't extensible via public props.
|
|
16
|
+
*/
|
|
17
|
+
export function BlockActionsItem(props: ObjectItemProps<ReferenceItem>) {
|
|
18
|
+
const { value, renderDefault } = props;
|
|
19
|
+
const client = useClient({ apiVersion });
|
|
20
|
+
const toast = useToast();
|
|
21
|
+
const [busy, setBusy] = useState(false);
|
|
22
|
+
|
|
23
|
+
// Open document id (draft while editing).
|
|
24
|
+
const documentId = useFormValue(["_id"]) as string | undefined;
|
|
25
|
+
const hiddenKeys =
|
|
26
|
+
(useFormValue([HIDDEN_KEYS_FIELD]) as string[] | undefined) ?? [];
|
|
27
|
+
const itemKey = value._key;
|
|
28
|
+
const hidden = hiddenKeys.includes(itemKey);
|
|
29
|
+
const label = hidden ? "Show on this page" : "Hide on this page";
|
|
30
|
+
|
|
31
|
+
async function handleToggleHidden() {
|
|
32
|
+
if (busy || !documentId) return;
|
|
33
|
+
setBusy(true);
|
|
34
|
+
try {
|
|
35
|
+
// Atomic array ops (not read-modify-write) so concurrent toggles
|
|
36
|
+
// of different blocks don't clobber each other.
|
|
37
|
+
const patch = client.patch(documentId);
|
|
38
|
+
if (hidden) {
|
|
39
|
+
patch.unset([`${HIDDEN_KEYS_FIELD}[@ == "${itemKey}"]`]);
|
|
40
|
+
} else {
|
|
41
|
+
patch
|
|
42
|
+
.setIfMissing({ [HIDDEN_KEYS_FIELD]: [] })
|
|
43
|
+
.insert("after", `${HIDDEN_KEYS_FIELD}[-1]`, [itemKey]);
|
|
44
|
+
}
|
|
45
|
+
await patch.commit();
|
|
46
|
+
toast.push({
|
|
47
|
+
status: "success",
|
|
48
|
+
title: hidden ? "Block shown" : "Block hidden",
|
|
49
|
+
});
|
|
50
|
+
} catch {
|
|
51
|
+
toast.push({ status: "error", title: "Failed to update visibility" });
|
|
52
|
+
} finally {
|
|
53
|
+
setBusy(false);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Flex align="center" gap={1} paddingLeft={1}>
|
|
59
|
+
<Tooltip content={<Text size={1}>{label}</Text>} placement="top" portal>
|
|
60
|
+
<Button
|
|
61
|
+
mode="bleed"
|
|
62
|
+
// Open eye = visible, closed eye = hidden.
|
|
63
|
+
icon={hidden ? EyeClosedIcon : EyeOpenIcon}
|
|
64
|
+
tone={hidden ? "caution" : "default"}
|
|
65
|
+
aria-label={label}
|
|
66
|
+
// Unsaved doc has no id to patch — disable, don't no-op.
|
|
67
|
+
disabled={busy || !documentId}
|
|
68
|
+
onClick={handleToggleHidden}
|
|
69
|
+
/>
|
|
70
|
+
</Tooltip>
|
|
71
|
+
{hidden && (
|
|
72
|
+
<Badge fontSize={0} mode="outline" tone="caution">
|
|
73
|
+
Hidden
|
|
74
|
+
</Badge>
|
|
75
|
+
)}
|
|
76
|
+
<Box flex={1} style={hidden ? { opacity: 0.5 } : undefined}>
|
|
77
|
+
{renderDefault(props)}
|
|
78
|
+
</Box>
|
|
79
|
+
</Flex>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { usePathname } from "next/navigation";
|
|
5
|
+
import { useIsPresentationTool } from "next-sanity/hooks";
|
|
6
|
+
|
|
7
|
+
export function DisableDraftMode() {
|
|
8
|
+
const isPresentationTool = useIsPresentationTool();
|
|
9
|
+
const pathname = usePathname();
|
|
10
|
+
|
|
11
|
+
if (isPresentationTool) return null;
|
|
12
|
+
if (pathname.startsWith("/studio")) return null;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Link
|
|
16
|
+
href="/api/draft-mode/disable"
|
|
17
|
+
scroll={false}
|
|
18
|
+
className="dr-p-4 fixed top-safe right-safe z-50 bg-red font-mono text-primary text-sm uppercase"
|
|
19
|
+
>
|
|
20
|
+
Disable Draft Mode
|
|
21
|
+
</Link>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ArrayOfObjectsInputProps, useFormValue } from "sanity";
|
|
2
|
+
import {
|
|
3
|
+
getVisiblePageBuilderInsertMenuGroups,
|
|
4
|
+
getVisiblePageBuilderReferenceMembers,
|
|
5
|
+
type PageBuilderGroupName,
|
|
6
|
+
} from "@/lib/integrations/sanity/page-builder-config";
|
|
7
|
+
|
|
8
|
+
export function PageBuilderInput(props: ArrayOfObjectsInputProps) {
|
|
9
|
+
const pageTypeValue = useFormValue(["type"]);
|
|
10
|
+
const pageType =
|
|
11
|
+
typeof pageTypeValue === "string"
|
|
12
|
+
? (pageTypeValue as PageBuilderGroupName)
|
|
13
|
+
: undefined;
|
|
14
|
+
|
|
15
|
+
const visibleMemberNames = new Set(
|
|
16
|
+
getVisiblePageBuilderReferenceMembers(pageType).map(
|
|
17
|
+
(member) => member.name,
|
|
18
|
+
),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return props.renderDefault({
|
|
22
|
+
...props,
|
|
23
|
+
schemaType: {
|
|
24
|
+
...props.schemaType,
|
|
25
|
+
of: props.schemaType.of.filter(
|
|
26
|
+
(member) =>
|
|
27
|
+
typeof member.name === "string" &&
|
|
28
|
+
visibleMemberNames.has(member.name),
|
|
29
|
+
),
|
|
30
|
+
options: {
|
|
31
|
+
...props.schemaType.options,
|
|
32
|
+
insertMenu: {
|
|
33
|
+
...props.schemaType.options?.insertMenu,
|
|
34
|
+
groups: getVisiblePageBuilderInsertMenuGroups(pageType),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Select } from "@sanity/ui";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { type StringInputProps, set, setIfMissing } from "sanity";
|
|
4
|
+
|
|
5
|
+
type PageCategoryOption = {
|
|
6
|
+
title: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const isPageCategoryOption = (option: unknown): option is PageCategoryOption =>
|
|
11
|
+
typeof option === "object" &&
|
|
12
|
+
option !== null &&
|
|
13
|
+
"title" in option &&
|
|
14
|
+
"value" in option &&
|
|
15
|
+
typeof option.title === "string" &&
|
|
16
|
+
typeof option.value === "string";
|
|
17
|
+
|
|
18
|
+
export function PageCategoryInput(props: StringInputProps) {
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (props.value === undefined) {
|
|
21
|
+
props.onChange(setIfMissing("generic"));
|
|
22
|
+
}
|
|
23
|
+
}, [props.onChange, props.value]);
|
|
24
|
+
|
|
25
|
+
const options = Array.isArray(props.schemaType.options?.list)
|
|
26
|
+
? props.schemaType.options.list.filter(isPageCategoryOption)
|
|
27
|
+
: [];
|
|
28
|
+
|
|
29
|
+
if (options.length === 0) {
|
|
30
|
+
return props.renderDefault({ ...props, value: props.value ?? "generic" });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Select
|
|
35
|
+
{...props.elementProps}
|
|
36
|
+
disabled={props.readOnly}
|
|
37
|
+
onChange={(event) => props.onChange(set(event.currentTarget.value))}
|
|
38
|
+
value={props.value ?? "generic"}
|
|
39
|
+
{...(props.validationError
|
|
40
|
+
? { customValidity: props.validationError }
|
|
41
|
+
: {})}
|
|
42
|
+
>
|
|
43
|
+
{options.map((option) => (
|
|
44
|
+
<option key={option.value} value={option.value}>
|
|
45
|
+
{option.title}
|
|
46
|
+
</option>
|
|
47
|
+
))}
|
|
48
|
+
</Select>
|
|
49
|
+
);
|
|
50
|
+
}
|