[251023] fix: 일반검색 수정
🕐 커밋 시간: 2025. 10. 23. 10:25:47 📊 변경 통계: • 총 파일: 4개 • 추가: +33줄 • 삭제: -12줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/SearchPanel/SearchInpuOverlay.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.module.less 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx (javascript): ✅ Added: SpotlightContainerDecorator() 🔄 Modified: clearAllTimers() 📄 com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.module.less (unknown): ✅ Added: scale()
This commit is contained in:
@@ -1,73 +1,65 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import SpotlightContainerDecorator
|
||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
|
||||
import { getSearch } from '../../actions/searchActions';
|
||||
import TFullPopup from '../../components/TFullPopup/TFullPopup';
|
||||
import TInput, {
|
||||
ICONS,
|
||||
KINDS,
|
||||
} from '../../components/TInput/TInput';
|
||||
import TInput, { ICONS, KINDS } from '../../components/TInput/TInput';
|
||||
import css from './SearchInputOverlay.module.less';
|
||||
|
||||
const OverlayContainer = SpotlightContainerDecorator(
|
||||
{
|
||||
enterTo: "default-element",
|
||||
restrict: "self-only", // 포커스를 overlay 내부로만 제한
|
||||
},
|
||||
"div"
|
||||
);
|
||||
// const OverlayContainer = SpotlightContainerDecorator(
|
||||
// {
|
||||
// enterTo: "default-element",
|
||||
// restrict: "self-only", // 포커스를 overlay 내부로만 제한
|
||||
// },
|
||||
// "div"
|
||||
// );
|
||||
|
||||
const SpottableKeyword = Spottable("div");
|
||||
const SpottableKeyword = Spottable('div');
|
||||
|
||||
const SearchInputOverlay = ({
|
||||
isVisible,
|
||||
onClose,
|
||||
searchQuery = "",
|
||||
searchQuery = '',
|
||||
onSearchChange,
|
||||
onSearchSubmit,
|
||||
// onSearchSubmit,
|
||||
handleClick,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const recentResultSearches = useMemo(
|
||||
() => [
|
||||
"Puppy food",
|
||||
"Dog toy",
|
||||
'Puppy food',
|
||||
'Dog toy',
|
||||
"Mather's Day",
|
||||
"Gift",
|
||||
"Easter Day",
|
||||
"Royal Canin puppy food2",
|
||||
"Shark",
|
||||
'Gift',
|
||||
'Easter Day',
|
||||
'Royal Canin puppy food2',
|
||||
'Shark',
|
||||
],
|
||||
[]
|
||||
);
|
||||
// Input 창에서 API 호출 핸들러 (돋보기 아이콘 클릭 시에만)
|
||||
const handleSearchSubmit = useCallback(
|
||||
(query) => {
|
||||
console.log("[SearchInputOverlay] Search submit:", searchQuery);
|
||||
console.log('[SearchInputOverlay] Search submit:', searchQuery);
|
||||
if (searchQuery && searchQuery.trim()) {
|
||||
dispatch(
|
||||
getSearch({
|
||||
service: "com.lgshop.app",
|
||||
service: 'com.lgshop.app',
|
||||
query: query,
|
||||
domain: "theme,show,item",
|
||||
domain: 'theme,show,item',
|
||||
})
|
||||
);
|
||||
|
||||
// API 호출 후 Input 박스로 포커스 이동
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
Spotlight.focus("voice-overlay-input-box");
|
||||
Spotlight.focus('voice-overlay-input-box');
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
@@ -76,7 +68,7 @@ const SearchInputOverlay = ({
|
||||
|
||||
// Input 창에서 엔터키 핸들러 (API 호출하지 않음)
|
||||
const handleInputKeyDown = useCallback((e) => {
|
||||
if (e.key === "Enter" || e.keyCode === 13) {
|
||||
if (e.key === 'Enter' || e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
// Enter 키로는 API 호출하지 않음
|
||||
// 돋보기 아이콘 클릭/Enter로만 API 호출
|
||||
@@ -85,7 +77,7 @@ const SearchInputOverlay = ({
|
||||
|
||||
const handleDimClick = useCallback(
|
||||
(e) => {
|
||||
console.log("[VoiceInputOverlay] dimBackground clicked");
|
||||
console.log('[VoiceInputOverlay] dimBackground clicked');
|
||||
onClose();
|
||||
},
|
||||
[onClose]
|
||||
@@ -93,11 +85,9 @@ const SearchInputOverlay = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
const input = document.querySelector(
|
||||
`[data-spotlight-id="input-field-box"] > input`
|
||||
);
|
||||
console.log("###input", input);
|
||||
console.log("###input.value", input.value);
|
||||
const input = document.querySelector(`[data-spotlight-id="input-field-box"] > input`);
|
||||
console.log('###input', input);
|
||||
console.log('###input.value', input.value);
|
||||
if (input) {
|
||||
input.focus();
|
||||
}
|
||||
@@ -110,7 +100,7 @@ const SearchInputOverlay = ({
|
||||
onClose={onClose}
|
||||
noAutoDismiss={true}
|
||||
spotlightRestrict="self-only"
|
||||
spotlightId={"search_input_overlay_container"}
|
||||
spotlightId={'search_input_overlay_container'}
|
||||
noAnimation={false}
|
||||
scrimType="transparent"
|
||||
className={css.tFullPopupWrapper}
|
||||
@@ -132,7 +122,7 @@ const SearchInputOverlay = ({
|
||||
onIconClick={() => {
|
||||
handleSearchSubmit(searchQuery);
|
||||
}}
|
||||
spotlightId={"search_overlay_input_box"}
|
||||
spotlightId={'search_overlay_input_box'}
|
||||
spotlightBoxDisabled
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,37 +1,19 @@
|
||||
// src/views/SearchPanel/SearchPanel.new.jsx
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import SpotlightContainerDecorator
|
||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
|
||||
import micIcon from '../../../assets/images/searchpanel/image-mic.png';
|
||||
import hotPicksImage from '../../../assets/images/searchpanel/img-hotpicks.png';
|
||||
import hotPicksBrandImage
|
||||
from '../../../assets/images/searchpanel/img-search-hotpicks.png';
|
||||
import {
|
||||
sendLogGNB,
|
||||
sendLogTotalRecommend,
|
||||
} from '../../actions/logActions';
|
||||
import hotPicksBrandImage from '../../../assets/images/searchpanel/img-search-hotpicks.png';
|
||||
import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions';
|
||||
import { getMyRecommandedKeyword } from '../../actions/myPageActions';
|
||||
import {
|
||||
popPanel,
|
||||
pushPanel,
|
||||
updatePanel,
|
||||
} from '../../actions/panelActions';
|
||||
import { popPanel, pushPanel, updatePanel } from '../../actions/panelActions';
|
||||
import {
|
||||
getSearch,
|
||||
getSearchMain,
|
||||
@@ -48,64 +30,43 @@ import {
|
||||
// } from '../../actions/toastActions';
|
||||
import TBody from '../../components/TBody/TBody';
|
||||
import TPanel from '../../components/TPanel/TPanel';
|
||||
import TVerticalPagenator
|
||||
from '../../components/TVerticalPagenator/TVerticalPagenator';
|
||||
import TVirtualGridList
|
||||
from '../../components/TVirtualGridList/TVirtualGridList';
|
||||
import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator';
|
||||
import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList';
|
||||
// import VirtualKeyboardContainer from "../../components/TToast/VirtualKeyboardContainer";
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import {
|
||||
LOG_CONTEXT_NAME,
|
||||
LOG_MENU,
|
||||
LOG_MESSAGE_ID,
|
||||
panel_names,
|
||||
} from '../../utils/Config';
|
||||
import NoSearchResults from './NoSearchResults/NoSearchResults';
|
||||
import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../utils/Config';
|
||||
// import NoSearchResults from './NoSearchResults/NoSearchResults';
|
||||
import SearchInputOverlay from './SearchInpuOverlay';
|
||||
import css from './SearchPanel.new.module.less';
|
||||
import SearchResultsNew from './SearchResults.new';
|
||||
import TInput, {
|
||||
ICONS,
|
||||
KINDS,
|
||||
} from './TInput/TInput';
|
||||
import VoiceInputOverlay, {
|
||||
VOICE_MODES,
|
||||
} from './VoiceInputOverlay/VoiceInputOverlay';
|
||||
import TInput, { ICONS, KINDS } from './TInput/TInput';
|
||||
import VoiceInputOverlay, { VOICE_MODES } from './VoiceInputOverlay/VoiceInputOverlay';
|
||||
|
||||
const ContainerBasic = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
||||
|
||||
// 검색 입력 영역 컨테이너
|
||||
const InputContainer = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
const InputContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
||||
|
||||
// 콘텐츠 섹션 컨테이너
|
||||
const SectionContainer = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
const SectionContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
||||
|
||||
// Spottable 컴포넌트들
|
||||
const SpottableMicButton = Spottable("div");
|
||||
const SpottableKeyword = Spottable("div");
|
||||
const SpottableProduct = Spottable("div");
|
||||
const SpottableMicButton = Spottable('div');
|
||||
const SpottableKeyword = Spottable('div');
|
||||
const SpottableProduct = Spottable('div');
|
||||
|
||||
const ITEMS_PER_PAGE = 9;
|
||||
|
||||
// Spotlight ID 상수
|
||||
const SPOTLIGHT_IDS = {
|
||||
SEARCH_INPUT_LAYER: "search-input-layer",
|
||||
SEARCH_INPUT_BOX: "search-input-box",
|
||||
MICROPHONE_BUTTON: "microphone-button",
|
||||
RECENT_SEARCHES_SECTION: "recent-searches-section",
|
||||
TOP_SEARCHES_SECTION: "top-searches-section",
|
||||
POPULAR_BRANDS_SECTION: "popular-brands-section",
|
||||
HOT_PICKS_SECTION: "hot-picks-section",
|
||||
SEARCH_VERTICAL_PAGENATOR: "search_verticalPagenator",
|
||||
SEARCH_INPUT_LAYER: 'search-input-layer',
|
||||
SEARCH_INPUT_BOX: 'search-input-box',
|
||||
MICROPHONE_BUTTON: 'microphone-button',
|
||||
RECENT_SEARCHES_SECTION: 'recent-searches-section',
|
||||
TOP_SEARCHES_SECTION: 'top-searches-section',
|
||||
POPULAR_BRANDS_SECTION: 'popular-brands-section',
|
||||
HOT_PICKS_SECTION: 'hot-picks-section',
|
||||
SEARCH_VERTICAL_PAGENATOR: 'search_verticalPagenator',
|
||||
};
|
||||
|
||||
export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
@@ -121,21 +82,13 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
// 0hun: 패널 전역 상태
|
||||
const panels = useSelector((state) => state.panels.panels);
|
||||
// 0hun: 음성 검색 결과에 대한 전역 상태
|
||||
const shopperHouseData = useSelector(
|
||||
(state) => state.search.shopperHouseData
|
||||
);
|
||||
const shopperHouseData = useSelector((state) => state.search.shopperHouseData);
|
||||
// 0hun: 검색 메인, Hot Picks for you 영역에 대한 전역 상태 값
|
||||
const hotPicksForYou = useSelector(
|
||||
(state) => state.search.searchMainData.hotPicksForYou
|
||||
);
|
||||
const hotPicksForYou = useSelector((state) => state.search.searchMainData.hotPicksForYou);
|
||||
// 0hun: 검색 메인, Popular Brands 영역에 대한 전역 상태 값
|
||||
const popularBrands = useSelector(
|
||||
(state) => state.search.searchMainData.popularBrands
|
||||
);
|
||||
const popularBrands = useSelector((state) => state.search.searchMainData.popularBrands);
|
||||
// 0hun: 검색 메인, Top Searchs 영역에 대한 전역 상태 값
|
||||
const topSearchs = useSelector(
|
||||
(state) => state.search.searchMainData.topSearchs
|
||||
);
|
||||
const topSearchs = useSelector((state) => state.search.searchMainData.topSearchs);
|
||||
|
||||
/**
|
||||
* states
|
||||
@@ -143,9 +96,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
// 0hun: 초기 포커스 유무를 나타내는 Boolean 상태
|
||||
const [firstSpot, setFirstSpot] = useState(false);
|
||||
// 0hun: 검색어 상태
|
||||
const [searchQuery, setSearchQuery] = useState(
|
||||
panelInfo.searchVal ? panelInfo.searchVal : null
|
||||
);
|
||||
const [searchQuery, setSearchQuery] = useState(panelInfo.searchVal ? panelInfo.searchVal : null);
|
||||
// 0hun: 검색 컨테이너 포커스 position 상태 값
|
||||
const [position, setPosition] = useState(null);
|
||||
// 0hun: 가상 키보드 Display 유무 Boolean 값
|
||||
@@ -159,9 +110,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
// TInput의 입력 모드 상태 (webOS 키보드가 뜨는지 여부)
|
||||
const [isInputModeActive, setIsInputModeActive] = useState(false);
|
||||
// 0hun: 현재 포커스된 container의 spotlightId를 관리하는 상태 값
|
||||
const [focusedContainerId, setFocusedContainerId] = useState(
|
||||
panelInfo?.focusedContainerId
|
||||
);
|
||||
const [focusedContainerId, setFocusedContainerId] = useState(panelInfo?.focusedContainerId);
|
||||
|
||||
/**
|
||||
* refs
|
||||
@@ -177,10 +126,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
* memoized variables
|
||||
*/
|
||||
// 가짜 데이터 - 실제로는 Redux store나 API에서 가져와야 함
|
||||
const recentSearches = useMemo(
|
||||
() => ["Puppy food", "Dog toy", "Fitness"],
|
||||
[]
|
||||
);
|
||||
const recentSearches = useMemo(() => ['Puppy food', 'Dog toy', 'Fitness'], []);
|
||||
|
||||
// Voice overlay suggestions (동적으로 변경 가능)
|
||||
const voiceSuggestions = useMemo(
|
||||
@@ -216,7 +162,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
}
|
||||
|
||||
// Enter 키 처리
|
||||
if (e.key === "Enter") {
|
||||
if (e.key === 'Enter') {
|
||||
// e.preventDefault();
|
||||
if (showVirtualKeyboard) {
|
||||
// 가상 키보드가 열려있으면 검색 실행하고 키보드 닫기
|
||||
@@ -230,32 +176,26 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
|
||||
// 방향키 처리 - Spotlight 네비게이션 허용
|
||||
const arrowKeys = [
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"ArrowUp",
|
||||
"ArrowDown",
|
||||
"Left",
|
||||
"Right",
|
||||
"Up",
|
||||
"Down",
|
||||
'ArrowLeft',
|
||||
'ArrowRight',
|
||||
'ArrowUp',
|
||||
'ArrowDown',
|
||||
'Left',
|
||||
'Right',
|
||||
'Up',
|
||||
'Down',
|
||||
];
|
||||
if (arrowKeys.includes(e.key)) {
|
||||
// 입력 필드가 비어있고 왼쪽 화살표인 경우에만 방지
|
||||
if (
|
||||
position === 0 &&
|
||||
(e.key === "Left" || e.key === "ArrowLeft") &&
|
||||
!searchQuery
|
||||
) {
|
||||
if (position === 0 && (e.key === 'Left' || e.key === 'ArrowLeft') && !searchQuery) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
// 오른쪽 화살표 키 처리 - 포커스 이동 허용
|
||||
if (e.key === "ArrowRight" || e.key === "Right") {
|
||||
if (e.key === 'ArrowRight' || e.key === 'Right') {
|
||||
// 커서가 텍스트 끝에 있을 때만 포커스 이동 허용
|
||||
const input = document.querySelector(
|
||||
`[data-spotlight-id="input-field-box"] > input`
|
||||
);
|
||||
const input = document.querySelector(`[data-spotlight-id="input-field-box"] > input`);
|
||||
if (input && position === input.value.length) {
|
||||
// 커서가 텍스트 끝에 있으면 포커스 이동 허용
|
||||
return;
|
||||
@@ -274,8 +214,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
*/
|
||||
const handleInputModeChange = useCallback((isActive) => {
|
||||
console.log(
|
||||
"[SearchPanel] TInput 입력 모드:",
|
||||
isActive ? "활성화 (키보드 표시)" : "비활성화 (키보드 숨김)"
|
||||
'[SearchPanel] TInput 입력 모드:',
|
||||
isActive ? '활성화 (키보드 표시)' : '비활성화 (키보드 숨김)'
|
||||
);
|
||||
setIsInputModeActive(isActive);
|
||||
}, []);
|
||||
@@ -303,9 +243,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
if (query.trim()) {
|
||||
dispatch(
|
||||
getSearch({
|
||||
domain: "theme,show,item",
|
||||
domain: 'theme,show,item',
|
||||
query: query,
|
||||
service: "com.lgshop.app",
|
||||
service: 'com.lgshop.app',
|
||||
})
|
||||
);
|
||||
|
||||
@@ -328,9 +268,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
* 0hun: keyUp 이벤트 핸들러, keyUp 시 `position`의 상태값 변경하는 함수
|
||||
*/
|
||||
const cursorPosition = useCallback(() => {
|
||||
const input = document.querySelector(
|
||||
`[data-spotlight-id="input-field-box"] > input`
|
||||
);
|
||||
const input = document.querySelector(`[data-spotlight-id="input-field-box"] > input`);
|
||||
|
||||
if (input) {
|
||||
setPosition(input.selectionStart);
|
||||
@@ -346,7 +284,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
}
|
||||
|
||||
console.log(
|
||||
"🖱️ [DEBUG][SearchPanel] onClickMic called, current isVoiceOverlayVisible:",
|
||||
'🖱️ [DEBUG][SearchPanel] onClickMic called, current isVoiceOverlayVisible:',
|
||||
isVoiceOverlayVisible
|
||||
);
|
||||
setIsVoiceOverlayVisible(true);
|
||||
@@ -367,14 +305,20 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchQuery === null || searchQuery === "") {
|
||||
// SearchInputOverlay가 열려있으면 먼저 닫기
|
||||
if (isSearchOverlayVisible) {
|
||||
setIsSearchOverlayVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchQuery === null || searchQuery === '') {
|
||||
dispatch(popPanel(panel_names.SEARCH_PANEL));
|
||||
} else {
|
||||
setSearchQuery("");
|
||||
setSearchQuery('');
|
||||
dispatch(resetSearch());
|
||||
Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX);
|
||||
}
|
||||
}, [isVoiceOverlayVisible, searchQuery]);
|
||||
}, [isVoiceOverlayVisible, isSearchOverlayVisible, searchQuery]);
|
||||
|
||||
/**
|
||||
* 0hun: paginator 내부 아이템들의 onFocus 이벤트, containerId인자로 받는다
|
||||
@@ -393,7 +337,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
Spotlight.resume();
|
||||
setFirstSpot(true);
|
||||
if (panelInfo.currentSpot) {
|
||||
if (panels[panels.length - 1]?.name === "searchpanel") {
|
||||
if (panels[panels.length - 1]?.name === 'searchpanel') {
|
||||
Spotlight.focus(panelInfo.currentSpot);
|
||||
}
|
||||
}
|
||||
@@ -435,6 +379,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
*/
|
||||
const handleSearchOverlayClose = useCallback(() => {
|
||||
setIsSearchOverlayVisible(false);
|
||||
// VoiceInputOverlay와 동일하게 닫힐 때 TInput으로 포커스 이동
|
||||
setTimeout(() => {
|
||||
Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX);
|
||||
}, 150); // Overlay 닫히는 시간을 고려한 지연
|
||||
}, []);
|
||||
|
||||
/**
|
||||
@@ -442,7 +390,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
*/
|
||||
const handleVoiceOverlayClose = useCallback(() => {
|
||||
console.log(
|
||||
"🚪 [DEBUG][SearchPanel] handleVoiceOverlayClose called, setting isVoiceOverlayVisible to FALSE"
|
||||
'🚪 [DEBUG][SearchPanel] handleVoiceOverlayClose called, setting isVoiceOverlayVisible to FALSE'
|
||||
);
|
||||
|
||||
// ✨ Redux 정리는 VoiceInputOverlay.handleClose()에서 처리함
|
||||
@@ -481,7 +429,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
*/
|
||||
const handleMicKeyDown = useCallback(
|
||||
(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (e.key === 'Enter') {
|
||||
onClickMic();
|
||||
}
|
||||
},
|
||||
@@ -523,27 +471,17 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
{...rest}
|
||||
>
|
||||
<div className={css.productImageWrapper}>
|
||||
<img
|
||||
src={bgImgPath}
|
||||
alt={curationNm}
|
||||
className={css.productImage}
|
||||
/>
|
||||
<img src={bgImgPath} alt={curationNm} className={css.productImage} />
|
||||
</div>
|
||||
<div className={css.productInfo}>
|
||||
{showBrandLogo && (
|
||||
<div className={css.productBrandWrapper}>
|
||||
<img
|
||||
src={patncLogoPath}
|
||||
alt={patncNm}
|
||||
className={css.brandLogo}
|
||||
/>
|
||||
<img src={patncLogoPath} alt={patncNm} className={css.brandLogo} />
|
||||
</div>
|
||||
)}
|
||||
<div className={css.productDetails}>
|
||||
{showBrandName && <div className={css.brandName}>{patncNm}</div>}
|
||||
{showProductTitle && (
|
||||
<div className={css.productTitle}>{curationNm}</div>
|
||||
)}
|
||||
{showProductTitle && <div className={css.productTitle}>{curationNm}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</SpottableProduct>
|
||||
@@ -680,7 +618,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
dispatch(
|
||||
sendLogTotalRecommend({
|
||||
query: searchQuery,
|
||||
searchType: searchPerformed ? "query" : "keyword",
|
||||
searchType: searchPerformed ? 'query' : 'keyword',
|
||||
result: result,
|
||||
contextName: LOG_CONTEXT_NAME.SEARCH,
|
||||
messageId: LOG_MESSAGE_ID.SEARCH_ITEM,
|
||||
@@ -734,11 +672,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<TPanel
|
||||
className={css.container}
|
||||
handleCancel={onCancel}
|
||||
spotlightId={spotlightId}
|
||||
>
|
||||
<TPanel className={css.container} handleCancel={onCancel} spotlightId={spotlightId}>
|
||||
<TBody
|
||||
className={css.tBody}
|
||||
scrollable
|
||||
@@ -762,10 +696,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
className={classNames(
|
||||
css.inputContainer,
|
||||
inputFocus === true && css.inputFocus,
|
||||
searchDatas &&
|
||||
css.searchValue /* 이건 결과값 있을때만. 조건 추가필요 */,
|
||||
(isVoiceOverlayVisible || isSearchOverlayVisible) &&
|
||||
css.hidden
|
||||
searchDatas && css.searchValue /* 이건 결과값 있을때만. 조건 추가필요 */,
|
||||
(isVoiceOverlayVisible || isSearchOverlayVisible) && css.hidden
|
||||
)}
|
||||
data-wheel-point="true"
|
||||
spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_LAYER}
|
||||
@@ -806,11 +738,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
spotlightId={SPOTLIGHT_IDS.MICROPHONE_BUTTON}
|
||||
>
|
||||
<div className={css.microphoneCircle}>
|
||||
<img
|
||||
src={micIcon}
|
||||
alt="Microphone"
|
||||
className={css.microphoneIcon}
|
||||
/>
|
||||
<img src={micIcon} alt="Microphone" className={css.microphoneIcon} />
|
||||
</div>
|
||||
</SpottableMicButton>
|
||||
|
||||
@@ -876,9 +804,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
>
|
||||
<div className={css.sectionHeader}>
|
||||
<div className={css.sectionIndicator} />
|
||||
<div className={css.sectionTitle}>
|
||||
Your Recent Searches
|
||||
</div>
|
||||
<div className={css.sectionTitle}>Your Recent Searches</div>
|
||||
</div>
|
||||
<div className={css.keywordList}>
|
||||
{recentSearches.map((keyword, index) => (
|
||||
@@ -959,9 +885,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
>
|
||||
<div className={css.sectionHeader}>
|
||||
<div className={css.sectionIndicator} />
|
||||
<div className={css.sectionTitle}>
|
||||
Hot Picks for You
|
||||
</div>
|
||||
<div className={css.sectionTitle}>Hot Picks for You</div>
|
||||
</div>
|
||||
<div className={css.productList}>
|
||||
{hotPicksForYou && hotPicksForYou.length > 0 && (
|
||||
|
||||
@@ -35,6 +35,7 @@ const OverlayContainer = SpotlightContainerDecorator(
|
||||
);
|
||||
|
||||
const SpottableMicButton = Spottable('div');
|
||||
const SpottableDebugButton = Spottable('div');
|
||||
|
||||
// Debug mode constant - 항상 디버그 화면 표시
|
||||
const DEBUG_MODE = true;
|
||||
@@ -1483,13 +1484,14 @@ const VoiceInputOverlay = ({
|
||||
// Memoize debug toggle button
|
||||
const debugToggleButton = useMemo(() => {
|
||||
return (
|
||||
<button
|
||||
<SpottableDebugButton
|
||||
className={classNames(css.debugToggleButton, showDashboard && css.active)}
|
||||
onClick={handleToggleDashboard}
|
||||
title={showDashboard ? 'Close Debug Dashboard' : 'Open Debug Dashboard'}
|
||||
spotlightId="debug-toggle-button"
|
||||
>
|
||||
<span className={css.debugToggleIcon}>⚙️</span>
|
||||
</button>
|
||||
</SpottableDebugButton>
|
||||
);
|
||||
}, [showDashboard, handleToggleDashboard]);
|
||||
|
||||
|
||||
@@ -493,6 +493,15 @@
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
// Spotlight 포커스 스타일 (붉은색 테두리)
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #ff0000;
|
||||
border-width: 6px;
|
||||
box-shadow: 0 0 0 3px rgba(255, 0, 0, 0.3);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #FFB81C; // 활성화 상태 (노란색)
|
||||
border-color: #FFB81C;
|
||||
|
||||
Reference in New Issue
Block a user