리사이징 유지와 연속작성 구현 모달 살짝 늘어나는 문제 해결
This commit is contained in:
parent
55204dd38c
commit
f286b6c695
|
|
@ -57,16 +57,18 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
// 폼 데이터 상태 추가
|
// 폼 데이터 상태 추가
|
||||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
// 연속 등록 모드 상태 (localStorage에 저장하여 리렌더링에 영향받지 않도록)
|
// 연속 등록 모드 상태 (state로 변경 - 체크박스 UI 업데이트를 위해)
|
||||||
const continuousModeRef = useRef(false);
|
const [continuousMode, setContinuousMode] = useState(false);
|
||||||
const [, setForceUpdate] = useState(0); // 강제 리렌더링용 (값은 사용하지 않음)
|
|
||||||
|
// 화면 리셋 키 (컴포넌트 강제 리마운트용)
|
||||||
|
const [resetKey, setResetKey] = useState(0);
|
||||||
|
|
||||||
// localStorage에서 연속 모드 상태 복원
|
// localStorage에서 연속 모드 상태 복원
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedMode = localStorage.getItem("screenModal_continuousMode");
|
const savedMode = localStorage.getItem("screenModal_continuousMode");
|
||||||
if (savedMode === "true") {
|
if (savedMode === "true") {
|
||||||
continuousModeRef.current = true;
|
setContinuousMode(true);
|
||||||
// console.log("🔄 연속 모드 복원: true");
|
console.log("🔄 연속 모드 복원: true");
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -162,29 +164,39 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
});
|
});
|
||||||
setScreenData(null);
|
setScreenData(null);
|
||||||
setFormData({});
|
setFormData({});
|
||||||
continuousModeRef.current = false;
|
setContinuousMode(false);
|
||||||
localStorage.setItem("screenModal_continuousMode", "false"); // localStorage에 저장
|
localStorage.setItem("screenModal_continuousMode", "false"); // localStorage에 저장
|
||||||
// console.log("🔄 연속 모드 초기화: false");
|
console.log("🔄 연속 모드 초기화: false");
|
||||||
};
|
};
|
||||||
|
|
||||||
// 저장 성공 이벤트 처리 (연속 등록 모드 지원)
|
// 저장 성공 이벤트 처리 (연속 등록 모드 지원)
|
||||||
const handleSaveSuccess = () => {
|
const handleSaveSuccess = () => {
|
||||||
const isContinuousMode = continuousModeRef.current;
|
const isContinuousMode = continuousMode;
|
||||||
// console.log("💾 저장 성공 이벤트 수신");
|
console.log("💾 저장 성공 이벤트 수신");
|
||||||
// console.log("📌 현재 연속 모드 상태 (ref):", isContinuousMode);
|
console.log("📌 현재 연속 모드 상태:", isContinuousMode);
|
||||||
// console.log("📌 localStorage:", localStorage.getItem("screenModal_continuousMode"));
|
console.log("📌 localStorage:", localStorage.getItem("screenModal_continuousMode"));
|
||||||
|
|
||||||
if (isContinuousMode) {
|
if (isContinuousMode) {
|
||||||
// 연속 모드: 폼만 초기화하고 모달은 유지
|
// 연속 모드: 폼만 초기화하고 모달은 유지
|
||||||
// console.log("✅ 연속 모드 활성화 - 폼만 초기화");
|
console.log("✅ 연속 모드 활성화 - 폼 초기화 및 화면 리셋");
|
||||||
|
|
||||||
// 폼만 초기화 (연속 모드 상태는 localStorage에 저장되어 있으므로 유지됨)
|
// 1. 폼 데이터 초기화
|
||||||
setFormData({});
|
setFormData({});
|
||||||
|
|
||||||
|
// 2. 리셋 키 변경 (컴포넌트 강제 리마운트)
|
||||||
|
setResetKey(prev => prev + 1);
|
||||||
|
console.log("🔄 resetKey 증가 - 컴포넌트 리마운트");
|
||||||
|
|
||||||
|
// 3. 화면 데이터 다시 로드 (채번 규칙 새로 생성)
|
||||||
|
if (modalState.screenId) {
|
||||||
|
console.log("🔄 화면 데이터 다시 로드:", modalState.screenId);
|
||||||
|
loadScreenData(modalState.screenId);
|
||||||
|
}
|
||||||
|
|
||||||
toast.success("저장되었습니다. 계속 입력하세요.");
|
toast.success("저장되었습니다. 계속 입력하세요.");
|
||||||
} else {
|
} else {
|
||||||
// 일반 모드: 모달 닫기
|
// 일반 모드: 모달 닫기
|
||||||
// console.log("❌ 일반 모드 - 모달 닫기");
|
console.log("❌ 일반 모드 - 모달 닫기");
|
||||||
handleCloseModal();
|
handleCloseModal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -198,7 +210,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
window.removeEventListener("closeSaveModal", handleCloseModal);
|
window.removeEventListener("closeSaveModal", handleCloseModal);
|
||||||
window.removeEventListener("saveSuccessInModal", handleSaveSuccess);
|
window.removeEventListener("saveSuccessInModal", handleSaveSuccess);
|
||||||
};
|
};
|
||||||
}, []); // 의존성 제거 (ref 사용으로 최신 상태 참조)
|
}, [continuousMode]); // continuousMode 의존성 추가
|
||||||
|
|
||||||
// 화면 데이터 로딩
|
// 화면 데이터 로딩
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -415,18 +427,21 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
setFormData({}); // 폼 데이터 초기화
|
setFormData({}); // 폼 데이터 초기화
|
||||||
};
|
};
|
||||||
|
|
||||||
// 모달 크기 설정 - 화면 내용에 맞게 동적 조정
|
// 모달 크기 설정 - 화면관리 설정 크기 + 헤더/푸터
|
||||||
const getModalStyle = () => {
|
const getModalStyle = () => {
|
||||||
if (!screenDimensions) {
|
if (!screenDimensions) {
|
||||||
return {
|
return {
|
||||||
className: "w-fit min-w-[400px] max-w-4xl max-h-[90vh] overflow-hidden p-0",
|
className: "w-fit min-w-[400px] max-w-4xl max-h-[90vh] overflow-hidden p-0",
|
||||||
style: {},
|
style: undefined, // undefined로 변경 - defaultWidth/defaultHeight 사용
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 헤더 높이를 최소화 (제목 영역만)
|
// 화면관리에서 설정한 크기 = 컨텐츠 영역 크기
|
||||||
const headerHeight = 60; // DialogHeader 최소 높이 (타이틀 + 최소 패딩)
|
// 실제 모달 크기 = 컨텐츠 + 헤더 + 연속등록 체크박스
|
||||||
const totalHeight = screenDimensions.height + headerHeight;
|
const headerHeight = 60; // DialogHeader (타이틀 + 패딩)
|
||||||
|
const footerHeight = 52; // 연속 등록 모드 체크박스 영역
|
||||||
|
|
||||||
|
const totalHeight = screenDimensions.height + headerHeight + footerHeight;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
className: "overflow-hidden p-0",
|
className: "overflow-hidden p-0",
|
||||||
|
|
@ -504,7 +519,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
<ResizableDialog open={modalState.isOpen} onOpenChange={handleClose}>
|
<ResizableDialog open={modalState.isOpen} onOpenChange={handleClose}>
|
||||||
<ResizableDialogContent
|
<ResizableDialogContent
|
||||||
className={`${modalStyle.className} ${className || ""}`}
|
className={`${modalStyle.className} ${className || ""}`}
|
||||||
style={modalStyle.style}
|
{...(modalStyle.style && { style: modalStyle.style })} // undefined일 때는 prop 자체를 전달하지 않음
|
||||||
defaultWidth={600}
|
defaultWidth={600}
|
||||||
defaultHeight={800}
|
defaultHeight={800}
|
||||||
minWidth={500}
|
minWidth={500}
|
||||||
|
|
@ -530,7 +545,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
</div>
|
</div>
|
||||||
</ResizableDialogHeader>
|
</ResizableDialogHeader>
|
||||||
|
|
||||||
<div className="flex-1 overflow-auto p-6">
|
<div className="flex-1 overflow-auto">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex h-full items-center justify-center">
|
<div className="flex h-full items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
|
|
@ -568,7 +583,7 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InteractiveScreenViewerDynamic
|
<InteractiveScreenViewerDynamic
|
||||||
key={component.id}
|
key={`${component.id}-${resetKey}`}
|
||||||
component={adjustedComponent}
|
component={adjustedComponent}
|
||||||
allComponents={screenData.components}
|
allComponents={screenData.components}
|
||||||
formData={formData}
|
formData={formData}
|
||||||
|
|
@ -607,13 +622,12 @@ export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="continuous-mode"
|
id="continuous-mode"
|
||||||
checked={continuousModeRef.current}
|
checked={continuousMode}
|
||||||
onCheckedChange={(checked) => {
|
onCheckedChange={(checked) => {
|
||||||
const isChecked = checked === true;
|
const isChecked = checked === true;
|
||||||
continuousModeRef.current = isChecked;
|
setContinuousMode(isChecked);
|
||||||
localStorage.setItem("screenModal_continuousMode", String(isChecked));
|
localStorage.setItem("screenModal_continuousMode", String(isChecked));
|
||||||
setForceUpdate((prev) => prev + 1); // 체크박스 UI 업데이트를 위한 강제 리렌더링
|
console.log("🔄 연속 모드 변경:", isChecked);
|
||||||
// console.log("🔄 연속 모드 변경:", isChecked);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="continuous-mode" className="cursor-pointer text-sm font-normal select-none">
|
<Label htmlFor="continuous-mode" className="cursor-pointer text-sm font-normal select-none">
|
||||||
|
|
|
||||||
|
|
@ -92,18 +92,18 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
||||||
const contentWidth = maxX - minX;
|
const contentWidth = maxX - minX;
|
||||||
const contentHeight = maxY - minY;
|
const contentHeight = maxY - minY;
|
||||||
|
|
||||||
// 적절한 여백 추가
|
// 적절한 여백 추가 (주석처리 - 사용자 설정 크기 그대로 사용)
|
||||||
const paddingX = 40;
|
// const paddingX = 40;
|
||||||
const paddingY = 40;
|
// const paddingY = 40;
|
||||||
|
|
||||||
const finalWidth = Math.max(contentWidth + paddingX, 400);
|
const finalWidth = Math.max(contentWidth, 400); // padding 제거
|
||||||
const finalHeight = Math.max(contentHeight + paddingY, 300);
|
const finalHeight = Math.max(contentHeight, 300); // padding 제거
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: Math.min(finalWidth, window.innerWidth * 0.95),
|
width: Math.min(finalWidth, window.innerWidth * 0.95),
|
||||||
height: Math.min(finalHeight, window.innerHeight * 0.9),
|
height: Math.min(finalHeight, window.innerHeight * 0.9),
|
||||||
offsetX: Math.max(0, minX - paddingX / 2),
|
offsetX: Math.max(0, minX), // paddingX 제거
|
||||||
offsetY: Math.max(0, minY - paddingY / 2),
|
offsetY: Math.max(0, minY), // paddingY 제거
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -269,16 +269,18 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 모달 크기 설정 - ScreenModal과 동일
|
// 모달 크기 설정 - 화면관리 설정 크기 + 헤더
|
||||||
const getModalStyle = () => {
|
const getModalStyle = () => {
|
||||||
if (!screenDimensions) {
|
if (!screenDimensions) {
|
||||||
return {
|
return {
|
||||||
className: "w-fit min-w-[400px] max-w-4xl max-h-[90vh] overflow-hidden p-0",
|
className: "w-fit min-w-[400px] max-w-4xl max-h-[90vh] overflow-hidden p-0",
|
||||||
style: {},
|
style: undefined, // undefined로 변경 - defaultWidth/defaultHeight 사용
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerHeight = 60;
|
// 화면관리에서 설정한 크기 = 컨텐츠 영역 크기
|
||||||
|
// 실제 모달 크기 = 컨텐츠 + 헤더
|
||||||
|
const headerHeight = 60; // DialogHeader
|
||||||
const totalHeight = screenDimensions.height + headerHeight;
|
const totalHeight = screenDimensions.height + headerHeight;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -216,10 +216,16 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
||||||
return y + height;
|
return y + height;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const padding = 40;
|
// 컨텐츠 영역 크기 (화면관리 설정 크기)
|
||||||
|
const contentWidth = Math.max(maxX, 400);
|
||||||
|
const contentHeight = Math.max(maxY, 300);
|
||||||
|
|
||||||
|
// 실제 모달 크기 = 컨텐츠 + 헤더
|
||||||
|
const headerHeight = 60; // DialogHeader
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: Math.max(maxX + padding, 400),
|
width: contentWidth,
|
||||||
height: Math.max(maxY + padding, 300),
|
height: contentHeight + headerHeight, // 헤더 높이 포함
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -229,8 +235,12 @@ export const SaveModal: React.FC<SaveModalProps> = ({
|
||||||
<ResizableDialog open={isOpen} onOpenChange={(open) => !isSaving && !open && onClose()}>
|
<ResizableDialog open={isOpen} onOpenChange={(open) => !isSaving && !open && onClose()}>
|
||||||
<ResizableDialogContent
|
<ResizableDialogContent
|
||||||
modalId={`save-modal-${screenId}`}
|
modalId={`save-modal-${screenId}`}
|
||||||
defaultWidth={dynamicSize.width + 48}
|
style={{
|
||||||
defaultHeight={dynamicSize.height + 120}
|
width: `${dynamicSize.width}px`,
|
||||||
|
height: `${dynamicSize.height}px`, // 화면관리 설정 크기 그대로 사용
|
||||||
|
}}
|
||||||
|
defaultWidth={600} // 폴백용 기본값
|
||||||
|
defaultHeight={400} // 폴백용 기본값
|
||||||
minWidth={400}
|
minWidth={400}
|
||||||
minHeight={300}
|
minHeight={300}
|
||||||
className="gap-0 p-0"
|
className="gap-0 p-0"
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,10 @@ const ResizableDialogContent = React.forwardRef<
|
||||||
|
|
||||||
// 1순위: userStyle에서 크기 추출 (화면관리에서 지정한 크기 - 항상 초기값으로 사용)
|
// 1순위: userStyle에서 크기 추출 (화면관리에서 지정한 크기 - 항상 초기값으로 사용)
|
||||||
if (userStyle) {
|
if (userStyle) {
|
||||||
|
console.log("🔍 userStyle 감지:", userStyle);
|
||||||
|
console.log("🔍 userStyle.width 타입:", typeof userStyle.width, "값:", userStyle.width);
|
||||||
|
console.log("🔍 userStyle.height 타입:", typeof userStyle.height, "값:", userStyle.height);
|
||||||
|
|
||||||
const styleWidth = typeof userStyle.width === 'string'
|
const styleWidth = typeof userStyle.width === 'string'
|
||||||
? parseInt(userStyle.width)
|
? parseInt(userStyle.width)
|
||||||
: userStyle.width;
|
: userStyle.width;
|
||||||
|
|
@ -129,24 +133,41 @@ const ResizableDialogContent = React.forwardRef<
|
||||||
? parseInt(userStyle.height)
|
? parseInt(userStyle.height)
|
||||||
: userStyle.height;
|
: userStyle.height;
|
||||||
|
|
||||||
|
console.log("📏 파싱된 크기:", {
|
||||||
|
styleWidth,
|
||||||
|
styleHeight,
|
||||||
|
"styleWidth truthy?": !!styleWidth,
|
||||||
|
"styleHeight truthy?": !!styleHeight,
|
||||||
|
minWidth,
|
||||||
|
maxWidth,
|
||||||
|
minHeight,
|
||||||
|
maxHeight
|
||||||
|
});
|
||||||
|
|
||||||
if (styleWidth && styleHeight) {
|
if (styleWidth && styleHeight) {
|
||||||
return {
|
const finalSize = {
|
||||||
width: Math.max(minWidth, Math.min(maxWidth, styleWidth)),
|
width: Math.max(minWidth, Math.min(maxWidth, styleWidth)),
|
||||||
height: Math.max(minHeight, Math.min(maxHeight, styleHeight)),
|
height: Math.max(minHeight, Math.min(maxHeight, styleHeight)),
|
||||||
};
|
};
|
||||||
|
console.log("✅ userStyle 크기 사용:", finalSize);
|
||||||
|
return finalSize;
|
||||||
|
} else {
|
||||||
|
console.log("❌ styleWidth 또는 styleHeight가 falsy:", { styleWidth, styleHeight });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2순위: 현재 렌더링된 크기 사용
|
console.log("⚠️ userStyle 없음, defaultWidth/defaultHeight 사용:", { defaultWidth, defaultHeight });
|
||||||
if (contentRef.current) {
|
|
||||||
const rect = contentRef.current.getBoundingClientRect();
|
// 2순위: 현재 렌더링된 크기 사용 (주석처리 - 모달이 열린 후 늘어나는 현상 방지)
|
||||||
if (rect.width > 0 && rect.height > 0) {
|
// if (contentRef.current) {
|
||||||
return {
|
// const rect = contentRef.current.getBoundingClientRect();
|
||||||
width: Math.max(minWidth, Math.min(maxWidth, rect.width)),
|
// if (rect.width > 0 && rect.height > 0) {
|
||||||
height: Math.max(minHeight, Math.min(maxHeight, rect.height)),
|
// return {
|
||||||
};
|
// width: Math.max(minWidth, Math.min(maxWidth, rect.width)),
|
||||||
}
|
// height: Math.max(minHeight, Math.min(maxHeight, rect.height)),
|
||||||
}
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// 3순위: defaultWidth/defaultHeight 사용
|
// 3순위: defaultWidth/defaultHeight 사용
|
||||||
return { width: defaultWidth, height: defaultHeight };
|
return { width: defaultWidth, height: defaultHeight };
|
||||||
|
|
@ -156,6 +177,58 @@ const ResizableDialogContent = React.forwardRef<
|
||||||
const [isResizing, setIsResizing] = React.useState(false);
|
const [isResizing, setIsResizing] = React.useState(false);
|
||||||
const [resizeDirection, setResizeDirection] = React.useState<string>("");
|
const [resizeDirection, setResizeDirection] = React.useState<string>("");
|
||||||
const [isInitialized, setIsInitialized] = React.useState(false);
|
const [isInitialized, setIsInitialized] = React.useState(false);
|
||||||
|
|
||||||
|
// userStyle이 변경되면 크기 업데이트 (화면 데이터 로딩 완료 시)
|
||||||
|
React.useEffect(() => {
|
||||||
|
// 1. localStorage에서 사용자가 리사이징한 크기 확인
|
||||||
|
let savedSize: { width: number; height: number; userResized: boolean } | null = null;
|
||||||
|
|
||||||
|
if (effectiveModalId && typeof window !== 'undefined') {
|
||||||
|
try {
|
||||||
|
const storageKey = `modal_size_${effectiveModalId}_${userId}`;
|
||||||
|
const saved = localStorage.getItem(storageKey);
|
||||||
|
|
||||||
|
if (saved) {
|
||||||
|
const parsed = JSON.parse(saved);
|
||||||
|
if (parsed.userResized) {
|
||||||
|
savedSize = {
|
||||||
|
width: Math.max(minWidth, Math.min(maxWidth, parsed.width)),
|
||||||
|
height: Math.max(minHeight, Math.min(maxHeight, parsed.height)),
|
||||||
|
userResized: true,
|
||||||
|
};
|
||||||
|
console.log("💾 사용자가 리사이징한 크기 복원:", savedSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ 모달 크기 복원 실패:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 우선순위: 사용자 리사이징 > userStyle > 기본값
|
||||||
|
if (savedSize && savedSize.userResized) {
|
||||||
|
// 사용자가 리사이징한 크기 우선
|
||||||
|
setSize({ width: savedSize.width, height: savedSize.height });
|
||||||
|
setUserResized(true);
|
||||||
|
console.log("✅ 사용자 리사이징 크기 적용:", savedSize);
|
||||||
|
} else if (userStyle && userStyle.width && userStyle.height) {
|
||||||
|
// 화면관리에서 설정한 크기
|
||||||
|
const styleWidth = typeof userStyle.width === 'string'
|
||||||
|
? parseInt(userStyle.width)
|
||||||
|
: userStyle.width;
|
||||||
|
const styleHeight = typeof userStyle.height === 'string'
|
||||||
|
? parseInt(userStyle.height)
|
||||||
|
: userStyle.height;
|
||||||
|
|
||||||
|
if (styleWidth && styleHeight) {
|
||||||
|
const newSize = {
|
||||||
|
width: Math.max(minWidth, Math.min(maxWidth, styleWidth)),
|
||||||
|
height: Math.max(minHeight, Math.min(maxHeight, styleHeight)),
|
||||||
|
};
|
||||||
|
console.log("🔄 userStyle 크기 적용:", newSize);
|
||||||
|
setSize(newSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [userStyle, minWidth, maxWidth, minHeight, maxHeight, effectiveModalId, userId]);
|
||||||
const [lastModalId, setLastModalId] = React.useState<string | null>(null);
|
const [lastModalId, setLastModalId] = React.useState<string | null>(null);
|
||||||
const [userResized, setUserResized] = React.useState(false); // 사용자가 실제로 리사이징했는지 추적
|
const [userResized, setUserResized] = React.useState(false); // 사용자가 실제로 리사이징했는지 추적
|
||||||
|
|
||||||
|
|
@ -192,97 +265,98 @@ const ResizableDialogContent = React.forwardRef<
|
||||||
}, [effectiveModalId, lastModalId, isInitialized]);
|
}, [effectiveModalId, lastModalId, isInitialized]);
|
||||||
|
|
||||||
// 모달이 열릴 때 초기 크기 설정 (localStorage와 내용 크기 중 큰 값 사용)
|
// 모달이 열릴 때 초기 크기 설정 (localStorage와 내용 크기 중 큰 값 사용)
|
||||||
React.useEffect(() => {
|
// 주석처리 - 사용자가 설정한 크기(userStyle)만 사용하도록 변경
|
||||||
// console.log("🔍 초기 크기 설정 useEffect 실행:", { isInitialized, hasContentRef: !!contentRef.current, effectiveModalId });
|
// React.useEffect(() => {
|
||||||
|
// // console.log("🔍 초기 크기 설정 useEffect 실행:", { isInitialized, hasContentRef: !!contentRef.current, effectiveModalId });
|
||||||
if (!isInitialized) {
|
//
|
||||||
// 내용의 실제 크기 측정 (약간의 지연 후, contentRef가 준비될 때까지 대기)
|
// if (!isInitialized) {
|
||||||
// 여러 번 시도하여 contentRef가 준비될 때까지 대기
|
// // 내용의 실제 크기 측정 (약간의 지연 후, contentRef가 준비될 때까지 대기)
|
||||||
let attempts = 0;
|
// // 여러 번 시도하여 contentRef가 준비될 때까지 대기
|
||||||
const maxAttempts = 10;
|
// let attempts = 0;
|
||||||
|
// const maxAttempts = 10;
|
||||||
const measureContent = () => {
|
//
|
||||||
attempts++;
|
// const measureContent = () => {
|
||||||
|
// attempts++;
|
||||||
// scrollHeight/scrollWidth를 사용하여 실제 내용 크기 측정 (스크롤 포함)
|
//
|
||||||
let contentWidth = defaultWidth;
|
// // scrollHeight/scrollWidth를 사용하여 실제 내용 크기 측정 (스크롤 포함)
|
||||||
let contentHeight = defaultHeight;
|
// let contentWidth = defaultWidth;
|
||||||
|
// let contentHeight = defaultHeight;
|
||||||
if (contentRef.current) {
|
//
|
||||||
// scrollHeight/scrollWidth 그대로 사용 (여유 공간 제거)
|
// // if (contentRef.current) {
|
||||||
contentWidth = contentRef.current.scrollWidth || defaultWidth;
|
// // // scrollHeight/scrollWidth 그대로 사용 (여유 공간 제거)
|
||||||
contentHeight = contentRef.current.scrollHeight || defaultHeight;
|
// // contentWidth = contentRef.current.scrollWidth || defaultWidth;
|
||||||
|
// // contentHeight = contentRef.current.scrollHeight || defaultHeight;
|
||||||
// console.log("📏 모달 내용 크기 측정:", { attempt: attempts, scrollWidth: contentRef.current.scrollWidth, scrollHeight: contentRef.current.scrollHeight, clientWidth: contentRef.current.clientWidth, clientHeight: contentRef.current.clientHeight, contentWidth, contentHeight });
|
// //
|
||||||
} else {
|
// // // console.log("📏 모달 내용 크기 측정:", { attempt: attempts, scrollWidth: contentRef.current.scrollWidth, scrollHeight: contentRef.current.scrollHeight, clientWidth: contentRef.current.clientWidth, clientHeight: contentRef.current.clientHeight, contentWidth, contentHeight });
|
||||||
// console.log("⚠️ contentRef 없음, 재시도:", { attempt: attempts, maxAttempts, defaultWidth, defaultHeight });
|
// // } else {
|
||||||
|
// // // console.log("⚠️ contentRef 없음, 재시도:", { attempt: attempts, maxAttempts, defaultWidth, defaultHeight });
|
||||||
// contentRef가 아직 없으면 재시도
|
// //
|
||||||
if (attempts < maxAttempts) {
|
// // // contentRef가 아직 없으면 재시도
|
||||||
setTimeout(measureContent, 100);
|
// // if (attempts < maxAttempts) {
|
||||||
return;
|
// // setTimeout(measureContent, 100);
|
||||||
}
|
// // return;
|
||||||
}
|
// // }
|
||||||
|
// // }
|
||||||
// 패딩 추가 (p-6 * 2 = 48px)
|
//
|
||||||
const paddingAndMargin = 48;
|
// // 패딩 추가 (p-6 * 2 = 48px)
|
||||||
const initialSize = getInitialSize();
|
// const paddingAndMargin = 48;
|
||||||
|
// const initialSize = getInitialSize();
|
||||||
// 내용 크기 기반 최소 크기 계산
|
//
|
||||||
const contentBasedSize = {
|
// // 내용 크기 기반 최소 크기 계산
|
||||||
width: Math.max(minWidth, Math.min(maxWidth, Math.max(contentWidth + paddingAndMargin, initialSize.width))),
|
// const contentBasedSize = {
|
||||||
height: Math.max(minHeight, Math.min(maxHeight, Math.max(contentHeight + paddingAndMargin, initialSize.height))),
|
// width: Math.max(minWidth, Math.min(maxWidth, Math.max(contentWidth + paddingAndMargin, initialSize.width))),
|
||||||
};
|
// height: Math.max(minHeight, Math.min(maxHeight, Math.max(contentHeight + paddingAndMargin, initialSize.height))),
|
||||||
|
// };
|
||||||
// console.log("📐 내용 기반 크기:", contentBasedSize);
|
//
|
||||||
|
// // console.log("📐 내용 기반 크기:", contentBasedSize);
|
||||||
// localStorage에서 저장된 크기 확인
|
//
|
||||||
let finalSize = contentBasedSize;
|
// // localStorage에서 저장된 크기 확인
|
||||||
|
// let finalSize = contentBasedSize;
|
||||||
if (effectiveModalId && typeof window !== 'undefined') {
|
//
|
||||||
try {
|
// if (effectiveModalId && typeof window !== 'undefined') {
|
||||||
const storageKey = `modal_size_${effectiveModalId}_${userId}`;
|
// try {
|
||||||
const saved = localStorage.getItem(storageKey);
|
// const storageKey = `modal_size_${effectiveModalId}_${userId}`;
|
||||||
|
// const saved = localStorage.getItem(storageKey);
|
||||||
// console.log("📦 localStorage 확인:", { effectiveModalId, userId, storageKey, saved: saved ? "있음" : "없음" });
|
//
|
||||||
|
// // console.log("📦 localStorage 확인:", { effectiveModalId, userId, storageKey, saved: saved ? "있음" : "없음" });
|
||||||
if (saved) {
|
//
|
||||||
const parsed = JSON.parse(saved);
|
// if (saved) {
|
||||||
|
// const parsed = JSON.parse(saved);
|
||||||
// userResized 플래그 확인
|
//
|
||||||
if (parsed.userResized) {
|
// // userResized 플래그 확인
|
||||||
const savedSize = {
|
// if (parsed.userResized) {
|
||||||
width: Math.max(minWidth, Math.min(maxWidth, parsed.width)),
|
// const savedSize = {
|
||||||
height: Math.max(minHeight, Math.min(maxHeight, parsed.height)),
|
// width: Math.max(minWidth, Math.min(maxWidth, parsed.width)),
|
||||||
};
|
// height: Math.max(minHeight, Math.min(maxHeight, parsed.height)),
|
||||||
|
// };
|
||||||
// console.log("💾 사용자가 리사이징한 크기 복원:", savedSize);
|
//
|
||||||
|
// // console.log("💾 사용자가 리사이징한 크기 복원:", savedSize);
|
||||||
// ✅ 중요: 사용자가 명시적으로 리사이징한 경우, 사용자 크기를 우선 사용
|
//
|
||||||
// (사용자가 의도적으로 작게 만든 것을 존중)
|
// // ✅ 중요: 사용자가 명시적으로 리사이징한 경우, 사용자 크기를 우선 사용
|
||||||
finalSize = savedSize;
|
// // (사용자가 의도적으로 작게 만든 것을 존중)
|
||||||
setUserResized(true);
|
// finalSize = savedSize;
|
||||||
|
// setUserResized(true);
|
||||||
// console.log("✅ 최종 크기 (사용자가 설정한 크기 우선 적용):", { savedSize, contentBasedSize, finalSize, note: "사용자가 리사이징한 크기를 그대로 사용합니다" });
|
//
|
||||||
} else {
|
// // console.log("✅ 최종 크기 (사용자가 설정한 크기 우선 적용):", { savedSize, contentBasedSize, finalSize, note: "사용자가 리사이징한 크기를 그대로 사용합니다" });
|
||||||
// console.log("ℹ️ 자동 계산된 크기는 무시, 내용 크기 사용");
|
// } else {
|
||||||
}
|
// // console.log("ℹ️ 자동 계산된 크기는 무시, 내용 크기 사용");
|
||||||
} else {
|
// }
|
||||||
// console.log("ℹ️ localStorage에 저장된 크기 없음, 내용 크기 사용");
|
// } else {
|
||||||
}
|
// // console.log("ℹ️ localStorage에 저장된 크기 없음, 내용 크기 사용");
|
||||||
} catch (error) {
|
// }
|
||||||
// console.error("❌ 모달 크기 복원 실패:", error);
|
// } catch (error) {
|
||||||
}
|
// // console.error("❌ 모달 크기 복원 실패:", error);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
setSize(finalSize);
|
//
|
||||||
setIsInitialized(true);
|
// setSize(finalSize);
|
||||||
};
|
// setIsInitialized(true);
|
||||||
|
// };
|
||||||
// 첫 시도는 300ms 후에 시작
|
//
|
||||||
setTimeout(measureContent, 300);
|
// // 첫 시도는 300ms 후에 시작
|
||||||
}
|
// setTimeout(measureContent, 300);
|
||||||
}, [isInitialized, getInitialSize, effectiveModalId, userId, minWidth, maxWidth, minHeight, maxHeight, defaultWidth, defaultHeight]);
|
// }
|
||||||
|
// }, [isInitialized, getInitialSize, effectiveModalId, userId, minWidth, maxWidth, minHeight, maxHeight, defaultWidth, defaultHeight]);
|
||||||
|
|
||||||
const startResize = (direction: string) => (e: React.MouseEvent) => {
|
const startResize = (direction: string) => (e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -433,6 +507,37 @@ const ResizableDialogContent = React.forwardRef<
|
||||||
onMouseDown={startResize("nw")}
|
onMouseDown={startResize("nw")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 리셋 버튼 (사용자가 리사이징한 경우만 표시) */}
|
||||||
|
{userResized && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
// localStorage에서 저장된 크기 삭제
|
||||||
|
if (effectiveModalId && typeof window !== 'undefined') {
|
||||||
|
const storageKey = `modal_size_${effectiveModalId}_${userId}`;
|
||||||
|
localStorage.removeItem(storageKey);
|
||||||
|
console.log("🗑️ 저장된 모달 크기 삭제:", storageKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 화면관리 설정 크기로 복원
|
||||||
|
const initialSize = getInitialSize();
|
||||||
|
setSize(initialSize);
|
||||||
|
setUserResized(false);
|
||||||
|
console.log("🔄 기본 크기로 리셋:", initialSize);
|
||||||
|
}}
|
||||||
|
className="absolute right-12 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
||||||
|
style={{ zIndex: 20 }}
|
||||||
|
title="기본 크기로 리셋"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/>
|
||||||
|
<path d="M21 3v5h-5"/>
|
||||||
|
<path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/>
|
||||||
|
<path d="M3 21v-5h5"/>
|
||||||
|
</svg>
|
||||||
|
<span className="sr-only">기본 크기로 리셋</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<DialogPrimitive.Close
|
<DialogPrimitive.Close
|
||||||
className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
||||||
style={{ zIndex: 20 }}
|
style={{ zIndex: 20 }}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue