미리보기 기능 수정
This commit is contained in:
@@ -48,6 +48,8 @@ import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRendere
|
||||
import { DynamicWebTypeRenderer } from "@/lib/registry";
|
||||
import { isFileComponent, getComponentWebType } from "@/lib/utils/componentTypeUtils";
|
||||
import { TableOptionsProvider } from "@/contexts/TableOptionsContext";
|
||||
import { RealtimePreview } from "./RealtimePreviewDynamic";
|
||||
import { ScreenPreviewProvider } from "@/contexts/ScreenPreviewContext";
|
||||
|
||||
// InteractiveScreenViewer를 동적으로 import (SSR 비활성화)
|
||||
const InteractiveScreenViewer = dynamic(
|
||||
@@ -1316,8 +1318,9 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
<DialogHeader>
|
||||
<DialogTitle>화면 미리보기 - {screenToPreview?.screenName}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<TableOptionsProvider>
|
||||
<div className="flex flex-1 items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 to-slate-100 p-6">
|
||||
<ScreenPreviewProvider isPreviewMode={true}>
|
||||
<TableOptionsProvider>
|
||||
<div className="flex flex-1 items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 to-slate-100 p-6">
|
||||
{isLoadingPreview ? (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="text-center">
|
||||
@@ -1331,10 +1334,24 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
const screenHeight = previewLayout.screenResolution?.height || 800;
|
||||
|
||||
// 모달 내부 가용 공간 계산 (헤더, 푸터, 패딩 제외)
|
||||
const availableWidth = typeof window !== "undefined" ? window.innerWidth * 0.95 - 100 : 1800; // 95vw - 패딩
|
||||
const modalPadding = 100; // 헤더 + 푸터 + 패딩
|
||||
const availableWidth = typeof window !== "undefined" ? window.innerWidth * 0.95 - modalPadding : 1700;
|
||||
const availableHeight = typeof window !== "undefined" ? window.innerHeight * 0.95 - modalPadding : 900;
|
||||
|
||||
// 가로폭 기준으로 스케일 계산 (가로폭에 맞춤)
|
||||
const scale = availableWidth / screenWidth;
|
||||
// 가로/세로 비율을 모두 고려하여 작은 쪽에 맞춤 (화면이 잘리지 않도록)
|
||||
const scaleX = availableWidth / screenWidth;
|
||||
const scaleY = availableHeight / screenHeight;
|
||||
const scale = Math.min(scaleX, scaleY, 1); // 최대 1배율 (확대 방지)
|
||||
|
||||
console.log("📐 미리보기 스케일 계산:", {
|
||||
screenWidth,
|
||||
screenHeight,
|
||||
availableWidth,
|
||||
availableHeight,
|
||||
scaleX,
|
||||
scaleY,
|
||||
finalScale: scale,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -1416,115 +1433,61 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
);
|
||||
}
|
||||
|
||||
// 라벨 표시 여부 계산
|
||||
const templateTypes = ["datatable"];
|
||||
const shouldShowLabel =
|
||||
component.style?.labelDisplay !== false &&
|
||||
(component.label || component.style?.labelText) &&
|
||||
!templateTypes.includes(component.type);
|
||||
|
||||
const labelText = component.style?.labelText || component.label || "";
|
||||
const labelStyle = {
|
||||
fontSize: component.style?.labelFontSize || "14px",
|
||||
color: component.style?.labelColor || "#212121",
|
||||
fontWeight: component.style?.labelFontWeight || "500",
|
||||
backgroundColor: component.style?.labelBackgroundColor || "transparent",
|
||||
};
|
||||
const labelMarginBottom = component.style?.labelMarginBottom || "4px";
|
||||
|
||||
// 일반 컴포넌트 렌더링
|
||||
// 일반 컴포넌트 렌더링 - RealtimePreview 사용 (실제 화면과 동일)
|
||||
return (
|
||||
<div key={component.id}>
|
||||
{/* 라벨을 외부에 별도로 렌더링 */}
|
||||
{shouldShowLabel && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: `${component.position.x}px`,
|
||||
top: `${component.position.y - 25}px`, // 컴포넌트 위쪽에 라벨 배치
|
||||
zIndex: (component.position.z || 1) + 1,
|
||||
...labelStyle,
|
||||
}}
|
||||
>
|
||||
{labelText}
|
||||
{component.required && <span style={{ color: "#f97316", marginLeft: "2px" }}>*</span>}
|
||||
</div>
|
||||
)}
|
||||
<RealtimePreview
|
||||
key={component.id}
|
||||
component={component}
|
||||
isSelected={false}
|
||||
isDesignMode={false}
|
||||
onClick={() => {}}
|
||||
screenId={screenToPreview!.screenId}
|
||||
tableName={screenToPreview?.tableName}
|
||||
formData={previewFormData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setPreviewFormData((prev) => ({
|
||||
...prev,
|
||||
[fieldName]: value,
|
||||
}));
|
||||
}}
|
||||
>
|
||||
{/* 자식 컴포넌트들 */}
|
||||
{(component.type === "group" ||
|
||||
component.type === "container" ||
|
||||
component.type === "area") &&
|
||||
previewLayout.components
|
||||
.filter((child: any) => child.parentId === component.id)
|
||||
.map((child: any) => {
|
||||
// 자식 컴포넌트의 위치를 부모 기준 상대 좌표로 조정
|
||||
const relativeChildComponent = {
|
||||
...child,
|
||||
position: {
|
||||
x: child.position.x - component.position.x,
|
||||
y: child.position.y - component.position.y,
|
||||
z: child.position.z || 1,
|
||||
},
|
||||
};
|
||||
|
||||
{/* 실제 컴포넌트 */}
|
||||
<div
|
||||
style={(() => {
|
||||
const style = {
|
||||
position: "absolute" as const,
|
||||
left: `${component.position.x}px`,
|
||||
top: `${component.position.y}px`,
|
||||
width: component.style?.width || `${component.size.width}px`,
|
||||
height: component.style?.height || `${component.size.height}px`,
|
||||
zIndex: component.position.z || 1,
|
||||
};
|
||||
|
||||
return style;
|
||||
})()}
|
||||
>
|
||||
{/* 위젯 컴포넌트가 아닌 경우 DynamicComponentRenderer 사용 */}
|
||||
{component.type !== "widget" ? (
|
||||
<DynamicComponentRenderer
|
||||
component={{
|
||||
...component,
|
||||
style: {
|
||||
...component.style,
|
||||
labelDisplay: shouldShowLabel ? false : (component.style?.labelDisplay ?? true), // 상위에서 라벨을 표시했으면 컴포넌트 내부에서는 숨김
|
||||
},
|
||||
}}
|
||||
isInteractive={true}
|
||||
formData={previewFormData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setPreviewFormData((prev) => ({
|
||||
...prev,
|
||||
[fieldName]: value,
|
||||
}));
|
||||
}}
|
||||
screenId={screenToPreview!.screenId}
|
||||
tableName={screenToPreview?.tableName}
|
||||
/>
|
||||
) : (
|
||||
<DynamicWebTypeRenderer
|
||||
webType={(() => {
|
||||
// 유틸리티 함수로 파일 컴포넌트 감지
|
||||
if (isFileComponent(component)) {
|
||||
return "file";
|
||||
}
|
||||
// 다른 컴포넌트는 유틸리티 함수로 webType 결정
|
||||
return getComponentWebType(component) || "text";
|
||||
})()}
|
||||
config={component.webTypeConfig}
|
||||
props={{
|
||||
component: component,
|
||||
value: previewFormData[component.columnName || component.id] || "",
|
||||
onChange: (value: any) => {
|
||||
const fieldName = component.columnName || component.id;
|
||||
setPreviewFormData((prev) => ({
|
||||
...prev,
|
||||
[fieldName]: value,
|
||||
}));
|
||||
},
|
||||
onFormDataChange: (fieldName, value) => {
|
||||
setPreviewFormData((prev) => ({
|
||||
...prev,
|
||||
[fieldName]: value,
|
||||
}));
|
||||
},
|
||||
isInteractive: true,
|
||||
formData: previewFormData,
|
||||
readonly: component.readonly,
|
||||
required: component.required,
|
||||
placeholder: component.placeholder,
|
||||
className: "w-full h-full",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<RealtimePreview
|
||||
key={child.id}
|
||||
component={relativeChildComponent}
|
||||
isSelected={false}
|
||||
isDesignMode={false}
|
||||
onClick={() => {}}
|
||||
screenId={screenToPreview!.screenId}
|
||||
tableName={screenToPreview?.tableName}
|
||||
formData={previewFormData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setPreviewFormData((prev) => ({
|
||||
...prev,
|
||||
[fieldName]: value,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RealtimePreview>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
@@ -1538,8 +1501,9 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TableOptionsProvider>
|
||||
</div>
|
||||
</TableOptionsProvider>
|
||||
</ScreenPreviewProvider>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setPreviewDialogOpen(false)}>
|
||||
닫기
|
||||
|
||||
@@ -12,6 +12,7 @@ import { GroupingPanel } from "@/components/screen/table-options/GroupingPanel";
|
||||
import { TableFilter } from "@/types/table-options";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { ModernDatePicker } from "@/components/screen/filters/ModernDatePicker";
|
||||
import { useScreenPreview } from "@/contexts/ScreenPreviewContext";
|
||||
|
||||
interface PresetFilter {
|
||||
id: string;
|
||||
@@ -44,6 +45,7 @@ interface TableSearchWidgetProps {
|
||||
|
||||
export function TableSearchWidget({ component, screenId, onHeightChange }: TableSearchWidgetProps) {
|
||||
const { registeredTables, selectedTableId, setSelectedTableId, getTable } = useTableOptions();
|
||||
const { isPreviewMode } = useScreenPreview(); // 미리보기 모드 확인
|
||||
|
||||
// 높이 관리 context (실제 화면에서만 사용)
|
||||
let setWidgetHeight:
|
||||
@@ -445,14 +447,14 @@ export function TableSearchWidget({ component, screenId, onHeightChange }: Table
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 동적 모드일 때만 설정 버튼들 표시 */}
|
||||
{/* 동적 모드일 때만 설정 버튼들 표시 (미리보기에서는 비활성화) */}
|
||||
{filterMode === "dynamic" && (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setColumnVisibilityOpen(true)}
|
||||
disabled={!selectedTableId}
|
||||
onClick={() => !isPreviewMode && setColumnVisibilityOpen(true)}
|
||||
disabled={!selectedTableId || isPreviewMode}
|
||||
className="h-8 text-xs sm:h-9 sm:text-sm"
|
||||
>
|
||||
<Settings className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
|
||||
@@ -462,8 +464,8 @@ export function TableSearchWidget({ component, screenId, onHeightChange }: Table
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setFilterOpen(true)}
|
||||
disabled={!selectedTableId}
|
||||
onClick={() => !isPreviewMode && setFilterOpen(true)}
|
||||
disabled={!selectedTableId || isPreviewMode}
|
||||
className="h-8 text-xs sm:h-9 sm:text-sm"
|
||||
>
|
||||
<Filter className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
|
||||
@@ -473,8 +475,8 @@ export function TableSearchWidget({ component, screenId, onHeightChange }: Table
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setGroupingOpen(true)}
|
||||
disabled={!selectedTableId}
|
||||
onClick={() => !isPreviewMode && setGroupingOpen(true)}
|
||||
disabled={!selectedTableId || isPreviewMode}
|
||||
className="h-8 text-xs sm:h-9 sm:text-sm"
|
||||
>
|
||||
<Layers className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
|
||||
|
||||
Reference in New Issue
Block a user