ERP-node/frontend/lib/registry/layouts/hero-section/HeroSectionLayout.tsx

209 lines
6.9 KiB
TypeScript

"use client";
import React from "react";
import { LayoutRendererProps } from "../BaseLayoutRenderer";
/**
* heroSection 컴포넌트
*/
export interface HeroSectionLayoutProps extends LayoutRendererProps {
renderer: any; // HeroSectionLayoutRenderer 타입
}
export const HeroSectionLayout: React.FC<HeroSectionLayoutProps> = ({
layout,
isDesignMode = false,
isSelected = false,
onClick,
className = "",
renderer,
onZoneComponentDrop,
onZoneClick,
...props
}) => {
if (!layout.layoutConfig.heroSection) {
return (
<div className="error-layout flex items-center justify-center rounded border-2 border-red-300 bg-red-50 p-4">
<div className="text-center text-red-600">
<div className="font-medium">heroSection .</div>
<div className="mt-1 text-sm">layoutConfig.heroSection가 .</div>
</div>
</div>
);
}
const heroSectionConfig = layout.layoutConfig.heroSection;
const containerStyle = renderer.getLayoutContainerStyle();
// heroSection 컨테이너 스타일
const heroSectionStyle: React.CSSProperties = {
...containerStyle,
display: "flex",
flexDirection: "column",
height: "100%",
width: "100%",
padding: "16px",
};
// 디자인 모드 스타일
if (isDesignMode) {
heroSectionStyle.border = isSelected ? "2px solid #3b82f6" : "1px solid #e2e8f0";
heroSectionStyle.borderRadius = "8px";
}
// DOM props만 추출 (React DOM에서 인식하는 props만)
const {
children: propsChildren,
onUpdateLayout,
onSelectComponent,
isDesignMode: _isDesignMode,
allComponents,
onComponentDrop,
onDragStart,
onDragEnd,
selectedScreen, // DOM에 전달하지 않도록 제외
...domProps
} = props;
return (
<>
<style jsx>{`
.force-hero-layout {
display: flex !important;
flex-direction: column !important;
height: ${layout.size?.height ? `${layout.size.height}px` : "100%"} !important;
min-height: ${layout.size?.height ? `${layout.size.height}px` : "200px"} !important;
width: 100% !important;
}
`}</style>
<div
className={`hero-section-layout force-hero-layout ${isDesignMode ? "design-mode" : ""} ${className}`}
style={heroSectionStyle}
onClick={onClick}
draggable={isDesignMode}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
{...domProps}
>
{layout.zones.map((zone: any, index: number) => {
const zoneChildren = renderer.getZoneChildren(zone.id);
// 레이아웃 전체 높이 기준으로 존 높이 계산
const layoutHeight = layout.size?.height || 600; // 영웅 섹션은 기본값 600px
const defaultZoneHeight = Math.floor(layoutHeight / layout.zones.length) - 32; // 존 개수로 나눔
// 영웅 섹션 존 스타일 (일반적으로 세로로 배치)
const zoneStyle: React.CSSProperties = {
width: "100%",
marginBottom: index < layout.zones.length - 1 ? "16px" : "0",
// 카드 레이아웃처럼 항상 명확한 경계 표시
backgroundColor: "white",
border: "1px solid #e5e7eb",
borderRadius: "8px",
padding: "16px",
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1)",
// 존의 높이: 개별 설정이 있으면 우선, 없으면 flex로 자동 분배
height: zone.size?.height
? typeof zone.size.height === "number"
? `${zone.size.height}px`
: zone.size.height
: "auto", // flex 컨테이너에서 자동으로 높이 분배
flex: zone.size?.height ? "none" : "1", // 개별 높이가 없으면 flex로 균등 분배
minHeight: zone.size?.minHeight
? typeof zone.size.minHeight === "number"
? `${zone.size.minHeight}px`
: zone.size.minHeight
: "120px",
maxHeight: zone.size?.maxHeight
? typeof zone.size.maxHeight === "number"
? `${zone.size.maxHeight}px`
: zone.size.maxHeight
: "none",
position: "relative",
transition: "all 0.2s ease",
overflow: "hidden",
display: "flex",
flexDirection: "column",
};
return (
<div
key={zone.id}
style={zoneStyle}
className="hero-section-zone"
onMouseEnter={(e) => {
e.currentTarget.style.borderColor = "#3b82f6";
e.currentTarget.style.boxShadow =
"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(59, 130, 246, 0.1)";
}}
onMouseLeave={(e) => {
e.currentTarget.style.borderColor = "#e5e7eb";
e.currentTarget.style.boxShadow = "0 1px 3px 0 rgba(0, 0, 0, 0.1)";
}}
>
{/* 존 라벨 */}
{isDesignMode && (
<div
className="zone-label"
style={{
position: "absolute",
top: "-2px",
left: "8px",
backgroundColor: "#3b82f6",
color: "white",
fontSize: "10px",
padding: "2px 6px",
borderRadius: "0 0 4px 4px",
fontWeight: "500",
zIndex: 10,
}}
>
{zone.name || zone.id}
</div>
)}
{/* 존 내용 */}
<div
style={{ paddingTop: isDesignMode ? "16px" : "0", flex: 1, display: "flex", flexDirection: "column" }}
>
{renderer.renderZone(zone, zoneChildren, {
style: {
border: "none",
backgroundColor: "transparent",
flex: 1,
minHeight: "0",
},
className: "hero-section-zone-content",
})}
</div>
</div>
);
})}
{/* 디자인 모드에서 빈 영역 표시 */}
{isDesignMode && layout.zones.length === 0 && (
<div
className="empty-hero-section-container"
style={{
flex: 1,
border: "2px dashed #cbd5e1",
borderRadius: "8px",
backgroundColor: "rgba(148, 163, 184, 0.05)",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: "14px",
color: "#64748b",
minHeight: "100px",
padding: "20px",
textAlign: "center",
}}
>
heroSection에
</div>
)}
</div>
</>
);
};