이미지 파일 업로드 기능
CI / test (push) Failing after 10m34s
CI / pr_and_merge (push) Has been cancelled

This commit is contained in:
2025-11-23 19:07:41 +09:00
parent 8ea8a186a0
commit 7a8ad7c057
77 changed files with 3206 additions and 124 deletions
@@ -356,6 +356,7 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
const optionTextStyle: CSSProperties = {};
const groupTextStyle: CSSProperties = {};
const textSizeClass = props.fontSizeCustom && props.fontSizeCustom.trim() !== "" ? "" : "text-xs";
const groupLabelMode = props.groupLabelMode ?? "text";
if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
groupStyle.width = pxToEm(props.widthPx);
@@ -425,7 +426,17 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
.join(" ")}
style={groupStyle}
>
<span style={groupTextStyle}>{props.groupLabel}</span>
{groupLabelMode === "image" && props.groupLabelImageUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={props.groupLabelImageUrl}
alt={props.groupLabel || "폼 그룹 타이틀"}
className="inline-block max-w-full h-auto"
style={groupTextStyle}
/>
) : (
<span style={groupTextStyle}>{props.groupLabel}</span>
)}
<div className="flex flex-col" data-testid="preview-form-checkbox-options" style={optionsStyle}>
{props.options.map((opt) => (
<label key={opt.value} className="inline-flex items-center gap-1">
@@ -433,9 +444,19 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
type="checkbox"
className="h-4 w-4 rounded border-slate-700 bg-slate-900 text-sky-500"
/>
<span data-testid="preview-form-checkbox-option" style={optionTextStyle}>
{opt.label}
</span>
{opt.labelImageUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={opt.labelImageUrl}
alt={opt.label || props.groupLabel || "체크박스 옵션"}
className="inline-block max-w-full h-auto"
style={optionTextStyle}
/>
) : (
<span data-testid="preview-form-checkbox-option" style={optionTextStyle}>
{opt.label}
</span>
)}
</label>
))}
</div>
@@ -451,6 +472,7 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
const optionTextStyle: CSSProperties = {};
const groupTextStyle: CSSProperties = {};
const textSizeClass = props.fontSizeCustom && props.fontSizeCustom.trim() !== "" ? "" : "text-xs";
const groupLabelMode = props.groupLabelMode ?? "text";
if (widthMode === "fixed" && typeof props.widthPx === "number" && props.widthPx > 0) {
groupStyle.width = pxToEm(props.widthPx);
@@ -520,7 +542,17 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
.join(" ")}
style={groupStyle}
>
<span style={groupTextStyle}>{props.groupLabel}</span>
{groupLabelMode === "image" && props.groupLabelImageUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={props.groupLabelImageUrl}
alt={props.groupLabel || "폼 그룹 타이틀"}
className="inline-block max-w-full h-auto"
style={groupTextStyle}
/>
) : (
<span style={groupTextStyle}>{props.groupLabel}</span>
)}
<div className="flex flex-col" data-testid="preview-form-radio-options" style={optionsStyle}>
{props.options.map((opt) => (
<label key={opt.value} className="inline-flex items-center gap-1">
@@ -529,9 +561,19 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
className="h-4 w-4 border-slate-700 bg-slate-900 text-sky-500"
name={props.formFieldName}
/>
<span data-testid="preview-form-radio-option" style={optionTextStyle}>
{opt.label}
</span>
{opt.labelImageUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={opt.labelImageUrl}
alt={opt.label || props.groupLabel || "라디오 옵션"}
className="inline-block max-w-full h-auto"
style={optionTextStyle}
/>
) : (
<span data-testid="preview-form-radio-option" style={optionTextStyle}>
{opt.label}
</span>
)}
</label>
))}
</div>
@@ -952,7 +994,7 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
<img
src={field.groupLabelImageUrl}
alt={field.label}
className="h-4 w-auto"
className="max-h-10 w-auto max-w-[200px]"
/>
) : (
<span>{field.label}</span>
@@ -986,7 +1028,7 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
<img
src={field.groupLabelImageUrl}
alt={field.label}
className="h-4 w-auto"
className="max-h-10 w-auto max-w-[200px] md:max-w-[300px] lg:max-w-[400px]"
/>
) : (
<span>{field.label}</span>
@@ -1005,7 +1047,7 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
<img
src={opt.labelImageUrl}
alt={opt.label || field.label || "라디오 옵션"}
className="h-4 w-auto"
className="h-5 w-auto max-w-[120px]"
/>
) : (
<span>{opt.label}</span>
@@ -1066,7 +1108,20 @@ export function PublicPageRenderer({ blocks }: PublicPageRendererProps) {
}
const radiusToken = props.borderRadius ?? "md";
const radiusPx = radiusToken === "none" ? 0 : radiusToken === "sm" ? 2 : radiusToken === "lg" ? 6 : radiusToken === "full" ? 9999 : 4;
const fallbackRadiusPx =
radiusToken === "none"
? 0
: radiusToken === "sm"
? 4
: radiusToken === "lg"
? 16
: radiusToken === "full"
? 9999
: 8;
const radiusPx =
typeof (props as any).borderRadiusPx === "number" && (props as any).borderRadiusPx >= 0
? (props as any).borderRadiusPx
: fallbackRadiusPx;
imageStyle.borderRadius = radiusPx === 9999 ? "9999px" : pxToEm(radiusPx);
return (