스타일 수정
CI / test (push) Failing after 44m2s
CI / pr_and_merge (push) Has been skipped

This commit is contained in:
2025-11-29 15:11:49 +09:00
parent c9a62d479c
commit 1f085bd64c
64 changed files with 568 additions and 126 deletions
@@ -26,7 +26,7 @@ import {
buildVideoEmbedUrl,
computeVideoPublicTokens,
} from "@/features/editor/utils/videoHelpers";
import { computeButtonPublicTokens } from "@/features/editor/utils/buttonHelpers";
import { computeButtonPublicTokens, computeButtonPbTokens } from "@/features/editor/utils/buttonHelpers";
import { computeTextPublicTokens } from "@/features/editor/utils/textHelpers";
import { computeDividerPublicTokens } from "@/features/editor/utils/dividerHelpers";
import { computeImagePublicTokens } from "@/features/editor/utils/imageHelpers";
@@ -50,8 +50,12 @@ export function getSectionLayoutConfig(props: SectionBlockProps) {
? "bg-sky-900"
: "bg-slate-950";
// 섹션 수직 패딩: builder.css 의 pb-section-py-sm/md/lg (1rem/1.5rem/2.5rem)에 대응
// - sm → 1rem → py-4
// - md → 1.5rem → py-6
// - lg → 2.5rem → py-10
const paddingYClass =
props.paddingY === "sm" ? "py-8" : props.paddingY === "lg" ? "py-20" : "py-12";
props.paddingY === "sm" ? "py-4" : props.paddingY === "lg" ? "py-10" : "py-6";
const maxWidthClass =
props.maxWidthMode === "narrow"
@@ -302,16 +306,40 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
if (block.type === "button") {
const props = block.props as ButtonBlockProps;
const tokens = computeButtonPublicTokens(props);
const buttonStyle: CSSProperties = { ...tokens.styleOverrides };
const pbTokens = computeButtonPbTokens({
align: props.align ?? "left",
size: props.size ?? "md",
variant: props.variant ?? "solid",
colorPalette: props.colorPalette ?? "primary",
borderRadius: props.borderRadius ?? "md",
fullWidth: props.fullWidth ?? false,
widthMode: props.widthMode ?? undefined,
widthPx: props.widthPx ?? undefined,
paddingX: props.paddingX ?? undefined,
paddingY: props.paddingY ?? undefined,
fillColorCustom: props.fillColorCustom ?? undefined,
strokeColorCustom: props.strokeColorCustom ?? undefined,
textColorCustom: props.textColorCustom ?? undefined,
});
const publicTokens = computeButtonPublicTokens(props);
const buttonStyle: CSSProperties = { ...publicTokens.styleOverrides };
const wrapperClass = pbTokens.alignClass;
const buttonClassName = [
"pb-btn-base",
pbTokens.sizeClass,
pbTokens.variantClass,
pbTokens.radiusClass,
publicTokens.widthClass,
]
.filter(Boolean)
.join(" ");
return (
<div key={block.id} className={tokens.alignClass}>
<a
href={props.href}
className={`inline-flex items-center justify-center text-sm font-medium hover:bg-sky-500 transition-colors ${tokens.widthClass}`}
style={buttonStyle}
>
<div key={block.id} className={wrapperClass}>
<a href={props.href} className={buttonClassName} style={buttonStyle}>
<span className="whitespace-pre-wrap">{props.label}</span>
</a>
</div>
@@ -326,13 +354,13 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
<div
key={block.id}
data-testid="preview-divider"
className={`flex ${tokens.alignClass}`}
className={`flex w-full ${tokens.alignClass}`}
style={{ marginTop: tokens.wrapperMarginEm, marginBottom: tokens.wrapperMarginEm }}
>
<div style={tokens.innerStyle}>
<div className={tokens.innerWidthClass} style={tokens.innerStyle}>
<div
data-testid="preview-divider-line"
className={`${tokens.thicknessClass} ${tokens.innerWidthClass}`}
className={tokens.thicknessClass}
style={tokens.lineStyle}
/>
</div>
@@ -367,27 +395,17 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
return (
<ListTag
className={tokens.alignClass}
className={`pb-list ${tokens.alignClass}`}
style={{
...tokens.listStyle,
listStyleType:
tokens.bulletStyle === "none"
? "none"
: tokens.bulletStyle,
paddingLeft: 12 + level * 8,
}}
>
{nodes.map((node, index) => (
<li
key={node.id}
style={
index < nodes.length - 1
? {
marginBottom: `${tokens.gapEm}em`,
}
: undefined
}
>
{nodes.map((node) => (
<li key={node.id}>
{node.text}
{node.children && node.children.length > 0 && renderListNodes(node.children, level + 1)}
</li>
+7 -5
View File
@@ -64,17 +64,19 @@ export function computeButtonPbTokens(input: ButtonStyleInput): ButtonPbTokens {
const widthMode = input.widthMode ?? (input.fullWidth ? "full" : "auto");
if (widthMode === "fixed" && typeof input.widthPx === "number" && input.widthPx > 0) {
inlineStyles.push(`width:${input.widthPx}px`);
inlineStyles.push(`width:${pxToEm(input.widthPx)}`);
}
if (typeof input.paddingX === "number") {
inlineStyles.push(`padding-left:${input.paddingX}px`);
inlineStyles.push(`padding-right:${input.paddingX}px`);
const paddingInline = pxToEm(input.paddingX);
inlineStyles.push(`padding-left:${paddingInline}`);
inlineStyles.push(`padding-right:${paddingInline}`);
}
if (typeof input.paddingY === "number") {
inlineStyles.push(`padding-top:${input.paddingY}px`);
inlineStyles.push(`padding-bottom:${input.paddingY}px`);
const paddingBlock = pxToEm(input.paddingY);
inlineStyles.push(`padding-top:${paddingBlock}`);
inlineStyles.push(`padding-bottom:${paddingBlock}`);
}
if (input.fillColorCustom && input.fillColorCustom.trim() !== "") {
+2 -1
View File
@@ -19,8 +19,9 @@ export const computeDividerExportTokens = (
const colorRaw = typeof props.colorHex === "string" ? props.colorHex.trim() : "";
const color = colorRaw !== "" ? colorRaw : "#475569";
const marginY = typeof props.marginYPx === "number" && props.marginYPx > 0 ? props.marginYPx : 16;
const marginEm = pxToEm(marginY);
const style = `border:0;border-bottom:${thickness} solid ${escapeAttr(color)};margin:${marginY}px 0;`;
const style = `border:0;border-bottom:${thickness} solid ${escapeAttr(color)};margin:${marginEm} 0;`;
return { style };
};
+22 -20
View File
@@ -84,20 +84,21 @@ export const computeFormInputExportTokens = (
}
if (typeof props.paddingX === "number" && props.paddingX >= 0) {
const px = props.paddingX;
inputStyleParts.push(`padding-left:${px}px`);
inputStyleParts.push(`padding-right:${px}px`);
const em = props.paddingX / 16;
inputStyleParts.push(`padding-left:${em}em`);
inputStyleParts.push(`padding-right:${em}em`);
}
if (typeof props.paddingY === "number" && props.paddingY >= 0) {
const py = props.paddingY;
inputStyleParts.push(`padding-top:${py}px`);
inputStyleParts.push(`padding-bottom:${py}px`);
const em = props.paddingY / 16;
inputStyleParts.push(`padding-top:${em}em`);
inputStyleParts.push(`padding-bottom:${em}em`);
}
const widthMode = computeWidthMode({ widthMode: props.widthMode, fullWidth: props.fullWidth });
if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
inputStyleParts.push(`width:${props.widthPx}px`);
const em = props.widthPx / 16;
inputStyleParts.push(`width:${em}em`);
}
const radiusPx = computeRadiusPx(props.borderRadius);
@@ -127,19 +128,20 @@ export const computeFormSelectExportTokens = (
const widthMode = computeWidthMode({ widthMode: props.widthMode, fullWidth: props.fullWidth });
if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
selectStyleParts.push(`width:${props.widthPx}px`);
const em = props.widthPx / 16;
selectStyleParts.push(`width:${em}em`);
}
if (typeof props.paddingX === "number" && props.paddingX >= 0) {
const px = props.paddingX;
selectStyleParts.push(`padding-left:${px}px`);
selectStyleParts.push(`padding-right:${px}px`);
const em = props.paddingX / 16;
selectStyleParts.push(`padding-left:${em}em`);
selectStyleParts.push(`padding-right:${em}em`);
}
if (typeof props.paddingY === "number" && props.paddingY >= 0) {
const py = props.paddingY;
selectStyleParts.push(`padding-top:${py}px`);
selectStyleParts.push(`padding-bottom:${py}px`);
const em = props.paddingY / 16;
selectStyleParts.push(`padding-top:${em}em`);
selectStyleParts.push(`padding-bottom:${em}em`);
}
if (typeof props.fillColorCustom === "string" && props.fillColorCustom.trim() !== "") {
@@ -176,15 +178,15 @@ const computeOptionGroupExportTokensBase = (
}
if (typeof props.paddingX === "number" && props.paddingX >= 0) {
const px = props.paddingX;
optionStyleParts.push(`padding-left:${px}px`);
optionStyleParts.push(`padding-right:${px}px`);
const em = props.paddingX / 16;
optionStyleParts.push(`padding-left:${em}em`);
optionStyleParts.push(`padding-right:${em}em`);
}
if (typeof props.paddingY === "number" && props.paddingY >= 0) {
const py = props.paddingY;
optionStyleParts.push(`padding-top:${py}px`);
optionStyleParts.push(`padding-bottom:${py}px`);
const em = props.paddingY / 16;
optionStyleParts.push(`padding-top:${em}em`);
optionStyleParts.push(`padding-bottom:${em}em`);
}
if (typeof props.fillColorCustom === "string" && props.fillColorCustom.trim() !== "") {
+2 -1
View File
@@ -27,7 +27,8 @@ export function computeImageExportStyles(input: ImageExportStyleInput): ImageExp
const widthMode: ImageWidthMode = input.widthMode ?? "auto";
if (widthMode === "fixed" && typeof input.widthPx === "number" && input.widthPx > 0) {
imgStyleParts.push(`width:${input.widthPx}px`);
const widthEm = input.widthPx / 16;
imgStyleParts.push(`width:${widthEm}em`);
}
const radiusToken: ImageBorderRadiusToken = input.borderRadius ?? "md";
+9 -1
View File
@@ -134,7 +134,15 @@ export const computeListPublicTokens = (props: ListBlockProps): ListPublicTokens
}
}
if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
listStyle.lineHeight = props.lineHeightCustom;
const lineHeightValue = props.lineHeightCustom.trim();
if (lineHeightValue.endsWith("px")) {
const lineHeightEm = convertPxStringToEm(lineHeightValue);
if (lineHeightEm) {
listStyle.lineHeight = lineHeightEm;
}
} else {
listStyle.lineHeight = lineHeightValue;
}
}
if (props.textColorCustom && props.textColorCustom.trim() !== "") {
listStyle.color = props.textColorCustom;
+44 -1
View File
@@ -276,6 +276,17 @@ export interface TextPublicTokens {
styleOverrides: CSSProperties;
}
const pxToEm = (px: number, base = 16) => `${px / base}em`;
const convertPxStringToEm = (value?: string | null) => {
if (!value) return null;
const match = value.trim().match(/-?\d+(?:\.\d+)?/);
if (!match) return null;
const px = parseFloat(match[0]);
if (!Number.isFinite(px)) return null;
return pxToEm(px);
};
export function computeTextPublicTokens(props: TextBlockProps): TextPublicTokens {
const alignClass =
props.align === "center"
@@ -308,7 +319,15 @@ export function computeTextPublicTokens(props: TextBlockProps): TextPublicTokens
props.fontSizeCustom &&
props.fontSizeCustom.trim() !== ""
) {
styleOverrides.fontSize = props.fontSizeCustom;
const fontSizeValue = props.fontSizeCustom.trim();
if (fontSizeValue.endsWith("px")) {
const fontSizeEm = convertPxStringToEm(fontSizeValue);
if (fontSizeEm) {
styleOverrides.fontSize = fontSizeEm;
}
} else {
styleOverrides.fontSize = fontSizeValue;
}
}
if (props.colorCustom && props.colorCustom.trim() !== "") {
@@ -319,6 +338,30 @@ export function computeTextPublicTokens(props: TextBlockProps): TextPublicTokens
styleOverrides.backgroundColor = props.backgroundColorCustom.trim();
}
if (props.lineHeightCustom && props.lineHeightCustom.trim() !== "") {
const lineHeightValue = props.lineHeightCustom.trim();
if (lineHeightValue.endsWith("px")) {
const lineHeightEm = convertPxStringToEm(lineHeightValue);
if (lineHeightEm) {
styleOverrides.lineHeight = lineHeightEm;
}
} else {
styleOverrides.lineHeight = lineHeightValue;
}
}
if (props.letterSpacingCustom && props.letterSpacingCustom.trim() !== "") {
const letterSpacingValue = props.letterSpacingCustom.trim();
if (letterSpacingValue.endsWith("px")) {
const letterSpacingEm = convertPxStringToEm(letterSpacingValue);
if (letterSpacingEm) {
styleOverrides.letterSpacing = letterSpacingEm;
}
} else {
styleOverrides.letterSpacing = letterSpacingValue;
}
}
return {
alignClass,
sizeClass,
+5 -4
View File
@@ -101,8 +101,9 @@ export function computeVideoExportTokens(
const widthMode = props.widthMode ?? "auto";
if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
wrapperStyleParts.push(`width:${props.widthPx}px`);
videoStyleParts.push(`width:${props.widthPx}px`);
const widthEm = pxToEm(props.widthPx);
wrapperStyleParts.push(`width:${widthEm}`);
videoStyleParts.push(`width:${widthEm}`);
} else if (widthMode === "full") {
wrapperStyleParts.push("width:100%");
videoStyleParts.push("width:100%");
@@ -113,11 +114,11 @@ export function computeVideoExportTokens(
}
if (typeof props.cardPaddingPx === "number" && props.cardPaddingPx >= 0) {
wrapperStyleParts.push(`padding:${props.cardPaddingPx}px`);
wrapperStyleParts.push(`padding:${pxToEm(props.cardPaddingPx)}`);
}
if (typeof props.borderRadiusPx === "number" && props.borderRadiusPx >= 0) {
wrapperStyleParts.push(`border-radius:${props.borderRadiusPx}px`);
wrapperStyleParts.push(`border-radius:${pxToEm(props.borderRadiusPx)}`);
}
const align =