[251122] fix: DetailPanel ThemeButton
🕐 커밋 시간: 2025. 11. 22. 22:11:22 📊 변경 통계: • 총 파일: 3개 • 추가: +91줄 • 삭제: -7줄 📁 추가된 파일: + com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/heightCalculator.js 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/heightCalculator.js (javascript): ✅ Added: handleResize() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선
This commit is contained in:
@@ -15,6 +15,7 @@ import couponImg from '../../../../assets/images/icons/coupon.png';
|
|||||||
// import Spottable from '@enact/spotlight/Spottable';
|
// import Spottable from '@enact/spotlight/Spottable';
|
||||||
//image
|
//image
|
||||||
import arrowDown from '../../../../assets/images/icons/ic_arrow_down_3x_new.png';
|
import arrowDown from '../../../../assets/images/icons/ic_arrow_down_3x_new.png';
|
||||||
|
import arrowDownIcon from '../../../../assets/images/icons/ic-arrow-down.svg';
|
||||||
import indicatorDefaultImage from '../../../../assets/images/img-thumb-empty-144@3x.png';
|
import indicatorDefaultImage from '../../../../assets/images/img-thumb-empty-144@3x.png';
|
||||||
import { setHidePopup, setShowPopup } from '../../../actions/commonActions.js';
|
import { setHidePopup, setShowPopup } from '../../../actions/commonActions.js';
|
||||||
import {
|
import {
|
||||||
@@ -1452,15 +1453,22 @@ export default function ProductAllSection({
|
|||||||
})()} */}
|
})()} */}
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{panelInfo && panelInfo.type === 'theme' && !openThemeItemOverlay && (
|
{/* Theme Item Button - 새로운 bottomButtonWrapper로 감싸기 */}
|
||||||
<TButton
|
{/* {panelInfo && panelInfo.type === 'theme' && !openThemeItemOverlay && ( */}
|
||||||
|
<Container
|
||||||
|
className={css.bottomButtonWrapper}
|
||||||
|
spotlightId="theme-item-button-container"
|
||||||
|
>
|
||||||
|
<div
|
||||||
className={css.themeButton}
|
className={css.themeButton}
|
||||||
onClick={handleThemeItemButtonClick}
|
onClick={handleThemeItemButtonClick}
|
||||||
spotlightId="theme-open-button"
|
spotlightId="theme-open-button"
|
||||||
>
|
>
|
||||||
{$L('THEME ITEM')}
|
<div>{$L('THEME ITEM')}</div>
|
||||||
</TButton>
|
<img src={arrowDownIcon} className={css.themeButtonIcon} />
|
||||||
)}
|
</div>
|
||||||
|
</Container>
|
||||||
|
{/* )} */}
|
||||||
|
|
||||||
<DetailMobileSendPopUp
|
<DetailMobileSendPopUp
|
||||||
ismobileSendPopupOpen={mobileSendPopupOpen}
|
ismobileSendPopupOpen={mobileSendPopupOpen}
|
||||||
|
|||||||
@@ -661,6 +661,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Theme Item Button을 위한 새로운 Wrapper
|
||||||
|
.bottomButtonWrapper {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 40px; // 바닥에서 40px 마진
|
||||||
|
left: 60px; // 왼쪽에서 60px
|
||||||
|
width: 635px; // 고정 너비
|
||||||
|
min-width: 13.5rem; // 최소 너비
|
||||||
|
max-width: 27.08333rem; // 최대 너비
|
||||||
|
letter-spacing: -0.75px; // 자간 조정
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.productDetailsButton,
|
.productDetailsButton,
|
||||||
.userReviewsButton,
|
.userReviewsButton,
|
||||||
.youMayLikeButton {
|
.youMayLikeButton {
|
||||||
@@ -689,6 +707,64 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.productDetailsButton,
|
||||||
|
.userReviewsButton,
|
||||||
|
.youMayLikeButton {
|
||||||
|
align-self: stretch;
|
||||||
|
height: 60px;
|
||||||
|
background: rgba(255, 255, 255, 0.05); // 기본 회색 배경
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
color: #eaeaea;
|
||||||
|
font-size: 25px;
|
||||||
|
font-family: @baseFont; // LG Smart 폰트 사용
|
||||||
|
font-weight: 400; // Bold에서 Regular로 변경
|
||||||
|
line-height: 35px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: @PRIMARY_COLOR_RED; // 포커스시만 빨간색
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border: 4px solid #4f172c;
|
||||||
|
background: #4f172c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.themeButton {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
padding: 20px 30px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 6px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
font-size: 25px;
|
||||||
|
font-family: @baseFont; // LG Smart UI
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 35px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: @PRIMARY_COLOR_RED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.themeButtonIcon {
|
||||||
|
width: 52.5px;
|
||||||
|
height: 31.25px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
.addToCartButton {
|
.addToCartButton {
|
||||||
flex: 1 1 0% !important;
|
flex: 1 1 0% !important;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// InfoSection 높이 측정을 위한 유틸리티 함수
|
||||||
|
|
||||||
|
// InfoSection 내부 요소들의 높이를 계산하는 함수
|
||||||
|
export const calculateInfoSectionHeight = (infoSectionElement) => {
|
||||||
|
if (!infoSectionElement) {
|
||||||
|
console.error('InfoSection element not found');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
// 전체 InfoSection 높이
|
||||||
|
totalHeight: infoSectionElement.offsetHeight || infoSectionElement.clientHeight,
|
||||||
|
|
||||||
|
// 내부 요소들의 높이
|
||||||
|
elements: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 주요 요소들의 높이 측정
|
||||||
|
const selectors = [
|
||||||
|
'.leftInfoContainer', // 전체 왼쪽 컨테이너
|
||||||
|
'.leftInfoWrapper', // 내부 래퍼
|
||||||
|
'.headerContent', // 헤더 콘텐츠 (태그, 별점)
|
||||||
|
'.productOverview', // 제품 개요
|
||||||
|
'.qrWrapper', // QR 코드
|
||||||
|
'.buttonStackContainer', // 버튼 스택 컨테이너
|
||||||
|
'.couponStackContainer', // 쿠폰 스택 (있을 경우)
|
||||||
|
'.buyNowCartContainer', // BUY NOW + ADD TO CART (있을 경우)
|
||||||
|
'.buttonContainer', // SHOP BY MOBILE (있을 경우)
|
||||||
|
'.callToOrderSection', // 전화 주문 섹션
|
||||||
|
'.actionButtonsWrapper', // PRODUCT DETAILS, USER REVIEWS, YOU MAY ALSO LIKE
|
||||||
|
'.themeButton', // THEME ITEM 버튼
|
||||||
|
'.DetailMobileSendPopUp', // 모바일 전송 팝업
|
||||||
|
];
|
||||||
|
|
||||||
|
selectors.forEach((selector) => {
|
||||||
|
const element = infoSectionElement.querySelector(selector);
|
||||||
|
if (element) {
|
||||||
|
result.elements[selector] = {
|
||||||
|
height: element.offsetHeight,
|
||||||
|
clientHeight: element.clientHeight,
|
||||||
|
scrollHeight: element.scrollHeight,
|
||||||
|
marginTop: parseInt(window.getComputedStyle(element).marginTop) || 0,
|
||||||
|
marginBottom: parseInt(window.getComputedStyle(element).marginBottom) || 0,
|
||||||
|
paddingTop: parseInt(window.getComputedStyle(element).paddingTop) || 0,
|
||||||
|
paddingBottom: parseInt(window.getComputedStyle(element).paddingBottom) || 0,
|
||||||
|
isVisible: element.offsetParent !== null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 실제 사용된 높이 계산
|
||||||
|
const calculatedHeight = Object.values(result.elements).reduce((total, element) => {
|
||||||
|
if (element && element.isVisible) {
|
||||||
|
return total + element.height + element.marginTop + element.marginBottom;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
result.calculatedHeight = calculatedHeight;
|
||||||
|
result.remainingSpace = result.totalHeight - calculatedHeight;
|
||||||
|
result.isOverflowing = calculatedHeight > result.totalHeight;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// React Hook으로 만든 버전
|
||||||
|
export const useInfoSectionHeight = (infoSectionRef) => {
|
||||||
|
const [heightInfo, setHeightInfo] = useState(null);
|
||||||
|
|
||||||
|
const measureHeight = useCallback(() => {
|
||||||
|
if (infoSectionRef.current) {
|
||||||
|
const info = calculateInfoSectionHeight(infoSectionRef.current);
|
||||||
|
setHeightInfo(info);
|
||||||
|
console.log('InfoSection Height Info:', info);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}, [infoSectionRef]);
|
||||||
|
|
||||||
|
// 컴포넌트 마운트 시 측정
|
||||||
|
useEffect(() => {
|
||||||
|
measureHeight();
|
||||||
|
}, [measureHeight]);
|
||||||
|
|
||||||
|
// 윈도우 리사이즈 시 재측정 (선택사항)
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
measureHeight();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [measureHeight]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
heightInfo,
|
||||||
|
measureHeight,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 사용 예시:
|
||||||
|
// const infoSectionRef = useRef(null);
|
||||||
|
// const { heightInfo, measureHeight } = useInfoSectionHeight(infoSectionRef);
|
||||||
|
//
|
||||||
|
// // JSX에서
|
||||||
|
// <div ref={infoSectionRef} className={css.infoSection}>
|
||||||
|
// ... content ...
|
||||||
|
// </div>
|
||||||
Reference in New Issue
Block a user