호텔 인디게이터 기능 구현 (80%) , 탭레이아웃 SubDepth css 수정

This commit is contained in:
고동영
2024-03-15 16:46:51 +09:00
parent 3baf7c099b
commit 45a303637b
6 changed files with 162 additions and 54 deletions

View File

@@ -127,6 +127,7 @@ const TabItemBase = ({
className={classNames(
css.icon,
focused && css.focused,
!path && selected && css.selected,
css[`category-icon-${lgCatCd}`]
)}
/>

View File

@@ -162,7 +162,8 @@
&.category-icon-1013 {
background-image: url("../../../assets/images/icons/ic-category-clearance-nor@3x.png");
}
&.focused {
&.focused,
&.selected {
opacity: 1;
}
}

View File

@@ -56,6 +56,7 @@ export const homeReducer = (state = initialState, action) => {
return {
...state,
themeCurationHotelDetailData: hotelInfos,
HotelData: action.payload,
};
}

View File

@@ -1,49 +1,87 @@
import React, { useCallback, useEffect } from "react";
import React, { useCallback, useEffect, useState } from "react";
import classNames from "classnames";
import { useSelector } from "react-redux";
import Image from "@enact/sandstone/Image";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import CustomImage from "../../../../components/CustomImage/CustomImage";
import TItemCard from "../../../../components/TItemCard/TItemCard";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import css from "./ThemeHotelIndicator.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
{ enterTo: "last-focused", preserveld: true },
"div"
);
const SpottableComponent = Spottable("div");
const SpottableImage = Spottable(Image);
export default function ThemeHotelIndicator({ hotelInfos }) {
// const hotelInfos = useSelector(
// (state) => state.home.themeCurationHotelDetailData
// );
console.log("#hotelInfos", hotelInfos);
export default function ThemeHotelIndicator() {
const [selectedIndex, setSelectedIndex] = useState(0);
const [selectedImage, setSelectedImage] = useState(null);
const [imageSelectedIndex, setImageSelectedIndex] = useState(0);
const hotelInfos = useSelector(
(state) => state.home.themeCurationHotelDetailData
);
const HotelData = useSelector((state) => state.home.HotelData);
console.log("#hotelInfos", hotelInfos);
console.log("#HotelData", HotelData);
const imageLength = hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls.length;
useEffect(() => {
const image =
hotelInfos[selectedIndex]?.hotelDetailInfo.imgUrls[imageSelectedIndex];
setSelectedImage(image || hotelInfos[0]?.hotelDetailInfo.imgUrls[0]);
}, [selectedIndex, imageSelectedIndex, hotelInfos]);
const handlePrevClick = () => {
if (imageSelectedIndex > 0) {
setImageSelectedIndex((prev) => prev - 1);
}
};
const handleNextClick = () => {
if (imageSelectedIndex + 1 < imageLength) {
setImageSelectedIndex((prev) => prev + 1);
}
};
const renderItem = useCallback(
({ index, ...rest }) => {
const { hotelImgUrl } = hotelInfos[index];
const handleItemClick = () => {};
const handleItemClick = () => {
setSelectedIndex(index);
setImageSelectedIndex(0);
};
return (
<>
<SpottableImage
src={hotelImgUrl}
alt=""
className={css.image}
// className={classNames(css.image, css.selected)}
className={classNames(
css.image,
selectedIndex === index && css.selected
)}
onClick={handleItemClick}
{...rest}
>
{/* <span className={css.checkIcon} /> */}
<span
className={
selectedIndex === index && css.selected && css.checkIcon
}
/>
</SpottableImage>
</>
);
},
[hotelInfos]
[hotelInfos, selectedIndex]
);
return (
<Container className={css.Wrap}>
@@ -51,15 +89,41 @@ export default function ThemeHotelIndicator({ hotelInfos }) {
<div>
{hotelInfos && (
<SpottableImage
src={hotelInfos[0]?.hotelImgUrl}
src={selectedImage}
alt=""
className={css.thumbnail}
/>
>
<Container className={css.thumbnailIndicator}>
<SpottableComponent
className={classNames(
css.prevButton,
imageSelectedIndex === 0 && css.disable
)}
onClick={handlePrevClick}
spotlightDisabled={imageSelectedIndex === 0}
/>
<span>
{imageSelectedIndex + 1} /{imageLength}
</span>
<SpottableComponent
className={classNames(
css.nextButton,
imageLength - 1 === imageSelectedIndex && css.disable
)}
onClick={handleNextClick}
spotlightDisabled={imageLength - 1 === imageSelectedIndex}
/>
</Container>
</SpottableImage>
)}
<div className={css.address}>
<span className={css.location} />
<div>{hotelInfos[selectedIndex]?.hotelDetailInfo.hotelAddr}</div>
</div>
</div>
<div>
<SpottableComponent spotlightDisabled className={css.upButton} />
<Container className={css.tVirtualGridListContainer}>
<div className={css.tVirtualGridListContainer}>
{hotelInfos && hotelInfos.length > 0 && (
<TVirtualGridList
className={css.tVirtualGridList}
@@ -70,7 +134,7 @@ export default function ThemeHotelIndicator({ hotelInfos }) {
renderItem={renderItem}
/>
)}
</Container>
</div>
<SpottableComponent spotlightDisabled className={css.downButton} />
</div>
</div>

View File

@@ -5,14 +5,6 @@
padding-left: 120px;
.size(@w: 894px, @h: 930px);
.tVirtualGridListContainer {
overflow: hidden;
.size(@w: 144px , @h: 432px);
> div:nth-child(1) {
.size(@w: inherit, @h: 432px);
}
}
.indicatorContainer {
margin: 30px 0 0 10px;
width: 714px;
@@ -25,12 +17,87 @@
background-color: #fff;
margin: 0 10px 10px 0;
position: relative;
display: flex;
justify-content: center;
&:focus {
&::after {
.focused(@boxShadow: 22px, @borderRadius:0px);
}
}
.thumbnailIndicator {
margin-top: auto;
position: relative;
margin-bottom: 30px;
z-index: 10;
.prevButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @right: 70px, @bottom: 0 , @top: 0);
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
background-image: url("../../../../../assets/images/btn/btn-prev-thumb-nor.svg");
}
}
.nextButton {
.size(@w:42px, @h: 42px);
.position(@position: absolute, @left: 70px, @bottom: 0 , @top: 0);
background-image: url("../../../../../assets/images/btn/btn-next-thumb-nor.svg");
background-position: center;
background-size: cover;
&:focus {
background-image: url("../../../../../assets/images/btn/btn-next-thumb-foc.svg");
}
&.disable {
opacity: 0.1;
}
}
> span {
-webkit-text-stroke: 1px #222222;
color: rgba(255, 255, 255, 0.7);
font-family: LGSmartUI;
font-size: 24px;
font-weight: bold;
line-height: 1.33;
}
}
}
.address {
font-size: 24px;
color: #808080;
position: relative;
.location {
.size(@w:36px, @h: 36px);
position: absolute;
background-image: url("../../../../../assets/images/icons/ic-location.svg");
background-position: center;
background-size: cover;
}
> div {
padding-left: 36px;
}
}
.tVirtualGridListContainer {
overflow: hidden;
.size(@w: 144px , @h: 447px);
> div:nth-child(1) {
.size(@w: inherit, @h: 447px);
}
}
.upButton {
@@ -95,29 +162,3 @@
}
}
}
.content {
.size(@w: 980px , @h: 300px);
padding: 30px 0 0 30px;
background-color: #fff;
border: solid 1px #dadada;
position: relative;
.upButton {
position: absolute;
top: 0px;
left: 928px;
.size(@w: 48px , @h: 48px);
background-image: url("../../../../../assets/images/btn/btn-scroll-up-dim.svg");
background-position: center;
background-size: cover;
}
.downButton {
position: absolute;
top: 250px;
left: 928px;
.size(@w: 48px , @h: 48px);
background-image: url("../../../../../assets/images/btn/btn-scroll-down-dim.svg");
background-position: center;
background-size: cover;
}
}

View File

@@ -8,7 +8,7 @@ import ThemeOption from "../components/optionTypes/ThemeOption";
import css from "./ThemeProduct.module.less";
export default function ThemeProduct() {
const productData = useSelector(
const productInfos = useSelector(
(state) => state.home.themeCurationDetailInfoData
);
const hotelInfos = useSelector(
@@ -18,8 +18,8 @@ export default function ThemeProduct() {
return (
<div className={css.container}>
<ThemeHotelIndicator hotelInfos={hotelInfos} />
{productData.themeInfo?.length <= 0 && <HotelOption />}
{productData.themeInfo?.length > 0 && <ThemeOption />}
{productInfos.themeInfo?.length > 0 ? <ThemeOption /> : <HotelOption />}
</div>
);
}