{!focusTrack ? (
-
-
+
) : (
@@ -100,9 +93,8 @@ export function VideoConference({ chatMessageFormatter, ...props }: VideoConfere
)}
-
+
-
)}
diff --git a/src/components/VideoConference/VideoConference/VideoConference.types.ts b/src/components/VideoConference/VideoConference/VideoConference.types.ts
index 4c7552f..9e54dd2 100644
--- a/src/components/VideoConference/VideoConference/VideoConference.types.ts
+++ b/src/components/VideoConference/VideoConference/VideoConference.types.ts
@@ -1,8 +1,4 @@
-import { MessageFormatter } from '@livekit/components-react'
-
/**
* @public
*/
-export interface VideoConferenceProps extends React.HTMLAttributes
{
- chatMessageFormatter?: MessageFormatter
-}
+export type VideoConferenceProps = React.HTMLAttributes
diff --git a/src/components/VideoConference/index.ts b/src/components/VideoConference/index.ts
index 1f7b281..09a1a06 100644
--- a/src/components/VideoConference/index.ts
+++ b/src/components/VideoConference/index.ts
@@ -1,3 +1,3 @@
-export { default as Chat } from './Chat'
+export { default as Chat } from './RightPanel/Chat'
export { default as ParticipantTile } from './ParticipantTile'
export { VideoConference } from './VideoConference'
diff --git a/src/hooks/useLayoutContext.ts b/src/hooks/useLayoutContext.ts
new file mode 100644
index 0000000..e85556d
--- /dev/null
+++ b/src/hooks/useLayoutContext.ts
@@ -0,0 +1,127 @@
+import React, { useContext, useReducer } from 'react'
+import { WIDGET_DEFAULT_STATE, PIN_DEFAULT_STATE } from '@livekit/components-core'
+import { LayoutContext } from '@livekit/components-react'
+import type { WidgetState as LivekitWidgetState, PinState, TrackReference } from '@livekit/components-core'
+
+export type PinAction =
+ | {
+ msg: 'set_pin'
+ trackReference: TrackReference
+ }
+ | { msg: 'clear_pin' }
+
+export type PinContextType = {
+ dispatch?: React.Dispatch
+ state?: PinState
+}
+
+export function pinReducer(state: PinState, action: PinAction): PinState {
+ if (action.msg === 'set_pin') {
+ return [action.trackReference]
+ } else if (action.msg === 'clear_pin') {
+ return []
+ } else {
+ return { ...state }
+ }
+}
+
+export type WidgetState = LivekitWidgetState & {
+ showPeoplePanel: boolean
+}
+
+const widgetDefaultState: WidgetState = {
+ ...WIDGET_DEFAULT_STATE,
+ showPeoplePanel: false
+}
+
+type WidgetContextAction =
+ | { msg: 'show_chat' }
+ | { msg: 'hide_chat' }
+ | { msg: 'toggle_chat' }
+ | { msg: 'unread_msg'; count: number }
+ | { msg: 'show_people_panel' }
+ | { msg: 'hide_people_panel' }
+ | { msg: 'toggle_people_panel' }
+
+export type WidgetContextType = {
+ dispatch?: React.Dispatch
+ state?: WidgetState
+}
+
+function widgetReducer(state: WidgetState, action: WidgetContextAction): WidgetState {
+ switch (action.msg) {
+ case 'show_chat': {
+ return { ...state, showChat: true, unreadMessages: 0 }
+ }
+ case 'hide_chat': {
+ return { ...state, showChat: false }
+ }
+ case 'toggle_chat': {
+ const newState = { ...state, showChat: !state.showChat }
+ if (newState.showChat === true) {
+ newState.unreadMessages = 0
+ newState.showPeoplePanel = false
+ }
+ return newState
+ }
+ case 'unread_msg': {
+ return { ...state, unreadMessages: action.count }
+ }
+ case 'show_people_panel': {
+ return { ...state, showPeoplePanel: true }
+ }
+ case 'hide_people_panel': {
+ return { ...state, showPeoplePanel: false }
+ }
+ case 'toggle_people_panel': {
+ const newState = { ...state, showPeoplePanel: !state.showPeoplePanel }
+ if (newState.showPeoplePanel === true) {
+ newState.showChat = false
+ }
+ return newState
+ }
+ default: {
+ return { ...state }
+ }
+ }
+}
+
+export type LayoutContextType = {
+ pin: PinContextType
+ widget: WidgetContextType
+}
+
+/**
+ * @public
+ */
+export function useCreateLayoutContext(): LayoutContextType {
+ const [pinState, pinDispatch] = useReducer(pinReducer, PIN_DEFAULT_STATE)
+ const [widgetState, widgetDispatch] = useReducer(widgetReducer, widgetDefaultState)
+ return {
+ pin: { dispatch: pinDispatch, state: pinState },
+ widget: { dispatch: widgetDispatch, state: widgetState }
+ }
+}
+
+export function useEnsureCreateLayoutContext(layoutContext?: LayoutContextType): LayoutContextType {
+ const [pinState, pinDispatch] = useReducer(pinReducer, PIN_DEFAULT_STATE)
+ const [widgetState, widgetDispatch] = useReducer(widgetReducer, widgetDefaultState)
+ return (
+ layoutContext ?? {
+ pin: { dispatch: pinDispatch, state: pinState },
+ widget: { dispatch: widgetDispatch, state: widgetState }
+ }
+ )
+}
+
+/**
+ * @public
+ */
+export function useLayoutContext(): LayoutContextType {
+ const layoutContext = useContext(LayoutContext)
+ if (!layoutContext) {
+ throw Error('Tried to access LayoutContext context outside a LayoutContextProvider provider.')
+ }
+
+ return layoutContext as LayoutContextType
+}
diff --git a/src/modules/translation/locales/en.json b/src/modules/translation/locales/en.json
index f8e3c4f..c5a7340 100644
--- a/src/modules/translation/locales/en.json
+++ b/src/modules/translation/locales/en.json
@@ -6,5 +6,9 @@
"cta": "Connect",
"input_label": "World name",
"input_placeholder": "example:.dcl.eth"
+ },
+ "people_panel": {
+ "title": "People",
+ "subtitle": "People in this meeting"
}
}
diff --git a/src/modules/translation/locales/es.json b/src/modules/translation/locales/es.json
index 1e745bd..ed58a53 100644
--- a/src/modules/translation/locales/es.json
+++ b/src/modules/translation/locales/es.json
@@ -6,5 +6,9 @@
"cta": "Conectar",
"input_label": "Nombre del mundo",
"input_placeholder": "ejemplo:.dcl.eth"
+ },
+ "people_panel": {
+ "title": "Personas",
+ "subtitle": "Personas en esta reunión"
}
}
diff --git a/src/modules/translation/locales/zh.json b/src/modules/translation/locales/zh.json
index cbb0329..e6520b5 100644
--- a/src/modules/translation/locales/zh.json
+++ b/src/modules/translation/locales/zh.json
@@ -6,5 +6,9 @@
"cta": "连接",
"input_label": "世界名称",
"input_placeholder": "example:.dcl.eth"
+ },
+ "people_panel": {
+ "title": "人们",
+ "subtitle": "这次会议的人"
}
}