[상품 상세] 리뷰 및 디테일 변경건.#1
- 디테일부분에 대한 figma 부분과 동일하게 스타일 처리. - 리뷰부분 및 리뷰 팝업 부분 처리중
This commit is contained in:
@@ -39,12 +39,12 @@ import ShowUserReviews from "../../UserReview/ShowUserReviews";
|
|||||||
// CSS imports
|
// CSS imports
|
||||||
// import infoCSS from "../ProductInfoSection/ProductInfoSection.module.less";
|
// import infoCSS from "../ProductInfoSection/ProductInfoSection.module.less";
|
||||||
// import contentCSS from "../ProductContentSection/ProductContentSection.module.less";
|
// import contentCSS from "../ProductContentSection/ProductContentSection.module.less";
|
||||||
import css from "./ProductAllSection.module.less";
|
import css from './ProductAllSection.module.less';
|
||||||
|
|
||||||
const Container = SpotlightContainerDecorator(
|
const Container = SpotlightContainerDecorator(
|
||||||
{
|
{
|
||||||
enterTo: "last-focused",
|
enterTo: "last-focused",
|
||||||
preserveld: true,
|
preserveld: true,
|
||||||
leaveFor: { right: "content-scroller-container" },
|
leaveFor: { right: "content-scroller-container" },
|
||||||
spotlightDirection: "vertical"
|
spotlightDirection: "vertical"
|
||||||
},
|
},
|
||||||
@@ -52,10 +52,10 @@ const Container = SpotlightContainerDecorator(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const ContentContainer = SpotlightContainerDecorator(
|
const ContentContainer = SpotlightContainerDecorator(
|
||||||
{
|
{
|
||||||
enterTo: "default-element",
|
enterTo: "default-element",
|
||||||
preserveld: true,
|
preserveld: true,
|
||||||
leaveFor: {
|
leaveFor: {
|
||||||
left: "spotlight-product-info-section-container"
|
left: "spotlight-product-info-section-container"
|
||||||
},
|
},
|
||||||
restrict: "none",
|
restrict: "none",
|
||||||
@@ -65,9 +65,9 @@ const ContentContainer = SpotlightContainerDecorator(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const HorizontalContainer = SpotlightContainerDecorator(
|
const HorizontalContainer = SpotlightContainerDecorator(
|
||||||
{
|
{
|
||||||
enterTo: "last-focused",
|
enterTo: "last-focused",
|
||||||
preserveld: true,
|
preserveld: true,
|
||||||
defaultElement: "spotlight-product-info-section-container",
|
defaultElement: "spotlight-product-info-section-container",
|
||||||
spotlightDirection: "horizontal"
|
spotlightDirection: "horizontal"
|
||||||
},
|
},
|
||||||
@@ -110,7 +110,7 @@ const extractProductMeta = (productInfo) => ({
|
|||||||
const SpottableComponent = Spottable("div");
|
const SpottableComponent = Spottable("div");
|
||||||
|
|
||||||
const LayoutSample = ({ onClick }) => (
|
const LayoutSample = ({ onClick }) => (
|
||||||
<SpottableComponent
|
<SpottableComponent
|
||||||
className={css.layoutSample}
|
className={css.layoutSample}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
spotlightId="layout-sample-button"
|
spotlightId="layout-sample-button"
|
||||||
@@ -132,16 +132,16 @@ export default function ProductAllSection({
|
|||||||
themeProductInfo,
|
themeProductInfo,
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const productData = useMemo(() =>
|
const productData = useMemo(() =>
|
||||||
getProductData(productType, themeProductInfo, productInfo),
|
getProductData(productType, themeProductInfo, productInfo),
|
||||||
[productType, themeProductInfo, productInfo]
|
[productType, themeProductInfo, productInfo]
|
||||||
);
|
);
|
||||||
|
|
||||||
// useReviews Hook 사용 - 모든 리뷰 관련 로직을 담당
|
// useReviews Hook 사용 - 모든 리뷰 관련 로직을 담당
|
||||||
const {
|
const {
|
||||||
previewReviews,
|
previewReviews,
|
||||||
stats,
|
stats,
|
||||||
isLoading: reviewsLoading,
|
isLoading: reviewsLoading,
|
||||||
hasReviews // 리뷰 존재 여부 플래그 추가
|
hasReviews // 리뷰 존재 여부 플래그 추가
|
||||||
} = useReviews(productData.prdtId);
|
} = useReviews(productData.prdtId);
|
||||||
@@ -179,7 +179,7 @@ export default function ProductAllSection({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [dispatch, productData, stats]);
|
}, [dispatch, productData, stats]);
|
||||||
|
|
||||||
// 디버깅: 실제 이미지 데이터 확인
|
// 디버깅: 실제 이미지 데이터 확인
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("[ProductId] ProductAllSection productData check:", {
|
console.log("[ProductId] ProductAllSection productData check:", {
|
||||||
@@ -206,7 +206,7 @@ export default function ProductAllSection({
|
|||||||
|
|
||||||
const [mobileSendPopupOpen, setMobileSendPopupOpen] = useState(false);
|
const [mobileSendPopupOpen, setMobileSendPopupOpen] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
// useReviews에서 모든 리뷰 데이터 관리
|
// useReviews에서 모든 리뷰 데이터 관리
|
||||||
const reviewTotalCount = stats.totalReviews;
|
const reviewTotalCount = stats.totalReviews;
|
||||||
const reviewData = { reviewList: previewReviews, reviewDetail: { totRvwCnt: stats.totalReviews, avgRvwScr: stats.averageRating } };
|
const reviewData = { reviewList: previewReviews, reviewDetail: { totRvwCnt: stats.totalReviews, avgRvwScr: stats.averageRating } };
|
||||||
@@ -281,7 +281,7 @@ export default function ProductAllSection({
|
|||||||
<HorizontalContainer className={css.detailArea}>
|
<HorizontalContainer className={css.detailArea}>
|
||||||
{/* Left Margin Section - 60px */}
|
{/* Left Margin Section - 60px */}
|
||||||
<div className={css.leftMarginSection}></div>
|
<div className={css.leftMarginSection}></div>
|
||||||
|
|
||||||
{/* Info Section - 645px */}
|
{/* Info Section - 645px */}
|
||||||
<div className={css.infoSection}>
|
<div className={css.infoSection}>
|
||||||
<Container
|
<Container
|
||||||
@@ -292,7 +292,7 @@ export default function ProductAllSection({
|
|||||||
<div className={css.leftInfoWrapper}>
|
<div className={css.leftInfoWrapper}>
|
||||||
<div className={css.headerContent}>
|
<div className={css.headerContent}>
|
||||||
<ProductTag productInfo={productData} />
|
<ProductTag productInfo={productData} />
|
||||||
{revwGrd && (
|
{revwGrd && revwGrd !== "0.0" && (
|
||||||
<StarRating
|
<StarRating
|
||||||
rating={revwGrd}
|
rating={revwGrd}
|
||||||
aria-label={"star rating " + revwGrd + " out of 5"}
|
aria-label={"star rating " + revwGrd + " out of 5"}
|
||||||
@@ -309,7 +309,11 @@ export default function ProductAllSection({
|
|||||||
productType={productType}
|
productType={productType}
|
||||||
>
|
>
|
||||||
<div className={css.qrWrapper}>
|
<div className={css.qrWrapper}>
|
||||||
<QRCode productInfo={productData} productType={productType} />
|
<QRCode
|
||||||
|
productInfo={productData}
|
||||||
|
productType={productType}
|
||||||
|
kind={"detail"}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ProductOverview>
|
</ProductOverview>
|
||||||
|
|
||||||
@@ -332,6 +336,7 @@ export default function ProductAllSection({
|
|||||||
selectedPrdtId={panelInfo && panelInfo.prdtId}
|
selectedPrdtId={panelInfo && panelInfo.prdtId}
|
||||||
favoriteFlag={favoriteFlag}
|
favoriteFlag={favoriteFlag}
|
||||||
onFavoriteFlagChanged={onFavoriteFlagChanged}
|
onFavoriteFlagChanged={onFavoriteFlagChanged}
|
||||||
|
kind={"item_detail"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -363,7 +368,7 @@ export default function ProductAllSection({
|
|||||||
{$L("PRODUCT DETAILS")}
|
{$L("PRODUCT DETAILS")}
|
||||||
</TButton>
|
</TButton>
|
||||||
{hasReviews && (
|
{hasReviews && (
|
||||||
<TButton
|
<TButton
|
||||||
className={css.userReviewsButton}
|
className={css.userReviewsButton}
|
||||||
onClick={handleUserReviewsClick}
|
onClick={handleUserReviewsClick}
|
||||||
spotlightId="user-reviews-button"
|
spotlightId="user-reviews-button"
|
||||||
@@ -430,14 +435,14 @@ export default function ProductAllSection({
|
|||||||
<div id="product-details-section">
|
<div id="product-details-section">
|
||||||
{productData && productData.imgUrls600 && productData.imgUrls600.length > 0 ? (
|
{productData && productData.imgUrls600 && productData.imgUrls600.length > 0 ? (
|
||||||
productData.imgUrls600.map((image, index) => (
|
productData.imgUrls600.map((image, index) => (
|
||||||
<ProductDetail
|
<ProductDetail
|
||||||
key={`product-detail-${index}`}
|
key={`product-detail-${index}`}
|
||||||
productInfo={{
|
productInfo={{
|
||||||
...productData,
|
...productData,
|
||||||
singleImage: image,
|
singleImage: image,
|
||||||
imageIndex: index,
|
imageIndex: index,
|
||||||
totalImages: productData.imgUrls600.length
|
totalImages: productData.imgUrls600.length
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
@@ -452,8 +457,8 @@ export default function ProductAllSection({
|
|||||||
<>
|
<>
|
||||||
<div id="scroll-marker-user-reviews" className={css.scrollMarker}></div>
|
<div id="scroll-marker-user-reviews" className={css.scrollMarker}></div>
|
||||||
<div id="user-reviews-section">
|
<div id="user-reviews-section">
|
||||||
<UserReviews
|
<UserReviews
|
||||||
productInfo={productData}
|
productInfo={productData}
|
||||||
panelInfo={panelInfo}
|
panelInfo={panelInfo}
|
||||||
reviewsData={{
|
reviewsData={{
|
||||||
previewReviews: previewReviews.slice(0, 5), // 처음 5개만
|
previewReviews: previewReviews.slice(0, 5), // 처음 5개만
|
||||||
@@ -489,4 +494,4 @@ export default function ProductAllSection({
|
|||||||
|
|
||||||
ProductAllSection.propTypes = {
|
ProductAllSection.propTypes = {
|
||||||
productType: PropTypes.oneOf(["buyNow", "shopByMobile", "theme"]).isRequired,
|
productType: PropTypes.oneOf(["buyNow", "shopByMobile", "theme"]).isRequired,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
position: relative; // 절대 위치 기준점
|
position: relative; // 절대 위치 기준점
|
||||||
|
|
||||||
// Spotlight 좌우 이동을 위한 설정
|
// Spotlight 좌우 이동을 위한 설정
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -35,21 +35,24 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: 60px;
|
left: 60px;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 645px;
|
width: 650px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
> div {
|
||||||
|
height: 339px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Content Section - 1180px (1114px 콘텐츠 + 66px 스크롤바)
|
// 3. Content Section - 1180px (1114px 콘텐츠 + 66px 스크롤바)
|
||||||
.contentSection {
|
.contentSection {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 705px; // 60px + 645px
|
left: 705px; // 60px + 645px
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 1200px; // 30px 마진 + 1114px 콘텐츠 + 66px 스크롤바
|
width: 1210px; // 30px 마진 + 1114px 콘텐츠 + 66px 스크롤바
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -84,11 +87,13 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
||||||
// gap 대신 margin 사용 (Chromium 68 호환성)
|
// gap 대신 margin 사용 (Chromium 68 호환성)
|
||||||
> * {
|
> * {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
&:last-child { margin-bottom: 0; }
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +119,6 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
position: relative; // 자식 absolute 요소의 기준점
|
position: relative; // 자식 absolute 요소의 기준점
|
||||||
|
|
||||||
|
|
||||||
// 스크롤러 오버라이드 (1210px = 30px + content + 스크롤바)
|
// 스크롤러 오버라이드 (1210px = 30px + content + 스크롤바)
|
||||||
.scrollerOverride {
|
.scrollerOverride {
|
||||||
@@ -139,17 +143,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
background: #9C9C9C; // 스크롤바 색상
|
background: #9c9c9c; // 스크롤바 색상
|
||||||
border-radius: 3px; // 스크롤바 둥근 모서리
|
border-radius: 3px; // 스크롤바 둥근 모서리
|
||||||
}
|
}
|
||||||
|
|
||||||
// 스크롤바 thumb에 hover 효과 적용
|
// 스크롤바 thumb에 hover 효과 적용
|
||||||
&:hover::-webkit-scrollbar-thumb {
|
&:hover::-webkit-scrollbar-thumb {
|
||||||
background: #C72054;
|
background: #c72054;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 내부 콘텐츠는 별도 너비 계산 없이 100%를 사용
|
// 내부 콘텐츠는 별도 너비 계산 없이 100%를 사용
|
||||||
> div {
|
> div {
|
||||||
width: 100%; // 부모의 패딩을 제외한 나머지 공간(1114px)을 모두 사용
|
width: 100%; // 부모의 패딩을 제외한 나머지 공간(1114px)을 모두 사용
|
||||||
@@ -174,7 +177,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
||||||
// ProductDetail.new 컴포넌트들
|
// ProductDetail.new 컴포넌트들
|
||||||
> div[class*="rollingWrap"] {
|
> div[class*="rollingWrap"] {
|
||||||
width: 100% !important; // 부모 영역 전체 사용
|
width: 100% !important; // 부모 영역 전체 사용
|
||||||
@@ -182,9 +185,9 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#product-description-section,
|
#product-description-section,
|
||||||
#user-reviews-section,
|
#user-reviews-section,
|
||||||
#you-may-also-like-section {
|
#you-may-also-like-section {
|
||||||
width: 100%; // 부모 콘텐츠 영역 전체 사용
|
width: 100%; // 부모 콘텐츠 영역 전체 사용
|
||||||
max-width: none;
|
max-width: none;
|
||||||
@@ -192,13 +195,13 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
max-width: 100% !important; // 부모 영역 전체 사용
|
max-width: 100% !important; // 부모 영역 전체 사용
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 이미지들이 컨테이너를 넘지 않도록
|
// 이미지들이 컨테이너를 넘지 않도록
|
||||||
img {
|
img {
|
||||||
max-width: 100% !important;
|
max-width: 100% !important;
|
||||||
@@ -229,7 +232,6 @@
|
|||||||
|
|
||||||
// (중복 제거됨) 최상위 스크롤러/섹션 정의는 .scrollerWrapper 중첩 내부로 이동
|
// (중복 제거됨) 최상위 스크롤러/섹션 정의는 .scrollerWrapper 중첩 내부로 이동
|
||||||
|
|
||||||
|
|
||||||
// ProductDetailCard 스타일 참고 - 크기/간격만 적용
|
// ProductDetailCard 스타일 참고 - 크기/간격만 적용
|
||||||
|
|
||||||
// 헤더 컨텐츠 영역 (태그, 별점)
|
// 헤더 컨텐츠 영역 (태그, 별점)
|
||||||
@@ -237,7 +239,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 모바일 쇼핑 섹션 (mobileSection 참고)
|
// 모바일 쇼핑 섹션 (mobileSection 참고)
|
||||||
@@ -247,10 +248,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
&:last-child { margin-right: 0; }
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,15 +261,18 @@
|
|||||||
flex: 1 1 0 !important;
|
flex: 1 1 0 !important;
|
||||||
width: auto !important; // flex로 크기 조정
|
width: auto !important; // flex로 크기 조정
|
||||||
height: 60px !important;
|
height: 60px !important;
|
||||||
background: rgba(68, 68, 68, 0.50) !important;
|
background: rgba(68, 68, 68, 0.5) !important;
|
||||||
border-radius: 6px !important;
|
border-radius: 6px !important;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
margin: 0 !important;
|
margin: 0;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
|
&.shopByMobileOne {
|
||||||
|
margin: 0 6px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
.shopByMobileText {
|
.shopByMobileText {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
font-size: 25px !important;
|
font-size: 25px !important;
|
||||||
@@ -275,12 +281,484 @@
|
|||||||
line-height: 35px !important;
|
line-height: 35px !important;
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 포커스 상태 추가
|
// 포커스 상태 추가
|
||||||
&:focus {
|
&:focus {
|
||||||
background: @PRIMARY_COLOR_RED !important; // 포커스시 빨간색 배경
|
background: @PRIMARY_COLOR_RED !important; // 포커스시 빨간색 배경
|
||||||
outline: 2px solid @PRIMARY_COLOR_RED !important;
|
outline: 2px solid @PRIMARY_COLOR_RED !important;
|
||||||
|
|
||||||
|
.shopByMobileText {
|
||||||
|
color: white !important; // 포커스시에도 텍스트는 흰색 유지
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.favoriteBtnWrapper {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: 6px;
|
||||||
|
// 배경색과 라운드는 FavoriteBtn 내부에서 처리하므로 제거
|
||||||
|
}
|
||||||
|
|
||||||
|
// 주문 전화 섹션 (callToOrderSection 참고)
|
||||||
|
.callToOrderSection {
|
||||||
|
align-self: stretch;
|
||||||
|
height: 40px;
|
||||||
|
padding: 17px 30px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px !important;
|
||||||
|
.callToOrderText {
|
||||||
|
color: #eaeaea;
|
||||||
|
font-size: 25px;
|
||||||
|
font-family: @baseFont; // LG Smart 폰트 사용
|
||||||
|
font-weight: 400; // Bold에서 Regular로 변경
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneSection {
|
||||||
|
padding: 0 1px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin-right: 10px;
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneIconContainer {
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.phoneIcon {
|
||||||
|
width: 24.94px;
|
||||||
|
height: 24.97px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
// 전화 아이콘 이미지 또는 CSS로 구현
|
||||||
|
background-image: url("../../../../assets/images/icons/ic-gr-call-1.png");
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneNumber {
|
||||||
|
color: #eaeaea;
|
||||||
|
font-size: 25px;
|
||||||
|
font-family: "LG Smart UI";
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 액션 버튼들 (actionButtons 참고)
|
||||||
|
.actionButtonsWrapper {
|
||||||
|
align-self: stretch;
|
||||||
|
padding-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모든 버튼 기본 스타일 (PRODUCT DETAILS는 빨간색 아님!)
|
||||||
|
.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;
|
||||||
|
|
||||||
|
color: #eaeaea;
|
||||||
|
font-size: 25px;
|
||||||
|
font-family: @baseFont; // LG Smart 폰트 사용
|
||||||
|
font-weight: 400; // Bold에서 Regular로 변경
|
||||||
|
line-height: 35px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: #c72054; // 포커스시만 빨간색
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.themeButton {
|
||||||
|
align-self: stretch;
|
||||||
|
height: 60px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: #c72054;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QR 래퍼 (imageSection 참고 - 240px 고정)
|
||||||
|
.qrWrapper {
|
||||||
|
width: 240px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductOverview 컨테이너 스타일 수정 (자식 요소에 맞게 크기 조정)
|
||||||
|
[class*="ProductOverview"] {
|
||||||
|
padding: 0 0 5px;
|
||||||
|
// 내부 div (productInfoWrapper)
|
||||||
|
> div {
|
||||||
|
align-self: stretch;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
> div:first-child {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LayoutSample 포커스 테스트용 스타일
|
||||||
|
.layoutSample {
|
||||||
|
width: 1124px;
|
||||||
|
height: 300px;
|
||||||
|
background-color: yellow;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: black;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
&::after {
|
||||||
|
.focused(@boxShadow:22px, @borderRadius:8px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
// 1920px 화면 기준 전체 구조 (절대 위치로 정확히 배치)
|
||||||
|
.detailArea {
|
||||||
|
width: 1920px; // 명시적으로 화면 크기 설정
|
||||||
|
height: 100%;
|
||||||
|
padding: 0; // 모든 패딩 제거
|
||||||
|
margin: 0; // 모든 마진 제거
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative; // 절대 위치 기준점
|
||||||
|
|
||||||
|
// Spotlight 좌우 이동을 위한 설정
|
||||||
|
&:focus-within {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Left Margin Section - 60px
|
||||||
|
.leftMarginSection {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 60px;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Info Section - 645px
|
||||||
|
.infoSection {
|
||||||
|
position: absolute;
|
||||||
|
left: 60px;
|
||||||
|
top: 0;
|
||||||
|
width: 650px;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
> div {
|
||||||
|
height: 339px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Content Section - 1180px (1114px 콘텐츠 + 66px 스크롤바)
|
||||||
|
.contentSection {
|
||||||
|
position: absolute;
|
||||||
|
left: 705px; // 60px + 645px
|
||||||
|
top: 0;
|
||||||
|
width: 1210px; // 30px 마진 + 1114px 콘텐츠 + 66px 스크롤바
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Scroll Section - 66px (삭제 - contentSection에 포함)
|
||||||
|
.scrollSection {
|
||||||
|
display: none; // 사용하지 않음
|
||||||
|
}
|
||||||
|
|
||||||
|
// 왼쪽 영역 컨테이너 (infoSection 내부)
|
||||||
|
.leftInfoContainer {
|
||||||
|
width: 635px; // 실제 콘텐츠 영역
|
||||||
|
margin-right: 10px; // 우측 10px 간격
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 왼쪽 영역 내부 래퍼
|
||||||
|
.leftInfoWrapper {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
// gap 대신 margin 사용 (Chromium 68 호환성)
|
||||||
|
> * {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 오른쪽 영역 컨테이너 (contentSection 내부)
|
||||||
|
.rightContentContainer {
|
||||||
|
width: 1210px; // 30px 마진 + 1114px 콘텐츠 + 66px 스크롤바
|
||||||
|
height: @globalHeight - 136px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
// 스크롤러 래퍼 (contentSection 내부)
|
||||||
|
.scrollerWrapper {
|
||||||
|
width: 1210px; // 30px 마진 + 1114px 콘텐츠 + 66px 스크롤바 (절대값)
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible; // hidden에서 visible로 변경
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative; // 자식 absolute 요소의 기준점
|
||||||
|
|
||||||
|
// 스크롤러 오버라이드 (1210px = 30px + content + 스크롤바)
|
||||||
|
.scrollerOverride {
|
||||||
|
width: 1210px; // 절대 크기 지정
|
||||||
|
height: 100%;
|
||||||
|
// 좌측 30px, 우측 66px(스크롤바) 패딩을 명시적으로 적용
|
||||||
|
padding: 0 10px 0 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
// 스크롤바 너비를 6px로 명확하게 설정
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: transparent; // 트랙 배경은 투명하게
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #9c9c9c; // 스크롤바 색상
|
||||||
|
border-radius: 3px; // 스크롤바 둥근 모서리
|
||||||
|
}
|
||||||
|
|
||||||
|
// 스크롤바 thumb에 hover 효과 적용
|
||||||
|
&:hover::-webkit-scrollbar-thumb {
|
||||||
|
background: #c72054;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 내부 콘텐츠는 별도 너비 계산 없이 100%를 사용
|
||||||
|
> div {
|
||||||
|
width: 100%; // 부모의 패딩을 제외한 나머지 공간(1114px)을 모두 사용
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 스크롤 콘텐츠 내부의 모든 섹션들 (패딩 제거 - scrollerOverride에서 처리함)
|
||||||
|
#product-details-section {
|
||||||
|
width: 1124px; // 부모 콘텐츠 영역 전체 사용
|
||||||
|
max-width: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: visible;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
// ProductDetail.new 컴포넌트들
|
||||||
|
> div[class*="rollingWrap"] {
|
||||||
|
width: 100% !important; // 부모 영역 전체 사용
|
||||||
|
max-width: none !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#product-description-section,
|
||||||
|
#user-reviews-section,
|
||||||
|
#you-may-also-like-section {
|
||||||
|
width: 100%; // 부모 콘텐츠 영역 전체 사용
|
||||||
|
max-width: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
max-width: 100% !important; // 부모 영역 전체 사용
|
||||||
|
width: 100% !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 이미지들이 컨테이너를 넘지 않도록
|
||||||
|
img {
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: auto !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 상품 상세 영역 (마진 포함 크기)
|
||||||
|
.productDetail {
|
||||||
|
width: 1124px; // 1114px + 10px
|
||||||
|
max-width: 1124px;
|
||||||
|
height: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch; // 자식 요소들이 전체 너비 사용하도록
|
||||||
|
}
|
||||||
|
|
||||||
|
// 스크롤 마커
|
||||||
|
.scrollMarker {
|
||||||
|
height: 1px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
} // .scrollerWrapper
|
||||||
|
} // .rightContentContainer
|
||||||
|
|
||||||
|
// (중복 제거됨) .scrollerWrapper는 .rightContentContainer 하위로 중첩 이동
|
||||||
|
|
||||||
|
// (중복 제거됨) 최상위 스크롤러/섹션 정의는 .scrollerWrapper 중첩 내부로 이동
|
||||||
|
|
||||||
|
// ProductDetailCard 스타일 참고 - 크기/간격만 적용
|
||||||
|
|
||||||
|
// 헤더 컨텐츠 영역 (태그, 별점)
|
||||||
|
.headerContent {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모바일 쇼핑 섹션 (mobileSection 참고)
|
||||||
|
.buttonContainer {
|
||||||
|
align-self: stretch;
|
||||||
|
padding-top: 19px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin-right: 6px;
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shopByMobileButton {
|
||||||
|
flex: 1 1 0 !important;
|
||||||
|
width: auto !important; // flex로 크기 조정
|
||||||
|
height: 60px !important;
|
||||||
|
background: rgba(68, 68, 68, 0.5) !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
&.shopByMobileOne {
|
||||||
|
margin: 0 6px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shopByMobileText {
|
||||||
|
color: white !important;
|
||||||
|
font-size: 25px !important;
|
||||||
|
font-family: @baseFont !important; // LG Smart 폰트 사용
|
||||||
|
font-weight: 400 !important; // Bold에서 Regular로 변경
|
||||||
|
line-height: 35px !important;
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 포커스 상태 추가
|
||||||
|
&:focus {
|
||||||
|
background: @PRIMARY_COLOR_RED !important; // 포커스시 빨간색 배경
|
||||||
|
outline: 2px solid @PRIMARY_COLOR_RED !important;
|
||||||
|
|
||||||
.shopByMobileText {
|
.shopByMobileText {
|
||||||
color: white !important; // 포커스시에도 텍스트는 흰색 유지
|
color: white !important; // 포커스시에도 텍스트는 흰색 유지
|
||||||
}
|
}
|
||||||
@@ -306,38 +784,39 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.callToOrderText {
|
.callToOrderText {
|
||||||
color: #EAEAEA;
|
color: #eaeaea;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
font-family: @baseFont; // LG Smart 폰트 사용
|
font-family: @baseFont; // LG Smart 폰트 사용
|
||||||
font-weight: 400; // Bold에서 Regular로 변경
|
font-weight: 400; // Bold에서 Regular로 변경
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phoneSection {
|
.phoneSection {
|
||||||
padding: 0 1px;
|
padding: 0 1px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
&:last-child { margin-right: 0; }
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.phoneIconContainer {
|
.phoneIconContainer {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.phoneIcon {
|
.phoneIcon {
|
||||||
width: 24.94px;
|
width: 24.94px;
|
||||||
height: 24.97px;
|
height: 24.97px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background: #EAEAEA;
|
|
||||||
// 전화 아이콘 이미지 또는 CSS로 구현
|
// 전화 아이콘 이미지 또는 CSS로 구현
|
||||||
background-image: url("../../../../assets/images/icons/ic-gr-call-1.png");
|
background-image: url("../../../../assets/images/icons/ic-gr-call-1.png");
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
@@ -345,11 +824,11 @@
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.phoneNumber {
|
.phoneNumber {
|
||||||
color: #EAEAEA;
|
color: #eaeaea;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
font-family: 'LG Smart UI';
|
font-family: "LG Smart UI";
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
}
|
}
|
||||||
@@ -362,10 +841,15 @@
|
|||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
&:last-child { margin-bottom: 0; }
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,15 +864,15 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
color: #EAEAEA;
|
color: #eaeaea;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
font-family: @baseFont; // LG Smart 폰트 사용
|
font-family: @baseFont; // LG Smart 폰트 사용
|
||||||
font-weight: 400; // Bold에서 Regular로 변경
|
font-weight: 400; // Bold에서 Regular로 변경
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
background: #C72054; // 포커스시만 빨간색
|
background: #c72054; // 포커스시만 빨간색
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,9 +882,9 @@
|
|||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
background: #C72054;
|
background: #c72054;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,65 +895,34 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
&:last-child { margin-bottom: 0; }
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProductOverview 컨테이너 스타일 수정 (자식 요소에 맞게 크기 조정)
|
// ProductOverview 컨테이너 스타일 수정 (자식 요소에 맞게 크기 조정)
|
||||||
[class*="ProductOverview"] {
|
[class*="ProductOverview"] {
|
||||||
align-self: stretch;
|
padding: 0 0 5px;
|
||||||
padding: 0 0 5px; // ProductDetailCard mainContent와 동일한 패딩
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
// 내부 div (productInfoWrapper)
|
// 내부 div (productInfoWrapper)
|
||||||
> div {
|
> div {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
}
|
||||||
> * {
|
> div:first-child {
|
||||||
margin-right: 15px; // ProductDetailCard와 동일한 간격
|
text-align: left;
|
||||||
&:last-child { margin-right: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 가격 섹션 (flex로 남은 공간 차지)
|
|
||||||
> div:first-child {
|
|
||||||
flex: 1 1 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이미지 섹션 (QR 포함, 고정 크기)
|
|
||||||
> div:last-child {
|
|
||||||
width: 240px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
&:last-child { margin-bottom: 0; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LayoutSample 포커스 테스트용 스타일
|
// LayoutSample 포커스 테스트용 스타일
|
||||||
.layoutSample {
|
.layoutSample {
|
||||||
width: 1124px;
|
width: 1124px;
|
||||||
height: 35px;
|
height: 300px;
|
||||||
background-color: yellow;
|
background-color: yellow;
|
||||||
// border: 2px solid white;
|
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -480,7 +933,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
&::after {
|
&::after {
|
||||||
.focused(@boxShadow:22px, @borderRadius:8px);
|
.focused(@boxShadow:22px, @borderRadius:8px);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
outline: 2px solid @PRIMARY_COLOR_RED;
|
outline: 2px solid @PRIMARY_COLOR_RED;
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
.title {
|
.title {
|
||||||
.font(@fontFamily: @baseFont, @fontSize: 30px);
|
.font(@fontFamily: @baseFont, @fontSize: 30px);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin: 90px 0 20px 0;
|
margin: 30px 0 20px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 6px solid @PRIMARY_COLOR_RED;
|
outline: 6px solid @PRIMARY_COLOR_RED;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
|
|||||||
@@ -1,30 +1,43 @@
|
|||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, {
|
||||||
import css from "./CustomerImages.module.less";
|
useCallback,
|
||||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
useEffect,
|
||||||
import Spottable from "@enact/spotlight/Spottable";
|
useState,
|
||||||
import THeader from "../../../../../components/THeader/THeader";
|
} from 'react';
|
||||||
import { $L } from "../../../../../utils/helperMethods";
|
|
||||||
import classNames from "classnames";
|
import classNames from 'classnames';
|
||||||
import Spotlight from "@enact/spotlight";
|
|
||||||
|
import Spotlight from '@enact/spotlight';
|
||||||
|
import SpotlightContainerDecorator
|
||||||
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
|
import Spottable from '@enact/spotlight/Spottable';
|
||||||
|
|
||||||
|
import THeader from '../../../../../components/THeader/THeader';
|
||||||
|
import { $L } from '../../../../../utils/helperMethods';
|
||||||
|
import css from './CustomerImages.module.less';
|
||||||
|
|
||||||
const Container = SpotlightContainerDecorator(
|
const Container = SpotlightContainerDecorator(
|
||||||
{
|
{
|
||||||
enterTo: "default-element",
|
enterTo: "default-element",
|
||||||
preserveld: true,
|
preserveld: true,
|
||||||
leaveFor: {
|
leaveFor: {
|
||||||
left: "spotlight-product-info-section-container"
|
left: "spotlight-product-info-section-container",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
"div"
|
"div"
|
||||||
);
|
);
|
||||||
|
|
||||||
const SpottableComponent = Spottable("div");
|
const SpottableComponent = Spottable("div");
|
||||||
|
|
||||||
export default function CustomerImages({ onImageClick, onViewMoreClick, imageData }) {
|
export default function CustomerImages({
|
||||||
|
onImageClick,
|
||||||
|
onViewMoreClick,
|
||||||
|
imageData,
|
||||||
|
}) {
|
||||||
// Props로 전달받은 imageData 사용 (useReviews Hook에서 추출된 이미지 데이터)
|
// Props로 전달받은 imageData 사용 (useReviews Hook에서 추출된 이미지 데이터)
|
||||||
const [selectedIndex, setSelectedIndex] = useState(null);
|
const [selectedIndex, setSelectedIndex] = useState(null);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const IMAGES_PER_PAGE = 5;
|
const IMAGES_PER_PAGE = 5;
|
||||||
|
const [focusIdx, setFocusIdx] = useState(0);
|
||||||
|
|
||||||
// [CustomerImages] useReviews 이미지 데이터 수신 확인
|
// [CustomerImages] useReviews 이미지 데이터 수신 확인
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
@@ -43,7 +56,7 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
|
|
||||||
const handleReviewImageClick = (index) => {
|
const handleReviewImageClick = (index) => {
|
||||||
setSelectedIndex(index);
|
setSelectedIndex(index);
|
||||||
|
|
||||||
// 이미지 클릭 시 All-Images 모드로 팝업 열기
|
// 이미지 클릭 시 All-Images 모드로 팝업 열기
|
||||||
if (onImageClick) {
|
if (onImageClick) {
|
||||||
onImageClick(index);
|
onImageClick(index);
|
||||||
@@ -58,25 +71,35 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 키 이벤트 처리 (왼쪽 화살표, Enter 키)
|
// 키 이벤트 처리 (왼쪽 화살표, Enter 키)
|
||||||
const handleKeyDown = useCallback((ev, index) => {
|
const handleKeyDown = useCallback(
|
||||||
if (ev.keyCode === 37) { // 왼쪽 화살표 키
|
(ev, index) => {
|
||||||
ev.preventDefault();
|
if (ev.keyCode === 37) {
|
||||||
ev.stopPropagation();
|
// 왼쪽 화살표 키
|
||||||
console.log("[CustomerImages] Left arrow pressed, focusing product-details-button");
|
ev.preventDefault();
|
||||||
Spotlight.focus("product-details-button");
|
ev.stopPropagation();
|
||||||
} else if (ev.keyCode === 13) { // Enter 키
|
console.log(
|
||||||
ev.preventDefault();
|
"[CustomerImages] Left arrow pressed, focusing product-details-button"
|
||||||
ev.stopPropagation();
|
);
|
||||||
console.log("[CustomerImages] Enter pressed on image:", index);
|
Spotlight.focus("product-details-button");
|
||||||
handleReviewImageClick(index);
|
} else if (ev.keyCode === 13) {
|
||||||
}
|
// Enter 키
|
||||||
}, [handleReviewImageClick]);
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
console.log("[CustomerImages] Enter pressed on image:", index);
|
||||||
|
handleReviewImageClick(index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[handleReviewImageClick]
|
||||||
|
);
|
||||||
|
|
||||||
// 이미지가 없을 때도 컴포넌트를 렌더링하되 내용은 표시하지 않음
|
// 이미지가 없을 때도 컴포넌트를 렌더링하되 내용은 표시하지 않음
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container className={css.container}>
|
<Container className={css.container}>
|
||||||
<THeader className={css.tHeader} title={$L("Customer Images")} />
|
<THeader
|
||||||
|
className={classNames(css.tHeader, css.customTHeader)}
|
||||||
|
title={$L("Customer Images")}
|
||||||
|
/>
|
||||||
{imageData && imageData.length > 0 ? (
|
{imageData && imageData.length > 0 ? (
|
||||||
<div className={css.wrapper}>
|
<div className={css.wrapper}>
|
||||||
{(() => {
|
{(() => {
|
||||||
@@ -84,7 +107,7 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
const endIndex = startIndex + IMAGES_PER_PAGE;
|
const endIndex = startIndex + IMAGES_PER_PAGE;
|
||||||
const displayImages = imageData.slice(startIndex, endIndex);
|
const displayImages = imageData.slice(startIndex, endIndex);
|
||||||
const hasMoreImages = imageData.length > endIndex;
|
const hasMoreImages = imageData.length > endIndex;
|
||||||
|
|
||||||
console.log("[CustomerImages] Pagination debug:", {
|
console.log("[CustomerImages] Pagination debug:", {
|
||||||
currentPage,
|
currentPage,
|
||||||
IMAGES_PER_PAGE,
|
IMAGES_PER_PAGE,
|
||||||
@@ -92,9 +115,9 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
startIndex,
|
startIndex,
|
||||||
endIndex,
|
endIndex,
|
||||||
displayImagesCount: displayImages.length,
|
displayImagesCount: displayImages.length,
|
||||||
hasMoreImages
|
hasMoreImages,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{displayImages.map((reviewImage, displayIndex) => {
|
{displayImages.map((reviewImage, displayIndex) => {
|
||||||
@@ -105,16 +128,22 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
<SpottableComponent
|
<SpottableComponent
|
||||||
className={classNames(
|
className={classNames(
|
||||||
css.reviewCard,
|
css.reviewCard,
|
||||||
selectedIndex === actualIndex ? css.selectedReviewImage : null
|
selectedIndex === actualIndex
|
||||||
|
? css.selectedReviewImage
|
||||||
|
: null,
|
||||||
|
focusIdx === displayIndex ? css.focused : ""
|
||||||
)}
|
)}
|
||||||
key={`review-image-${imgId}-${reviewId}`}
|
key={`review-image-${imgId}-${reviewId}`}
|
||||||
onClick={() => handleReviewImageClick(actualIndex)}
|
onClick={() => handleReviewImageClick(actualIndex)}
|
||||||
onKeyDown={(ev) => handleKeyDown(ev, actualIndex)}
|
onKeyDown={(ev) => handleKeyDown(ev, actualIndex)}
|
||||||
spotlightId={`customer-image-${actualIndex}`}
|
spotlightId={`customer-image-${actualIndex}`}
|
||||||
|
onFocus={() =>
|
||||||
|
displayIndex < 5 ? setFocusIdx(displayIndex) : ""
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className={css.reviewImg}
|
className={css.reviewImg}
|
||||||
src={imgUrl}
|
src={imgUrl}
|
||||||
alt={`Review image ${actualIndex + 1}`}
|
alt={`Review image ${actualIndex + 1}`}
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
/* console.log(`[CustomerImages] Image loaded successfully:`, {
|
/* console.log(`[CustomerImages] Image loaded successfully:`, {
|
||||||
@@ -124,19 +153,22 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
}); */
|
}); */
|
||||||
}}
|
}}
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
console.error(`[CustomerImages] Image load failed:`, {
|
console.error(
|
||||||
index: actualIndex,
|
`[CustomerImages] Image load failed:`,
|
||||||
imgUrl,
|
{
|
||||||
imgId,
|
index: actualIndex,
|
||||||
error: e.target.error
|
imgUrl,
|
||||||
});
|
imgId,
|
||||||
e.target.style.display = 'none';
|
error: e.target.error,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
e.target.style.display = "none";
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SpottableComponent>
|
</SpottableComponent>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{hasMoreImages && (
|
{hasMoreImages && (
|
||||||
<SpottableComponent
|
<SpottableComponent
|
||||||
className={css.viewMoreButton}
|
className={css.viewMoreButton}
|
||||||
@@ -161,13 +193,17 @@ export default function CustomerImages({ onImageClick, onViewMoreClick, imageDat
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={css.wrapper}>
|
<div className={css.wrapper}>
|
||||||
<div style={{
|
<div
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
style={{
|
||||||
textAlign: 'center',
|
color: "rgba(255, 255, 255, 0.7)",
|
||||||
padding: '20px',
|
textAlign: "center",
|
||||||
fontSize: '16px'
|
padding: "20px",
|
||||||
}}>
|
fontSize: "16px",
|
||||||
{imageData ? 'No customer images available' : 'Loading customer images...'}
|
}}
|
||||||
|
>
|
||||||
|
{imageData
|
||||||
|
? "No customer images available"
|
||||||
|
: "Loading customer images..."}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
.container {
|
.container {
|
||||||
width: 1124px;
|
width: 1124px;
|
||||||
height: 236px;
|
height: 299px;
|
||||||
max-width: 1124px;
|
max-width: 1124px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
margin: 0 0 10px 0;
|
margin: 0 0 10px 0;
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
padding: 0;
|
padding: 0 0 0 20px;
|
||||||
> span {
|
> span {
|
||||||
.font(@fontFamily: @baseFont, @fontSize: 24px);
|
.font(@fontFamily: @baseFont, @fontSize: 24px);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 190px;
|
height: 252px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -36,13 +36,25 @@
|
|||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
||||||
.reviewCard {
|
.reviewCard {
|
||||||
width: calc((100% - 75px) / 6); // 6개 슬롯(5이미지+1버튼), margin-right 15px * 5 = 75px
|
// width: calc(
|
||||||
height: 150px;
|
// (100% - 75px) / 6
|
||||||
|
// ); // 6개 슬롯(5이미지+1버튼), margin-right 15px * 5 = 75px
|
||||||
|
// height: 150px;
|
||||||
|
width: 157.3px;
|
||||||
|
height: 192.5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
|
|
||||||
|
&.focused {
|
||||||
|
width: 211.75px;
|
||||||
|
height: 211.75px;
|
||||||
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
//포커스시 확대
|
||||||
|
// width: 211.75px;
|
||||||
|
// height: 211.75px;
|
||||||
&::after {
|
&::after {
|
||||||
.focused(@boxShadow:22px, @borderRadius:12px);
|
.focused(@boxShadow:22px, @borderRadius:12px);
|
||||||
}
|
}
|
||||||
@@ -61,13 +73,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.viewMoreButton {
|
.viewMoreButton {
|
||||||
width: calc((100% - 75px) / 6); // reviewCard와 동일한 크기
|
// width: calc((100% - 75px) / 6); // reviewCard와 동일한 크기
|
||||||
height: 150px;
|
// height: 150px;
|
||||||
|
width: 157.3px;
|
||||||
|
height: 192.5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
// //포커스시 확대
|
||||||
|
// width: 211.75px;
|
||||||
|
// height: 211.75px;
|
||||||
&::after {
|
&::after {
|
||||||
.focused(@boxShadow:22px, @borderRadius:12px);
|
.focused(@boxShadow:22px, @borderRadius:12px);
|
||||||
}
|
}
|
||||||
@@ -77,7 +94,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.80) 0%, rgba(0, 0, 0, 0.80) 100%);
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(0, 0, 0, 0.8) 0%,
|
||||||
|
rgba(0, 0, 0, 0.8) 100%
|
||||||
|
);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import React, { useCallback } from "react";
|
import React, { useCallback } from 'react';
|
||||||
import classNames from "classnames";
|
|
||||||
import Spottable from "@enact/spotlight/Spottable";
|
import classNames from 'classnames';
|
||||||
import StarRating from "../../../components/StarRating";
|
|
||||||
import { $L } from "../../../../../utils/helperMethods";
|
import Spottable from '@enact/spotlight/Spottable';
|
||||||
import css from "./UserReviewDetail.module.less";
|
|
||||||
|
import { $L } from '../../../../../utils/helperMethods';
|
||||||
|
import StarRating from '../../../components/StarRating';
|
||||||
|
import css from './UserReviewDetail.module.less';
|
||||||
|
|
||||||
const SpottableButton = Spottable("div");
|
const SpottableButton = Spottable("div");
|
||||||
|
|
||||||
@@ -36,9 +39,15 @@ export default function UserReviewDetail({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const reviewImage = currentReview.reviewImageList && currentReview.reviewImageList[0];
|
const reviewImage =
|
||||||
|
currentReview.reviewImageList && currentReview.reviewImageList[0];
|
||||||
const hasMultipleReviews = totalReviews > 1;
|
const hasMultipleReviews = totalReviews > 1;
|
||||||
|
|
||||||
|
const formatDate = (dateStr) => {
|
||||||
|
const [year, month, day] = dateStr.split("-");
|
||||||
|
return `${year.slice(2)}.${month}.${day}`;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(css.container, className)}>
|
<div className={classNames(css.container, className)}>
|
||||||
{/* Left Arrow - 이전 리뷰가 있을 때만 표시 */}
|
{/* Left Arrow - 이전 리뷰가 있을 때만 표시 */}
|
||||||
@@ -57,14 +66,14 @@ export default function UserReviewDetail({
|
|||||||
{/* Review Image */}
|
{/* Review Image */}
|
||||||
{reviewImage && (
|
{reviewImage && (
|
||||||
<div className={css.imageSection}>
|
<div className={css.imageSection}>
|
||||||
<img
|
<img
|
||||||
src={reviewImage.imgUrl}
|
src={reviewImage.imgUrl}
|
||||||
alt="Review image"
|
alt="Review image"
|
||||||
className={css.reviewImage}
|
className={css.reviewImage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Review Info */}
|
{/* Review Info */}
|
||||||
<div className={css.infoSection}>
|
<div className={css.infoSection}>
|
||||||
{/* Rating and Meta */}
|
{/* Rating and Meta */}
|
||||||
@@ -78,31 +87,29 @@ export default function UserReviewDetail({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Email */}
|
{/* Email */}
|
||||||
{(currentReview.wrtrNknm || currentReview.rvwWrtrId) && (
|
{(currentReview.wrtrNknm || currentReview.rvwWrtrId) && (
|
||||||
<div className={css.email}>
|
<div className={css.email}>
|
||||||
{currentReview.wrtrNknm || currentReview.rvwWrtrId}
|
{currentReview.wrtrNknm || currentReview.rvwWrtrId}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Date */}
|
{/* Date */}
|
||||||
{currentReview.rvwRgstDtt && (
|
{currentReview.rvwRgstDtt && (
|
||||||
<div className={css.date}>
|
<div className={css.date}>
|
||||||
{currentReview.rvwRgstDtt}
|
{formatDate(currentReview.rvwRgstDtt)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Review Text */}
|
{/* Review Text */}
|
||||||
{currentReview.rvwCtnt && (
|
{currentReview.rvwCtnt && (
|
||||||
<div className={css.reviewText}>
|
<div className={css.reviewText}>"{currentReview.rvwCtnt}"</div>
|
||||||
"{currentReview.rvwCtnt}"
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Custom Scrollbar (피그마 스타일) */}
|
{/* Custom Scrollbar (피그마 스타일) */}
|
||||||
<div className={css.customScrollbar}>
|
<div className={css.customScrollbar}>
|
||||||
<div className={css.scrollTrack} />
|
<div className={css.scrollTrack} />
|
||||||
@@ -120,4 +127,4 @@ export default function UserReviewDetail({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,32 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
import React, {
|
||||||
import css from "./UserReviews.module.less";
|
useCallback,
|
||||||
import UserReviewsScroller from "../../components/UserReviewsScroller/UserReviewsScroller";
|
useEffect,
|
||||||
import useScrollTo from "../../../../hooks/useScrollTo";
|
useMemo,
|
||||||
import THeaderDetail from "../../components/THeaderDetail";
|
useRef,
|
||||||
import { $L } from "../../../../utils/helperMethods";
|
useState,
|
||||||
import { useMemo } from "react";
|
} from 'react';
|
||||||
import Spottable from "@enact/spotlight/Spottable";
|
|
||||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
import classNames from 'classnames';
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import {
|
||||||
import { toggleShowAllReviews } from "../../../../actions/productActions";
|
useDispatch,
|
||||||
import useReviews from "../../../../hooks/useReviews/useReviews";
|
useSelector,
|
||||||
import StarRating from "../../components/StarRating";
|
} from 'react-redux';
|
||||||
import CustomerImages from "./CustomerImages/CustomerImages";
|
|
||||||
import UserReviewsPopup from "./UserReviewsPopup/UserReviewsPopup";
|
import SpotlightContainerDecorator
|
||||||
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
|
import Spottable from '@enact/spotlight/Spottable';
|
||||||
|
|
||||||
|
import { toggleShowAllReviews } from '../../../../actions/productActions';
|
||||||
|
import useReviews from '../../../../hooks/useReviews/useReviews';
|
||||||
|
import useScrollTo from '../../../../hooks/useScrollTo';
|
||||||
|
import { $L } from '../../../../utils/helperMethods';
|
||||||
|
import StarRating from '../../components/StarRating';
|
||||||
|
import THeaderDetail from '../../components/THeaderDetail';
|
||||||
|
import UserReviewsScroller
|
||||||
|
from '../../components/UserReviewsScroller/UserReviewsScroller';
|
||||||
|
import CustomerImages from './CustomerImages/CustomerImages';
|
||||||
|
import css from './UserReviews.module.less';
|
||||||
|
import UserReviewsPopup from './UserReviewsPopup/UserReviewsPopup';
|
||||||
|
|
||||||
const SpottableComponent = Spottable("div");
|
const SpottableComponent = Spottable("div");
|
||||||
|
|
||||||
@@ -22,10 +36,10 @@ const Container = SpotlightContainerDecorator(
|
|||||||
preserveld: true,
|
preserveld: true,
|
||||||
leaveFor: {
|
leaveFor: {
|
||||||
left: "spotlight-product-info-section-container",
|
left: "spotlight-product-info-section-container",
|
||||||
up: "view-all-reviews-button"
|
up: "view-all-reviews-button",
|
||||||
},
|
},
|
||||||
restrict: "none",
|
restrict: "none",
|
||||||
spotlightDirection: "vertical"
|
spotlightDirection: "vertical",
|
||||||
},
|
},
|
||||||
"div"
|
"div"
|
||||||
);
|
);
|
||||||
@@ -35,32 +49,39 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const tScrollerRef = useRef(null);
|
const tScrollerRef = useRef(null);
|
||||||
|
|
||||||
// ProductAllSection에서 전달받은 데이터 사용 (우선순위)
|
// ProductAllSection에서 전달받은 데이터 사용 (우선순위)
|
||||||
// 없으면 자체 useReviews Hook 사용 (UserReviewPanel에서 직접 접근할 때)
|
// 없으면 자체 useReviews Hook 사용 (UserReviewPanel에서 직접 접근할 때)
|
||||||
const fallbackReviews = useReviews(productInfo && productInfo.prdtId);
|
const fallbackReviews = useReviews(productInfo && productInfo.prdtId);
|
||||||
|
|
||||||
const actualReviewsData = reviewsData || {
|
const actualReviewsData = reviewsData || {
|
||||||
previewReviews: fallbackReviews.previewReviews,
|
previewReviews: fallbackReviews.previewReviews,
|
||||||
stats: fallbackReviews.stats,
|
stats: fallbackReviews.stats,
|
||||||
isLoading: fallbackReviews.isLoading
|
isLoading: fallbackReviews.isLoading,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 팝업 상태 관리 - 모드와 선택된 이미지 인덱스 추가
|
// 팝업 상태 관리 - 모드와 선택된 이미지 인덱스 추가
|
||||||
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
||||||
const [popupMode, setPopupMode] = useState("customer-images"); // "customer-images", "all-images"
|
const [popupMode, setPopupMode] = useState("customer-images"); // "customer-images", "all-images"
|
||||||
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
|
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
|
||||||
// Redux에서 showAllReviews 상태 가져오기
|
// Redux에서 showAllReviews 상태 가져오기
|
||||||
const showAllReviews = useSelector((state) => state.product.showAllReviews);
|
const showAllReviews = useSelector((state) => state.product.showAllReviews);
|
||||||
|
|
||||||
// 디버깅: showAllReviews 상태 변경 확인
|
// 디버깅: showAllReviews 상태 변경 확인
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("[UserReviews] showAllReviews state changed:", {
|
console.log("[UserReviews] showAllReviews state changed:", {
|
||||||
showAllReviews,
|
showAllReviews,
|
||||||
reviewListLength: (actualReviewsData.previewReviews && actualReviewsData.previewReviews.length) || 0,
|
reviewListLength:
|
||||||
willShowCount: showAllReviews ? ((actualReviewsData.previewReviews && actualReviewsData.previewReviews.length) || 0) : 5,
|
(actualReviewsData.previewReviews &&
|
||||||
|
actualReviewsData.previewReviews.length) ||
|
||||||
|
0,
|
||||||
|
willShowCount: showAllReviews
|
||||||
|
? (actualReviewsData.previewReviews &&
|
||||||
|
actualReviewsData.previewReviews.length) ||
|
||||||
|
0
|
||||||
|
: 5,
|
||||||
hasReviewsData: !!reviewsData,
|
hasReviewsData: !!reviewsData,
|
||||||
isFromProductAllSection: !!reviewsData
|
isFromProductAllSection: !!reviewsData,
|
||||||
});
|
});
|
||||||
}, [showAllReviews, actualReviewsData.previewReviews, reviewsData]);
|
}, [showAllReviews, actualReviewsData.previewReviews, reviewsData]);
|
||||||
|
|
||||||
@@ -68,33 +89,36 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showAllReviews && tScrollerRef.current) {
|
if (showAllReviews && tScrollerRef.current) {
|
||||||
// console.log("[UserReviews] Forcing TScroller to update scroll area for all reviews");
|
// console.log("[UserReviews] Forcing TScroller to update scroll area for all reviews");
|
||||||
|
|
||||||
// 다음 렌더링 사이클 후 스크롤 영역 재계산
|
// 다음 렌더링 사이클 후 스크롤 영역 재계산
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (tScrollerRef.current) {
|
if (tScrollerRef.current) {
|
||||||
// TScroller의 스크롤 영역을 강제로 업데이트
|
// TScroller의 스크롤 영역을 강제로 업데이트
|
||||||
if (typeof tScrollerRef.current.calculateMetrics === 'function') {
|
if (typeof tScrollerRef.current.calculateMetrics === "function") {
|
||||||
tScrollerRef.current.calculateMetrics();
|
tScrollerRef.current.calculateMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 또는 scrollTo를 호출해서 스크롤 영역 업데이트
|
// 또는 scrollTo를 호출해서 스크롤 영역 업데이트
|
||||||
if (typeof tScrollerRef.current.scrollTo === 'function') {
|
if (typeof tScrollerRef.current.scrollTo === "function") {
|
||||||
tScrollerRef.current.scrollTo({ position: { y: 0 }, animate: false });
|
tScrollerRef.current.scrollTo({
|
||||||
|
position: { y: 0 },
|
||||||
|
animate: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log("[UserReviews] TScroller scroll area updated");
|
// console.log("[UserReviews] TScroller scroll area updated");
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
}, [showAllReviews]);
|
}, [showAllReviews]);
|
||||||
|
|
||||||
// actualReviewsData에서 데이터 가져오기 (ProductAllSection에서 전달받거나 자체 useReviews)
|
// actualReviewsData에서 데이터 가져오기 (ProductAllSection에서 전달받거나 자체 useReviews)
|
||||||
const reviewListData = actualReviewsData.previewReviews; // 리뷰 리스트 (5개)
|
const reviewListData = actualReviewsData.previewReviews; // 리뷰 리스트 (5개)
|
||||||
const reviewTotalCount = actualReviewsData.stats.totalReviews;
|
const reviewTotalCount = actualReviewsData.stats.totalReviews;
|
||||||
const reviewDetailData = {
|
const reviewDetailData = {
|
||||||
totRvwCnt: actualReviewsData.stats.totalReviews,
|
totRvwCnt: actualReviewsData.stats.totalReviews,
|
||||||
avgRvwScr: actualReviewsData.stats.averageRating,
|
avgRvwScr: actualReviewsData.stats.averageRating,
|
||||||
totRvwAvg: actualReviewsData.stats.averageRating
|
totRvwAvg: actualReviewsData.stats.averageRating,
|
||||||
};
|
};
|
||||||
|
|
||||||
// [UserReviews] 데이터 수신 확인 로그
|
// [UserReviews] 데이터 수신 확인 로그
|
||||||
@@ -105,7 +129,9 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
averageRating: actualReviewsData.stats.averageRating,
|
averageRating: actualReviewsData.stats.averageRating,
|
||||||
isLoading: actualReviewsData.isLoading,
|
isLoading: actualReviewsData.isLoading,
|
||||||
hasData: reviewListData && reviewListData.length > 0,
|
hasData: reviewListData && reviewListData.length > 0,
|
||||||
dataSource: reviewsData ? 'ProductAllSection props' : 'useReviews fallback'
|
dataSource: reviewsData
|
||||||
|
? "ProductAllSection props"
|
||||||
|
: "useReviews fallback",
|
||||||
});
|
});
|
||||||
}, [reviewListData, actualReviewsData, reviewsData]);
|
}, [reviewListData, actualReviewsData, reviewsData]);
|
||||||
|
|
||||||
@@ -118,26 +144,32 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 리뷰 클릭으로 User Reviews 모드 팝업 열기
|
// 리뷰 클릭으로 User Reviews 모드 팝업 열기
|
||||||
const handleReviewClick = useCallback((reviewIndex) => {
|
const handleReviewClick = useCallback(
|
||||||
// 클릭한 리뷰 정보 (previewReviews에서)
|
(reviewIndex) => {
|
||||||
const clickedReview = reviewListData[reviewIndex];
|
// 클릭한 리뷰 정보 (previewReviews에서)
|
||||||
|
const clickedReview = reviewListData[reviewIndex];
|
||||||
// 전체 리뷰에서 클릭한 리뷰의 실제 인덱스 찾기
|
|
||||||
const realIndex = fallbackReviews.allReviews.findIndex(
|
// 전체 리뷰에서 클릭한 리뷰의 실제 인덱스 찾기
|
||||||
review => review.rvwId === clickedReview.rvwId
|
const realIndex = fallbackReviews.allReviews.findIndex(
|
||||||
);
|
(review) => review.rvwId === clickedReview.rvwId
|
||||||
|
);
|
||||||
console.log("[UserReviews] Review clicked, opening popup in User Reviews mode:", {
|
|
||||||
previewIndex: reviewIndex,
|
console.log(
|
||||||
realIndex,
|
"[UserReviews] Review clicked, opening popup in User Reviews mode:",
|
||||||
clickedReviewId: clickedReview.rvwId,
|
{
|
||||||
totalReviews: fallbackReviews.allReviews.length
|
previewIndex: reviewIndex,
|
||||||
});
|
realIndex,
|
||||||
|
clickedReviewId: clickedReview.rvwId,
|
||||||
setSelectedImageIndex(realIndex >= 0 ? realIndex : reviewIndex);
|
totalReviews: fallbackReviews.allReviews.length,
|
||||||
setPopupMode("user-reviews");
|
}
|
||||||
setIsPopupOpen(true);
|
);
|
||||||
}, [reviewListData, fallbackReviews.allReviews]);
|
|
||||||
|
setSelectedImageIndex(realIndex >= 0 ? realIndex : reviewIndex);
|
||||||
|
setPopupMode("user-reviews");
|
||||||
|
setIsPopupOpen(true);
|
||||||
|
},
|
||||||
|
[reviewListData, fallbackReviews.allReviews]
|
||||||
|
);
|
||||||
|
|
||||||
// 팝업 관련 핸들러들
|
// 팝업 관련 핸들러들
|
||||||
// +View More 버튼으로 Customer Images 모드 팝업 열기
|
// +View More 버튼으로 Customer Images 모드 팝업 열기
|
||||||
@@ -149,7 +181,10 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
|
|
||||||
// 이미지 클릭으로 All-Images 모드 팝업 열기
|
// 이미지 클릭으로 All-Images 모드 팝업 열기
|
||||||
const handleOpenAllImagesPopup = useCallback((imageIndex = 0) => {
|
const handleOpenAllImagesPopup = useCallback((imageIndex = 0) => {
|
||||||
console.log("[UserReviews] Opening popup in All-Images mode, image index:", imageIndex);
|
console.log(
|
||||||
|
"[UserReviews] Opening popup in All-Images mode, image index:",
|
||||||
|
imageIndex
|
||||||
|
);
|
||||||
setSelectedImageIndex(imageIndex);
|
setSelectedImageIndex(imageIndex);
|
||||||
setPopupMode("all-images");
|
setPopupMode("all-images");
|
||||||
setIsPopupOpen(true);
|
setIsPopupOpen(true);
|
||||||
@@ -164,7 +199,10 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
|
|
||||||
// 팝업 모드 변경 핸들러
|
// 팝업 모드 변경 핸들러
|
||||||
const handleModeChange = useCallback((newMode, imageIndex = 0) => {
|
const handleModeChange = useCallback((newMode, imageIndex = 0) => {
|
||||||
console.log("[UserReviews] Mode change requested:", { newMode, imageIndex });
|
console.log("[UserReviews] Mode change requested:", {
|
||||||
|
newMode,
|
||||||
|
imageIndex,
|
||||||
|
});
|
||||||
setPopupMode(newMode);
|
setPopupMode(newMode);
|
||||||
if (newMode === "all-images" || newMode === "user-reviews") {
|
if (newMode === "all-images" || newMode === "user-reviews") {
|
||||||
setSelectedImageIndex(imageIndex);
|
setSelectedImageIndex(imageIndex);
|
||||||
@@ -173,9 +211,6 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
|
|
||||||
// handleImageClick 제거 - 더 이상 필요없음
|
// handleImageClick 제거 - 더 이상 필요없음
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// customerImages 로직 제거 - useReviews의 extractImagesFromReviews 사용
|
// customerImages 로직 제거 - useReviews의 extractImagesFromReviews 사용
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -190,13 +225,15 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
verticalScrollbar="auto"
|
verticalScrollbar="auto"
|
||||||
cbScrollTo={getScrollTo}
|
cbScrollTo={getScrollTo}
|
||||||
forceUpdate={showAllReviews}
|
forceUpdate={showAllReviews}
|
||||||
key={showAllReviews ? `all-${(reviewListData && reviewListData.length) || 0}` : 'limited-5'}
|
key={
|
||||||
|
showAllReviews
|
||||||
|
? `all-${(reviewListData && reviewListData.length) || 0}`
|
||||||
|
: "limited-5"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<THeaderDetail
|
<THeaderDetail
|
||||||
title={$L(
|
title={$L(`USER REVIEWS (${reviewTotalCount})`)}
|
||||||
`USER REVIEWS (${reviewTotalCount})`
|
className={classNames(css.tHeader, css.tHeaderDetail)}
|
||||||
)}
|
|
||||||
className={css.tHeader}
|
|
||||||
>
|
>
|
||||||
{reviewDetailData && reviewDetailData.totRvwAvg && (
|
{reviewDetailData && reviewDetailData.totRvwAvg && (
|
||||||
<StarRating
|
<StarRating
|
||||||
@@ -205,8 +242,8 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</THeaderDetail>
|
</THeaderDetail>
|
||||||
<CustomerImages
|
<CustomerImages
|
||||||
panelInfo={panelInfo}
|
panelInfo={panelInfo}
|
||||||
onImageClick={handleOpenPopup}
|
onImageClick={handleOpenPopup}
|
||||||
onViewMoreClick={handleOpenPopup}
|
onViewMoreClick={handleOpenPopup}
|
||||||
imageData={fallbackReviews.extractImagesFromReviews}
|
imageData={fallbackReviews.extractImagesFromReviews}
|
||||||
@@ -219,31 +256,48 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
</div>
|
</div>
|
||||||
{reviewListData &&
|
{reviewListData &&
|
||||||
(() => {
|
(() => {
|
||||||
const reviewsToShow = showAllReviews ? reviewListData : reviewListData.slice(0, 5);
|
const reviewsToShow = showAllReviews
|
||||||
|
? reviewListData
|
||||||
|
: reviewListData.slice(0, 5);
|
||||||
console.log("[UserReviews] Reviews to render:", {
|
console.log("[UserReviews] Reviews to render:", {
|
||||||
showAllReviews,
|
showAllReviews,
|
||||||
totalReviews: reviewListData.length,
|
totalReviews: reviewListData.length,
|
||||||
reviewsToShowCount: reviewsToShow.length,
|
reviewsToShowCount: reviewsToShow.length,
|
||||||
isShowingAll: showAllReviews,
|
isShowingAll: showAllReviews,
|
||||||
reviewListData: reviewListData
|
reviewListData: reviewListData,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 실제 렌더링될 각 리뷰 로그
|
// 실제 렌더링될 각 리뷰 로그
|
||||||
reviewsToShow.forEach((review, index) => {
|
reviewsToShow.forEach((review, index) => {
|
||||||
console.log(`[UserReviews] Review ${index + 1}/${reviewsToShow.length}:`, {
|
console.log(
|
||||||
rvwId: review.rvwId,
|
`[UserReviews] Review ${index + 1}/${reviewsToShow.length}:`,
|
||||||
rvwCtnt: (review.rvwCtnt && review.rvwCtnt.substring(0, 50)) + "...",
|
{
|
||||||
rvwRtng: review.rvwRtng,
|
rvwId: review.rvwId,
|
||||||
hasImages: (review.reviewImageList && review.reviewImageList.length) || 0,
|
rvwCtnt:
|
||||||
rvwRgstDtt: review.rvwRgstDtt,
|
(review.rvwCtnt && review.rvwCtnt.substring(0, 50)) +
|
||||||
fullReview: review
|
"...",
|
||||||
});
|
rvwRtng: review.rvwRtng,
|
||||||
|
hasImages:
|
||||||
|
(review.reviewImageList &&
|
||||||
|
review.reviewImageList.length) ||
|
||||||
|
0,
|
||||||
|
rvwRgstDtt: review.rvwRgstDtt,
|
||||||
|
fullReview: review,
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return reviewsToShow;
|
return reviewsToShow;
|
||||||
})().map((review, index, array) => {
|
})().map((review, index, array) => {
|
||||||
const { reviewImageList, rvwRtng, rvwRgstDtt, rvwCtnt, rvwId, wrtrNknm, rvwWrtrId } =
|
const {
|
||||||
review;
|
reviewImageList,
|
||||||
|
rvwRtng,
|
||||||
|
rvwRgstDtt,
|
||||||
|
rvwCtnt,
|
||||||
|
rvwId,
|
||||||
|
wrtrNknm,
|
||||||
|
rvwWrtrId,
|
||||||
|
} = review;
|
||||||
const isLastReview = index === array.length - 1;
|
const isLastReview = index === array.length - 1;
|
||||||
/* console.log(`[UserReviews] Rendering review ${index}:`, {
|
/* console.log(`[UserReviews] Rendering review ${index}:`, {
|
||||||
rvwId,
|
rvwId,
|
||||||
@@ -258,7 +312,11 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
aria-label={`user-reviews-:${rvwId}`}
|
aria-label={`user-reviews-:${rvwId}`}
|
||||||
className={css.reviewContentContainer}
|
className={css.reviewContentContainer}
|
||||||
onClick={() => handleReviewClick(index)}
|
onClick={() => handleReviewClick(index)}
|
||||||
spotlightId={isLastReview ? 'user-review-at-last' : `user-review-${index}`}
|
spotlightId={
|
||||||
|
isLastReview
|
||||||
|
? "user-review-at-last"
|
||||||
|
: `user-review-${index}`
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{reviewImageList && reviewImageList.length > 0 && (
|
{reviewImageList && reviewImageList.length > 0 && (
|
||||||
<img
|
<img
|
||||||
@@ -285,17 +343,14 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{rvwCtnt && (
|
{rvwCtnt && <div className={css.reviewText}>{rvwCtnt}</div>}
|
||||||
<div className={css.reviewText}>{rvwCtnt}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</SpottableComponent>
|
</SpottableComponent>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</UserReviewsScroller>
|
</UserReviewsScroller>
|
||||||
|
|
||||||
{/* UserReviewsPopup 추가 - 모드별 데이터 전달 */}
|
{/* UserReviewsPopup 추가 - 모드별 데이터 전달 */}
|
||||||
<UserReviewsPopup
|
<UserReviewsPopup
|
||||||
open={isPopupOpen}
|
open={isPopupOpen}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
height: auto !important; // 동적 높이 강제 적용
|
height: auto !important; // 동적 높이 강제 적용
|
||||||
min-height: 500px; // 최소 높이 보장
|
min-height: 500px; // 최소 높이 보장
|
||||||
max-height: none !important; // 최대 높이 제한 완전 제거
|
max-height: none !important; // 최대 높이 제한 완전 제거
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
// 스크롤 컨테이너 내부도 동적 높이 허용
|
// 스크롤 컨테이너 내부도 동적 높이 허용
|
||||||
> * {
|
> * {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
@@ -28,14 +28,26 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
&.tHeaderDetail {
|
||||||
|
height: 56px;
|
||||||
|
max-width: none;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
.size(@w:100%,@h:100%);
|
.size(@w:100%,@h:100%);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
&:first-child {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> &.title {
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.averageOverallRating {
|
.averageOverallRating {
|
||||||
.size(@w: 176px,@h:30px);
|
width: 176px;
|
||||||
|
height: 30px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@@ -54,7 +66,7 @@
|
|||||||
.reviewItem {
|
.reviewItem {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
.showReviewsText {
|
.showReviewsText {
|
||||||
.size(@w:100%, @h:36px);
|
.size(@w:100%, @h:36px);
|
||||||
.font(@fontFamily: @baseFont, @fontSize: 24px);
|
.font(@fontFamily: @baseFont, @fontSize: 24px);
|
||||||
@@ -71,7 +83,7 @@
|
|||||||
.flex(@justifyCenter:flex-start);
|
.flex(@justifyCenter:flex-start);
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
&::after {
|
&::after {
|
||||||
.focused(@boxShadow:22px, @borderRadius:12px);
|
.focused(@boxShadow:22px, @borderRadius:12px);
|
||||||
@@ -92,10 +104,10 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
@@ -146,7 +158,7 @@
|
|||||||
width: auto; // "View All Reviews +" 한 줄 표시용으로 확장
|
width: auto; // "View All Reviews +" 한 줄 표시용으로 확장
|
||||||
height: 75px; // 20 + 35 + 20
|
height: 75px; // 20 + 35 + 20
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
&::after {
|
&::after {
|
||||||
.focused(@boxShadow:22px, @borderRadius:6px);
|
.focused(@boxShadow:22px, @borderRadius:6px);
|
||||||
@@ -159,13 +171,13 @@
|
|||||||
padding: 20px 30px;
|
padding: 20px 30px;
|
||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #EEEEEE;
|
border: 1px solid #eeeeee;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.viewAllReviewsText {
|
.viewAllReviewsText {
|
||||||
color: #EAEAEA;
|
color: #eaeaea;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-family: @baseFont;
|
font-family: @baseFont;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -181,4 +193,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
import React, { useCallback, useState, useEffect } from "react";
|
import React, {
|
||||||
import classNames from "classnames";
|
useCallback,
|
||||||
import Spottable from "@enact/spotlight/Spottable";
|
useEffect,
|
||||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
useRef,
|
||||||
import TNewPopUp from "../../../../../components/TPopUp/TNewPopUp";
|
useState,
|
||||||
import TButton from "../../../../../components/TButton/TButton";
|
} from 'react';
|
||||||
import { $L } from "../../../../../utils/helperMethods";
|
|
||||||
import UserReviewDetail from "../UserReviewDetail/UserReviewDetail";
|
import classNames from 'classnames';
|
||||||
import ImageSkeleton from "./ImageSkeleton/ImageSkeleton";
|
|
||||||
import css from "./UserReviewsPopup.module.less";
|
import SpotlightContainerDecorator
|
||||||
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
|
import Spottable from '@enact/spotlight/Spottable';
|
||||||
|
|
||||||
|
import TButton from '../../../../../components/TButton/TButton';
|
||||||
|
import TNewPopUp from '../../../../../components/TPopUp/TNewPopUp';
|
||||||
|
import useScrollTo from '../../../../../hooks/useScrollTo';
|
||||||
|
import { $L } from '../../../../../utils/helperMethods';
|
||||||
|
import TScrollerDetail from '../../../components/TScroller/TScrollerDetail';
|
||||||
|
import UserReviewDetail from '../UserReviewDetail/UserReviewDetail';
|
||||||
|
import ImageSkeleton from './ImageSkeleton/ImageSkeleton';
|
||||||
|
import css from './UserReviewsPopup.module.less';
|
||||||
|
|
||||||
const SpottableImage = Spottable("div");
|
const SpottableImage = Spottable("div");
|
||||||
|
|
||||||
@@ -24,7 +35,7 @@ const FooterContainer = SpotlightContainerDecorator(
|
|||||||
{
|
{
|
||||||
enterTo: "default-element",
|
enterTo: "default-element",
|
||||||
preserveId: true,
|
preserveId: true,
|
||||||
defaultElement: "close-button"
|
defaultElement: "close-button",
|
||||||
},
|
},
|
||||||
"div"
|
"div"
|
||||||
);
|
);
|
||||||
@@ -40,6 +51,9 @@ export default function UserReviewsPopup({
|
|||||||
onModeChange, // 모드 변경 콜백 함수
|
onModeChange, // 모드 변경 콜백 함수
|
||||||
className,
|
className,
|
||||||
}) {
|
}) {
|
||||||
|
const scrollContainerRef = useRef(null);
|
||||||
|
const { getScrollTo } = useScrollTo();
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
if (onClose) {
|
if (onClose) {
|
||||||
onClose();
|
onClose();
|
||||||
@@ -47,12 +61,18 @@ export default function UserReviewsPopup({
|
|||||||
}, [onClose]);
|
}, [onClose]);
|
||||||
|
|
||||||
// Customer Images 모드에서 이미지 클릭 시 All Images 모드로 변경
|
// Customer Images 모드에서 이미지 클릭 시 All Images 모드로 변경
|
||||||
const handleCustomerImageClick = useCallback((index) => {
|
const handleCustomerImageClick = useCallback(
|
||||||
console.log("[UserReviewsPopup] Customer image clicked, switching to All Images mode, index:", index);
|
(index) => {
|
||||||
if (onModeChange) {
|
console.log(
|
||||||
onModeChange("all-images", index);
|
"[UserReviewsPopup] Customer image clicked, switching to All Images mode, index:",
|
||||||
}
|
index
|
||||||
}, [onModeChange]);
|
);
|
||||||
|
if (onModeChange) {
|
||||||
|
onModeChange("all-images", index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onModeChange]
|
||||||
|
);
|
||||||
|
|
||||||
// 모드별 헤더 정보
|
// 모드별 헤더 정보
|
||||||
const getHeaderInfo = useCallback((mode) => {
|
const getHeaderInfo = useCallback((mode) => {
|
||||||
@@ -61,20 +81,20 @@ export default function UserReviewsPopup({
|
|||||||
return {
|
return {
|
||||||
title: $L("All images"),
|
title: $L("All images"),
|
||||||
hasIcon: true,
|
hasIcon: true,
|
||||||
iconType: "all-images"
|
iconType: "all-images",
|
||||||
};
|
};
|
||||||
case "user-reviews":
|
case "user-reviews":
|
||||||
return {
|
return {
|
||||||
title: $L("User Reviews"),
|
title: $L("User Reviews"),
|
||||||
hasIcon: true,
|
hasIcon: true,
|
||||||
iconType: "user-reviews"
|
iconType: "user-reviews",
|
||||||
};
|
};
|
||||||
case "customer-images":
|
case "customer-images":
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
title: $L("Customer Images"),
|
title: $L("Customer Images"),
|
||||||
hasIcon: false,
|
hasIcon: false,
|
||||||
iconType: null
|
iconType: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@@ -88,8 +108,8 @@ export default function UserReviewsPopup({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (mode === "all-images" && images && images[selectedImageIndex]) {
|
if (mode === "all-images" && images && images[selectedImageIndex]) {
|
||||||
const selectedImage = images[selectedImageIndex];
|
const selectedImage = images[selectedImageIndex];
|
||||||
const reviewIndex = reviewsWithImages.findIndex(review =>
|
const reviewIndex = reviewsWithImages.findIndex(
|
||||||
review.rvwId === selectedImage.reviewId
|
(review) => review.rvwId === selectedImage.reviewId
|
||||||
);
|
);
|
||||||
if (reviewIndex !== -1) {
|
if (reviewIndex !== -1) {
|
||||||
setCurrentReviewIndex(reviewIndex);
|
setCurrentReviewIndex(reviewIndex);
|
||||||
@@ -108,42 +128,39 @@ export default function UserReviewsPopup({
|
|||||||
}, [currentReviewIndex]);
|
}, [currentReviewIndex]);
|
||||||
|
|
||||||
const handleNextReview = useCallback(() => {
|
const handleNextReview = useCallback(() => {
|
||||||
const maxIndex = mode === "user-reviews"
|
const maxIndex =
|
||||||
? allReviews.length - 1
|
mode === "user-reviews"
|
||||||
: reviewsWithImages.length - 1;
|
? allReviews.length - 1
|
||||||
|
: reviewsWithImages.length - 1;
|
||||||
|
|
||||||
if (currentReviewIndex < maxIndex) {
|
if (currentReviewIndex < maxIndex) {
|
||||||
setCurrentReviewIndex(currentReviewIndex + 1);
|
setCurrentReviewIndex(currentReviewIndex + 1);
|
||||||
}
|
}
|
||||||
}, [currentReviewIndex, mode, allReviews.length, reviewsWithImages.length]);
|
}, [currentReviewIndex, mode, allReviews.length, reviewsWithImages.length]);
|
||||||
|
|
||||||
// All Images 아이콘 컴포넌트 (PNG 파일 사용)
|
// All Images 아이콘 컴포넌트 (PNG 파일 사용)
|
||||||
const AllImagesIcon = () => (
|
const AllImagesIcon = () => <div className={css.headerIcon} />;
|
||||||
<div className={css.headerIcon} />
|
|
||||||
);
|
|
||||||
|
|
||||||
// User Reviews 아이콘 컴포넌트 (추후 구현)
|
// User Reviews 아이콘 컴포넌트 (추후 구현)
|
||||||
const UserReviewsIcon = () => (
|
const UserReviewsIcon = () => (
|
||||||
<div className={css.headerIcon}>
|
<div className={css.headerIcon}>{/* User Reviews 아이콘 내용 */}</div>
|
||||||
{/* User Reviews 아이콘 내용 */}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 이미지 로딩 상태 관리
|
// 이미지 로딩 상태 관리
|
||||||
const [imageLoadStates, setImageLoadStates] = useState({});
|
const [imageLoadStates, setImageLoadStates] = useState({});
|
||||||
|
|
||||||
const handleImageLoad = useCallback((index) => {
|
const handleImageLoad = useCallback((index) => {
|
||||||
setImageLoadStates(prev => ({
|
setImageLoadStates((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[index]: true
|
[index]: true,
|
||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleImageError = useCallback((index) => {
|
const handleImageError = useCallback((index) => {
|
||||||
console.error(`[UserReviewsPopup] Image load failed for index: ${index}`);
|
console.error(`[UserReviewsPopup] Image load failed for index: ${index}`);
|
||||||
setImageLoadStates(prev => ({
|
setImageLoadStates((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[index]: false
|
[index]: false,
|
||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -171,63 +188,76 @@ export default function UserReviewsPopup({
|
|||||||
{headerInfo.iconType === "user-reviews" && <UserReviewsIcon />}
|
{headerInfo.iconType === "user-reviews" && <UserReviewsIcon />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className={css.headerTitle}>
|
<div className={css.headerTitle}>{headerInfo.title}</div>
|
||||||
{headerInfo.title}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content - 모드별 내용 */}
|
{/* Content - 모드별 내용 */}
|
||||||
<ContentContainer
|
<ContentContainer
|
||||||
className={css.content}
|
className={css.content}
|
||||||
defaultElement={
|
defaultElement={
|
||||||
mode === "all-images" ? "review-detail-prev" :
|
mode === "all-images"
|
||||||
mode === "user-reviews" ? "user-review-detail-prev" :
|
? "review-detail-prev"
|
||||||
"user-review-image-0"
|
: mode === "user-reviews"
|
||||||
|
? "user-review-detail-prev"
|
||||||
|
: "user-review-image-0"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{mode === "customer-images" && (
|
{mode === "customer-images" && (
|
||||||
<div className={css.imageGrid}>
|
<TScrollerDetail
|
||||||
{displayImages.map((image, index) => {
|
ref={scrollContainerRef}
|
||||||
const isLoaded = imageLoadStates[index] === true;
|
verticalScrollbar="visible"
|
||||||
const isFailed = imageLoadStates[index] === false;
|
className={css.scrollerOverride}
|
||||||
|
cbScrollTo={getScrollTo}
|
||||||
return (
|
spotlightDisabled={false}
|
||||||
<SpottableImage
|
spotlightRestrict="none"
|
||||||
key={`user-review-image-${index}`}
|
>
|
||||||
spotlightId={`user-review-image-${index}`}
|
<div className={css.imageGrid}>
|
||||||
className={css.imageItem}
|
{displayImages.map((image, index) => {
|
||||||
onClick={() => handleCustomerImageClick(index)}
|
const isLoaded = imageLoadStates[index] === true;
|
||||||
>
|
const isFailed = imageLoadStates[index] === false;
|
||||||
{/* Skeleton UI - 이미지 로딩 중일 때 표시 */}
|
|
||||||
{!isLoaded && !isFailed && (
|
return (
|
||||||
<ImageSkeleton className={css.image} />
|
<SpottableImage
|
||||||
)}
|
key={`user-review-image-${index}`}
|
||||||
|
spotlightId={`user-review-image-${index}`}
|
||||||
{/* 실제 이미지 */}
|
className={css.imageItem}
|
||||||
<img
|
onClick={() => handleCustomerImageClick(index)}
|
||||||
src={image.imgUrl || image}
|
>
|
||||||
alt={`Customer review ${index + 1}`}
|
<div>
|
||||||
className={css.image}
|
{/* Skeleton UI - 이미지 로딩 중일 때 표시 */}
|
||||||
style={{
|
{!isLoaded && !isFailed && (
|
||||||
opacity: isLoaded ? 1 : 0,
|
<ImageSkeleton className={css.image} />
|
||||||
transition: 'opacity 0.3s ease-in-out'
|
)}
|
||||||
}}
|
|
||||||
onLoad={() => handleImageLoad(index)}
|
{/* 실제 이미지 */}
|
||||||
onError={() => handleImageError(index)}
|
<img
|
||||||
/>
|
src={image.imgUrl || image}
|
||||||
|
alt={`Customer review ${index + 1}`}
|
||||||
{/* 이미지 로드 실패 시 표시할 플레이스홀더 */}
|
className={css.image}
|
||||||
{isFailed && (
|
style={{
|
||||||
<div className={css.imagePlaceholder}>
|
opacity: isLoaded ? 1 : 0,
|
||||||
<div className={css.placeholderText}>이미지 없음</div>
|
transition: "opacity 0.3s ease-in-out",
|
||||||
|
}}
|
||||||
|
onLoad={() => handleImageLoad(index)}
|
||||||
|
onError={() => handleImageError(index)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 이미지 로드 실패 시 표시할 플레이스홀더 */}
|
||||||
|
{isFailed && (
|
||||||
|
<div className={css.imagePlaceholder}>
|
||||||
|
<div className={css.placeholderText}>
|
||||||
|
이미지 없음
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
</SpottableImage>
|
||||||
</SpottableImage>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</div>
|
||||||
</div>
|
</TScrollerDetail>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{mode === "all-images" && (
|
{mode === "all-images" && (
|
||||||
<UserReviewDetail
|
<UserReviewDetail
|
||||||
currentReview={reviewsWithImages[currentReviewIndex]}
|
currentReview={reviewsWithImages[currentReviewIndex]}
|
||||||
@@ -238,7 +268,7 @@ export default function UserReviewsPopup({
|
|||||||
className={css.reviewDetailContainer}
|
className={css.reviewDetailContainer}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{mode === "user-reviews" && (
|
{mode === "user-reviews" && (
|
||||||
<UserReviewDetail
|
<UserReviewDetail
|
||||||
currentReview={allReviews[currentReviewIndex]}
|
currentReview={allReviews[currentReviewIndex]}
|
||||||
@@ -265,4 +295,4 @@ export default function UserReviewsPopup({
|
|||||||
</div>
|
</div>
|
||||||
</TNewPopUp>
|
</TNewPopUp>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,16 +12,16 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
// Header 영역 - 모드별 아이콘과 제목 지원 (기존 레이아웃 유지)
|
// Header 영역 - 모드별 아이콘과 제목 지원 (기존 레이아웃 유지)
|
||||||
.header {
|
.header {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
background: #E7EBEF;
|
background: #e7ebef;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
// All Images 아이콘 (PNG 파일 사용)
|
// All Images 아이콘 (PNG 파일 사용)
|
||||||
.headerIcon {
|
.headerIcon {
|
||||||
width: 52px;
|
width: 52px;
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
margin-right: 15px; // gap: 15 → margin-right: 15px
|
margin-right: 15px; // gap: 15 → margin-right: 15px
|
||||||
}
|
}
|
||||||
|
|
||||||
.headerTitle {
|
.headerTitle {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: black;
|
color: black;
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content 영역
|
// Content 영역
|
||||||
.content {
|
.content {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
@@ -54,123 +54,177 @@
|
|||||||
justify-content: center; // 중앙 정렬
|
justify-content: center; // 중앙 정렬
|
||||||
align-items: center; // 중앙 정렬
|
align-items: center; // 중앙 정렬
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.imageGrid {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center; // 중앙 정렬로 균등 배치
|
|
||||||
align-items: flex-start;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-content: flex-start;
|
|
||||||
overflow-y: scroll; // 스크롤바 항상 표시
|
|
||||||
overflow-x: hidden;
|
|
||||||
padding: 30px 40px; // 좌우 패딩 증가
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
// gap 대신 margin 사용 (TV 호환성) - 화면을 적절히 채우도록 조정
|
|
||||||
.imageItem {
|
|
||||||
width: 210px; // 크기 약간 증가
|
|
||||||
height: 190px; // 비율 맞춤
|
|
||||||
border-radius: 12px;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 35px; // 마진 증가로 균등 분배
|
|
||||||
margin-bottom: 30px; // 세로 마진도 증가
|
|
||||||
|
|
||||||
// 4개씩 배치하므로 4번째마다 margin-right 제거
|
|
||||||
&:nth-child(4n) {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&::after {
|
.scrollerOverride {
|
||||||
.focused(@boxShadow: 0px, @borderRadius: 12px);
|
width: 1060px; // 절대 크기 지정
|
||||||
// 프로젝트 표준 포커스 스타일 사용 (4px solid @PRIMARY_COLOR_RED)
|
height: 100%;
|
||||||
}
|
// 좌측 30px, 우측 66px(스크롤바) 패딩을 명시적으로 적용
|
||||||
}
|
padding: 30px 20px 30px 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
.image {
|
margin: 0;
|
||||||
width: 100%;
|
overflow-y: auto;
|
||||||
height: 100%;
|
overflow-x: hidden;
|
||||||
border-radius: 12px;
|
display: flex;
|
||||||
object-fit: cover;
|
flex-direction: column;
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
// 스크롤바 너비를 6px로 명확하게 설정
|
||||||
}
|
&::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
// 이미지 로드 실패 시 플레이스홀더
|
|
||||||
.imagePlaceholder {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: #f5f5f5;
|
|
||||||
border-radius: 12px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.placeholderText {
|
|
||||||
color: #999;
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: @baseFont;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// selectedImage 스타일 제거 - 오직 포커스만 사용
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// View More 아이템
|
&::-webkit-scrollbar-track {
|
||||||
.viewMoreItem {
|
background: transparent; // 트랙 배경은 투명하게
|
||||||
width: 210px; // 크기 증가
|
}
|
||||||
height: 190px; // 비율 맞춤
|
|
||||||
border-radius: 12px;
|
&::-webkit-scrollbar-thumb {
|
||||||
position: relative;
|
background: #9c9c9c; // 스크롤바 색상
|
||||||
margin-right: 35px; // 마진 증가
|
border-radius: 3px; // 스크롤바 둥근 모서리
|
||||||
margin-bottom: 30px; // 세로 마진 증가
|
}
|
||||||
|
|
||||||
&:nth-child(4n) {
|
// 스크롤바 thumb에 hover 효과 적용
|
||||||
margin-right: 0;
|
&:hover::-webkit-scrollbar-thumb {
|
||||||
}
|
background: #c72054;
|
||||||
|
}
|
||||||
.image {
|
// gap 대신 margin 사용 (TV 호환성) - 화면을 적절히 채우도록 조정
|
||||||
width: 100%;
|
.imageGrid {
|
||||||
height: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
overflow: visible;
|
||||||
|
height: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: flex-start;
|
||||||
|
// padding: 30px 40px; // 좌우 패딩 증가
|
||||||
|
// padding: 30px 0px 30px 15px; // 좌우 패딩 증가
|
||||||
|
.imageItem {
|
||||||
|
//스타일 변경
|
||||||
|
// width: 210px; // 크기 약간 증가
|
||||||
|
// height: 190px; // 비율 맞춤
|
||||||
|
|
||||||
|
width: 226px; // 크기 약간 증가
|
||||||
|
height: 218px; // 비율 맞춤
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
object-fit: cover;
|
position: relative;
|
||||||
padding: 4px;
|
cursor: pointer;
|
||||||
box-sizing: border-box;
|
|
||||||
|
//스타일 변경
|
||||||
|
// margin-right: 35px; // 마진 증가로 균등 분배
|
||||||
|
// margin-bottom: 30px; // 세로 마진도 증가
|
||||||
|
margin-right: 20px; // 마진 증가로 균등 분배
|
||||||
|
margin-top: 20px; // 세로 마진도 증가
|
||||||
|
|
||||||
|
// 4개씩 배치하므로 4번째마다 margin-right 제거
|
||||||
|
&:nth-child(4n) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
//확대 이미지
|
||||||
|
width: 240px;
|
||||||
|
height: 240px;
|
||||||
|
margin-right: 6px;
|
||||||
|
margin-top: -2px;
|
||||||
|
// margin-top: -3px;
|
||||||
|
outline: none;
|
||||||
|
&::after {
|
||||||
|
.focused(@boxShadow: 0px, @borderRadius: 12px);
|
||||||
|
// 프로젝트 표준 포커스 스타일 사용 (4px solid @PRIMARY_COLOR_RED)
|
||||||
|
}
|
||||||
|
&:nth-child(4n) {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: -14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
object-fit: cover;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 이미지 로드 실패 시 플레이스홀더
|
||||||
|
.imagePlaceholder {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.placeholderText {
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: @baseFont;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectedImage 스타일 제거 - 오직 포커스만 사용
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewMoreOverlay {
|
// View More 아이템
|
||||||
position: absolute;
|
.viewMoreItem {
|
||||||
top: 0;
|
width: 210px; // 크기 증가
|
||||||
left: 0;
|
height: 190px; // 비율 맞춤
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.80) 0%, rgba(0, 0, 0, 0.80) 100%);
|
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
display: flex;
|
position: relative;
|
||||||
justify-content: center;
|
margin-right: 35px; // 마진 증가
|
||||||
align-items: center;
|
margin-bottom: 30px; // 세로 마진 증가
|
||||||
|
|
||||||
.viewMoreText {
|
&:nth-child(4n) {
|
||||||
color: white;
|
margin-right: 0;
|
||||||
font-size: 16px;
|
}
|
||||||
font-family: @baseFont;
|
|
||||||
font-weight: 700;
|
.image {
|
||||||
line-height: 31px;
|
width: 100%;
|
||||||
word-wrap: break-word;
|
height: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
object-fit: cover;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewMoreOverlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(0, 0, 0, 0.8) 0%,
|
||||||
|
rgba(0, 0, 0, 0.8) 100%
|
||||||
|
);
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.viewMoreText {
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: @baseFont;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 31px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// User Reviews 모드용 reviewGrid 스타일
|
// User Reviews 모드용 reviewGrid 스타일
|
||||||
.reviewGrid {
|
.reviewGrid {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -181,20 +235,20 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
// User Reviews 콘텐츠 스타일 - 추후 구현
|
// User Reviews 콘텐츠 스타일 - 추후 구현
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserReviewDetail 컴포넌트를 위한 컨테이너
|
// UserReviewDetail 컴포넌트를 위한 컨테이너
|
||||||
.reviewDetailContainer {
|
.reviewDetailContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 스크롤바 표시 (기본 브라우저 스타일 사용)
|
// 스크롤바 표시 (기본 브라우저 스타일 사용)
|
||||||
// 별도 커스텀 스크롤바 스타일 없음
|
// 별도 커스텀 스크롤바 스타일 없음
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer 영역
|
// Footer 영역
|
||||||
.footer {
|
.footer {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
@@ -202,31 +256,31 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.closeButton {
|
.closeButton {
|
||||||
width: 300px !important;
|
width: 300px !important;
|
||||||
height: 78px !important;
|
height: 78px !important;
|
||||||
background: #7A808D !important;
|
background: #7a808d !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 12px !important;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
|
||||||
color: white !important;
|
color: white !important;
|
||||||
font-size: 30px !important;
|
font-size: 30px !important;
|
||||||
font-family: @baseFont !important;
|
font-family: @baseFont !important;
|
||||||
font-weight: 700 !important;
|
font-weight: 700 !important;
|
||||||
line-height: 30px !important;
|
line-height: 30px !important;
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
background: @PRIMARY_COLOR_RED !important;
|
background: @PRIMARY_COLOR_RED !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: @PRIMARY_COLOR_RED !important;
|
background: @PRIMARY_COLOR_RED !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
@@ -234,4 +288,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from 'react';
|
||||||
import css from "./QRCode.module.less";
|
|
||||||
import { getQRCodeUrl } from "../../../../utils/helperMethods";
|
import { useSelector } from 'react-redux';
|
||||||
import TQRCode from "../../../../components/TQRCode/TQRCode";
|
|
||||||
import { useSelector } from "react-redux";
|
import TQRCode from '../../../../components/TQRCode/TQRCode';
|
||||||
|
import { getQRCodeUrl } from '../../../../utils/helperMethods';
|
||||||
|
import css from './QRCode.module.less';
|
||||||
|
|
||||||
export default function QRCode({
|
export default function QRCode({
|
||||||
productType,
|
productType,
|
||||||
@@ -59,7 +61,7 @@ export default function QRCode({
|
|||||||
{kind === "detail" ? (
|
{kind === "detail" ? (
|
||||||
<TQRCode text={qrCodeUrl} width="240" height="240" />
|
<TQRCode text={qrCodeUrl} width="240" height="240" />
|
||||||
) : (
|
) : (
|
||||||
""
|
qrCodeUrl && <TQRCode text={qrCodeUrl} width="190" height="190" />
|
||||||
)}
|
)}
|
||||||
{/* todo : 시나리오,UI 릴리즈 후 */}
|
{/* todo : 시나리오,UI 릴리즈 후 */}
|
||||||
{/* <div className={css.tooltip}>
|
{/* <div className={css.tooltip}>
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
@import "../../../style/utils.module.less";
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
.size(@w:100%,@h:100%);
|
// .size(@w:100%,@h:100%);
|
||||||
|
.size(@w:100%,@h:334px);
|
||||||
.productInfoWrapper {
|
.productInfoWrapper {
|
||||||
.flex(@justifyCenter:flex-start,@alignCenter:flex-start);
|
.flex(@justifyCenter:flex-start,@alignCenter:flex-start);
|
||||||
margin: 54px 0 10px 0;
|
// margin: 54px 0 10px 0;
|
||||||
|
margin: 20px 0 10px 0;
|
||||||
// 고정 높이로 인해 QR 영역과 하단 버튼 영역 사이에 과도한 여백이 생김
|
// 고정 높이로 인해 QR 영역과 하단 버튼 영역 사이에 과도한 여백이 생김
|
||||||
// 콘텐츠 높이에 맞춰 자동으로 계산되도록 변경하여 불필요한 간격 제거
|
// 콘텐츠 높이에 맞춰 자동으로 계산되도록 변경하여 불필요한 간격 제거
|
||||||
.size(@w:100%,@h:auto);
|
.size(@w:100%,@h:auto);
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import React, { useCallback, useMemo } from "react";
|
import React, {
|
||||||
import usePriceInfo from "../../../../../hooks/usePriceInfo";
|
useCallback,
|
||||||
import { $L } from "../../../../../utils/helperMethods";
|
useMemo,
|
||||||
import css from "./BuyNowPriceDisplay.module.less";
|
} from 'react';
|
||||||
|
|
||||||
|
import usePriceInfo from '../../../../../hooks/usePriceInfo';
|
||||||
|
import { $L } from '../../../../../utils/helperMethods';
|
||||||
|
import css from './BuyNowPriceDisplay.module.less';
|
||||||
|
|
||||||
export default function BuyNowPriceDisplay({
|
export default function BuyNowPriceDisplay({
|
||||||
priceData,
|
priceData,
|
||||||
@@ -41,16 +45,26 @@ export default function BuyNowPriceDisplay({
|
|||||||
{discountRate && Number(discountRate.replace("%", "")) > 4 && (
|
{discountRate && Number(discountRate.replace("%", "")) > 4 && (
|
||||||
<div className={css.rateTag}>{discountRate}</div>
|
<div className={css.rateTag}>{discountRate}</div>
|
||||||
)}
|
)}
|
||||||
<span className={css.price}>
|
<div
|
||||||
{isDiscountedPriceEmpty ? offerInfo : discountedPrice}
|
style={{
|
||||||
</span>
|
width: "100%",
|
||||||
{isDiscounted && (
|
marginTop: "10px",
|
||||||
<span className={css.discountedPrc}>
|
display: "inline-flex",
|
||||||
{originalPrice && isOriginalPriceEmpty
|
height: "60px",
|
||||||
? offerInfo
|
lineHeight: "60px",
|
||||||
: originalPrice}
|
}}
|
||||||
|
>
|
||||||
|
<span className={css.price}>
|
||||||
|
{isDiscountedPriceEmpty ? offerInfo : discountedPrice}
|
||||||
</span>
|
</span>
|
||||||
)}
|
{isDiscounted && (
|
||||||
|
<span className={css.discountedPrc}>
|
||||||
|
{originalPrice && isOriginalPriceEmpty
|
||||||
|
? offerInfo
|
||||||
|
: originalPrice}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 할부 */}
|
{/* 할부 */}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
@import "../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.partnerName {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 36px;
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.flex(@alignCenter:flex-start,@direction:column);
|
||||||
|
.topLayer {
|
||||||
|
height: 42px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
// margin-bottom: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.rateTag {
|
||||||
|
background: linear-gradient(309.43deg, #ef775b 23.84%, #c70850 100%);
|
||||||
|
width: 70px;
|
||||||
|
height: 42px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
.font(@fontFamily: @baseFont, @fontSize: 24px);
|
||||||
|
font-weight: 700;
|
||||||
|
.flex();
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 36px;
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.btmLayer {
|
||||||
|
//margin-top:14px;
|
||||||
|
margin: 10px 0;
|
||||||
|
// display: flex;rateTag
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.price {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 60px;
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
margin-right: 9px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.offerInfo {
|
||||||
|
.elip(4);
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
color: #808080;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
.discountedPrc {
|
||||||
|
font-size: 24px;
|
||||||
|
color: @COLOR_GRAY03;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
//rewd Layer
|
||||||
|
.rewdTopLayer {
|
||||||
|
width: 500px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
border-bottom: 1px solid @COLOR_GRAY02;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 36px;
|
||||||
|
color: @COLOR_GRAY03;
|
||||||
|
}
|
||||||
|
.partnerPrc {
|
||||||
|
text-decoration: line-through;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rewdBtmLayer {
|
||||||
|
padding-top: 24px;
|
||||||
|
.flex(@direction:column,@alignCenter:flex-start);
|
||||||
|
.rewdNm {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 36px;
|
||||||
|
color: @COLOR_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btmPrc {
|
||||||
|
margin-top: 17px;
|
||||||
|
.flex();
|
||||||
|
.rewdPrc {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #808080;
|
||||||
|
margin-right: 10px;
|
||||||
|
padding-top: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rewdRate {
|
||||||
|
font-size: 60px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: @PRIMARY_COLOR_RED;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ export default function ProductPriceDisplay({ productType, productInfo }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{productType && productInfo && (
|
{productType && productInfo && (
|
||||||
<div>
|
/* <div> */
|
||||||
|
<div style={{ margin: "0 10px 0 0", width: "380px" }}>
|
||||||
{/* shop by mobile (구매불가) 상품 price render */}
|
{/* shop by mobile (구매불가) 상품 price render */}
|
||||||
{(productType === "shopByMobile" || isThemeShopByMobile) && (
|
{(productType === "shopByMobile" || isThemeShopByMobile) && (
|
||||||
<ShopByMobilePriceDisplay
|
<ShopByMobilePriceDisplay
|
||||||
|
|||||||
@@ -12,9 +12,10 @@
|
|||||||
}
|
}
|
||||||
.flex(@alignCenter:flex-start,@direction:column);
|
.flex(@alignCenter:flex-start,@direction:column);
|
||||||
.topLayer {
|
.topLayer {
|
||||||
margin-bottom: 20px;
|
|
||||||
height: 42px;
|
height: 42px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
// margin-bottom: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.rateTag {
|
.rateTag {
|
||||||
background: linear-gradient(309.43deg, #ef775b 23.84%, #c70850 100%);
|
background: linear-gradient(309.43deg, #ef775b 23.84%, #c70850 100%);
|
||||||
@@ -34,14 +35,15 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.btmLayer {
|
.btmLayer {
|
||||||
margin-top: 14px;
|
//margin-top:14px;
|
||||||
|
margin: 10px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.price {
|
.price {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 60px;
|
font-size: 60px;
|
||||||
color: @PRIMARY_COLOR_RED;
|
color: @COLOR_WHITE;
|
||||||
margin-right: 9px;
|
margin-right: 9px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user