Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const MemberInfo = ({ name, birthDate, gender, memberRank }: IMember) => {
</Typography>
<Typography
variant={isDesktop ? "Heading1" : "Headline1"}
sx={{ color: "label.neutral", width: "6rem" }}
sx={{ color: "label.neutral", width: "8rem" }}
>
{gradeLabel[memberRank]}
</Typography>
Expand Down
69 changes: 65 additions & 4 deletions src/components/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface IVideoHandle {
toggle: () => void;
mute: (m?: boolean) => void;
seek: (timeSec: number) => void;
toggleFullscreen: () => void;
getEl: () => HTMLVideoElement | null;
}

Expand Down Expand Up @@ -78,6 +79,8 @@ const VideoPlayer = forwardRef<IVideoHandle, IVideoPlayerProps>(
ref,
) {
const videoRef = useRef<HTMLVideoElement>(null);
const wrapperRef = useRef<HTMLDivElement>(null);
const [isFullscreen, setIsFullscreen] = useState(false);
// controlsRef removed; controls are separate component

// 재생/일시정지 플래시 아이콘
Expand All @@ -100,6 +103,43 @@ const VideoPlayer = forwardRef<IVideoHandle, IVideoPlayerProps>(
}, 650);
};

const handleToggleFullscreen = useCallback(() => {
if (!wrapperRef.current) return;

if (!document.fullscreenElement) {
wrapperRef.current.requestFullscreen().catch((err) => {
console.error(
`Error attempting to enable full-screen mode: ${err.message}`,
);
});
} else {
document.exitFullscreen();
}
}, []);

useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(!!document.fullscreenElement);
};

document.addEventListener("fullscreenchange", handleFullscreenChange);
document.addEventListener(
"webkitfullscreenchange",
handleFullscreenChange,
);

return () => {
document.removeEventListener(
"fullscreenchange",
handleFullscreenChange,
);
document.removeEventListener(
"webkitfullscreenchange",
handleFullscreenChange,
);
};
}, []);

const {
playing,
muted,
Expand Down Expand Up @@ -127,6 +167,7 @@ const VideoPlayer = forwardRef<IVideoHandle, IVideoPlayerProps>(
toggle: () => toggle?.(),
mute: (m?: boolean) => mute?.(m),
seek: (t: number) => seek?.(t),
toggleFullscreen: handleToggleFullscreen,
getEl: () => videoRef.current,
}));

Expand Down Expand Up @@ -193,24 +234,42 @@ const VideoPlayer = forwardRef<IVideoHandle, IVideoPlayerProps>(
const ratioNum = parseAspectRatioToNumber(aspectRatio);
const aspectCss =
typeof aspectRatio === "number" ? aspectRatio : (aspectRatio ?? "16 / 9");
const maxWFromHeightExpr = `calc((100dvh - ${viewportOffsetPx}px) * ${ratioNum})`;
const maxWFromHeightExpr = `calc((100dvh - ${isFullscreen ? 0 : viewportOffsetPx}px) * ${ratioNum})`;
return (
<Stack spacing={1} sx={{ width: "100%", color: "common.white" }}>
<Stack
spacing={isFullscreen ? 0 : 1}
sx={{
width: "100%",
height: isFullscreen ? "100%" : "auto",
color: "common.white",
}}
>
{/* 비디오 영역: 남은 높이를 꽉 채우되 16:9 유지 */}
<Box
ref={wrapperRef}
sx={{
width: fitViewport ? `min(100%, ${maxWFromHeightExpr})` : "100%",
width:
fitViewport && !isFullscreen
? `min(100%, ${maxWFromHeightExpr})`
: "100%",
height: isFullscreen ? "100dvh" : "auto",
mx: "auto",
alignSelf: "center",
display: "flex",
flexDirection: "column",
justifyContent: "center",
bgcolor: "black",
}}
>
<Box
sx={{
position: "relative",
width: "100%",
height: isFullscreen ? "auto" : "100%",
maxHeight: isFullscreen ? "100dvh" : "unset",
overflow: "hidden",
bgcolor: "black",
aspectRatio: aspectCss,
aspectRatio: isFullscreen ? "unset" : aspectCss,
}}
onPointerEnter={() => showControls()}
onPointerMove={() => showControls()}
Expand Down Expand Up @@ -316,6 +375,8 @@ const VideoPlayer = forwardRef<IVideoHandle, IVideoPlayerProps>(
v.currentTime = next;
setScrub(null);
}}
isFullscreen={isFullscreen}
onToggleFullscreen={handleToggleFullscreen}
visible={controlsVisible}
/>

Expand Down
14 changes: 14 additions & 0 deletions src/components/video-player/VideoControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import PlayArrowRounded from "@mui/icons-material/PlayArrowRounded";
import PauseRounded from "@mui/icons-material/PauseRounded";
import VolumeUpRounded from "@mui/icons-material/VolumeUpRounded";
import VolumeOffRounded from "@mui/icons-material/VolumeOffRounded";
import FullscreenRounded from "@mui/icons-material/FullscreenRounded";
import FullscreenExitRounded from "@mui/icons-material/FullscreenExitRounded";

const formatTime = (sec: number) =>
Number.isFinite(sec)
Expand All @@ -25,6 +27,8 @@ interface Props {
onToggleMute: () => void;
setScrub: (v: number | null) => void;
onSeek: (sec: number) => void;
isFullscreen: boolean;
onToggleFullscreen: () => void;
visible?: boolean;
}

Expand All @@ -43,6 +47,8 @@ export default function VideoControls({
onToggleMute,
setScrub,
onSeek,
isFullscreen,
onToggleFullscreen,
visible = true,
}: Props) {
return (
Expand Down Expand Up @@ -110,6 +116,14 @@ export default function VideoControls({
},
}}
/>

<IconButton
onClick={onToggleFullscreen}
aria-label={isFullscreen ? "전체화면 종료" : "전체화면"}
sx={{ color: "common.white" }}
>
{isFullscreen ? <FullscreenExitRounded /> : <FullscreenRounded />}
</IconButton>
</Box>
);
}