diff --git a/src/app/(with-container)/(exercise)/exercise/members/panel/MemberInfo.tsx b/src/app/(with-container)/(exercise)/exercise/members/panel/MemberInfo.tsx
index ff4deb4..26757bd 100644
--- a/src/app/(with-container)/(exercise)/exercise/members/panel/MemberInfo.tsx
+++ b/src/app/(with-container)/(exercise)/exercise/members/panel/MemberInfo.tsx
@@ -40,7 +40,7 @@ const MemberInfo = ({ name, birthDate, gender, memberRank }: IMember) => {
{gradeLabel[memberRank]}
diff --git a/src/components/VideoPlayer.tsx b/src/components/VideoPlayer.tsx
index 64f04e5..64db431 100644
--- a/src/components/VideoPlayer.tsx
+++ b/src/components/VideoPlayer.tsx
@@ -19,6 +19,7 @@ export interface IVideoHandle {
toggle: () => void;
mute: (m?: boolean) => void;
seek: (timeSec: number) => void;
+ toggleFullscreen: () => void;
getEl: () => HTMLVideoElement | null;
}
@@ -78,6 +79,8 @@ const VideoPlayer = forwardRef(
ref,
) {
const videoRef = useRef(null);
+ const wrapperRef = useRef(null);
+ const [isFullscreen, setIsFullscreen] = useState(false);
// controlsRef removed; controls are separate component
// 재생/일시정지 플래시 아이콘
@@ -100,6 +103,43 @@ const VideoPlayer = forwardRef(
}, 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,
@@ -127,6 +167,7 @@ const VideoPlayer = forwardRef(
toggle: () => toggle?.(),
mute: (m?: boolean) => mute?.(m),
seek: (t: number) => seek?.(t),
+ toggleFullscreen: handleToggleFullscreen,
getEl: () => videoRef.current,
}));
@@ -193,24 +234,42 @@ const VideoPlayer = forwardRef(
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 (
-
+
{/* 비디오 영역: 남은 높이를 꽉 채우되 16:9 유지 */}
showControls()}
onPointerMove={() => showControls()}
@@ -316,6 +375,8 @@ const VideoPlayer = forwardRef(
v.currentTime = next;
setScrub(null);
}}
+ isFullscreen={isFullscreen}
+ onToggleFullscreen={handleToggleFullscreen}
visible={controlsVisible}
/>
diff --git a/src/components/video-player/VideoControls.tsx b/src/components/video-player/VideoControls.tsx
index 94babd5..eecc644 100644
--- a/src/components/video-player/VideoControls.tsx
+++ b/src/components/video-player/VideoControls.tsx
@@ -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)
@@ -25,6 +27,8 @@ interface Props {
onToggleMute: () => void;
setScrub: (v: number | null) => void;
onSeek: (sec: number) => void;
+ isFullscreen: boolean;
+ onToggleFullscreen: () => void;
visible?: boolean;
}
@@ -43,6 +47,8 @@ export default function VideoControls({
onToggleMute,
setScrub,
onSeek,
+ isFullscreen,
+ onToggleFullscreen,
visible = true,
}: Props) {
return (
@@ -110,6 +116,14 @@ export default function VideoControls({
},
}}
/>
+
+
+ {isFullscreen ? : }
+
);
}