ERP-node/frontend/lib/registry/layouts/TabsLayoutRenderer.tsx

179 lines
5.8 KiB
TypeScript

"use client";
import React, { useState } from "react";
import { BaseLayoutRenderer, LayoutRendererProps } from "./BaseLayoutRenderer";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { X } from "lucide-react";
export default class TabsLayoutRenderer extends BaseLayoutRenderer {
render(): React.ReactElement {
const { layout, isDesignMode, isSelected, onClick, className } = this.props;
if (!layout.layoutConfig.tabs) {
return <div className="error-layout"> .</div>;
}
return (
<TabsLayoutComponent
layout={layout}
isDesignMode={isDesignMode}
isSelected={isSelected}
onClick={onClick}
className={className}
renderer={this}
/>
);
}
}
interface TabsLayoutComponentProps {
layout: any;
isDesignMode?: boolean;
isSelected?: boolean;
onClick?: (e: React.MouseEvent) => void;
className?: string;
renderer: TabsLayoutRenderer;
}
const TabsLayoutComponent: React.FC<TabsLayoutComponentProps> = ({
layout,
isDesignMode,
isSelected,
onClick,
className,
renderer,
}) => {
const tabsConfig = layout.layoutConfig.tabs;
const [activeTab, setActiveTab] = useState(tabsConfig.defaultTab || layout.zones[0]?.id || "");
const containerStyle = renderer.getLayoutContainerStyle();
// 탭 컨테이너 스타일
const tabsStyle: React.CSSProperties = {
...containerStyle,
display: "flex",
flexDirection: tabsConfig.position === "left" || tabsConfig.position === "right" ? "row" : "column",
};
// 디자인 모드 스타일
if (isDesignMode) {
tabsStyle.border = isSelected ? "2px solid #3b82f6" : "1px solid #e2e8f0";
tabsStyle.borderRadius = "8px";
}
// 탭 사이즈 클래스
const sizeClass = tabsConfig.size === "sm" ? "text-sm" : tabsConfig.size === "lg" ? "text-lg" : "";
return (
<div
className={`tabs-layout ${isDesignMode ? "design-mode" : ""} ${className || ""}`}
style={tabsStyle}
onClick={onClick}
draggable={isDesignMode}
onDragStart={renderer.props.onDragStart}
onDragEnd={renderer.props.onDragEnd}
>
{layout.zones.length === 0 ? (
/* 디자인 모드에서 존이 없을 때 안내 메시지 */
isDesignMode && (
<div
className="empty-tabs-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: "200px",
padding: "20px",
textAlign: "center",
}}
>
</div>
)
) : (
<Tabs
value={activeTab}
onValueChange={setActiveTab}
orientation={tabsConfig.position === "left" || tabsConfig.position === "right" ? "vertical" : "horizontal"}
className="flex h-full w-full flex-col"
>
{/* 탭 목록 */}
<TabsList
className={` ${sizeClass} ${tabsConfig.position === "bottom" ? "order-2" : ""} ${tabsConfig.position === "right" ? "order-2" : ""} ${tabsConfig.variant === "pills" ? "bg-gray-100" : ""} ${tabsConfig.variant === "underline" ? "border-b" : ""} `}
style={{
flexShrink: 0,
justifyContent:
tabsConfig.position === "left" || tabsConfig.position === "right" ? "flex-start" : "center",
}}
>
{layout.zones.map((zone: any) => (
<div key={zone.id} className="flex items-center">
<TabsTrigger
value={zone.id}
className={` ${sizeClass} ${tabsConfig.variant === "pills" ? "rounded-full" : ""} ${tabsConfig.variant === "underline" ? "border-b-2 border-transparent data-[state=active]:border-blue-500" : ""} `}
>
{zone.name}
</TabsTrigger>
{/* 닫기 버튼 (설정에서 허용한 경우) */}
{tabsConfig.closable && isDesignMode && layout.zones.length > 1 && (
<button
className="ml-1 rounded p-1 hover:bg-gray-200"
onClick={(e) => {
e.stopPropagation();
// 탭 닫기 로직 (실제 구현 시 필요)
console.log("탭 닫기:", zone.id);
}}
>
<X className="h-3 w-3" />
</button>
)}
</div>
))}
</TabsList>
{/* 탭 컨텐츠 */}
<div className="flex-1 overflow-auto">
{layout.zones.map((zone: any) => {
const zoneChildren = renderer.getZoneChildren(zone.id);
return (
<TabsContent
key={zone.id}
value={zone.id}
className="h-full p-2"
style={{
margin: 0,
borderRadius: "6px",
backgroundColor: "rgba(248, 250, 252, 0.3)",
}}
>
{renderer.renderZone(zone, zoneChildren, {
style: {
height: "100%",
minHeight: "100px",
},
className: "tab-panel",
})}
</TabsContent>
);
})}
</div>
</Tabs>
)}
</div>
);
};
// React 컴포넌트로 래핑
export const TabsLayout: React.FC<LayoutRendererProps> = (props) => {
const renderer = new TabsLayoutRenderer(props);
return renderer.render();
};