Merge branch 'fe/liveHeader' into 'frontend'

feat: 라이브 강의 헤더 변경

See merge request s11-webmobile1-sub2/S11P12A701!41
This commit is contained in:
정기영 2024-08-05 13:11:12 +09:00
commit fedebaeb0f
5 changed files with 80 additions and 103 deletions

View File

@ -5,9 +5,8 @@ import HomePage from './pages/HomePage';
import NotFoundPage from './pages/NotFoundPage'; import NotFoundPage from './pages/NotFoundPage';
import { lazy } from 'react'; import { lazy } from 'react';
import MyPageLayout from './components/Layout/MyPageLayout'; import MyPageLayout from './components/Layout/MyPageLayout';
import { LiveLayout } from './components/Layout'; import LivePage from './pages/LivePage';
const LivePage = lazy(async () => await import('./pages/LivePage'));
const LectureLayout = lazy(async () => await import('./components/Layout/LectureLayout')); const LectureLayout = lazy(async () => await import('./components/Layout/LectureLayout'));
const LearningLectureDetailPage = lazy(async () => await import('./pages/LearningLectureDetailPage')); const LearningLectureDetailPage = lazy(async () => await import('./pages/LearningLectureDetailPage'));
const NoticeListPage = lazy(async () => await import('./pages/NoticeListPage')); const NoticeListPage = lazy(async () => await import('./pages/NoticeListPage'));
@ -34,13 +33,7 @@ const QuizsetDetailPage = lazy(async () => await import('./pages/QuizsetDetailPa
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
path: 'live/:roomId', path: 'live/:roomId',
element: <LiveLayout />, element: <LivePage />,
children: [
{
index: true,
element: <LivePage />,
},
],
}, },
{ {
path: '', path: '',

View File

@ -1,3 +1,4 @@
import styles from './LiveRoom.module.css';
import { isEqualTrackRef, isTrackReference } from '@livekit/components-core'; import { isEqualTrackRef, isTrackReference } from '@livekit/components-core';
import { import {
CarouselLayout, CarouselLayout,
@ -11,7 +12,9 @@ import {
RoomAudioRenderer, RoomAudioRenderer,
useCreateLayoutContext, useCreateLayoutContext,
usePinnedTracks, usePinnedTracks,
useRoomInfo,
useTracks, useTracks,
useParticipants,
} from '@livekit/components-react'; } from '@livekit/components-react';
import { RoomEvent, Track } from 'livekit-client'; import { RoomEvent, Track } from 'livekit-client';
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
@ -20,6 +23,10 @@ import ChatRoom from '../ChatRoom/ChatRoom';
export default function LiveRoom() { export default function LiveRoom() {
const lastAutoFocusedScreenShareTrack = useRef(null); const lastAutoFocusedScreenShareTrack = useRef(null);
// get livekit identity
const room = useRoomInfo();
const participants = useParticipants();
const tracks = useTracks( const tracks = useTracks(
[ [
{ source: Track.Source.Camera, withPlaceholder: true }, { source: Track.Source.Camera, withPlaceholder: true },
@ -69,31 +76,40 @@ export default function LiveRoom() {
]); ]);
return ( return (
<div className="lk-video-conference"> <div className={styles.wrapper}>
<LayoutContextProvider value={layoutContext}> <header className={styles.header}>
<div className="lk-video-conference-inner"> <h1 className={styles.title}>{room.name}</h1>
{!focusTrack ? ( <div className={styles.roomInfo}>
<div className="lk-grid-layout-wrapper"> <span>참가자</span>
<GridLayout tracks={tracks}> <span>{participants.length}</span>
<ParticipantTile />
</GridLayout>
</div>
) : (
<div className="lk-focus-layout-wrapper">
<FocusLayoutContainer>
<CarouselLayout tracks={carouselTracks}>
<ParticipantTile />
</CarouselLayout>
{focusTrack && <FocusLayout trackRef={focusTrack} />}
</FocusLayoutContainer>
</div>
)}
<ControlBar controls={{ chat: false, leave: false }} />
</div> </div>
<ChatRoom /> </header>
</LayoutContextProvider> <div className="lk-video-conference">
<RoomAudioRenderer /> <LayoutContextProvider value={layoutContext}>
<ConnectionStateToast /> <div className="lk-video-conference-inner">
{!focusTrack ? (
<div className="lk-grid-layout-wrapper">
<GridLayout tracks={tracks}>
<ParticipantTile />
</GridLayout>
</div>
) : (
<div className="lk-focus-layout-wrapper">
<FocusLayoutContainer>
<CarouselLayout tracks={carouselTracks}>
<ParticipantTile />
</CarouselLayout>
{focusTrack && <FocusLayout trackRef={focusTrack} />}
</FocusLayoutContainer>
</div>
)}
<ControlBar controls={{ chat: false, leave: false }} />
</div>
<ChatRoom />
</LayoutContextProvider>
<RoomAudioRenderer />
<ConnectionStateToast />
</div>
</div> </div>
); );
} }

View File

@ -1,67 +1,32 @@
.main { .wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100vw;
height: 100vh;
} }
.videoWrapper { .header {
flex: 0 0 auto;
display: flex;
overflow-x: auto;
height: 80px;
gap: 10px;
padding: 10px;
border-bottom: 1px solid var(--border-color);
box-sizing: border-box;
& > audio {
display: none;
}
&::-webkit-scrollbar {
height: 6px;
}
&::-webkit-scrollbar-thumb {
background-color: var(--text-color-tertiary);
border-radius: 6px;
}
}
.mainContent {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
box-sizing: border-box;
& > video {
width: 100%;
height: calc(100vh - 208px);
object-fit: contain;
box-sizing: border-box;
}
}
.controlBar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
height: 80px; width: 100%;
border-top: 1px solid var(--border-color); height: 48px;
box-sizing: border-box; border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
& > button {
background-color: var(--background-color-secondary); .title {
color: var(--text-color-primary); padding: 0 16px;
border: none; font-size: 14px;
border-radius: 4px; line-height: 1.4;
padding: 8px 16px; font-weight: 500;
cursor: pointer; }
transition: background-color 0.2s;
.roomInfo {
&:hover { display: flex;
background-color: var(--background-color-tertiary); align-items: center;
} gap: 4px;
} padding: 0 16px;
font-size: 12px;
line-height: 1.4;
font-weight: 500;
} }

View File

@ -6,6 +6,7 @@ import instance from '../../utils/axios/instance';
import { API_URL, ROOM_URL } from '../../constants'; import { API_URL, ROOM_URL } from '../../constants';
import useBoundStore from '../../store'; import useBoundStore from '../../store';
import '@livekit/components-styles'; import '@livekit/components-styles';
import LoadingIndicator from '../../components/LoadingIndicator.jsx/LoadingIndicator';
export default function LivePage() { export default function LivePage() {
const { roomId } = useParams(); const { roomId } = useParams();
@ -26,16 +27,16 @@ export default function LivePage() {
} }
}, [generateToken, liveToken]); }, [generateToken, liveToken]);
return ( return liveToken ? (
liveToken && ( <LiveKitRoom
<LiveKitRoom token={liveToken}
token={liveToken} serverUrl={ROOM_URL}
serverUrl={ROOM_URL} connect={true}
connect={true} data-lk-theme="default"
data-lk-theme="default" >
> <LiveRoom />
<LiveRoom /> </LiveKitRoom>
</LiveKitRoom> ) : (
) <LoadingIndicator fill />
); );
} }

View File

@ -1,4 +1,6 @@
export const liveSlice = (set) => ({ export const liveSlice = (set) => ({
liveToken: null, liveToken: null,
setLiveToken: (liveToken) => set({ liveToken }), setLiveToken: (liveToken) => set({ liveToken }),
participants: 0,
setParticipants: (participants) => set({ participants }),
}); });