Skip to content

Commit 45cd133

Browse files
committed
Обновление: добавлен видеофон в компонент MikuMonday с управлением видимостью, улучшен стиль и размеры элементов в IntroStage
1 parent 51853c8 commit 45cd133

File tree

3 files changed

+134
-36
lines changed

3 files changed

+134
-36
lines changed

src/components/OBS_Components/MikuMonday/MikuMonday.module.scss

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,45 @@
1111
background: transparent;
1212
border: none;
1313
box-shadow: none;
14+
position: relative;
15+
overflow: hidden;
16+
}
17+
18+
.videoBackground {
19+
position: fixed;
20+
top: 0;
21+
left: 0;
22+
width: 100vw;
23+
height: 100vh;
24+
z-index: -1;
25+
overflow: hidden;
26+
transition: opacity 600ms ease-in-out;
27+
28+
&::after {
29+
content: '';
30+
position: absolute;
31+
top: 0;
32+
left: 0;
33+
width: 100%;
34+
height: 100%;
35+
background: rgba(0, 0, 0, 0.3);
36+
pointer-events: none;
37+
}
38+
39+
iframe {
40+
min-width: 100%;
41+
min-height: 100%;
42+
width: auto;
43+
height: auto;
44+
}
45+
}
46+
47+
.videoVisible {
48+
opacity: 1;
49+
}
50+
51+
.videoHidden {
52+
opacity: 0;
1453
}
1554

1655
.stage {
@@ -25,8 +64,9 @@
2564
align-items: center;
2665
gap: 32px;
2766
padding: 36px 44px;
67+
margin-bottom: 24px;
2868
border-radius: 32px;
29-
border: none;
69+
border: 2px solid rgba(255, 255, 255, 0.15);
3070
background: linear-gradient(135deg,
3171
rgba(var(--bs-primary-rgb), 0.35) 0%,
3272
rgba(var(--bs-secondary-rgb), 0.28) 45%,
@@ -260,19 +300,20 @@
260300
}
261301

262302
.result-stage {
263-
width: min(56vw, 720px);
303+
width: min(68vw, 880px);
264304
max-width: 90vw;
265-
min-height: 360px;
305+
min-height: 420px;
266306
position: relative;
267307
overflow: hidden;
268308
display: flex;
269309
flex-direction: column;
270310
align-items: center;
271311
justify-content: center;
272-
gap: 10px;
273-
padding: 28px 32px;
312+
gap: 12px;
313+
margin-bottom: 24px;
314+
padding: 36px 44px;
274315
border-radius: 28px;
275-
border: none;
316+
border: 2px solid rgba(255, 255, 255, 0.15);
276317
background: linear-gradient(140deg,
277318
rgba(var(--bs-secondary-rgb), 0.22) 0%,
278319
rgba(18, 22, 40, 0.68) 45%,

src/components/OBS_Components/MikuMonday/MikuMonday.tsx

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,33 @@ function MikuMondayContent() {
6666
}, [currentAlert, rouletteGroups]);
6767

6868
const [stage, setStage] = useState<StageKey>("waiting");
69+
const [isVideoVisible, setIsVideoVisible] = useState(false);
6970
const waitingTimeoutRef = useRef<number | null>(null);
7071
const stageSyncTimeoutRef = useRef<number | null>(null);
72+
const videoRef = useRef<HTMLVideoElement | null>(null);
73+
74+
// Предзагружаем видео при монтировании компонента
75+
useEffect(() => {
76+
const video = videoRef.current;
77+
if (video) {
78+
video.load(); // Начинаем загрузку видео
79+
}
80+
}, []);
81+
82+
// Управление воспроизведением видео
83+
useEffect(() => {
84+
const video = videoRef.current;
85+
if (!video) return;
86+
87+
if (isVideoVisible) {
88+
video.currentTime = 0; // Сбрасываем на начало
89+
video.play().catch(err => {
90+
console.warn("[MikuMonday] Не удалось воспроизвести видео:", err);
91+
});
92+
} else {
93+
video.pause();
94+
}
95+
}, [isVideoVisible]);
7196

7297
useEffect(
7398
() => () => {
@@ -98,6 +123,7 @@ function MikuMondayContent() {
98123
setStage(previousStage =>
99124
previousStage === "waiting" ? "intro" : previousStage
100125
);
126+
setIsVideoVisible(true);
101127
stageSyncTimeoutRef.current = null;
102128
}, 0);
103129
return;
@@ -140,6 +166,7 @@ function MikuMondayContent() {
140166
displayName: currentAlert?.twitchUser.displayName,
141167
trackNumber: currentAlert?.selectedTrack.number,
142168
});
169+
setIsVideoVisible(false);
143170
setStage("waiting");
144171
if (waitingTimeoutRef.current !== null) {
145172
window.clearTimeout(waitingTimeoutRef.current);
@@ -161,16 +188,45 @@ function MikuMondayContent() {
161188
}, QUEUE_PAUSE_MS);
162189
}, [dequeueCurrent, currentAlert]);
163190

191+
// Видео-фон существует постоянно, чтобы не перемонтироваться между стейджами
192+
const videoBackground = (
193+
<div
194+
className={`${styles.videoBackground} ${isVideoVisible ? styles.videoVisible : styles.videoHidden}`}
195+
>
196+
<video
197+
ref={videoRef}
198+
src="/static/miku.mp4"
199+
preload="auto"
200+
muted
201+
playsInline
202+
loop
203+
style={{
204+
position: "absolute",
205+
top: "50%",
206+
left: "50%",
207+
minWidth: "100%",
208+
minHeight: "100%",
209+
width: "auto",
210+
height: "auto",
211+
transform: "translate(-50%, -50%)",
212+
objectFit: "cover",
213+
pointerEvents: "none",
214+
}}
215+
/>
216+
</div>
217+
);
218+
219+
// Рендерим контент в зависимости от стейджа
220+
let stageContent;
221+
164222
if (!currentAlert || stage === "waiting") {
165-
return (
223+
stageContent = (
166224
<div className={styles.layout}>
167225
<WaitingStage onComplete={() => {}} />
168226
</div>
169227
);
170-
}
171-
172-
if (stage === "intro") {
173-
return (
228+
} else if (stage === "intro") {
229+
stageContent = (
174230
<div className={styles.layout}>
175231
<IntroStage
176232
twitchUser={currentAlert.twitchUser}
@@ -179,40 +235,41 @@ function MikuMondayContent() {
179235
/>
180236
</div>
181237
);
182-
}
183-
184-
if (stage === "roulette") {
185-
return (
238+
} else if (stage === "roulette") {
239+
stageContent = (
186240
<RouletteStage
187241
rouletteGroups={rouletteGroups}
188242
shouldSkipAvailableTracksUpdate={shouldSkipAvailableTracksUpdate}
189243
decrementAvailableTrack={decrementAvailableTrack}
190244
onComplete={handleRouletteComplete}
191245
/>
192246
);
247+
} else {
248+
const trackToDisplay = winnerTrack ?? currentAlert.selectedTrack;
249+
console.log("[MikuMonday] 📺 Отправляем трек в ResultStage", {
250+
trackId: trackToDisplay.id,
251+
trackNumber: trackToDisplay.number,
252+
trackTitle: trackToDisplay.title,
253+
trackArtist: trackToDisplay.artist,
254+
isWinnerTrack: winnerTrack !== undefined,
255+
winnerGroupExists: rouletteGroups.some(g => g.hasWinner),
256+
});
257+
stageContent = (
258+
<div className={styles.layout}>
259+
<ResultStage
260+
track={trackToDisplay}
261+
twitchUser={currentAlert.twitchUser}
262+
onComplete={handleResultComplete}
263+
/>
264+
</div>
265+
);
193266
}
194267

195268
return (
196-
<div className={styles.layout}>
197-
{(() => {
198-
const trackToDisplay = winnerTrack ?? currentAlert.selectedTrack;
199-
console.log("[MikuMonday] 📺 Отправляем трек в ResultStage", {
200-
trackId: trackToDisplay.id,
201-
trackNumber: trackToDisplay.number,
202-
trackTitle: trackToDisplay.title,
203-
trackArtist: trackToDisplay.artist,
204-
isWinnerTrack: winnerTrack !== undefined,
205-
winnerGroupExists: rouletteGroups.some(g => g.hasWinner),
206-
});
207-
return (
208-
<ResultStage
209-
track={trackToDisplay}
210-
twitchUser={currentAlert.twitchUser}
211-
onComplete={handleResultComplete}
212-
/>
213-
);
214-
})()}
215-
</div>
269+
<>
270+
{videoBackground}
271+
{stageContent}
272+
</>
216273
);
217274
}
218275

src/components/OBS_Components/MikuMonday/components/stages/IntroStage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface IntroStageProps {
1313
onComplete: () => void;
1414
}
1515

16-
const DEFAULT_INTRO_DURATION = 3200;
16+
const DEFAULT_INTRO_DURATION = 7000;
1717
const FADE_OUT_DURATION = 600;
1818

1919
export default function IntroStage({

0 commit comments

Comments
 (0)