[251115] fix: DetailPanel FullScreen Size

🕐 커밋 시간: 2025. 11. 15. 22:53:23

📊 변경 통계:
  • 총 파일: 6개
  • 추가: +211줄
  • 삭제: -76줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/actions/mediaActions.js
  ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less
  ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx
  ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx
  ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.module.less
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx

🔧 함수 변경 내용:
  📄 com.twin.app.shoptime/src/actions/mediaActions.js (javascript):
     Added: minimizeModalMedia()
  📄 com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less (unknown):
     Added: gradient()
     Deleted: gradient()
  📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript):
     Added: handleScrollReset()
    🔄 Modified: extractProductMeta()
  📄 com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx (javascript):
     Added: attemptRestore()
    🔄 Modified: normalizeModalStyle()
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx (javascript):
    🔄 Modified: SpotlightContainerDecorator()

🔧 주요 변경 내용:
  • 핵심 비즈니스 로직 개선
  • UI 컴포넌트 아키텍처 개선
This commit is contained in:
2025-11-15 22:53:23 +09:00
parent a503bf923a
commit ef04d805de
6 changed files with 211 additions and 71 deletions

View File

@@ -284,6 +284,14 @@ export const minimizeModalMedia = () => (dispatch, getState) => {
export const restoreModalMedia = () => (dispatch, getState) => {
const panels = getState().panels.panels;
if (typeof window !== 'undefined' && window.detailPanelScrollTop !== 0) {
console.log(
'[restoreModalMedia] Blocked restore because detail panel scroll not zero:',
window.detailPanelScrollTop
);
return;
}
// console.log('[Restore]] ========== Called ==========');
// console.log('[Restore] Total panels:', panels.length);
// console.log(

View File

@@ -5,12 +5,14 @@
@import "~@enact/sandstone/styles/skin.less";
@import "../../style/utils.module.less";
@import "../../style/CommonStyle.module.less";
.fullscreen .videoPlayer,
.videoPlayer {
// Set by counting the IconButtons inside the side components.
--liftDistance: 0px;
overflow: hidden;
padding: 2px;
margin: 0;
box-sizing: border-box;
:focus {
@@ -19,10 +21,17 @@
box-shadow: none !important;
}
&.fullscreen {
width: 100%;
height: 100%;
}
.video {
height: calc(100% - 4px);
width: calc(100% - 4px);
height: 100%;
width: 100%;
background: #000;
max-width: none;
max-height: none;
}
.media {
@@ -48,6 +57,16 @@
}
}
&.fullscreen {
--media-width: 100vw;
--media-height: 100vh;
}
.fullscreen .videoPlayer .media {
--media-width: 100vw;
--media-height: 100vh;
}
.preloadVideo {
display: none;
}

View File

@@ -537,6 +537,29 @@ export default function ProductAllSection({
}, []);
const scrollContainerRef = useRef(null);
useEffect(() => {
if (typeof window !== 'undefined') {
window.detailPanelScrollTop = 0;
}
}, []);
useEffect(() => {
const handleScrollReset = () => {
const container = scrollContainerRef.current;
if (!container) return;
if (typeof container.scrollTo === 'function') {
container.scrollTo({ top: 0, behavior: 'auto' });
} else if (typeof container.scrollTop === 'number') {
container.scrollTop = 0;
}
};
if (typeof document === 'undefined') return () => {};
document.addEventListener('detailpanel-scroll-reset', handleScrollReset);
return () => {
document.removeEventListener('detailpanel-scroll-reset', handleScrollReset);
};
}, []);
const productDetailRef = useRef(null); //높이값 변경때문
const descriptionRef = useRef(null);
const reviewRef = useRef(null);
@@ -666,6 +689,9 @@ export default function ProductAllSection({
const handleScroll = useCallback(
(e) => {
const currentScrollTop = e.scrollTop;
if (typeof window !== 'undefined') {
window.detailPanelScrollTop = Math.max(0, currentScrollTop);
}
const prevScrollTop = prevScrollTopRef.current;
scrollPositionRef.current = currentScrollTop;

View File

@@ -913,6 +913,7 @@ const MediaPanel = React.forwardRef(
if (!panelInfo.modal) {
dispatch(PanelActions.popPanel());
dispatch(changeAppStatus({ cursorVisible: false }));
document?.dispatchEvent?.(new CustomEvent('detailpanel-scroll-reset'));
//딮링크로 플레이어 진입 후 이전버튼 클릭시
if (panels.length === 1) {
@@ -1120,9 +1121,34 @@ const MediaPanel = React.forwardRef(
dispatch(minimizeModalMedia());
}, [dispatch]);
const restoreViaRef = useCallback(() => {
const requestDetailScrollReset = useCallback(() => {
if (typeof document !== 'undefined') {
document.dispatchEvent(new CustomEvent('detailpanel-scroll-reset'));
}
}, []);
const canRestoreFromDetailPanel = useCallback(() => {
if (typeof window === 'undefined') return true;
return window.detailPanelScrollTop === 0;
}, []);
const restoreWhenScrollZero = useCallback(() => {
let attempts = 0;
const attemptRestore = () => {
if (canRestoreFromDetailPanel()) {
dispatch(restoreModalMedia());
}, [dispatch]);
} else if (attempts < 5) {
attempts += 1;
requestDetailScrollReset();
setTimeout(attemptRestore, 50);
}
};
attemptRestore();
}, [canRestoreFromDetailPanel, dispatch, requestDetailScrollReset]);
const restoreViaRef = useCallback(() => {
restoreWhenScrollZero();
}, [restoreWhenScrollZero]);
useImperativeHandle(
ref,
@@ -1641,7 +1667,9 @@ const MediaPanel = React.forwardRef(
setModalStyle({});
setModalScale(1);
} else if (isOnTop && !panelInfo.modal && videoPlayer.current) {
console.log('[MediaPanel] Condition 3: Playing fullscreen video');
console.log(
'[MediaPanel] Condition 3: Playing fullscreen video - enforcing 1920x1080 rendering'
);
if (videoPlayer.current?.getMediaState()?.paused) {
videoPlayer.current.play();
}
@@ -1652,6 +1680,14 @@ const MediaPanel = React.forwardRef(
}
}, [panelInfo, isOnTop, dispatch]);
useEffect(() => {
if (!panelInfo.modal) {
console.log('[MediaPanel] modal=false - resetting inline styles for fullscreen');
setModalStyle({});
setModalScale(1);
}
}, [panelInfo.modal]);
const smallestOffsetHourIndex = useMemo(() => {
if (shopNowInfo) {
const filteredVideos = shopNowInfo.filter((video) => video.offsetHour >= currentTime);
@@ -2184,6 +2220,7 @@ const MediaPanel = React.forwardRef(
const containerClassName = classNames(
css.videoContainer,
panelInfo.modal && css.modal,
!panelInfo.modal && css.fullscreen,
panelInfo.shouldShrinkTo1px && css.shrinkTo1px,
// MediaPanel이 최상단 아니고, 최상단이 DetailPanel(from Player)이면 비디오 보이도록
!isOnTop && isTopPanelDetailFromPlayer && css['background-visible'],
@@ -2192,12 +2229,23 @@ const MediaPanel = React.forwardRef(
!captionEnable && css.hideSubtitle
);
const panelStyleOverride = !panelInfo.modal
? {
width: '100vw',
height: '100vh',
top: 0,
left: 0,
position: 'fixed',
}
: undefined;
return (
<TPanel
isTabActivated={false}
{...props}
className={containerClassName}
handleCancel={handleClickBack}
style={panelStyleOverride}
spotlightId={spotlightId}
>
<Container
@@ -2230,6 +2278,7 @@ const MediaPanel = React.forwardRef(
{isReadyToPlay && (
<div className={css.videoFrame}>
<VideoPlayer
className={!panelInfo.modal ? 'fullscreen' : undefined}
setApiProvider={getPlayer}
disabled={panelInfo.modal}
onEnded={onEnded}
@@ -2239,7 +2288,17 @@ const MediaPanel = React.forwardRef(
spotlightDisabled={panelInfo.modal}
isYoutube={isYoutube}
src={currentPlayingUrl}
style={panelInfo.modal ? modalStyle : {}}
style={
panelInfo.modal
? modalStyle
: {
width: '100vw',
height: '100vh',
position: 'fixed',
top: 0,
left: 0,
}
}
modalScale={panelInfo.modal ? modalScale : 1}
modalClassName={panelInfo.modal && panelInfo.modalClassName}
spotlightId={

View File

@@ -2,11 +2,12 @@
@import "../../style/utils.module.less";
@videoBackgroundColor: black;
.videoContainer {
.videoContainer {
position: absolute;
background-color: @videoBackgroundColor;
z-index: 21;
outline: none;
inset: 0;
&:focus-visible,
&:focus {
@@ -18,6 +19,19 @@
box-sizing: border-box;
}
&.fullscreen .videoFrame {
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
}
&.fullscreen .videoFrame video,
&.fullscreen .videoFrame iframe {
width: 100vw;
height: 100vh;
}
.videoFrame:focus-within {
outline: 2px solid #c70850;
border-radius: 6px;
@@ -134,6 +148,18 @@
display: none;
}
}
&.fullscreen {
width: 100vw;
height: 100vh;
left: 0;
top: 0;
pointer-events: auto;
z-index: 21;
}
&.fullscreen .media {
width: 1920px !important;
height: 100vh !important;
}
&.hideSubtitle {
video::cue {
visibility: hidden;

View File

@@ -322,12 +322,14 @@ function PlayerOverlayContents({
<h2 className={css.patnerName}>{partnerName}</h2>
{!panelInfo?.modal && (
<Marquee
className={classNames(css.title, videoVerticalVisible && css.videoVerticalMarquee)}
marqueeOn="render"
>
{showName}
</Marquee>
)}
</div>
</Container>
{type === 'VOD' && disclaimer && (