create-nextblock 0.14.1 → 0.14.4
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/docker-template/.dockerignore +23 -23
- package/docker-template/.env.docker.example +69 -69
- package/docker-template/docker/db/init/99-jwt.sql +6 -6
- package/docker-template/docker/db/init/99-roles.sql +25 -25
- package/docker-template/docker/kong/kong.yml +112 -112
- package/docker-template/scripts/docker-setup.mjs +310 -310
- package/libs/db/tsconfig.lib.json +3 -3
- package/libs/editor/tsconfig.lib.json +3 -3
- package/libs/ui/tsconfig.lib.json +3 -3
- package/libs/utils/tsconfig.json +3 -3
- package/package.json +1 -1
- package/project.json +19 -19
- package/templates/nextblock-template/.browserslistrc +11 -11
- package/templates/nextblock-template/.dockerignore +23 -23
- package/templates/nextblock-template/README.md +34 -34
- package/templates/nextblock-template/app/(auth-pages)/layout.tsx +9 -9
- package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -27
- package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +46 -46
- package/templates/nextblock-template/app/(auth-pages)/two-factor/page.tsx +51 -51
- package/templates/nextblock-template/app/ToasterProvider.tsx +17 -17
- package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -7
- package/templates/nextblock-template/app/actions/consent.ts +57 -57
- package/templates/nextblock-template/app/actions/postActions.ts +146 -146
- package/templates/nextblock-template/app/actions/twoFactorEmail.ts +22 -22
- package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +153 -153
- package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +96 -96
- package/templates/nextblock-template/app/api/brand/email-logo/route.ts +48 -48
- package/templates/nextblock-template/app/api/cms/check-updates/route.ts +44 -44
- package/templates/nextblock-template/app/api/cms/full-backup/export/route.ts +33 -33
- package/templates/nextblock-template/app/api/cms/full-backup/restore/route.ts +63 -63
- package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +3490 -3490
- package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +5881 -5623
- package/templates/nextblock-template/app/api/cron/sync-currencies/route.ts +39 -39
- package/templates/nextblock-template/app/api/custom-blocks/db-relations/route.ts +92 -92
- package/templates/nextblock-template/app/api/custom-blocks/editor-definitions/route.ts +43 -43
- package/templates/nextblock-template/app/api/media/library/route.ts +69 -69
- package/templates/nextblock-template/app/api/media/r2-presigned/route.ts +53 -53
- package/templates/nextblock-template/app/api/media/record/route.ts +160 -160
- package/templates/nextblock-template/app/api/search/route.ts +43 -43
- package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +441 -441
- package/templates/nextblock-template/app/auth/callback/route.ts +31 -31
- package/templates/nextblock-template/app/cart/page.tsx +7 -7
- package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +2 -2
- package/templates/nextblock-template/app/cms/blocks/components/ColumnEditor.tsx +17 -22
- package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -160
- package/templates/nextblock-template/app/cms/blocks/components/EditableBlock.tsx +13 -19
- package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -149
- package/templates/nextblock-template/app/cms/blocks/editors/DynamicCustomBlockEditor.tsx +167 -167
- package/templates/nextblock-template/app/cms/blocks/editors/HeadingBlockEditor.tsx +45 -34
- package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +4 -2
- package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +90 -90
- package/templates/nextblock-template/app/cms/components/ConnectGitHubButton.tsx +122 -122
- package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -58
- package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +36 -36
- package/templates/nextblock-template/app/cms/components/SystemAlertsBanner.tsx +112 -112
- package/templates/nextblock-template/app/cms/components/TwoFactorReminderBanner.tsx +45 -45
- package/templates/nextblock-template/app/cms/components/github-connect-actions.ts +102 -102
- package/templates/nextblock-template/app/cms/components/system-alerts-actions.ts +31 -31
- package/templates/nextblock-template/app/cms/custom-blocks/[id]/edit/page.tsx +66 -66
- package/templates/nextblock-template/app/cms/custom-blocks/actions.ts +519 -519
- package/templates/nextblock-template/app/cms/custom-blocks/components/BlocksLibraryTransferControls.tsx +256 -256
- package/templates/nextblock-template/app/cms/custom-blocks/components/DBRelationSelect.tsx +384 -384
- package/templates/nextblock-template/app/cms/custom-blocks/components/ImageR2Picker.tsx +221 -221
- package/templates/nextblock-template/app/cms/custom-blocks/new/page.tsx +12 -12
- package/templates/nextblock-template/app/cms/custom-blocks/page.tsx +438 -438
- package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -228
- package/templates/nextblock-template/app/cms/dashboard/components/DashboardOnboarding.tsx +130 -130
- package/templates/nextblock-template/app/cms/import-export/actions.ts +226 -226
- package/templates/nextblock-template/app/cms/layout.tsx +73 -73
- package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -273
- package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -122
- package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +26 -26
- package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -69
- package/templates/nextblock-template/app/cms/navigation/components/NavigationMenuDnd.tsx +3 -3
- package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -12
- package/templates/nextblock-template/app/cms/products/categories/page.tsx +12 -12
- package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -13
- package/templates/nextblock-template/app/cms/products/new/page.tsx +135 -135
- package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -133
- package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -5
- package/templates/nextblock-template/app/cms/promotions/PromotionsWorkspace.tsx +456 -456
- package/templates/nextblock-template/app/cms/promotions/actions.ts +115 -115
- package/templates/nextblock-template/app/cms/promotions/page.tsx +31 -31
- package/templates/nextblock-template/app/cms/revisions/service.ts +19 -19
- package/templates/nextblock-template/app/cms/revisions/utils.ts +132 -132
- package/templates/nextblock-template/app/cms/settings/backup-restore/BackupRestoreWorkspace.tsx +1004 -1004
- package/templates/nextblock-template/app/cms/settings/backup-restore/page.tsx +29 -29
- package/templates/nextblock-template/app/cms/settings/bot-protection/page.tsx +24 -24
- package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +688 -688
- package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -331
- package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -494
- package/templates/nextblock-template/app/cms/settings/email/page.tsx +28 -28
- package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -767
- package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -93
- package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeEditor.tsx +382 -0
- package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeManager.tsx +267 -0
- package/templates/nextblock-template/app/cms/settings/global-css/page.tsx +40 -24
- package/templates/nextblock-template/app/cms/settings/global-css/theme-actions.ts +259 -0
- package/templates/nextblock-template/app/cms/settings/google-analytics/page.tsx +26 -26
- package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
- package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -339
- package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +21 -21
- package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +23 -21
- package/templates/nextblock-template/app/cms/settings/logos/components/SetActiveLogoButton.tsx +42 -42
- package/templates/nextblock-template/app/cms/settings/logos/components/SiteSeoSettingsForm.tsx +133 -133
- package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
- package/templates/nextblock-template/app/cms/settings/packages/package-card.tsx +122 -122
- package/templates/nextblock-template/app/cms/settings/privacy/page.tsx +27 -27
- package/templates/nextblock-template/app/cms/settings/registration/page.tsx +27 -27
- package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +9 -7
- package/templates/nextblock-template/app/cms/settings/security/page.tsx +33 -33
- package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -21
- package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -20
- package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +12 -12
- package/templates/nextblock-template/app/layout.tsx +49 -0
- package/templates/nextblock-template/app/lib/site-settings.ts +105 -105
- package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -16
- package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -9
- package/templates/nextblock-template/app/profile/account-links.ts +22 -22
- package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
- package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
- package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -128
- package/templates/nextblock-template/app/profile/password/actions.ts +59 -59
- package/templates/nextblock-template/app/profile/password/page.tsx +27 -27
- package/templates/nextblock-template/app/providers.tsx +16 -4
- package/templates/nextblock-template/app/setup/SetupWizard.tsx +678 -678
- package/templates/nextblock-template/app/setup/layout.tsx +13 -13
- package/templates/nextblock-template/app/setup/page.tsx +111 -111
- package/templates/nextblock-template/app/sitemap.ts +130 -130
- package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -7
- package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -23
- package/templates/nextblock-template/components/DeferredGoogleAnalytics.tsx +70 -70
- package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -70
- package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -69
- package/templates/nextblock-template/components/FeatureImageHero.tsx +47 -47
- package/templates/nextblock-template/components/FooterNavigation.tsx +32 -32
- package/templates/nextblock-template/components/HtmlScriptExecutor.tsx +47 -47
- package/templates/nextblock-template/components/LanguageSwitcher.tsx +2 -2
- package/templates/nextblock-template/components/PublicEnvBootstrap.tsx +30 -30
- package/templates/nextblock-template/components/ResponsiveNav.tsx +14 -14
- package/templates/nextblock-template/components/auth/AuthBotProtection.tsx +182 -182
- package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -12
- package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -12
- package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -23
- package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +249 -249
- package/templates/nextblock-template/components/blocks/renderers/HeadingBlockRenderer.tsx +7 -10
- package/templates/nextblock-template/components/blocks/types.ts +7 -7
- package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
- package/templates/nextblock-template/components/form-message.tsx +32 -32
- package/templates/nextblock-template/components/media/YouTubeFacade.tsx +105 -105
- package/templates/nextblock-template/components/media/youtube-embed-replace.tsx +32 -32
- package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +170 -170
- package/templates/nextblock-template/components/privacy/ConsentGatedAnalytics.tsx +70 -70
- package/templates/nextblock-template/components/renderers/CachedDynamicLayoutEngine.tsx +28 -28
- package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.test.tsx +166 -166
- package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.tsx +471 -471
- package/templates/nextblock-template/components/submit-button.tsx +23 -23
- package/templates/nextblock-template/components/theme-icon.tsx +78 -0
- package/templates/nextblock-template/components/theme-switcher.tsx +77 -82
- package/templates/nextblock-template/components/visual-editing/DeferredVisualEditing.tsx +21 -21
- package/templates/nextblock-template/context/AuthContext.tsx +23 -23
- package/templates/nextblock-template/context/ThemeCatalogContext.tsx +44 -0
- package/templates/nextblock-template/context/language-rest-client.ts +32 -32
- package/templates/nextblock-template/docker/db/init/99-jwt.sql +6 -6
- package/templates/nextblock-template/docker/db/init/99-roles.sql +25 -25
- package/templates/nextblock-template/docker/kong/kong.yml +112 -112
- package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -94
- package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +364 -364
- package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +279 -202
- package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +246 -246
- package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +176 -176
- package/templates/nextblock-template/docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md +146 -146
- package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +222 -222
- package/templates/nextblock-template/docs/11-SELF-HOSTED-DOCKER.md +173 -173
- package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +170 -170
- package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +151 -151
- package/templates/nextblock-template/docs/README.md +39 -39
- package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -21
- package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -101
- package/templates/nextblock-template/index.d.ts +7 -7
- package/templates/nextblock-template/lib/app-secrets.ts +39 -39
- package/templates/nextblock-template/lib/auth/cookies.ts +47 -47
- package/templates/nextblock-template/lib/auth/crypto.ts +45 -45
- package/templates/nextblock-template/lib/auth/trustedDevices.ts +92 -92
- package/templates/nextblock-template/lib/auth-redirects.ts +46 -46
- package/templates/nextblock-template/lib/blocks/README.md +13 -13
- package/templates/nextblock-template/lib/blocks/blockColors.test.ts +114 -0
- package/templates/nextblock-template/lib/blocks/blockColors.ts +132 -0
- package/templates/nextblock-template/lib/blocks/blockRegistry.ts +17 -1
- package/templates/nextblock-template/lib/botProtection/verify.ts +134 -134
- package/templates/nextblock-template/lib/cms-transfer/server.ts +2243 -2243
- package/templates/nextblock-template/lib/cms-transfer/types.ts +145 -145
- package/templates/nextblock-template/lib/custom-block-definitions.ts +87 -87
- package/templates/nextblock-template/lib/custom-block-r2-upload-shared.ts +178 -178
- package/templates/nextblock-template/lib/custom-block-r2-upload.test.ts +140 -140
- package/templates/nextblock-template/lib/custom-block-r2-upload.ts +88 -88
- package/templates/nextblock-template/lib/custom-block-relations.test.ts +227 -227
- package/templates/nextblock-template/lib/custom-block-relations.ts +279 -279
- package/templates/nextblock-template/lib/custom-block-safelist.ts +14 -14
- package/templates/nextblock-template/lib/editor/dynamic-extension-core.test.ts +172 -172
- package/templates/nextblock-template/lib/editor/dynamic-extension-core.ts +213 -213
- package/templates/nextblock-template/lib/editor/dynamic-extension-loader.ts +22 -22
- package/templates/nextblock-template/lib/editor/dynamic-extensions.tsx +193 -193
- package/templates/nextblock-template/lib/email/branding-format.test.ts +133 -133
- package/templates/nextblock-template/lib/email/branding-format.ts +123 -123
- package/templates/nextblock-template/lib/email/branding.ts +76 -76
- package/templates/nextblock-template/lib/full-backup/manifest.test.ts +121 -121
- package/templates/nextblock-template/lib/full-backup/manifest.ts +206 -206
- package/templates/nextblock-template/lib/full-backup/server.ts +743 -743
- package/templates/nextblock-template/lib/logos/active-logo.ts +53 -53
- package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +54 -54
- package/templates/nextblock-template/lib/media/youtube.ts +99 -99
- package/templates/nextblock-template/lib/onboarding/actions.ts +31 -31
- package/templates/nextblock-template/lib/onboarding/status.ts +222 -222
- package/templates/nextblock-template/lib/posts/readTime.ts +60 -60
- package/templates/nextblock-template/lib/privacy/consent-client.ts +57 -57
- package/templates/nextblock-template/lib/privacy/contact-emails.ts +64 -64
- package/templates/nextblock-template/lib/privacy/settings.ts +115 -115
- package/templates/nextblock-template/lib/privacy/types.ts +69 -69
- package/templates/nextblock-template/lib/promotions/server.test.ts +74 -74
- package/templates/nextblock-template/lib/promotions/server.ts +741 -741
- package/templates/nextblock-template/lib/resolve-block-relations.test.ts +142 -142
- package/templates/nextblock-template/lib/resolve-block-relations.ts +255 -255
- package/templates/nextblock-template/lib/search/types.ts +27 -27
- package/templates/nextblock-template/lib/setup/actions.ts +460 -460
- package/templates/nextblock-template/lib/setup/env-status.ts +125 -125
- package/templates/nextblock-template/lib/setup/env-write.ts +111 -111
- package/templates/nextblock-template/lib/setup/migrations-bundle.ts +15 -10
- package/templates/nextblock-template/lib/setup/provisioning.ts +59 -59
- package/templates/nextblock-template/lib/setup/schema-apply.ts +408 -408
- package/templates/nextblock-template/lib/setup/system-config.ts +105 -105
- package/templates/nextblock-template/lib/setup/types.ts +18 -18
- package/templates/nextblock-template/lib/site-url.ts +48 -48
- package/templates/nextblock-template/lib/storage/provider.ts +66 -66
- package/templates/nextblock-template/lib/storage/supabase-storage.ts +103 -103
- package/templates/nextblock-template/lib/themes/buildThemeCss.test.ts +163 -0
- package/templates/nextblock-template/lib/themes/buildThemeCss.ts +124 -0
- package/templates/nextblock-template/lib/themes/tokenColor.ts +31 -0
- package/templates/nextblock-template/lib/themes/tokens.ts +143 -0
- package/templates/nextblock-template/lib/updates/check-upstream.ts +441 -441
- package/templates/nextblock-template/lib/updates/github-device.ts +206 -206
- package/templates/nextblock-template/lib/updates/repo-identity.ts +56 -56
- package/templates/nextblock-template/next-env.d.ts +2 -2
- package/templates/nextblock-template/package.json +1 -1
- package/templates/nextblock-template/postcss.config.js +6 -6
- package/templates/nextblock-template/scripts/backup.js +115 -115
- package/templates/nextblock-template/scripts/docker-setup.mjs +310 -310
- package/templates/nextblock-template/scripts/restore.js +385 -385
- package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +98 -98
- package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +62 -62
- package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +537 -537
- package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +58 -58
- package/templates/nextblock-template/scripts/verify-custom-block-definitions.ts +188 -188
- package/templates/nextblock-template/scripts/verify-dynamic-custom-block-extensions.ts +123 -123
- package/templates/nextblock-template/scripts/verify-dynamic-layout-engine.tsx +133 -133
- package/templates/nextblock-template/scripts/verify-milestone-2-custom-blocks.ts +65 -65
- package/templates/nextblock-template/scripts/verify-site-themes.ts +63 -0
- package/templates/nextblock-template/tailwind.config.js +25 -25
- package/templates/nextblock-template/tools/build-migrate.mjs +209 -209
- package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -282
- package/templates/nextblock-template/tsconfig.tsbuildinfo +1 -1
- package/templates/nextblock-template/types/jsdom.d.ts +6 -6
- package/tsconfig.base.json +3 -3
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { createClient, getProfileWithRoleServerSide } from "@nextblock-cms/db/server";
|
|
2
|
-
import { NextResponse } from "next/server";
|
|
3
|
-
import { resolvePostAuthRedirect } from "../../../lib/auth-redirects";
|
|
4
|
-
|
|
5
|
-
export async function GET(request: Request) {
|
|
6
|
-
const requestUrl = new URL(request.url);
|
|
7
|
-
const code = requestUrl.searchParams.get("code");
|
|
8
|
-
const origin = requestUrl.origin;
|
|
9
|
-
const initialRedirectTo = requestUrl.searchParams.get("redirect_to")?.toString();
|
|
10
|
-
|
|
11
|
-
if (code) {
|
|
12
|
-
const supabase = await createClient();
|
|
13
|
-
const { data: { user } , error: exchangeError } = await supabase.auth.exchangeCodeForSession(code);
|
|
14
|
-
|
|
15
|
-
if (exchangeError) {
|
|
16
|
-
console.error("Auth callback: Error exchanging code for session:", exchangeError.message);
|
|
17
|
-
return NextResponse.redirect(`${origin}${initialRedirectTo || '/'}`);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (user) {
|
|
21
|
-
const profile = await getProfileWithRoleServerSide(user.id);
|
|
22
|
-
const targetPath = resolvePostAuthRedirect(profile, initialRedirectTo);
|
|
23
|
-
return NextResponse.redirect(`${origin}${targetPath}`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.warn("Auth callback: User object is null after code exchange.");
|
|
27
|
-
return NextResponse.redirect(`${origin}/`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return NextResponse.redirect(`${origin}${initialRedirectTo || '/'}`);
|
|
31
|
-
}
|
|
1
|
+
import { createClient, getProfileWithRoleServerSide } from "@nextblock-cms/db/server";
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
import { resolvePostAuthRedirect } from "../../../lib/auth-redirects";
|
|
4
|
+
|
|
5
|
+
export async function GET(request: Request) {
|
|
6
|
+
const requestUrl = new URL(request.url);
|
|
7
|
+
const code = requestUrl.searchParams.get("code");
|
|
8
|
+
const origin = requestUrl.origin;
|
|
9
|
+
const initialRedirectTo = requestUrl.searchParams.get("redirect_to")?.toString();
|
|
10
|
+
|
|
11
|
+
if (code) {
|
|
12
|
+
const supabase = await createClient();
|
|
13
|
+
const { data: { user } , error: exchangeError } = await supabase.auth.exchangeCodeForSession(code);
|
|
14
|
+
|
|
15
|
+
if (exchangeError) {
|
|
16
|
+
console.error("Auth callback: Error exchanging code for session:", exchangeError.message);
|
|
17
|
+
return NextResponse.redirect(`${origin}${initialRedirectTo || '/'}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (user) {
|
|
21
|
+
const profile = await getProfileWithRoleServerSide(user.id);
|
|
22
|
+
const targetPath = resolvePostAuthRedirect(profile, initialRedirectTo);
|
|
23
|
+
return NextResponse.redirect(`${origin}${targetPath}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.warn("Auth callback: User object is null after code exchange.");
|
|
27
|
+
return NextResponse.redirect(`${origin}/`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return NextResponse.redirect(`${origin}${initialRedirectTo || '/'}`);
|
|
31
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Cart } from '@nextblock-cms/ecommerce';
|
|
4
|
-
|
|
5
|
-
export default function CartPage() {
|
|
6
|
-
return <Cart />;
|
|
7
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Cart } from '@nextblock-cms/ecommerce';
|
|
4
|
+
|
|
5
|
+
export default function CartPage() {
|
|
6
|
+
return <Cart />;
|
|
7
|
+
}
|
|
@@ -228,7 +228,7 @@ export default function CmsClientLayout({
|
|
|
228
228
|
// Fallback for general /cms/settings if no more specific language path matches
|
|
229
229
|
else if (pathname.startsWith("/cms/settings/logos")) pageTitle = "Branding";
|
|
230
230
|
else if (pathname.startsWith("/cms/settings/copyright")) pageTitle = "Copyright Settings";
|
|
231
|
-
else if (pathname.startsWith("/cms/settings/global-css")) pageTitle = "
|
|
231
|
+
else if (pathname.startsWith("/cms/settings/global-css")) pageTitle = "Themes & CSS";
|
|
232
232
|
else if (pathname.startsWith("/cms/settings/extra-translations")) pageTitle = "Extra Translations";
|
|
233
233
|
else if (pathname.startsWith("/cms/settings/backup-restore")) pageTitle = "Backup And Restore";
|
|
234
234
|
else if (pathname.startsWith("/cms/settings/currencies")) pageTitle = "Currency Settings";
|
|
@@ -422,7 +422,7 @@ export default function CmsClientLayout({
|
|
|
422
422
|
Copyright
|
|
423
423
|
</NavItem>
|
|
424
424
|
<NavItem href="/cms/settings/global-css" icon={Paintbrush} isActive={pathname.startsWith("/cms/settings/global-css")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
425
|
-
|
|
425
|
+
Themes & CSS
|
|
426
426
|
</NavItem>
|
|
427
427
|
<NavItem href="/cms/settings/privacy" icon={Cookie} isActive={pathname.startsWith("/cms/settings/privacy")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
428
428
|
Privacy & Consent
|
|
@@ -6,6 +6,7 @@ import { Button } from '@nextblock-cms/ui';
|
|
|
6
6
|
import { PlusCircle, Trash2, Edit2, GripVertical, Image as ImageIcon } from "lucide-react";
|
|
7
7
|
import { SectionBlockContent } from '../../../../lib/blocks/blockRegistry';
|
|
8
8
|
import { availableBlockTypes, blockHasEditableContent, getBlockDefinition, getInitialContent, BlockType } from '../../../../lib/blocks/blockRegistry';
|
|
9
|
+
import { resolveTextAlign, resolveTextColor } from '../../../../lib/blocks/blockColors';
|
|
9
10
|
import { useDroppable } from "@dnd-kit/core";
|
|
10
11
|
import { useSortable } from "@dnd-kit/sortable";
|
|
11
12
|
import { CSS } from "@dnd-kit/utilities";
|
|
@@ -136,9 +137,8 @@ function SortableColumnBlock({ block, index, columnIndex, onEdit, onDelete, bloc
|
|
|
136
137
|
case 'heading': {
|
|
137
138
|
const content = block.content as any;
|
|
138
139
|
const level = content.level || 1;
|
|
139
|
-
const headingAlign = content.textAlign || 'left';
|
|
140
140
|
const textColor = content.textColor || 'foreground';
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
const sizeClasses: Record<number, string> = {
|
|
143
143
|
1: "text-4xl font-extrabold",
|
|
144
144
|
2: "text-3xl font-bold",
|
|
@@ -148,32 +148,27 @@ function SortableColumnBlock({ block, index, columnIndex, onEdit, onDelete, bloc
|
|
|
148
148
|
6: "text-base font-semibold",
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
background: "text-background",
|
|
158
|
-
foreground: "text-foreground"
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// Override for dark background if color is basic
|
|
162
|
-
let appliedColorClass = colorClasses[textColor] || "text-foreground";
|
|
163
|
-
if (isDarkBackground) {
|
|
151
|
+
// Shared with HeadingBlockRenderer so the preview cannot drift.
|
|
152
|
+
const { className: resolvedColorClass, style: colorStyle } = resolveTextColor(textColor);
|
|
153
|
+
let appliedColorClass = resolvedColorClass ?? (colorStyle ? undefined : "text-foreground");
|
|
154
|
+
// A custom colour is literal — only the theme tokens get the dark-surface
|
|
155
|
+
// legibility override, since only they are ambiguous against it.
|
|
156
|
+
if (isDarkBackground && !colorStyle) {
|
|
164
157
|
if (textColor === 'foreground') appliedColorClass = 'text-white/90';
|
|
165
158
|
if (textColor === 'muted') appliedColorClass = 'text-white/70';
|
|
166
159
|
}
|
|
167
160
|
|
|
168
161
|
return (
|
|
169
162
|
<div className="flex gap-3">
|
|
170
|
-
<div
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
163
|
+
<div
|
|
164
|
+
style={colorStyle}
|
|
165
|
+
className={cn(
|
|
166
|
+
"w-full leading-tight",
|
|
167
|
+
sizeClasses[level] || sizeClasses[1],
|
|
168
|
+
appliedColorClass,
|
|
169
|
+
resolveTextAlign(content.textAlign)
|
|
170
|
+
)}
|
|
171
|
+
>
|
|
177
172
|
{content.text_content || <span className={cn("text-muted-foreground font-normal text-sm italic", isDarkBackground && "text-white/50")}>Empty heading</span>}
|
|
178
173
|
</div>
|
|
179
174
|
</div>
|
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { useEffect, useMemo, useState } from "react";
|
|
4
|
-
import { Loader2 } from "lucide-react";
|
|
5
|
-
import { DynamicLayoutEngine } from "../../../../components/renderers/DynamicLayoutEngine";
|
|
6
|
-
|
|
7
|
-
// Module-level cache so every block preview shares a single network request for
|
|
8
|
-
// the custom block definitions instead of re-fetching per card.
|
|
9
|
-
type EditorDefinition = {
|
|
10
|
-
slug: string;
|
|
11
|
-
name: string;
|
|
12
|
-
description?: string | null;
|
|
13
|
-
fields: any[];
|
|
14
|
-
layout_schema: any;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const definitionCache: { definitions: EditorDefinition[]; promise: Promise<EditorDefinition[]> | null } = {
|
|
18
|
-
definitions: [],
|
|
19
|
-
promise: null,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function loadCustomBlockDefinitions(): Promise<EditorDefinition[]> {
|
|
23
|
-
if (definitionCache.definitions.length > 0) {
|
|
24
|
-
return Promise.resolve(definitionCache.definitions);
|
|
25
|
-
}
|
|
26
|
-
if (!definitionCache.promise) {
|
|
27
|
-
definitionCache.promise = fetch("/api/custom-blocks/editor-definitions")
|
|
28
|
-
.then((res) => (res.ok ? res.json() : { definitions: [] }))
|
|
29
|
-
.then((data) => {
|
|
30
|
-
definitionCache.definitions = (data?.definitions ?? []) as EditorDefinition[];
|
|
31
|
-
return definitionCache.definitions;
|
|
32
|
-
})
|
|
33
|
-
.catch(() => []);
|
|
34
|
-
}
|
|
35
|
-
return definitionCache.promise;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function useCustomBlockDefinition(slug: string) {
|
|
39
|
-
const [definitions, setDefinitions] = useState<EditorDefinition[]>(definitionCache.definitions);
|
|
40
|
-
const [loading, setLoading] = useState(definitionCache.definitions.length === 0);
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
let cancelled = false;
|
|
44
|
-
loadCustomBlockDefinitions().then((defs) => {
|
|
45
|
-
if (!cancelled) {
|
|
46
|
-
setDefinitions(defs);
|
|
47
|
-
setLoading(false);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
return () => {
|
|
51
|
-
cancelled = true;
|
|
52
|
-
};
|
|
53
|
-
}, []);
|
|
54
|
-
|
|
55
|
-
const definition = useMemo(
|
|
56
|
-
() => definitions.find((def) => def.slug === slug) ?? null,
|
|
57
|
-
[definitions, slug]
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
return { definition, loading };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Resolve db_relation field values into records so the preview matches the front
|
|
64
|
-
// end (including relation images), mirroring the server-side hydration.
|
|
65
|
-
function useResolvedRelations(definition: EditorDefinition | null, content: Record<string, any>) {
|
|
66
|
-
const [resolvedRelations, setResolvedRelations] = useState<Record<string, any>>({});
|
|
67
|
-
|
|
68
|
-
const relationSignature = useMemo(() => {
|
|
69
|
-
if (!definition) return "";
|
|
70
|
-
return definition.fields
|
|
71
|
-
.filter((field) => field.type === "db_relation")
|
|
72
|
-
.map((field) => `${field.key}:${JSON.stringify(content?.[field.key] ?? null)}`)
|
|
73
|
-
.join("|");
|
|
74
|
-
}, [definition, content]);
|
|
75
|
-
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (!definition) return;
|
|
78
|
-
const relationFields = definition.fields.filter((field) => field.type === "db_relation");
|
|
79
|
-
if (relationFields.length === 0) {
|
|
80
|
-
setResolvedRelations({});
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
let cancelled = false;
|
|
85
|
-
(async () => {
|
|
86
|
-
const next: Record<string, any> = {};
|
|
87
|
-
await Promise.all(
|
|
88
|
-
relationFields.map(async (field) => {
|
|
89
|
-
const raw = content?.[field.key];
|
|
90
|
-
const values = Array.isArray(raw) ? raw : raw ? [raw] : [];
|
|
91
|
-
if (values.length === 0) return;
|
|
92
|
-
|
|
93
|
-
const params = new URLSearchParams({
|
|
94
|
-
table: field.table,
|
|
95
|
-
valueColumn: field.value_column || "id",
|
|
96
|
-
displayColumn: field.display_column || "title",
|
|
97
|
-
values: values.map(String).join(","),
|
|
98
|
-
limit: String(values.length),
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
const res = await fetch(`/api/custom-blocks/db-relations?${params.toString()}`, {
|
|
103
|
-
cache: "no-store",
|
|
104
|
-
});
|
|
105
|
-
if (!res.ok) return;
|
|
106
|
-
const data = await res.json();
|
|
107
|
-
const items = data?.items ?? [];
|
|
108
|
-
next[field.key] = field.multiple ? items : items[0] ?? null;
|
|
109
|
-
} catch {
|
|
110
|
-
// Leave the relation unresolved; the engine falls back gracefully.
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
if (!cancelled) {
|
|
116
|
-
setResolvedRelations(next);
|
|
117
|
-
}
|
|
118
|
-
})();
|
|
119
|
-
|
|
120
|
-
return () => {
|
|
121
|
-
cancelled = true;
|
|
122
|
-
};
|
|
123
|
-
}, [definition, relationSignature]);
|
|
124
|
-
|
|
125
|
-
return resolvedRelations;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export interface CustomBlockEditorPreviewProps {
|
|
129
|
-
blockType: string;
|
|
130
|
-
content: Record<string, any>;
|
|
131
|
-
fallback: React.ReactNode;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function CustomBlockEditorPreview({ blockType, content, fallback }: CustomBlockEditorPreviewProps) {
|
|
135
|
-
const { definition, loading } = useCustomBlockDefinition(blockType);
|
|
136
|
-
const resolvedRelations = useResolvedRelations(definition, content);
|
|
137
|
-
|
|
138
|
-
if (!definition) {
|
|
139
|
-
if (loading) {
|
|
140
|
-
return (
|
|
141
|
-
<div className="flex items-center gap-2 py-3 text-xs text-muted-foreground">
|
|
142
|
-
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
|
143
|
-
Loading block preview…
|
|
144
|
-
</div>
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
return <>{fallback}</>;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
// pointer-events-none lets clicks fall through to the card so editing still opens.
|
|
152
|
-
<div className="pointer-events-none w-full overflow-hidden">
|
|
153
|
-
<DynamicLayoutEngine
|
|
154
|
-
fields={definition.fields}
|
|
155
|
-
layoutSchema={definition.layout_schema}
|
|
156
|
-
data={{ ...(content || {}), resolved_relations: resolvedRelations }}
|
|
157
|
-
/>
|
|
158
|
-
</div>
|
|
159
|
-
);
|
|
160
|
-
}
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { Loader2 } from "lucide-react";
|
|
5
|
+
import { DynamicLayoutEngine } from "../../../../components/renderers/DynamicLayoutEngine";
|
|
6
|
+
|
|
7
|
+
// Module-level cache so every block preview shares a single network request for
|
|
8
|
+
// the custom block definitions instead of re-fetching per card.
|
|
9
|
+
type EditorDefinition = {
|
|
10
|
+
slug: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string | null;
|
|
13
|
+
fields: any[];
|
|
14
|
+
layout_schema: any;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const definitionCache: { definitions: EditorDefinition[]; promise: Promise<EditorDefinition[]> | null } = {
|
|
18
|
+
definitions: [],
|
|
19
|
+
promise: null,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function loadCustomBlockDefinitions(): Promise<EditorDefinition[]> {
|
|
23
|
+
if (definitionCache.definitions.length > 0) {
|
|
24
|
+
return Promise.resolve(definitionCache.definitions);
|
|
25
|
+
}
|
|
26
|
+
if (!definitionCache.promise) {
|
|
27
|
+
definitionCache.promise = fetch("/api/custom-blocks/editor-definitions")
|
|
28
|
+
.then((res) => (res.ok ? res.json() : { definitions: [] }))
|
|
29
|
+
.then((data) => {
|
|
30
|
+
definitionCache.definitions = (data?.definitions ?? []) as EditorDefinition[];
|
|
31
|
+
return definitionCache.definitions;
|
|
32
|
+
})
|
|
33
|
+
.catch(() => []);
|
|
34
|
+
}
|
|
35
|
+
return definitionCache.promise;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function useCustomBlockDefinition(slug: string) {
|
|
39
|
+
const [definitions, setDefinitions] = useState<EditorDefinition[]>(definitionCache.definitions);
|
|
40
|
+
const [loading, setLoading] = useState(definitionCache.definitions.length === 0);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
let cancelled = false;
|
|
44
|
+
loadCustomBlockDefinitions().then((defs) => {
|
|
45
|
+
if (!cancelled) {
|
|
46
|
+
setDefinitions(defs);
|
|
47
|
+
setLoading(false);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return () => {
|
|
51
|
+
cancelled = true;
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const definition = useMemo(
|
|
56
|
+
() => definitions.find((def) => def.slug === slug) ?? null,
|
|
57
|
+
[definitions, slug]
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return { definition, loading };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Resolve db_relation field values into records so the preview matches the front
|
|
64
|
+
// end (including relation images), mirroring the server-side hydration.
|
|
65
|
+
function useResolvedRelations(definition: EditorDefinition | null, content: Record<string, any>) {
|
|
66
|
+
const [resolvedRelations, setResolvedRelations] = useState<Record<string, any>>({});
|
|
67
|
+
|
|
68
|
+
const relationSignature = useMemo(() => {
|
|
69
|
+
if (!definition) return "";
|
|
70
|
+
return definition.fields
|
|
71
|
+
.filter((field) => field.type === "db_relation")
|
|
72
|
+
.map((field) => `${field.key}:${JSON.stringify(content?.[field.key] ?? null)}`)
|
|
73
|
+
.join("|");
|
|
74
|
+
}, [definition, content]);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (!definition) return;
|
|
78
|
+
const relationFields = definition.fields.filter((field) => field.type === "db_relation");
|
|
79
|
+
if (relationFields.length === 0) {
|
|
80
|
+
setResolvedRelations({});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let cancelled = false;
|
|
85
|
+
(async () => {
|
|
86
|
+
const next: Record<string, any> = {};
|
|
87
|
+
await Promise.all(
|
|
88
|
+
relationFields.map(async (field) => {
|
|
89
|
+
const raw = content?.[field.key];
|
|
90
|
+
const values = Array.isArray(raw) ? raw : raw ? [raw] : [];
|
|
91
|
+
if (values.length === 0) return;
|
|
92
|
+
|
|
93
|
+
const params = new URLSearchParams({
|
|
94
|
+
table: field.table,
|
|
95
|
+
valueColumn: field.value_column || "id",
|
|
96
|
+
displayColumn: field.display_column || "title",
|
|
97
|
+
values: values.map(String).join(","),
|
|
98
|
+
limit: String(values.length),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const res = await fetch(`/api/custom-blocks/db-relations?${params.toString()}`, {
|
|
103
|
+
cache: "no-store",
|
|
104
|
+
});
|
|
105
|
+
if (!res.ok) return;
|
|
106
|
+
const data = await res.json();
|
|
107
|
+
const items = data?.items ?? [];
|
|
108
|
+
next[field.key] = field.multiple ? items : items[0] ?? null;
|
|
109
|
+
} catch {
|
|
110
|
+
// Leave the relation unresolved; the engine falls back gracefully.
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (!cancelled) {
|
|
116
|
+
setResolvedRelations(next);
|
|
117
|
+
}
|
|
118
|
+
})();
|
|
119
|
+
|
|
120
|
+
return () => {
|
|
121
|
+
cancelled = true;
|
|
122
|
+
};
|
|
123
|
+
}, [definition, relationSignature]);
|
|
124
|
+
|
|
125
|
+
return resolvedRelations;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface CustomBlockEditorPreviewProps {
|
|
129
|
+
blockType: string;
|
|
130
|
+
content: Record<string, any>;
|
|
131
|
+
fallback: React.ReactNode;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function CustomBlockEditorPreview({ blockType, content, fallback }: CustomBlockEditorPreviewProps) {
|
|
135
|
+
const { definition, loading } = useCustomBlockDefinition(blockType);
|
|
136
|
+
const resolvedRelations = useResolvedRelations(definition, content);
|
|
137
|
+
|
|
138
|
+
if (!definition) {
|
|
139
|
+
if (loading) {
|
|
140
|
+
return (
|
|
141
|
+
<div className="flex items-center gap-2 py-3 text-xs text-muted-foreground">
|
|
142
|
+
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
|
143
|
+
Loading block preview…
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return <>{fallback}</>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
// pointer-events-none lets clicks fall through to the card so editing still opens.
|
|
152
|
+
<div className="pointer-events-none w-full overflow-hidden">
|
|
153
|
+
<DynamicLayoutEngine
|
|
154
|
+
fields={definition.fields}
|
|
155
|
+
layoutSchema={definition.layout_schema}
|
|
156
|
+
data={{ ...(content || {}), resolved_relations: resolvedRelations }}
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
@@ -9,6 +9,7 @@ type Block = Database['public']['Tables']['blocks']['Row'];
|
|
|
9
9
|
import { Button, Card, CardContent, Avatar, AvatarImage, AvatarFallback } from "@nextblock-cms/ui";
|
|
10
10
|
import { GripVertical, Edit2, Image as ImageIcon, MessageSquareQuote } from "lucide-react";
|
|
11
11
|
import { blockHasEditableContent, getBlockDefinition, blockRegistry, BlockType } from '../../../../lib/blocks/blockRegistry';
|
|
12
|
+
import { resolveTextAlign, resolveTextColor } from '../../../../lib/blocks/blockColors';
|
|
12
13
|
import { BlockEditorModal } from './BlockEditorModal';
|
|
13
14
|
import { DeleteBlockButtonClient } from './DeleteBlockButtonClient';
|
|
14
15
|
import { cn } from '@nextblock-cms/utils';
|
|
@@ -161,9 +162,7 @@ export default function EditableBlock({
|
|
|
161
162
|
case 'heading': {
|
|
162
163
|
const content = (block.content || {}) as any;
|
|
163
164
|
const level = content.level || 1;
|
|
164
|
-
|
|
165
|
-
const textColor = content.textColor || 'foreground';
|
|
166
|
-
|
|
165
|
+
|
|
167
166
|
const sizeClasses: Record<number, string> = {
|
|
168
167
|
1: "text-4xl font-extrabold",
|
|
169
168
|
2: "text-3xl font-bold",
|
|
@@ -173,25 +172,20 @@ export default function EditableBlock({
|
|
|
173
172
|
6: "text-base font-semibold",
|
|
174
173
|
};
|
|
175
174
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
secondary: "text-secondary",
|
|
179
|
-
accent: "text-accent",
|
|
180
|
-
destructive: "text-destructive",
|
|
181
|
-
muted: "text-muted-foreground",
|
|
182
|
-
background: "text-background",
|
|
183
|
-
foreground: "text-foreground"
|
|
184
|
-
};
|
|
175
|
+
// Shared with HeadingBlockRenderer so the preview cannot drift.
|
|
176
|
+
const { className: colorClass, style: colorStyle } = resolveTextColor(content.textColor);
|
|
185
177
|
|
|
186
178
|
return (
|
|
187
179
|
<div className="py-2">
|
|
188
|
-
<div
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
180
|
+
<div
|
|
181
|
+
style={colorStyle}
|
|
182
|
+
className={cn(
|
|
183
|
+
"w-full leading-tight",
|
|
184
|
+
sizeClasses[level] || sizeClasses[1],
|
|
185
|
+
colorClass ?? (colorStyle ? undefined : "text-foreground"),
|
|
186
|
+
resolveTextAlign(content.textAlign)
|
|
187
|
+
)}
|
|
188
|
+
>
|
|
195
189
|
{content.text_content || <span className="text-muted-foreground italic text-sm font-normal">Empty heading</span>}
|
|
196
190
|
</div>
|
|
197
191
|
</div>
|