279 lines
9.0 KiB
TypeScript
279 lines
9.0 KiB
TypeScript
import type { CSSProperties } from "react";
|
|
import type { SectionBlockProps } from "@/features/editor/state/editorStore";
|
|
|
|
export interface SectionExportTokens {
|
|
sectionClasses: string;
|
|
sectionStyleParts: string[];
|
|
backgroundVideoHtml: string;
|
|
}
|
|
|
|
export function computeSectionExportTokens(props: SectionBlockProps): SectionExportTokens {
|
|
const bgToken = props.background ?? "default";
|
|
const bgClassMap: Record<SectionBlockProps["background"], string> = {
|
|
default: "pb-section-bg-default",
|
|
muted: "pb-section-bg-muted",
|
|
primary: "pb-section-bg-primary",
|
|
};
|
|
const bgClass = bgClassMap[bgToken] ?? "pb-section-bg-default";
|
|
|
|
const pyToken = props.paddingY ?? "md";
|
|
const pyClassMap: Record<SectionBlockProps["paddingY"], string> = {
|
|
sm: "pb-section-py-sm",
|
|
md: "pb-section-py-md",
|
|
lg: "pb-section-py-lg",
|
|
};
|
|
const pyClass = pyClassMap[pyToken] ?? "pb-section-py-md";
|
|
|
|
const sectionClasses = ["pb-section", bgClass, pyClass].filter(Boolean).join(" ");
|
|
const sectionStyleParts: string[] = [];
|
|
|
|
if (typeof props.backgroundColorCustom === "string" && props.backgroundColorCustom.trim() !== "") {
|
|
sectionStyleParts.push(`background-color:${props.backgroundColorCustom.trim()}`);
|
|
}
|
|
|
|
const bgImgSrc = props.backgroundImageSrc;
|
|
if (typeof bgImgSrc === "string" && bgImgSrc.trim() !== "") {
|
|
const url = bgImgSrc.trim();
|
|
sectionStyleParts.push(`background-image:url(${url})`);
|
|
|
|
const size = props.backgroundImageSize ?? "cover";
|
|
sectionStyleParts.push(`background-size:${size}`);
|
|
|
|
const posMode = props.backgroundImagePositionMode ?? "preset";
|
|
if (posMode === "custom") {
|
|
const x = props.backgroundImagePositionXPercent;
|
|
const y = props.backgroundImagePositionYPercent;
|
|
const xSafe = typeof x === "number" ? x : 50;
|
|
const ySafe = typeof y === "number" ? y : 50;
|
|
sectionStyleParts.push(`background-position:${xSafe}% ${ySafe}%`);
|
|
} else {
|
|
const posToken = props.backgroundImagePosition ?? "center";
|
|
const position =
|
|
posToken === "top"
|
|
? "center top"
|
|
: posToken === "bottom"
|
|
? "center bottom"
|
|
: posToken === "left"
|
|
? "left center"
|
|
: posToken === "right"
|
|
? "right center"
|
|
: "center center";
|
|
sectionStyleParts.push(`background-position:${position}`);
|
|
}
|
|
|
|
const repeat = props.backgroundImageRepeat ?? "no-repeat";
|
|
sectionStyleParts.push(`background-repeat:${repeat}`);
|
|
}
|
|
|
|
const bgVideoSrc = props.backgroundVideoSrc;
|
|
let backgroundVideoHtml = "";
|
|
if (typeof bgVideoSrc === "string" && bgVideoSrc.trim() !== "") {
|
|
const url = bgVideoSrc.trim();
|
|
backgroundVideoHtml = `<video class="pb-section-bg-video" src="${url}" autoplay loop muted playsinline></video>`;
|
|
sectionStyleParts.push("position:relative");
|
|
sectionStyleParts.push("overflow:hidden");
|
|
}
|
|
|
|
return {
|
|
sectionClasses,
|
|
sectionStyleParts,
|
|
backgroundVideoHtml,
|
|
};
|
|
}
|
|
|
|
export interface SectionPublicTokens {
|
|
sectionStyle: CSSProperties;
|
|
innerWrapperStyle: CSSProperties;
|
|
columnsContainerStyle: CSSProperties;
|
|
hasBackgroundVideo: boolean;
|
|
backgroundVideoSrc: string | null;
|
|
}
|
|
|
|
const pxToEm = (px: number, base = 16) => `${px / base}em`;
|
|
|
|
export function computeSectionPublicTokens(props: SectionBlockProps): SectionPublicTokens {
|
|
const sectionStyle: CSSProperties = {};
|
|
|
|
if (props.backgroundColorCustom && props.backgroundColorCustom.trim() !== "") {
|
|
sectionStyle.backgroundColor = props.backgroundColorCustom.trim();
|
|
}
|
|
|
|
if (typeof props.paddingYPx === "number" && props.paddingYPx > 0) {
|
|
const paddingEm = pxToEm(props.paddingYPx);
|
|
sectionStyle.paddingTop = paddingEm;
|
|
sectionStyle.paddingBottom = paddingEm;
|
|
}
|
|
|
|
const rawBgVideoSrc = (props as any).backgroundVideoSrc;
|
|
let hasBackgroundVideo = false;
|
|
let backgroundVideoSrc: string | null = null;
|
|
if (typeof rawBgVideoSrc === "string" && rawBgVideoSrc.trim() !== "") {
|
|
hasBackgroundVideo = true;
|
|
backgroundVideoSrc = rawBgVideoSrc.trim();
|
|
sectionStyle.position = "relative";
|
|
sectionStyle.overflow = "hidden";
|
|
}
|
|
|
|
if (props.backgroundImageSrc && props.backgroundImageSrc.trim() !== "") {
|
|
const url = props.backgroundImageSrc.trim();
|
|
sectionStyle.backgroundImage = `url(${url})`;
|
|
|
|
const size = props.backgroundImageSize ?? "cover";
|
|
sectionStyle.backgroundSize = size;
|
|
|
|
const posMode = props.backgroundImagePositionMode ?? "preset";
|
|
if (
|
|
posMode === "custom" &&
|
|
typeof props.backgroundImagePositionXPercent === "number" &&
|
|
typeof props.backgroundImagePositionYPercent === "number"
|
|
) {
|
|
const x = props.backgroundImagePositionXPercent;
|
|
const y = props.backgroundImagePositionYPercent;
|
|
sectionStyle.backgroundPosition = `${x}% ${y}%`;
|
|
} else {
|
|
const posToken = props.backgroundImagePosition ?? "center";
|
|
const position =
|
|
posToken === "top"
|
|
? "center top"
|
|
: posToken === "bottom"
|
|
? "center bottom"
|
|
: posToken === "left"
|
|
? "left center"
|
|
: posToken === "right"
|
|
? "right center"
|
|
: "center center";
|
|
sectionStyle.backgroundPosition = position;
|
|
}
|
|
|
|
const repeat = props.backgroundImageRepeat ?? "no-repeat";
|
|
sectionStyle.backgroundRepeat = repeat;
|
|
}
|
|
|
|
const innerWrapperStyle: CSSProperties = {};
|
|
if (typeof props.maxWidthPx === "number" && props.maxWidthPx > 0) {
|
|
innerWrapperStyle.maxWidth = pxToEm(props.maxWidthPx);
|
|
}
|
|
|
|
const columnsContainerStyle: CSSProperties = {};
|
|
if (typeof props.gapXPx === "number" && props.gapXPx > 0) {
|
|
columnsContainerStyle.columnGap = pxToEm(props.gapXPx);
|
|
}
|
|
|
|
return {
|
|
sectionStyle,
|
|
innerWrapperStyle,
|
|
columnsContainerStyle,
|
|
hasBackgroundVideo,
|
|
backgroundVideoSrc,
|
|
};
|
|
}
|
|
|
|
export interface SectionEditorTokens {
|
|
bgClass: string;
|
|
pyClass: string;
|
|
alignItemsClass: string;
|
|
wrapperStyle: CSSProperties;
|
|
innerWrapperStyle: CSSProperties;
|
|
columnsContainerStyle: CSSProperties;
|
|
hasBackgroundVideo: boolean;
|
|
backgroundVideoSrc: string | null;
|
|
}
|
|
|
|
export function computeSectionEditorTokens(props: SectionBlockProps): SectionEditorTokens {
|
|
const bgClass =
|
|
props.background === "muted"
|
|
? "bg-slate-950/40"
|
|
: props.background === "primary"
|
|
? "bg-sky-950/40 border-sky-900/60"
|
|
: "bg-slate-900/60";
|
|
|
|
const pyClass =
|
|
props.paddingY === "sm"
|
|
? "py-4"
|
|
: props.paddingY === "lg"
|
|
? "py-10"
|
|
: "py-6";
|
|
|
|
const alignItemsClass =
|
|
props.alignItems === "center"
|
|
? "items-center"
|
|
: props.alignItems === "bottom"
|
|
? "items-end"
|
|
: "items-start";
|
|
|
|
const wrapperStyle: CSSProperties = {};
|
|
if (props.backgroundColorCustom && props.backgroundColorCustom.trim() !== "") {
|
|
wrapperStyle.backgroundColor = props.backgroundColorCustom;
|
|
}
|
|
|
|
if (typeof props.paddingYPx === "number" && props.paddingYPx > 0) {
|
|
wrapperStyle.paddingTop = `${props.paddingYPx}px`;
|
|
wrapperStyle.paddingBottom = `${props.paddingYPx}px`;
|
|
}
|
|
|
|
let hasBackgroundVideo = false;
|
|
let backgroundVideoSrc: string | null = null;
|
|
if (typeof props.backgroundVideoSrc === "string" && props.backgroundVideoSrc.trim() !== "") {
|
|
hasBackgroundVideo = true;
|
|
backgroundVideoSrc = props.backgroundVideoSrc.trim();
|
|
wrapperStyle.position = "relative";
|
|
wrapperStyle.overflow = "hidden";
|
|
}
|
|
|
|
if (props.backgroundImageSrc && props.backgroundImageSrc.trim() !== "") {
|
|
const url = props.backgroundImageSrc.trim();
|
|
wrapperStyle.backgroundImage = `url(${url})`;
|
|
|
|
const size = props.backgroundImageSize ?? "cover";
|
|
wrapperStyle.backgroundSize = size;
|
|
|
|
const posMode = props.backgroundImagePositionMode ?? "preset";
|
|
if (
|
|
posMode === "custom" &&
|
|
typeof props.backgroundImagePositionXPercent === "number" &&
|
|
typeof props.backgroundImagePositionYPercent === "number"
|
|
) {
|
|
const x = props.backgroundImagePositionXPercent;
|
|
const y = props.backgroundImagePositionYPercent;
|
|
wrapperStyle.backgroundPosition = `${x}% ${y}%`;
|
|
} else {
|
|
const posToken = props.backgroundImagePosition ?? "center";
|
|
const position =
|
|
posToken === "top"
|
|
? "center top"
|
|
: posToken === "bottom"
|
|
? "center bottom"
|
|
: posToken === "left"
|
|
? "left center"
|
|
: posToken === "right"
|
|
? "right center"
|
|
: "center center";
|
|
wrapperStyle.backgroundPosition = position;
|
|
}
|
|
|
|
const repeat = props.backgroundImageRepeat ?? "no-repeat";
|
|
wrapperStyle.backgroundRepeat = repeat;
|
|
}
|
|
|
|
const innerWrapperStyle: CSSProperties = {};
|
|
if (typeof props.maxWidthPx === "number" && props.maxWidthPx > 0) {
|
|
innerWrapperStyle.maxWidth = `${props.maxWidthPx}px`;
|
|
}
|
|
|
|
const columnsContainerStyle: CSSProperties = {};
|
|
if (typeof props.gapXPx === "number" && props.gapXPx > 0) {
|
|
columnsContainerStyle.columnGap = `${props.gapXPx}px`;
|
|
}
|
|
|
|
return {
|
|
bgClass,
|
|
pyClass,
|
|
alignItemsClass,
|
|
wrapperStyle,
|
|
innerWrapperStyle,
|
|
columnsContainerStyle,
|
|
hasBackgroundVideo,
|
|
backgroundVideoSrc,
|
|
};
|
|
}
|