From 942d926781eb13760c0f1a53637d1bd83d608d65 Mon Sep 17 00:00:00 2001 From: optrader Date: Tue, 11 Nov 2025 12:13:58 +0900 Subject: [PATCH] [251111] feat: views - MediaPlayer.jsx, MediaPlayer.v2.jsx, ProductAll... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 11. 11. 12:13:55 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 8๊ฐœ โ€ข ์ถ”๊ฐ€: +84์ค„ โ€ข ์‚ญ์ œ: -124์ค„ ๐Ÿ“ ์ถ”๊ฐ€๋œ ํŒŒ์ผ: + com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.module.less ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.v2.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.module.less ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข UI ์ปดํฌ๋„ŒํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„  โ€ข ์†Œ๊ทœ๋ชจ ๊ธฐ๋Šฅ ๊ฐœ์„  โ€ข ์ฝ”๋“œ ์ •๋ฆฌ ๋ฐ ์ตœ์ ํ™” โ€ข ๋ชจ๋“ˆ ๊ตฌ์กฐ ๊ฐœ์„  Performance: ์ฝ”๋“œ ์ตœ์ ํ™”๋กœ ์„ฑ๋Šฅ ๊ฐœ์„  ๊ธฐ๋Œ€ --- .../components/VideoPlayer/MediaPlayer.jsx | 2 +- .../VideoPlayer/MediaPlayer.module.less | 835 ++++++++++++++++++ .../components/VideoPlayer/MediaPlayer.v2.jsx | 28 +- .../ProductAllSection/ProductAllSection.jsx | 2 +- .../ProductVideo/ProductVideo.v2.jsx | 170 ++-- .../src/views/MediaPanel/MediaPanel.jsx | 2 +- .../PlayerOverlayContents.module.less | 2 +- .../VoiceInputOverlay/VoiceInputOverlay.jsx | 2 +- 8 files changed, 919 insertions(+), 124 deletions(-) create mode 100644 com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.module.less diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx index 618358d6..70d691bc 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx @@ -59,7 +59,7 @@ import Media from './Media'; import Overlay from './Overlay'; import TReactPlayer from './TReactPlayer'; import Video from './Video'; -import css from './VideoPlayer.module.less'; +import css from './MediaPlayer.module.less'; const isEnter = is('enter'); const isLeft = is('left'); diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.module.less b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.module.less new file mode 100644 index 00000000..24e091a8 --- /dev/null +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.module.less @@ -0,0 +1,835 @@ +// VideoPlayer.module.less +// +@import "~@enact/sandstone/styles/variables.less"; +@import "~@enact/sandstone/styles/mixins.less"; +@import "~@enact/sandstone/styles/skin.less"; +@import "../../style/utils.module.less"; +@import "../../style/CommonStyle.module.less"; +.videoPlayer { + // Set by counting the IconButtons inside the side components. + --liftDistance: 0px; + + overflow: hidden; + + .video { + height: 100%; + width: 100%; + background: #000; + } + + .media { + height: 100%; + width: 100%; + background: #000; + + &.mediaBackground { + &:after { + width: 560px; + height: 200px; + position: absolute; + left: 0; + bottom: 0; + content: ""; + background: linear-gradient( + to top, + rgba(255, 255, 255, 1), + transparent + ); + opacity: 0.2; + } + } + } + + .preloadVideo { + display: none; + } + + .thumbnail { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + display: flex; + justify-content: center; + align-items: center; + > img { + width: 100%; + max-height: 100%; + border-radius: 12px; + } + &.noRadiusThumbnail { + > img { + border-radius: 0; + } + } + &.verticalThumbnail { + > img { + width: auto; + height: 100%; + border-radius: 0; + } + } + &.smallThumbnail { + &::after { + .focused(@boxShadow:0, @borderRadius: 12px); + border: 6px solid @PRIMARY_COLOR_RED; + top: -4px; + right: -4px; + bottom: -4px; + left: -4px; + } + } + } + .disclaimer { + .size(@w: 100% , @h: 54px); + display: flex; + background-color: rgba(0, 0, 0, 0.9); + position: absolute; + bottom: 0; + left: 0; + align-items: center; + z-index: 1; + > span { + .size(@w: 18px , @h: 18px); + background-image: url("../../../assets/images/icons/ic-alert-20@3x.png"); + background-position: center; + background-size: cover; + margin: 0 12px 0 20px; + } + > h3 { + .size(@w: 100% , @h: 54px); + color: #ffffff; + font-size: 20px; + line-height: 54px; + .elip(@clamp:1); + .marquee { + width: 100%; + transition: opacity 0.5s ease-in-out; + } + } + } + .videoOverlayWithPhoneNumberFull { + bottom: 59px; + left: 141px; + } + .videoOverlayWithPhoneNumber { + display: none; + &.ru { + display: flex; + + width: 22%; + height: 12.5%; + bottom: 6.5% !important; + left: 48% !important; + padding: 4px !important; + margin-bottom: 0 !important; + > div:first-child { + font-size: 12px; + line-height: 12px; + } + > div:last-child { + margin-top: 0; + display: flex; + align-items: center; + > img { + width: 14px; + height: 14px; + } + > span { + font-size: 18px; + line-height: 18px; + height: auto; + width: auto; + } + } + } + + &.us { + &.vertical { + width: 105px; + height: 66px; + bottom: 225px !important; + left: -96px !important; + } + &.horizontal { + > div:first-child { + font-size: 12px; + line-height: 1; + } + > div:last-child { + display: flex; + align-items: center; + > img { + width: 14px; + height: 14px; + } + > span { + font-size: 16px; + height: auto; + width: auto; + } + } + &.qvc { + display: flex; + width: 18%; + height: 22%; + padding: 1%; + bottom: 4% !important; + left: 4.5% !important; + > div:first-child { + font-size: 48%; + } + > div:last-child { + > img { + width: 12px; + height: 12px; + } + > span { + font-size: 48%; + } + } + } + &.hsn { + display: flex; + width: 18.5%; + height: 22%; + padding: 1%; + bottom: 4% !important; + left: 7% !important; + > div:first-child { + font-size: 48%; + } + > div:last-child { + > img { + width: 12px; + height: 12px; + } + > span { + font-size: 48%; + } + } + } + &.verticalModal { + > div:last-child { + > img { + width: 20px; + height: 20px; + } + > span { + font-size: 20px; + } + } + } + } + } + > img { + width: 102px; + height: 35px; + } + + div > img { + width: 34px; + height: 34px; + } + } + + .videoOverlayMedia { + bottom: 24% !important; + left: 7% !important; + &.callToOrderHide { + display: none !important; + } + &.qvc { + display: flex; + width: 23%; + height: 15%; + padding: 30px 5px; + > div:first-child { + flex: none; + font-size: 13px !important; + line-height: 13px !important; + padding: 3px 5px; + } + > div:last-child { + display: flex; + flex: none; + align-items: center; + height: 4px; + > img { + flex: none; + width: 13px; + height: 13px; + } + > span { + flex: none; + font-size: 15px; + height: auto; + width: auto; + } + } + } + &.hsn { + display: flex; + width: 23%; + height: 15%; + padding: 30px 5px; + > div:first-child { + flex: none; + font-size: 13px !important; + line-height: 13px !important; + padding: 3px 5px; + } + > div:last-child { + display: flex; + flex: none; + align-items: center; + height: 4px; + > img { + flex: none; + width: 13px; + height: 13px; + } + > span { + flex: none; + font-size: 15px; + height: auto; + width: auto; + } + } + } + } + + .loaderWrap { + height: 100%; + > div { + width: 220px; + height: 220px; + position: relative; + overflow: hidden; + left: calc(50% - 110px); + top: calc(50% - 110px); + background-color: transparent; + > div { + > div { + -webkit-animation: mulShdSpinWhite 1.2s infinite ease !important; + animation: mulShdSpinWhite 1.2s infinite ease !important; + } + } + } + } + @-webkit-keyframes mulShdSpinWhite { + 0%, + 100% { + -webkit-box-shadow: 0em -2.6em 0em 0em #fff, + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7); + box-shadow: 0em -2.6em 0em 0em #fff, + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7); + } + 12.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), + 1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), + 1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5); + } + 25% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff, + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff, + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 37.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff, + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff, + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 50% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff, + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff, + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 62.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff, + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff, + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 75% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff, + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff, + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 87.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff; + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff; + } + } + + @keyframes mulShdSpinWhite { + 0%, + 100% { + -webkit-box-shadow: 0em -2.6em 0em 0em #fff, + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7); + box-shadow: 0em -2.6em 0em 0em #fff, + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7); + } + 12.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), + 1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), + 1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5); + } + 25% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff, + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff, + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 37.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff, + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff, + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 50% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff, + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff, + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 62.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff, + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff, + -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 75% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff, + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff, + -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2); + } + 87.5% { + -webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff; + box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), + 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), + 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), + 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), + 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), + -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), + -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff; + } + } + + .overlay { + .position(@position: absolute, @top: 0, @right: 0, @bottom: 0, @left: 0); + } + @keyframes spin { + 0% { + transform: rotate(0.25turn); + } + 33% { + transform: rotate(0.5turn); + } + 80% { + transform: rotate(0.95turn); + } + 85% { + transform: rotate(1turn); + } + 100% { + transform: rotate(1.25turn); + } + } + .spinner { + background-image: url("../../../assets/images/player/icon_loading.png"); + width: 100px; + height: 100px; + position: relative; + background-size: cover; + border-radius: 20.8125rem; + overflow: hidden; + // margin: 490px auto; + left: calc(50% - 50px); + top: calc(50% - 50px); + animation: none 1.25s linear infinite; + animation-name: spin; + // animation-play-state: paused; + } + .controlFeedbackBtnLayer { + position: absolute; + z-index: 50; + top: 0; + left: 0; + padding: 0; + width: 100%; + height: 94px; + display: flex; + justify-content: space-between; + &.lift { + transform: translateY(~"calc(var(--liftDistance) * -1)"); + transition: transform 0.3s linear; + } + } + .fullscreen { + .miniFeedback { + position: absolute; + z-index: 50; + top: 506px; + left: 0; + padding: 0; + width: 100%; + height: 94px; + -webkit-margin-end: 0px; + pointer-events: none; + } + &.liveFullScreen { + .bottom { + bottom: 78px; + } + } + .bottom { + position: absolute; + z-index: 3; // Value assigned as part of the VideoPlayer API so layers may be inserted in-between + bottom: 70px; + // bottom: 78px; + // bottom: -18px; + left: 0; + right: 0; + height: 70px; + // left: @sand-video-player-padding-side; + // right: @sand-video-player-padding-side; + + &.videoVerticalBottom { + height: 54px; + } + &.lift { + transform: translateY(~"calc(var(--liftDistance) * -1)"); + transition: transform 0.3s linear; + } + + &.hidden { + pointer-events: none; + + .sliderContainer { + position: absolute; + left: 0; + right: 0; + } + } + + .infoFrame { + display: flex; + margin-left: 64px; + } + + .sliderContainer { + // display: flex; + position: relative; + align-items: center; + margin-left: 60px; + margin-right: 59px; + height: 70px; + bottom: -20px; + > *:first-child { + text-align: right; + } + + .enact-locale-rtl({ + direction: ltr; + }); + + &.videoVertical { + margin-left: 680px; + margin-right: 673px; + } + } + } + } + + .controlsHandleAbove { + pointer-events: none; + .position(@position: absolute, @top: 0, @right: 0, @bottom: auto, @left: 0); + } + + // Skin colors + .applySkins({ + .fullscreen { + .bottom { + background-color: @sand-video-player-bottom-bg-color; + + .infoFrame { + text-shadow: @sand-video-player-title-text-shadow; + } + } + } + + .overlay { + z-index: 2; + + &.scrim::before, + &.scrim::after { + width: 100%; //1920px; + height: 50%; + position: absolute; + left: 0; + content: ""; + z-index: 4; + } + &.scrim::before { + bottom: 0; + background: linear-gradient(0deg, rgba(0, 0, 0, 1) 0%, transparent 50%); + } + &.scrim::after { + top: 0; + background: linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, transparent 50%); + } + + // &.scrim::after { + // background: @sand-video-player-scrim-gradient-color + // } + } + }); +} + +// ========== MediaPlayer.v2 Controls ========== +.controlsContainer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 20px 40px 30px; + background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.7) 60%, transparent 100%); + z-index: 10; + display: flex; + flex-direction: column; + gap: 16px; +} + +.sliderContainer { + display: flex; + align-items: center; + gap: 12px; + width: 100%; +} + +.times { + min-width: 80px; + text-align: center; +} + +.controlsButtons { + display: flex; + gap: 20px; + justify-content: center; + align-items: center; +} + +.playPauseBtn { + width: 60px; + height: 60px; + font-size: 24px; + background: rgba(255, 255, 255, 0.2); + border: 2px solid rgba(255, 255, 255, 0.6); + border-radius: 50%; + color: white; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + + &:hover { + background: rgba(255, 255, 255, 0.3); + border-color: white; + } + + &:active { + transform: scale(0.95); + } +} + +.backBtn { + padding: 12px 24px; + font-size: 18px; + background: rgba(255, 255, 255, 0.2); + border: 2px solid rgba(255, 255, 255, 0.6); + border-radius: 8px; + color: white; + cursor: pointer; + transition: all 0.2s; + + &:hover { + background: rgba(255, 255, 255, 0.3); + border-color: white; + } + + &:active { + transform: scale(0.98); + } +} diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.v2.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.v2.jsx index 8cdffe7b..9315d97f 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.v2.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.v2.jsx @@ -27,7 +27,7 @@ import Overlay from './Overlay'; import Media from './Media'; import TReactPlayer from './TReactPlayer'; -import css from './VideoPlayer.module.less'; +import css from './MediaPlayer.module.less'; const SpottableDiv = Touchable(Spottable('div')); const RootContainer = SpotlightContainerDecorator( @@ -203,7 +203,7 @@ const MediaPlayerV2 = forwardRef((props, ref) => { const bufferedEnd = video.buffered.end(video.buffered.length - 1); const loaded = bufferedEnd / video.duration; setProportionLoaded(loaded); - } catch (error) { + } catch (err) { // buffered.end() can throw if index is out of range setProportionLoaded(0); } @@ -294,7 +294,7 @@ const MediaPlayerV2 = forwardRef((props, ref) => { } }, [controlsVisible, hideControls, showControls]); - // ========== Playback Control Methods ========== + // ========== Playback Control ========== const play = useCallback(() => { if (videoRef.current && !sourceUnavailable) { videoRef.current.play(); @@ -359,17 +359,21 @@ const MediaPlayerV2 = forwardRef((props, ref) => { // ๊ธฐ๋ณธ ๋™์ž‘์€ MediaSlider ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌ }, []); - // ========== Video Click Handler (Modal ์ „ํ™˜) ========== + // ========== Video Click Handler ========== const handleVideoClick = useCallback(() => { - if (isModal && onClick) { - // Modal ๋ชจ๋“œ์—์„œ ํด๋ฆญ โ†’ Fullscreen ์ „ํ™˜ - onClick(); + // modal ์ƒํƒœ์ผ ๋•Œ๋Š” ์•„๋ฌด ๋™์ž‘๋„ ํ•˜์ง€ ์•Š์Œ (์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ ์•ˆ ํ•จ) + if (isModal) { return; } - // Fullscreen ๋ชจ๋“œ์—์„œ ํด๋ฆญ โ†’ Controls ํ† ๊ธ€ + // modal์ด ์•„๋‹ ๋•Œ๋งŒ ์ปจํŠธ๋กค ํ† ๊ธ€ toggleControls(); - }, [isModal, onClick, toggleControls]); + + // ์™ธ๋ถ€์—์„œ ์ „๋‹ฌ๋œ onClick ์ฝœ๋ฐฑ ํ˜ธ์ถœ + if (onClick) { + onClick(); + } + }, [isModal, toggleControls, onClick]); // ========== Modal isPaused ๋™๊ธฐํ™” ========== useEffect(() => { @@ -390,11 +394,11 @@ const MediaPlayerV2 = forwardRef((props, ref) => { if (videoRef.current?.paused) { play(); } - // Fullscreen ์ „ํ™˜ ์‹œ controls๋ฅผ 10์ดˆ๋กœ ์—ฐ์žฅ ํ‘œ์‹œ - showControls(10000); + // Fullscreen ์ „ํ™˜ ์‹œ controls๋ฅผ ์ž๋™์œผ๋กœ ํ‘œ์‹œํ•˜์ง€ ์•Š์Œ + // ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•  ๋•Œ๋งŒ ํ‘œ์‹œ๋จ } prevModalRef.current = isModal; - }, [isModal, play, showControls]); + }, [isModal, play]); // ========== proportionLoaded ์ฃผ๊ธฐ์  ์—…๋ฐ์ดํŠธ ========== // TReactPlayer์˜ ๊ฒฝ์šฐ buffered๊ฐ€ ๊ณ„์† ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ ์ฃผ๊ธฐ์  ์ฒดํฌ ํ•„์š” diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx index 2447300b..39af927f 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -174,7 +174,7 @@ export default function ProductAllSection({ const youmaylikeData = useSelector((state) => state.main.youmaylikeData); // ProductVideo ๋ฒ„์ „ ๊ด€๋ฆฌ (1: ๊ธฐ์กด modal ๋ฐฉ์‹, 2: ๋‚ด์žฅ ๋ฐฉ์‹ , 3: ๋น„๋””์˜ค ์ƒ๋žต) - const [productVideoVersion, setProductVideoVersion] = useState(3); + const [productVideoVersion, setProductVideoVersion] = useState(2); // const [currentHeight, setCurrentHeight] = useState(0); //ํ•˜๋‹จ๋ถ€๋ถ„๊นŒ์ง€ ๊ฐ”์„๋•Œ ์ฒดํฌ์šฉ diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx index 030476d1..86f1511a 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx @@ -68,11 +68,10 @@ export default function ProductVideoV2({ const autoPlayTimerRef = useRef(null); const containerRef = useRef(null); - // VideoPlayer DOM ์ด๋™์„ ์œ„ํ•œ refs + // VideoPlayer refs const videoPlayerWrapperRef = useRef(null); const normalContainerRef = useRef(null); const fullscreenContainerRef = useRef(null); - const initialRenderContainerRef = useRef(null); // React๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋งํ•˜๋Š” ์œ„์น˜ // ๋น„๋””์˜ค ์žฌ์ƒ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์ฒดํฌ const canPlayVideo = useMemo(() => { @@ -316,42 +315,6 @@ export default function ProductVideoV2({ }; }, [autoPlay, canPlayVideo, isPlaying, dispatch]); - // VideoPlayer wrapper๋ฅผ ์ ์ ˆํ•œ container๋กœ ์ด๋™ - useEffect(() => { - if (!isPlaying) return; - - const wrapper = videoPlayerWrapperRef.current; - const normalContainer = normalContainerRef.current; - const fullscreenContainer = fullscreenContainerRef.current; - - if (!wrapper || !normalContainer || !fullscreenContainer) { - console.warn('[ProductVideoV2] Refs not ready:', { - wrapper: !!wrapper, - normalContainer: !!normalContainer, - fullscreenContainer: !!fullscreenContainer, - }); - return; - } - - // ์ฒ˜์Œ ์žฌ์ƒ ์‹œ์ž‘ ์‹œ: ์ž„์‹œ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ ์ ˆํ•œ ์œ„์น˜๋กœ ์ด๋™ - // ์ดํ›„ ์ „ํ™˜ ์‹œ: ์ปจํ…Œ์ด๋„ˆ ๊ฐ„ ์ด๋™ - if (isFullscreen) { - // ์ „์ฒดํ™”๋ฉด: wrapper๋ฅผ fullscreen container๋กœ ์ด๋™ - if (wrapper.parentElement !== fullscreenContainer) { - fullscreenContainer.appendChild(wrapper); - fullscreenContainer.style.display = 'block'; - console.log('[ProductVideoV2] Moved to fullscreen'); - } - } else { - // ์ผ๋ฐ˜ ๋ชจ๋“œ: wrapper๋ฅผ normal container๋กœ ์ด๋™ - if (wrapper.parentElement !== normalContainer) { - normalContainer.appendChild(wrapper); - fullscreenContainer.style.display = 'none'; - console.log('[ProductVideoV2] Moved to normal'); - } - } - }, [isFullscreen, isPlaying]); - // ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ Redux ์ƒํƒœ ์ •๋ฆฌ ๋ฐ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋น„๋””์˜ค ์žฌ์ƒ ์žฌ๊ฐœ useEffect(() => { return () => { @@ -396,54 +359,58 @@ export default function ProductVideoV2({ } : {}; - // VideoPlayer ์ปดํฌ๋„ŒํŠธ (ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ, DOM ์ด๋™์œผ๋กœ ์œ„์น˜ ๋ณ€๊ฒฝ) - const videoPlayerElement = isPlaying ? ( -
- { + if (!isPlaying) return null; + + return ( +
- {typeof window === 'object' && window.PalmSystem && ( - - )} - {productInfo?.prdtMediaSubtitlUrl && typeof window === 'object' && window.PalmSystem && ( - - )} - -
- ) : null; + + {typeof window === 'object' && window.PalmSystem && ( + + )} + {productInfo?.prdtMediaSubtitlUrl && typeof window === 'object' && window.PalmSystem && ( + + )} + +
+ ); + }; return ( <> @@ -474,14 +441,16 @@ export default function ProductVideoV2({ - ) : ( - // ์ผ๋ฐ˜ ์žฌ์ƒ ๋ชจ๋“œ: VideoPlayer๊ฐ€ ์—ฌ๊ธฐ์— ์ดˆ๊ธฐ ๋ Œ๋”๋ง๋จ -
- )} + ) : !isFullscreen ? ( + // ์ผ๋ฐ˜ ์žฌ์ƒ ๋ชจ๋“œ: VideoPlayer๋ฅผ ์ง์ ‘ ๋ Œ๋”๋ง +
+ {renderVideoPlayer()} +
+ ) : null} - {/* ์ „์ฒดํ™”๋ฉด container (Portal, ํ•ญ์ƒ body์— ์กด์žฌ) */} - {ReactDOM.createPortal( + {/* ์ „์ฒดํ™”๋ฉด container (Portal) */} + {isPlaying && isFullscreen && ReactDOM.createPortal( + > + {renderVideoPlayer()} +
, document.body )} - - {/* ์ž„์‹œ ๋ Œ๋”๋ง ์ปจํ…Œ์ด๋„ˆ - React๊ฐ€ ์—ฌ๊ธฐ์— VideoPlayer ๋ Œ๋”๋ง, useEffect๊ฐ€ ์‹ค์ œ ์œ„์น˜๋กœ ์ด๋™ */} -
- {videoPlayerElement} -
); } diff --git a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx index ee51ff87..11fb634f 100644 --- a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx +++ b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx @@ -16,7 +16,7 @@ import * as PanelActions from '../../actions/panelActions'; import TPanel from '../../components/TPanel/TPanel'; import Media from '../../components/VideoPlayer/Media'; import TReactPlayer from '../../components/VideoPlayer/TReactPlayer'; -import { VideoPlayer } from '../../components/VideoPlayer/MediaPlayer'; +import { VideoPlayer } from '../../components/VideoPlayer/MediaPlayer.v2'; import usePrevious from '../../hooks/usePrevious'; import { panel_names } from '../../utils/Config'; import css from './MediaPanel.module.less'; diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.module.less b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.module.less index 2f2a97e6..12462c2e 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.module.less +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.module.less @@ -73,7 +73,7 @@ .size(@w: 60px, @h: 60px); background-size: 60px 60px; background-repeat: no-repeat; - background-image: url("../../../../assets/images/btn/btn-60-wh-back-nor@3x.png"); + background-image: url("../../../../assets/images/btn/btn-60-wh-back-nor@3x.png"); &:focus { background-image: url("../../../../assets/images/btn/btn-60-wh-back-foc@3x.png"); diff --git a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx index c04658bd..a80868ac 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx @@ -147,7 +147,7 @@ const VoiceInputOverlay = ({ isVoiceResultMode = false, externalResponseText = '', isExternalBubbleSearch = false, - shopperHouseData = null, // ๐ŸŽฏ [ํฌ์ปค์Šค ์ถฉ๋Œ ํ•ด๊ฒฐ] ์Œ์„ฑ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ + externalShopperHouseData = null, // ๐ŸŽฏ [ํฌ์ปค์Šค ์ถฉ๋Œ ํ•ด๊ฒฐ] ์™ธ๋ถ€ ์Œ์„ฑ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ }) => { if (DEBUG_MODE) { console.log('๐Ÿ”„ [DEBUG] VoiceInputOverlay render - isVisible:', isVisible, 'mode:', mode);