[251112] feat: ProductVideoV2 fullScreen Return Focus
🕐 커밋 시간: 2025. 11. 12. 18:16:27 📊 변경 통계: • 총 파일: 4개 • 추가: +64줄 • 삭제: -49줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.module.less 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx (javascript): ❌ Deleted: Spottable() 📄 com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.module.less (unknown): ✅ Added: imgElement() ❌ Deleted: imgElement() 🔧 주요 변경 내용: • UI 컴포넌트 아키텍처 개선
This commit is contained in:
@@ -534,23 +534,7 @@
|
||||
}
|
||||
|
||||
// FavoriteBtn 컴포넌트에 적용할 스타일
|
||||
.favoriteBtn {
|
||||
width: 60px !important;
|
||||
height: 60px !important;
|
||||
background: rgba(68, 68, 68, 0.5) !important;
|
||||
border-radius: 6px !important;
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
|
||||
&:focus {
|
||||
background: @PRIMARY_COLOR_RED !important;
|
||||
// outline은 사용하지 않음
|
||||
}
|
||||
}
|
||||
// .favoriteBtn 클래스는 FavoriteBtn 컴포넌트 내부 스타일로 대체됨
|
||||
|
||||
// 액션 버튼들 (actionButtons 참고)
|
||||
.actionButtonsWrapper {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState, useRef } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import CustomImage from '../../../../components/CustomImage/CustomImage';
|
||||
@@ -85,6 +86,7 @@ export function ProductVideoV2({
|
||||
const normalContainerRef = useRef(null);
|
||||
const fullscreenContainerRef = useRef(null);
|
||||
const videoPortalHostRef = useRef(null);
|
||||
const prevFullscreenRef = useRef(isFullscreen);
|
||||
|
||||
const isFullscreenRef = useRef(isFullscreen);
|
||||
useEffect(() => {
|
||||
@@ -638,6 +640,22 @@ export function ProductVideoV2({
|
||||
}
|
||||
}, [isFullscreen, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
const wasFullscreen = prevFullscreenRef.current;
|
||||
if (wasFullscreen && !isFullscreen && isPlaying) {
|
||||
const targetSpotlightId = 'product-video-v2-playing';
|
||||
if (typeof window !== 'undefined') {
|
||||
window.requestAnimationFrame(() => {
|
||||
const focused = Spotlight.focus?.(targetSpotlightId);
|
||||
if (!focused) {
|
||||
containerRef.current?.focus?.();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
prevFullscreenRef.current = isFullscreen;
|
||||
}, [isFullscreen, isPlaying]);
|
||||
|
||||
// VideoContainer의 모든 클릭 감시 (Hooks는 early return 전에 정의되어야 함)
|
||||
const handleVideoContainerClick = useCallback(
|
||||
(e) => {
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
|
||||
import {
|
||||
setHidePopup,
|
||||
setShowPopup,
|
||||
} from '../../../actions/commonActions';
|
||||
import { setHidePopup, setShowPopup } from '../../../actions/commonActions';
|
||||
import { sendLogTotalRecommend } from '../../../actions/logActions';
|
||||
import {
|
||||
getMyFavoriteFlag,
|
||||
setMainLikeCategory,
|
||||
} from '../../../actions/mainActions';
|
||||
import { getMyFavoriteFlag, setMainLikeCategory } from '../../../actions/mainActions';
|
||||
import { deleteMyFavorite } from '../../../actions/myPageActions';
|
||||
import TButton from '../../../components/TButton/TButton';
|
||||
import TPopUp from '../../../components/TPopUp/TPopUp';
|
||||
@@ -40,21 +28,19 @@ export default function FavoriteBtn({
|
||||
kind,
|
||||
}) {
|
||||
const dispatch = useDispatch();
|
||||
const { popupVisible, activePopup } = useSelector(
|
||||
(state) => state.common.popup
|
||||
);
|
||||
const { popupVisible, activePopup } = useSelector((state) => state.common.popup);
|
||||
|
||||
const handleFavoriteClick = useCallback(() => {
|
||||
dispatch(
|
||||
sendLogTotalRecommend({
|
||||
menu: logMenu,
|
||||
buttonTitle: "FAVORITE",
|
||||
buttonTitle: 'FAVORITE',
|
||||
contextName: Config.LOG_CONTEXT_NAME.DETAILPAGE,
|
||||
messageId: Config.LOG_MESSAGE_ID.BUTTONCLICK,
|
||||
})
|
||||
);
|
||||
switch (favoriteFlag) {
|
||||
case "N":
|
||||
case 'N':
|
||||
dispatch(
|
||||
setMainLikeCategory({
|
||||
patnrId: selectedPatnrId,
|
||||
@@ -63,10 +49,8 @@ export default function FavoriteBtn({
|
||||
);
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.favoritePopup));
|
||||
break;
|
||||
case "Y": {
|
||||
const productList = [
|
||||
{ patnrId: selectedPatnrId, prdtId: selectedPrdtId },
|
||||
];
|
||||
case 'Y': {
|
||||
const productList = [{ patnrId: selectedPatnrId, prdtId: selectedPrdtId }];
|
||||
const showList = [];
|
||||
dispatch(deleteMyFavorite({ productList, showList }));
|
||||
dispatch(setShowPopup(Config.ACTIVE_POPUP.favoritePopup));
|
||||
@@ -77,25 +61,24 @@ export default function FavoriteBtn({
|
||||
}, [dispatch, favoriteFlag, selectedPatnrId, selectedPrdtId, logMenu]);
|
||||
|
||||
const PopUpOnClick = useCallback(() => {
|
||||
setTimeout(() => Spotlight.focus("favoriteBtn"));
|
||||
setTimeout(() => Spotlight.focus('favoriteBtn'));
|
||||
dispatch(setHidePopup());
|
||||
onFavoriteFlagChanged(favoriteFlag === "Y" ? "N" : "Y");
|
||||
onFavoriteFlagChanged(favoriteFlag === 'Y' ? 'N' : 'Y');
|
||||
}, [dispatch, favoriteFlag, onFavoriteFlagChanged]);
|
||||
|
||||
return (
|
||||
<SpottableDiv
|
||||
className={classNames(
|
||||
css.favorBtnContainer,
|
||||
kind === "item_detail" ? css.smallSize : ""
|
||||
)}
|
||||
className={classNames(css.favorBtnContainer, kind === 'item_detail' ? css.smallSize : '')}
|
||||
spotlightId="favoriteBtn"
|
||||
>
|
||||
<TButton
|
||||
<div
|
||||
className={classNames(
|
||||
favoriteFlag === "N" ? css.favorBtn : css.favorUnableBtn
|
||||
css.favoriteButton,
|
||||
favoriteFlag === 'N' ? css.favorBtn : css.favorUnableBtn
|
||||
)}
|
||||
onClick={handleFavoriteClick}
|
||||
ariaLabel="Register in Favorites"
|
||||
spotlightId={"favoriteBtn"}
|
||||
role="button"
|
||||
aria-label="Register in Favorites"
|
||||
/>
|
||||
{activePopup === Config.ACTIVE_POPUP.favoritePopup && (
|
||||
<TPopUp
|
||||
@@ -103,12 +86,12 @@ export default function FavoriteBtn({
|
||||
open={popupVisible}
|
||||
onClose={PopUpOnClick}
|
||||
hasButton
|
||||
button1Text={$L("OK")}
|
||||
button1Text={$L('OK')}
|
||||
hasText
|
||||
text={
|
||||
favoriteFlag && favoriteFlag === "N"
|
||||
? $L("Added to My Favorites List")
|
||||
: $L("Removed from My Favorites List")
|
||||
favoriteFlag && favoriteFlag === 'N'
|
||||
? $L('Added to My Favorites List')
|
||||
: $L('Removed from My Favorites List')
|
||||
}
|
||||
onClick={PopUpOnClick}
|
||||
/>
|
||||
|
||||
@@ -3,40 +3,51 @@
|
||||
|
||||
.favorBtnContainer {
|
||||
height: 78px;
|
||||
&.smallSize {
|
||||
height: 60px;
|
||||
.flex();
|
||||
|
||||
.flex();
|
||||
.favorBtn {
|
||||
background-color: rgba(68, 68, 68, 0.5) !important;
|
||||
min-width: 60px;
|
||||
height: 60px;
|
||||
background-image: url(../../../../assets/images/icons/ic_heart_3x.png);
|
||||
.imgElement(29px, 25px, center, center);
|
||||
&:focus {
|
||||
background-color: @PRIMARY_COLOR_RED !important; // 포커스시 빨간색 배경
|
||||
// outline: 2px solid @PRIMARY_COLOR_RED !important;
|
||||
background-image: url(../../../../assets/images/icons/ic_heart_3x.png);
|
||||
}
|
||||
.favoriteButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&.favorBtn {
|
||||
min-width: 78px;
|
||||
height: 78px;
|
||||
background-image: url(../../../../assets/images/icons/ic-heart-nor@3x.png);
|
||||
background-color: rgba(68, 68, 68, 0.5);
|
||||
.imgElement(54px, 54px, center, center);
|
||||
}
|
||||
.favorUnableBtn {
|
||||
min-width: 60px;
|
||||
height: 60px;
|
||||
background-color: rgba(68, 68, 68, 0.5); // 다른 버튼들과 동일한 배경색
|
||||
|
||||
&.favorUnableBtn {
|
||||
min-width: 78px;
|
||||
height: 78px;
|
||||
background-image: url(../../../../assets/images/icons/ic-heart-sel@3x.png);
|
||||
background-color: rgba(68, 68, 68, 0.5);
|
||||
.imgElement(54px, 54px, center, center);
|
||||
}
|
||||
}
|
||||
.flex();
|
||||
.favorBtn {
|
||||
min-width: 78px;
|
||||
height: 78px;
|
||||
background-image: url(../../../../assets/images/icons/ic-heart-nor@3x.png);
|
||||
.imgElement(54px, 54px, center, center);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
.favoriteButton {
|
||||
background-color: @PRIMARY_COLOR_RED !important;
|
||||
}
|
||||
}
|
||||
.favorUnableBtn {
|
||||
min-width: 78px;
|
||||
height: 78px;
|
||||
background-image: url(../../../../assets/images/icons/ic-heart-sel@3x.png);
|
||||
.imgElement(54px, 54px, center, center);
|
||||
|
||||
&.smallSize {
|
||||
height: 60px;
|
||||
|
||||
.favoriteButton {
|
||||
&.favorBtn,
|
||||
&.favorUnableBtn {
|
||||
min-width: 60px;
|
||||
height: 60px;
|
||||
background-color: rgba(68, 68, 68, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user