diff --git a/com.twin.app.shoptime/assets/images/btn/btn_dropdown_wh.png b/com.twin.app.shoptime/assets/images/btn/btn_dropdown_wh.png new file mode 100644 index 00000000..9907648b Binary files /dev/null and b/com.twin.app.shoptime/assets/images/btn/btn_dropdown_wh.png differ diff --git a/com.twin.app.shoptime/assets/images/ico_mic.png b/com.twin.app.shoptime/assets/images/ico_mic.png new file mode 100644 index 00000000..ed7f39e9 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/ico_mic.png differ diff --git a/com.twin.app.shoptime/assets/images/searchpanel/image-mic.png b/com.twin.app.shoptime/assets/images/searchpanel/image-mic.png new file mode 100644 index 00000000..ed7f39e9 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/searchpanel/image-mic.png differ diff --git a/com.twin.app.shoptime/assets/images/searchpanel/img-hotpicks.png b/com.twin.app.shoptime/assets/images/searchpanel/img-hotpicks.png new file mode 100644 index 00000000..083d50d4 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/searchpanel/img-hotpicks.png differ diff --git a/com.twin.app.shoptime/assets/images/searchpanel/img-search-hotpicks.png b/com.twin.app.shoptime/assets/images/searchpanel/img-search-hotpicks.png new file mode 100644 index 00000000..350f6a94 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/searchpanel/img-search-hotpicks.png differ diff --git a/com.twin.app.shoptime/src/components/TInput/TInput.jsx b/com.twin.app.shoptime/src/components/TInput/TInput.jsx index edcd3403..80b91a17 100644 --- a/com.twin.app.shoptime/src/components/TInput/TInput.jsx +++ b/com.twin.app.shoptime/src/components/TInput/TInput.jsx @@ -1,14 +1,17 @@ -import React, { useCallback, useState } from "react"; +import React, { + useCallback, + useState, +} from 'react'; -import classNames from "classnames"; +import classNames from 'classnames'; -import { InputField } from "@enact/sandstone/Input"; -import Spotlight from "@enact/spotlight"; -import Spottable from "@enact/spotlight/Spottable"; +import { InputField } from '@enact/sandstone/Input'; +import Spotlight from '@enact/spotlight'; +import Spottable from '@enact/spotlight/Spottable'; -import useScrollReset from "../../hooks/useScrollReset"; -import TIconButton from "../TIconButton/TIconButton"; -import css from "./TInput.module.less"; +import useScrollReset from '../../hooks/useScrollReset'; +import TIconButton from '../TIconButton/TIconButton'; +import css from './TInput.module.less'; const KINDS = { withIcon: "withIcon" }; const ICONS = { search: "search" }; @@ -30,6 +33,8 @@ export default function TInput({ scrollTop, onIconClick, forcedSpotlight, + onFocus, + onBlur, ...rest }) { const { handleScrollReset, handleStopScrolling } = useScrollReset(scrollTop); @@ -66,6 +71,20 @@ export default function TInput({ } }, []); + //focus,blur 추가 + const _onFocus = useCallback(() => { + if (onFocus) { + onFocus(); + } + handleScrollReset(); + }, [onFocus]); + const _onBlur = useCallback(() => { + if (onBlur) { + onBlur(); + } + handleStopScrolling(); + }, [onBlur]); + return ( state.common?.loadingComplete); const recommandedKeywords = useSelector( @@ -105,6 +132,18 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { const [position, setPosition] = useState(null); const [showVirtualKeyboard, setShowVirtualKeyboard] = useState(false); + //인풋창 포커스 구분을 위함 + const [inputFocus, setInputFocus] = useState(false); + const _onFocus = () => { + setInputFocus(true); + }; + const _onBlur = () => { + setInputFocus(false); + }; + useEffect(() => { + console.log("###inputFocus", inputFocus); + }, [inputFocus]); + let searchQueryRef = usePrevious(searchQuery); let isOnTopRef = usePrevious(isOnTop); @@ -122,43 +161,62 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { ); // 가짜 데이터 - 실제로는 Redux store나 API에서 가져와야 함 - const recentSearches = useMemo(() => ["Puppy food", "Dog toy", "Fitness"], []); - const topSearches = useMemo(() => ["Mather's Day", "Gift", "Easter Day", "Royal Canin puppy food", "Fitness", "Parrot"], []); - const popularBrands = useMemo(() => ["Shark", "Ninja", "Skechers", "LocknLock", "8Greens", "LGE"], []); - const hotPicks = useMemo(() => [ - { - id: 1, - image: hotPicksImage, - brandLogo: hotPicksBrandImage, - brandName: "Product Name", - title: "New Shark Vacuum! Your pet Hair Solution!", - isForYou: false - }, - { - id: 2, - image: hotPicksImage, - brandLogo: hotPicksBrandImage, - brandName: "Product Name", - title: "New Shark Vacuum! Your pet Hair Solution!", - isForYou: false - }, - { - id: 3, - image: hotPicksImage, - brandLogo: hotPicksBrandImage, - brandName: "Product Name", - title: "New Shark Vacuum! Your pet Hair Solution!", - isForYou: false - }, - { - id: 4, - image: hotPicksImage, - brandLogo: hotPicksBrandImage, - brandName: "Product Name", - title: "New Shark Vacuum! Your pet Hair Solution!", - isForYou: true - } - ], []); + const recentSearches = useMemo( + () => ["Puppy food", "Dog toy", "Fitness"], + [] + ); + const topSearches = useMemo( + () => [ + "Mather's Day", + "Gift", + "Easter Day", + "Royal Canin puppy food", + "Fitness", + "Parrot", + ], + [] + ); + const popularBrands = useMemo( + () => ["Shark", "Ninja", "Skechers", "LocknLock", "8Greens", "LGE"], + [] + ); + const hotPicks = useMemo( + () => [ + { + id: 1, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: false, + }, + { + id: 2, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: false, + }, + { + id: 3, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: false, + }, + { + id: 4, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: true, + }, + ], + [] + ); useEffect(() => { if (loadingComplete && !recommandedKeywords) { @@ -250,7 +308,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { domain: "theme,show,item", }) ); - + // 검색 시작 알림 (선택사항) dispatch(showSuccessToast(`"${query}" 검색 중...`, { duration: 2000 })); } else { @@ -305,47 +363,65 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { }; }, []); - const handleKeydown = useCallback((e) => { - if (!isOnTopRef.current) { - return; - } - - // Enter 키 처리 - if (e.key === "Enter") { - e.preventDefault(); - if (showVirtualKeyboard) { - // 가상 키보드가 열려있으면 검색 실행하고 키보드 닫기 - handleSearchSubmit(searchQuery); - } else { - // 가상 키보드가 닫혀있으면 키보드 열기 - setShowVirtualKeyboard(true); - } - return; - } - - // 방향키 처리 - Spotlight 네비게이션 허용 - const arrowKeys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Left", "Right", "Up", "Down"]; - if (arrowKeys.includes(e.key)) { - // 입력 필드가 비어있고 왼쪽 화살표인 경우에만 방지 - if (position === 0 && (e.key === "Left" || e.key === "ArrowLeft") && !searchQuery) { - e.preventDefault(); + const handleKeydown = useCallback( + (e) => { + if (!isOnTopRef.current) { return; } - - // 오른쪽 화살표 키 처리 - 포커스 이동 허용 - if (e.key === "ArrowRight" || e.key === "Right") { - // 커서가 텍스트 끝에 있을 때만 포커스 이동 허용 - const input = document.querySelector(`[data-spotlight-id="input-field-box"] > input`); - if (input && position === input.value.length) { - // 커서가 텍스트 끝에 있으면 포커스 이동 허용 + + // Enter 키 처리 + if (e.key === "Enter") { + e.preventDefault(); + if (showVirtualKeyboard) { + // 가상 키보드가 열려있으면 검색 실행하고 키보드 닫기 + handleSearchSubmit(searchQuery); + } else { + // 가상 키보드가 닫혀있으면 키보드 열기 + setShowVirtualKeyboard(true); + } + return; + } + + // 방향키 처리 - Spotlight 네비게이션 허용 + const arrowKeys = [ + "ArrowLeft", + "ArrowRight", + "ArrowUp", + "ArrowDown", + "Left", + "Right", + "Up", + "Down", + ]; + if (arrowKeys.includes(e.key)) { + // 입력 필드가 비어있고 왼쪽 화살표인 경우에만 방지 + if ( + position === 0 && + (e.key === "Left" || e.key === "ArrowLeft") && + !searchQuery + ) { + e.preventDefault(); return; } + + // 오른쪽 화살표 키 처리 - 포커스 이동 허용 + if (e.key === "ArrowRight" || e.key === "Right") { + // 커서가 텍스트 끝에 있을 때만 포커스 이동 허용 + const input = document.querySelector( + `[data-spotlight-id="input-field-box"] > input` + ); + if (input && position === input.value.length) { + // 커서가 텍스트 끝에 있으면 포커스 이동 허용 + return; + } + } + + // 나머지 방향키는 Spotlight가 처리하도록 허용 + return; } - - // 나머지 방향키는 Spotlight가 처리하도록 허용 - return; - } - }, [searchQuery, position, handleSearchSubmit, showVirtualKeyboard]); + }, + [searchQuery, position, handleSearchSubmit, showVirtualKeyboard] + ); const cursorPosition = useCallback(() => { const input = document.querySelector( @@ -397,12 +473,19 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { }, [panelInfo, firstSpot]); // 키워드 클릭 핸들러 - const handleKeywordClick = useCallback((keyword) => { - setSearchQuery(keyword); - handleSearchSubmit(keyword); - // 키워드 선택 알림 - dispatch(showSuccessToast(`"${keyword}" 키워드로 검색합니다.`, { duration: 2000 })); - }, [handleSearchSubmit, dispatch]); + const handleKeywordClick = useCallback( + (keyword) => { + setSearchQuery(keyword); + handleSearchSubmit(keyword); + // 키워드 선택 알림 + dispatch( + showSuccessToast(`"${keyword}" 키워드로 검색합니다.`, { + duration: 2000, + }) + ); + }, + [handleSearchSubmit, dispatch] + ); // 상품 클릭 핸들러 const handleProductClick = useCallback((product) => { @@ -417,58 +500,62 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { }, [dispatch]); // ProductCard 컴포넌트 - const ProductCard = useCallback(({ - product, - index, - onClick, - showForYouBadge = true, - showBrandLogo = true, - showBrandName = true, - showProductTitle = true, - badgeText = "For You", - badgePosition = "top-right" - }) => { - return ( - onClick?.(product)} - spotlightId={`product-${index}`} - > -
- {product.title} - {showForYouBadge && product.isForYou && ( -
- {badgeText} -
- )} -
-
- {showBrandLogo && ( -
- {product.brandName} -
- )} -
- {showBrandName && ( -
{product.brandName}
- )} - {showProductTitle && ( -
{product.title}
- )} + const renderItem = useCallback( + ( + // { + // product, + // index, + // onClick, + // showBrandLogo = true, + // showBrandName = true, + // showProductTitle = true, + // ...rest + // } + { index, ...rest } + ) => { + const { + showBrandLogo = true, + showBrandName = true, + showProductTitle = true, + image, + title, + brandLogo, + brandName, + } = hotPicks[index]; + return ( + +
+ {title}
-
- - ); - }, []); +
+ {showBrandLogo && ( +
+ {brandName} +
+ )} +
+ {showBrandName && ( +
{brandName}
+ )} + {showProductTitle && ( +
{title}
+ )} +
+
+ + ); + }, + [] + ); return ( {/* 검색 입력 영역 */} - @@ -520,35 +611,37 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { tabIndex={0} spotlightDisabled={false} spotlightBoxDisabled={true} + onFocus={_onFocus} + onBlur={_onBlur} /> -
- Microphone
- + {/* 테스트용 Toast 버튼 (개발용) */} - -
- 🧪 -
-
+
🧪
+ */}
- - {/* 검색 결과 표시 영역 */} + {/* 결과갑 부분 작업중 */} + + {/* //결과갑 부분 작업중 */} + {/* 검색 결과 표시 영역 {searchPerformed && searchQuery !== null ? ( Object.keys(searchDatas).length > 0 ? ( - {/* 최근 검색어 섹션 */} - -
-
-
Your Recent Searches
-
-
- {recentSearches.map((keyword, index) => ( - handleKeywordClick(keyword)} - spotlightId={`recent-keyword-${index}`} - > - {keyword} - - ))} -
-
+ {/* 노출 조건 변경 필요. 포커스 블러만으로는 안됌.(가상 키보드 노출시가 맞을듯) + {inputFocus === false ? ( + <> + {/* 최근 검색어 섹션 + +
+
+
+ Your Recent Searches +
+
+
+ {recentSearches.map((keyword, index) => ( + handleKeywordClick(keyword)} + spotlightId={`recent-keyword-${index}`} + > + {keyword} + + ))} +
+
- {/* 인기 검색어 섹션 */} - -
-
-
Top Searches
-
-
- {topSearches.map((keyword, index) => ( - handleKeywordClick(keyword)} - spotlightId={`top-keyword-${index}`} - > - {keyword} - - ))} -
-
+ {/* 인기 검색어 섹션 + +
+
+
Top Searches
+
+
+ {topSearches.map((keyword, index) => ( + handleKeywordClick(keyword)} + spotlightId={`top-keyword-${index}`} + > + {keyword} + + ))} +
+
- {/* 인기 브랜드 섹션 */} - -
-
-
Popular Brands
-
-
- {popularBrands.map((brand, index) => ( - handleKeywordClick(brand)} - spotlightId={`brand-${index}`} - > - {brand} - - ))} -
-
+ {/* 인기 브랜드 섹션 + +
+
+
Popular Brands
+
+
+ {popularBrands.map((brand, index) => ( + handleKeywordClick(brand)} + spotlightId={`brand-${index}`} + > + {brand} + + ))} +
+
- {/* Hot Picks for You 섹션 */} - -
-
-
Hot Picks for You
+ {/* Hot Picks for You 섹션 + +
+
+
+ Hot Picks for You +
+
+
+ {hotPicks && hotPicks.length > 0 && ( + + )} +
+
+ + ) : ( +
+
+ {recentSearches.map((keyword, index) => ( + handleKeywordClick(keyword)} + spotlightId={`recent-keyword-${index}`} + > + {keyword} + + ))} +
-
- {hotPicks.map((product, index) => ( - - ))} -
- + )} )} + */} )} - + {/* Virtual Keyboard */} - setShowVirtualKeyboard(false)} - /> + /> */} ); -} \ No newline at end of file +} diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.module.less b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.module.less index 32fcac15..f6d34495 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.module.less +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.module.less @@ -26,10 +26,16 @@ flex-direction: column; justify-content: center; align-items: center; - + &.inputFocus { + padding-bottom: 10px; + } + &.searchValue { + padding-bottom: 55px; + padding-top: 55px; + } > * { margin-bottom: 10px; - + &:last-child { margin-bottom: 0; } @@ -45,7 +51,7 @@ > * { margin-right: 15px; - + &:last-child { margin-right: 0; } @@ -71,12 +77,12 @@ padding: 20px 40px 20px 50px !important; border: none !important; background-color: #fff !important; - + input { - text-align: center; + text-align: left; color: black; font-size: 42px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 700; line-height: 42px; outline: none; @@ -89,13 +95,13 @@ outline: none !important; border: none !important; } - + // TInput 내부 컨테이너의 포커스 스타일 완전 제거 &[data-spotlight-container="true"] { outline: none !important; border: none !important; box-shadow: none !important; - + &:focus, &:focus-within { outline: none !important; @@ -110,7 +116,7 @@ border: 5px solid @PRIMARY_COLOR_RED; box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5); } - + // TInput 컴포넌트 자체의 내부 포커스 스타일 제거 > div { &:focus, @@ -120,7 +126,7 @@ box-shadow: none !important; } } - + // 모든 내부 요소의 포커스 스타일 완전 제거 * { &:focus, @@ -130,13 +136,13 @@ box-shadow: none !important; } } - + // TInput 내부 Container의 포커스 제거 > div[data-spotlight-container="true"] { outline: none !important; border: none !important; box-shadow: none !important; - + &:focus, &:focus-within { outline: none !important; @@ -144,13 +150,13 @@ box-shadow: none !important; } } - + // InputField의 포커스 제거 input { outline: none !important; border: none !important; box-shadow: none !important; - + &:focus, &:focus-within { outline: none !important; @@ -166,13 +172,13 @@ position: relative; &::before { - content: ''; + content: ""; width: 36.27px; height: 36.27px; position: absolute; left: 1.95px; top: 1.95px; - border: 3.90px solid black; + border: 3.9px solid black; border-radius: 50%; } } @@ -202,10 +208,7 @@ align-items: center; .microphoneIcon { - width: 100%; - height: 100%; - object-fit: contain; - padding: 10px; + height: 50px; box-sizing: border-box; } } @@ -223,7 +226,7 @@ } } } - + // 테스트용 Toast 버튼 스타일 .testToastButton { width: 100px; @@ -277,6 +280,64 @@ justify-content: flex-start; align-items: flex-start; display: inline-flex; + .inputFocusBox { + width: 995px; + height: 355px; + margin: 0 auto; + .keywordList { + align-self: stretch; + padding-top: 10px; + justify-content: flex-start; + align-items: flex-start; + display: inline-flex; + flex-wrap: wrap; + flex-direction: column; + > * { + margin-bottom: 5px; + } + + .keywordButton { + padding: 20px; + background: white; + border-radius: 100px; + border: 5px solid #dadada; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + display: inline-flex; + cursor: pointer; + transition: all 0.2s ease; + height: 64px; + > * { + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + } + + color: black; + font-size: 24px; + font-family: "LG Smart UI"; + font-weight: 700; + line-height: 24px; + text-align: center; + word-wrap: break-word; + + &:hover { + border-color: @PRIMARY_COLOR_RED; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + transform: translateY(-2px); + } + + &:focus { + border: 5px solid @PRIMARY_COLOR_RED; + box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5); + outline: none; + } + } + } + } } // 섹션 공통 스타일 @@ -291,7 +352,7 @@ > * { margin-bottom: 10px; - + &:last-child { margin-bottom: 0; } @@ -306,7 +367,7 @@ > * { margin-right: 12px; - + &:last-child { margin-right: 0; } @@ -315,14 +376,14 @@ .sectionIndicator { width: 6px; height: 36px; - background: #C70850; + background: #c70850; } .sectionTitle { text-align: center; color: black; font-size: 42px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 700; line-height: 42px; word-wrap: break-word; @@ -341,17 +402,13 @@ > * { margin-right: 19px; margin-bottom: 19px; - - &:nth-child(3n) { - margin-right: 0; - } } .keywordButton { padding: 20px; background: white; border-radius: 100px; - border: 5px solid #DADADA; + border: 5px solid #dadada; flex-direction: column; justify-content: flex-start; align-items: flex-start; @@ -361,7 +418,7 @@ > * { margin-bottom: 10px; - + &:last-child { margin-bottom: 0; } @@ -369,7 +426,7 @@ color: black; font-size: 24px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 700; line-height: 24px; text-align: center; @@ -388,50 +445,68 @@ } } } + } - // 상품 리스트 스타일 (Hot Picks for You) - .productList { - align-self: stretch; - padding-top: 30px; + .hotpicksSection { + padding-top: 63px; + padding-left: 60px; + width: 1800px; + height: 580px; + .sectionHeader { + width: 1800px; + height: 42px; justify-content: flex-start; - align-items: flex-start; + align-items: center; display: inline-flex; - flex-wrap: wrap; > * { - margin-right: 19px; - margin-bottom: 19px; - - &:nth-child(2n) { + margin-right: 12px; + + &:last-child { margin-right: 0; } } + .sectionIndicator { + width: 6px; + height: 36px; + background: #c70850; + } + + .sectionTitle { + text-align: center; + color: black; + font-size: 42px; + font-family: "LG Smart UI"; + font-weight: 700; + line-height: 42px; + word-wrap: break-word; + } + } + // 상품 리스트 스타일 (Hot Picks for You) + .productList { + padding-top: 30px; + .size(@w: 100%, @h: inherit); + > div:nth-child(1) { + .size(@w: 100%, @h: inherit); + } + .productCard { width: 546px; padding: 18px; background: white; border-radius: 12px; - border: 5px solid #DADADA; + border: 5px solid #dadada; flex-direction: column; justify-content: flex-start; align-items: flex-start; display: inline-flex; - - > * { - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - } cursor: pointer; transition: all 0.2s ease; &:hover { border-color: @PRIMARY_COLOR_RED; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - transform: translateY(-2px); } &:focus { @@ -454,51 +529,6 @@ object-fit: cover; border-radius: 8px; } - - .forYouBadge { - height: 29.33px; - padding-left: 5.33px; - padding-right: 5.33px; - position: absolute; - background: #C70850; - border-radius: 5.33px; - display: flex; - justify-content: center; - align-items: center; - color: white; - font-size: 21.33px; - font-family: 'LG Smart UI'; - font-weight: 700; - word-wrap: break-word; - z-index: 10; - - // 위치별 스타일 - &.top-right { - right: 10px; - top: 10px; - } - - &.top-left { - left: 10px; - top: 10px; - } - - &.bottom-right { - right: 10px; - bottom: 10px; - } - - &.bottom-left { - left: 10px; - bottom: 10px; - } - - &.center { - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - } - } } .productInfo { @@ -511,7 +541,7 @@ > * { margin-right: 10px; - + &:last-child { margin-right: 0; } @@ -524,7 +554,7 @@ > * { margin-right: 10px; - + &:last-child { margin-right: 0; } @@ -547,7 +577,7 @@ > * { margin-bottom: 10px; - + &:last-child { margin-bottom: 0; } @@ -557,7 +587,7 @@ text-align: center; color: #808080; font-size: 18px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 700; line-height: 18px; word-wrap: break-word; @@ -567,7 +597,7 @@ align-self: stretch; color: black; font-size: 24px; - font-family: 'LG Smart UI'; + font-family: "LG Smart UI"; font-weight: 400; line-height: 24px; word-wrap: break-word; @@ -584,11 +614,11 @@ -ms-overflow-style: none; overflow-y: auto; height: 100%; - + &::-webkit-scrollbar { display: none; } - + // 스크롤 동작 개선 scroll-behavior: smooth; } @@ -606,7 +636,6 @@ [data-spotlight-id] { &:focus { outline: 2px solid @PRIMARY_COLOR_RED; - outline-offset: 2px; } } -} \ No newline at end of file +} diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx new file mode 100644 index 00000000..8902a292 --- /dev/null +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx @@ -0,0 +1,135 @@ +import React, { + useCallback, + useMemo, +} from 'react'; + +import { useDispatch } from 'react-redux'; + +import SpotlightContainerDecorator + from '@enact/spotlight/SpotlightContainerDecorator'; +import Spottable from '@enact/spotlight/Spottable'; + +import hotPicksImage from '../../../assets/images/searchpanel/img-hotpicks.png'; +import hotPicksBrandImage + from '../../../assets/images/searchpanel/img-search-hotpicks.png'; +import TVirtualGridList + from '../../components/TVirtualGridList/TVirtualGridList'; +import css from './SearchResults.new.module.less'; + +const SearchResultsNew = () => { + const Container = SpotlightContainerDecorator("div"); + const SectionContainer = SpotlightContainerDecorator("div"); + const SpottableLi = Spottable("li"); + const SpottableDiv = Spottable("div"); + const hotPicks = useMemo( + () => [ + { + id: 1, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: false, + }, + { + id: 2, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: false, + }, + { + id: 3, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: false, + }, + { + id: 4, + image: hotPicksImage, + brandLogo: hotPicksBrandImage, + brandName: "Product Name", + title: "New Shark Vacuum! Your pet Hair Solution!", + isForYou: true, + }, + ], + [] + ); + + // ProductCard 컴포넌트 + const renderItem = useCallback(({ index, ...rest }) => { + const { + showBrandLogo = true, + showBrandName = true, + showProductTitle = true, + image, + title, + brandLogo, + brandName, + } = hotPicks[index]; + return ( + +
+ {title} +
+
+ {showBrandLogo && ( +
+ {brandName} +
+ )} +
+ {showBrandName &&
{brandName}
} + {showProductTitle && ( +
{title}
+ )} +
+
+
+ ); + }, []); + return ( + + + How about these? +
    + Puppy food + Dog toy + Fitness +
+
+ +
+
+
Hot Picks (#)
+
+
+ {hotPicks && hotPicks.length > 0 && ( + + )} +
+
+
+ ); +}; + +export default SearchResultsNew; diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.module.less b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.module.less new file mode 100644 index 00000000..68612bc5 --- /dev/null +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.module.less @@ -0,0 +1,203 @@ +@import "../../style/CommonStyle.module.less"; +@import "../../style/utils.module.less"; + +.searchBox { + width: 100%; + height: 100%; + .topBox { + width: 100%; + height: 124px; + background-color: #ddd; + display: flex; + align-items: center; + .topBoxTitle { + margin-left: 60px; + font-size: 24px; + font-weight: 700; + color: #272727; + text-decoration: underline; + } + .topBoxList { + margin-left: 20px; + display: flex; + .topBoxListItem { + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + height: 64px; + padding: 0 20px; + background-color: @COLOR_WHITE; + border-radius: 32px; + color: #000; + font-weight: 700; + font-size: 24px; + border: 4px solid @COLOR_WHITE; + &:focus { + border: 4px solid @PRIMARY_COLOR_RED; + box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5); + } + } + } + } + .hotpicksSection { + padding-top: 63px; + padding-left: 60px; + width: 1800px; + height: 580px; + .sectionHeader { + width: 1800px; + height: 42px; + justify-content: flex-start; + align-items: center; + display: inline-flex; + + > * { + margin-right: 12px; + + &:last-child { + margin-right: 0; + } + } + + .sectionIndicator { + width: 6px; + height: 36px; + background: #c70850; + } + + .sectionTitle { + text-align: center; + color: black; + font-size: 42px; + font-family: "LG Smart UI"; + font-weight: 700; + line-height: 42px; + word-wrap: break-word; + } + } + // 상품 리스트 스타일 (Hot Picks for You) + .productList { + padding-top: 30px; + .size(@w: 100%, @h: inherit); + > div:nth-child(1) { + .size(@w: 100%, @h: inherit); + } + + .productCard { + width: 546px; + padding: 18px; + background: white; + border-radius: 12px; + border: 5px solid #dadada; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + display: inline-flex; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + border-color: @PRIMARY_COLOR_RED; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + } + + &:focus { + border: 5px solid @PRIMARY_COLOR_RED; + box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5); + outline: none; + } + + .productImageWrapper { + align-self: stretch; + height: 287px; + position: relative; + + .productImage { + width: 510px; + height: 287px; + position: absolute; + left: 0; + top: 0; + object-fit: cover; + border-radius: 8px; + } + } + + .productInfo { + align-self: stretch; + padding-top: 15px; + padding-bottom: 15px; + justify-content: flex-start; + align-items: flex-start; + display: inline-flex; + + > * { + margin-right: 10px; + + &:last-child { + margin-right: 0; + } + } + + .productBrandWrapper { + justify-content: flex-start; + align-items: center; + display: flex; + + > * { + margin-right: 10px; + + &:last-child { + margin-right: 0; + } + } + + .brandLogo { + width: 60px; + height: 60px; + border-radius: 8px; + object-fit: cover; + } + } + + .productDetails { + flex: 1; + flex-direction: column; + justify-content: center; + align-items: flex-start; + display: inline-flex; + + > * { + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + } + + .brandName { + text-align: center; + color: #808080; + font-size: 18px; + font-family: "LG Smart UI"; + font-weight: 700; + line-height: 18px; + word-wrap: break-word; + } + + .productTitle { + align-self: stretch; + color: black; + font-size: 24px; + font-family: "LG Smart UI"; + font-weight: 400; + line-height: 24px; + word-wrap: break-word; + } + } + } + } + } + } +}