Classroom and Proctor SDK
Updated
Easily update the look and feel of your classrooms.
This page explains the way UI components work in Classroom and Proctor SDK.
Introduction to UI components
The cloud classroom scene is included in FcrUIScene. If you need to integrate the cloud classroom scene UI, please refer to FcrUIScene SDK.
The UI components in Flexible Classroom can be divided into three types: function components, business components, and scenario components.
Function components
Function components are the most basic UI components in Flexible Classroom and are not bound to any business logic. A function component maintains the internal state and logic of a function, such as Button, Modal, Select, or Tree.
The Agora Classroom Education Scenario functional components are located in packages/agora-classroom-sdk/src/ui-kit, and the Agora Classroom Proctor Scenario components are in the packages/agora-proctor-sdk/src/ui-kit folder. The technologies used are react, ts, and storybook. Each functional component folder contains the following files:
.tsx: Implements the functionality of the component..css: Implements the style of the component..stories.tsx: Enables previewing and debugging the component in Storybook. Developers can run the project through theyarn dev:ui-kit:classroomornpm run dev:ui-kit:classroomcommand and preview the function components in Storybook.
The following table lists the function components used in Flexible Classroom:
| Folder | Function components |
|---|---|
/button | The button component. |
/card | The card component. |
/checkbox | The checkbox component. |
/input | The input box. |
/layout | The layout component helps with the overall layout of a web page. |
/loading | The loading component provides the state of joining a classroom or uploading a file. |
/modal | The modal dialog box is used for user interaction that does not interrupt the current operation. |
/pagination | The pagination component is used for displaying long lists. It loads only one page of the data. |
/placeholder | The placeholder for videos or files. |
/popover | The pop-up box is used to display more content when the mouse clicks or moves in. |
/radio | The radio buttons allow users to select one option from a set. |
/root-box | The root container wraps page elements. |
/roster | The roster is used to display the student list and allows teachers to invite students to address the class, send rewards to students, or kick students out of the classroom. |
/select | The drop-down menu. |
/sound-player | The component for playing audio files. |
/svg-img | SVG images. |
/table | The table displays rows of data. |
/tabs | The component for switching tabs. |
/toast | The component for global prompts. |
/toolbar | The toolbar displays the teaching tools of teachers and students. |
/tooltip | The pop-up box for simple text tips. |
/tree | The tree component is used to show tree-structured data. |
/volume | The component for displaying the volume. |
Business components
Business components are the UI components bound to business logic in Flexible Classroom. Most of the business components are composed of multiple function components. Depending on the observable objects and functions from the UI Store, the UI of business components can be automatically changed as the data updates. Taking the hand-raising feature as an example, this business component provides a button for users to raise their hands and ask for permission to speak, and then displays the list of users who have raised their hands.
You can find the business components in packages/agora-classroom-sdk/src/ui-kit/capabilities/containers.
The business components for the Agora Classroom Education Scenario are located in packages/agora-classroom-sdk/src/infra/capabilities/containers, and the business components for Agora Classroom Proctor Scenario are in packages/agora-proctor-sdk/src/infra/capabilities/containers
The following table lists the business components used in Flexible Classroom:
Education Scene
| Folder | Business components |
|---|---|
/aside | The video and chat box containers on the right side of a large and small classroom. |
/award | The reward component that implements the logic of teachers issuing rewards to students. When students receive rewards, they are displayed in the video box. |
/cloud-driver | The cloud drive component implements businesses such as uploading or deleting files. |
/device-setting | The component for device settings, such as displaying the list of cameras, microphones, and speakers. |
/dialog | Pop-up windows during the class. |
/hand-up | The component for the hand-raising feature. |
/loading | The loading component. |
/nav | The navigation component for businesses such as displaying the network status and class status. |
/pretest | The component for the device test before joining the classroom. Includes functions such as obtaining device list information and switching devices. |
/root-box | The root container. Used to maintain the 16 aspect ratio of the class, with areas outside the ratio showing a black background. |
/roster | The roster component implements businesses such as checking the student information, processing requests for going onto the stage, and issuing rewards. |
/scene-switch | The component for switching between scenes. |
/scenes-controller | The component for controlling whiteboard scenes, such as adding or deleting whiteboard pages. |
/screen-share | The component for the screen sharing feature. Responsible for rendering the shared screen and the screen sharing control bar. |
/stream | The component for rendering audio and video streams. Handles audio and video rendering of each class, a small class carousel component. |
/stream-window | The draggable window container component. Handles the dragging and arrangement logic of the video window. |
/toast | Toast prompt component. |
/toolbar | The toolbar for the teaching tools of the teachers and students. |
/widget | The Widget container component that is responsible for handling logic such as rendering and movement trajectory synchronization of custom Widgets. |
/camera-preview | The local video screen displayed in the lower right corner when the video wall function is turned on. |
Proctor Scene
| Folder | Business components |
|---|---|
/dialog | Pop-up windows during the class. |
/pretest | The component for the device test before joining the classroom. Includes functions such as obtaining device list information and switching devices. |
/root-box | The root container. |
/stream | The component for rendering audio and video streams. |
/toast | Toast prompt component. |
/widget | The Widget component handles logic such as widget rendering and loading. |
Scenario components
A scenario components is composed of multiple business components. Flexible classroom supports preset scenarios. Scenario components are located in packages/agora-classroom-sdk/src/infra/capabilities/scenarios for the Agora Classroom Education Scenario and in packages/agora-proctor-sdk/src/infra/capabilities/scenarios for the Agora Classroom Proctor Scenario. If you want to change the layout of a certain scene, just find the corresponding scene component and modify it.
Education Scene
| Folder | Scenario components |
|---|---|
/1v1 | One-to-one interactive teaching scene |
/big-class | Interactive live broadcast of large class scene |
/big-class-mobile | Interactive live broadcast, large class scene for web and mobile terminals |
/mid-class | Online interactive small class scene |
Proctor Scene
| Folder | Scenario components |
|---|---|
proctor | Proctor teacher scene |
/examinee | Invigilation student scene |
Relationship between the three types of UI components
The following figure illustrates the relationship between the three types of UI components:
Custom functional components
Add a functional component
To add a new functional component and use it in Flexible Classroom, follow these steps:
- Create a folder in the
packages/agora-classroom-sdk/src/ui-kit/componentsdirectory for the new functional component that you want to add. This folder should contain the following three files:index.tsx: Implements the functionality of the UI component.index.css: Implements the style of the UI component.index.stories.tsx: Enables previewing and debugging the UI component in Storybook.
- After adding the functional component, export this component in
packages/agora-classroom-sdk/src/ui-kit/components/index.ts:
Then you can import this component into your project.
The following example shows how to add a functional component agora-demo:
-
Create a new folder
packages/agora-classroom-sdk/src/ui-kit/componentsunder the directory, containing the corresponding files.agora-demo,index.tsx,index.css, andindex.stories.tsx:// index.css .agora-demo { color: red } // index.tsx import React from 'react' import './index.css' export const AgoraDemo = () => { return ( <div className="agora-demo">AgoraDemo</div> ) } // index.stories.tsx import React from 'react'; import { Meta } from '@storybook/react'; import { AgoraDemo } from './index'; const meta: Meta = { title: 'Components/AgoraDemo', component: AgoraDemo, }; export default meta; export const Docs = () => ( <AgoraDemo /> ) -
Add
export * from './agora-demo';topackages/agora-classroom-sdk/src/ui-kit/components/index.ts. You can see this function component in Storybook, as follows:
Edit an existing functional component
If you want to modify the function and style of an existing functional component, just find component folder and edit the code to suit your needs. The following examples are provided for your reference.
Change the placeholder color of the input component
To change the color of the placeholder text in the input component, edit the packages/agora-classroom-sdk/src/ui-kit/components/input/index.css file as follows:
Before
.fcr-input-wrapper input::-webkit-input-placeholder {
color: #999;
}After
.fcr-input-wrapper input::-webkit-input-placeholder {
color: #ff6600;
}Customize business components
Add a business component
To add a new business component and use it in Flexible Classroom, create a folder in packages/agora-classroom-sdk/src/infra/capabilities/containers. The folder should contain the following files:
index.tsx: Combines functional components and implements the business logic.index.css: Implements the style of the business component.
After adding the business component, you can directly import this business component and run the project to see how it looks in Flexible Classroom.
The following example shows how to add a business component that displays the class and network status:
// index.css
.agora-demo {
width: 50%;
height: 50%;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
border: 1px solid black;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 99999999;
}
.agora-demo-title {
color: red;
}
// index.tsx
import React from 'react';
import { observer } from 'mobx-react';
import { useStore } from '@classroom/infra/hooks/ui-store';
import './index.css';
export default observer(function AgoraDemo() {
const { navigationBarUIStore } = useStore();
const { classStatusText, networkQualityLabel, delay, packetLoss } = navigationBarUIStore;
return (
<div className="agora-demo">
<h1 className="agora-demo-title">This is our new business component.</h1>
<h2>This component is used to display the network status and class status.</h2>
<div>
Network Status: {networkQualityLabel} Network Delay: {delay} Packet Loss Rate: {packetLoss}
</div>
<div>Class Status: {classStatusText}</div>
</div>
);
});
// packages/agora-classroom-sdk/src/infra/capabilities/scenarios/mid-class/index.tsx
// Introduce this component in the small class scene
import classnames from 'classnames';
import { Layout } from '@classroom/ui-kit/components/layout';
import { DialogContainer } from '@classroom/infra/capabilities/containers/dialog';
import { HandsUpContainer } from '@classroom/infra/capabilities/containers/hand-up';
import { LoadingContainer } from '@classroom/infra/capabilities/containers/loading';
import { NavigationBar } from '@classroom/infra/capabilities/containers/nav';
import { FixedAspectRatioRootBox } from '@classroom/infra/capabilities/containers/root-box';
import { SceneSwitch } from '@classroom/infra/capabilities/containers/scene-switch';
import { RoomMidStreamsContainer } from '@classroom/infra/capabilities/containers/stream/room-mid-player';
import { ToastContainer } from '@classroom/infra/capabilities/containers/toast';
import { Award } from '@classroom/infra/capabilities/containers/award';
import Room from '../room';
import { useStore } from '@classroom/infra/hooks/ui-store';
import { Float } from '@classroom/ui-kit';
import { RemoteControlContainer } from '@classroom/infra/capabilities/containers/remote-control';
import { ScenesController } from '@classroom/infra/capabilities/containers/scenes-controller';
import { ScreenShareContainer } from '@classroom/infra/capabilities/containers/screen-share';
import { WhiteboardToolbar } from '@classroom/infra/capabilities/containers/toolbar';
import { WidgetContainer } from '@classroom/infra/capabilities/containers/widget';
import { Chat, Watermark, Whiteboard } from '@classroom/infra/capabilities/containers/widget/slots';
import { StreamWindowsContainer } from '@classroom/infra/capabilities/containers/stream-windows-container';
import { RemoteControlToolbar } from '@classroom/infra/capabilities/containers/remote-control/toolbar';
import AgoraDemo from '@classroom/infra/capabilities/containers/agora-demo';
export const MidClassScenario = () => {
// Scene layout
const layoutCls = classnames('edu-room', 'mid-class-room');
const { shareUIStore } = useStore();
return (
<Room>
{/* Here is the new business component */}
<AgoraDemo />
<FixedAspectRatioRootBox trackMargin={{ top: shareUIStore.navHeight }}>
<SceneSwitch>
<Layout className={layoutCls} direction="col">
<NavigationBar />
<Layout
className="flex-grow items-stretch relative justify-center fcr-room-bg"
direction="col">
<RoomMidStreamsContainer />
<Whiteboard />
<ScreenShareContainer />
<RemoteControlContainer />
<StreamWindowsContainer />
</Layout>
<RemoteControlToolbar />
<WhiteboardToolbar />
<ScenesController />
<Float bottom={15} right={10} align="flex-end" gap={2}>
<HandsUpContainer />
<Chat />
</Float>
<DialogContainer />
<LoadingContainer />
</Layout>
<WidgetContainer />
<ToastContainer />
<Award />
<Watermark />
</SceneSwitch>
</FixedAspectRatioRootBox>
</Room>
);
};The effect of this business component in Flexible Classroom is as follows:
Edit an existing business component
If you want to change the function and style of an existing business component, just find the component folder and edit the code to suit your needs. The following examples are provided for your reference.
Display the number of cameras that are available in the device settings pop-up window
Open the file packages/agora-classroom-sdk/src/infra/capabilities/containers/pretest/pretest-video.tsx and modify it as follows:
const VideoDeviceList = observer(() => {
const {
pretestUIStore: { setCameraDevice, currentCameraDeviceId, cameraDevicesList },
} = useStore();
const t = useI18n();
return (
<VideoDeviceListPanel>
<div className="-mt-10">{`${t('device.camera')} Number of devices: ${
cameraDevicesList.length - 1
}`}</div>
<Field
label=""
type="select"
value={currentCameraDeviceId}
options={cameraDevicesList.map((value) => ({
text: value.label,
value: value.value,
}))}
onChange={(value) => {
setCameraDevice(value);
}}
/>
</VideoDeviceListPanel>
);Before
After
Change the scenario layout
To change the layout of a scenario, just edit the code of the scenario component.
Move the position of the video and chat area
The following example demonstrates how to move the position of the video and chat areas from the right side of the screen to the left. This is a cross-component adjustment. Therefore, you need to edit the parent container of these two components, which is the one-to-one interactive teaching scene container in packages/agora-classroom-sdk/src/infra/capabilities/scenarios/1v1/index.tsx.
Before
import { useStore } from '@classroom/infra/hooks/ui-store';
import classnames from 'classnames';
import { Layout } from '@classroom/ui-kit/components/layout';
import { DialogContainer } from '@classroom/infra/capabilities/containers/dialog';
import { LoadingContainer } from '@classroom/infra/capabilities/containers/loading';
import { NavigationBar } from '@classroom/infra/capabilities/containers/nav';
import { FixedAspectRatioRootBox } from '@classroom/infra/capabilities/containers/root-box/fixed-aspect-ratio';
import { Room1v1StreamsContainer } from '@classroom/infra/capabilities/containers/stream/room-1v1-player';
import { ToastContainer } from '@classroom/infra/capabilities/containers/toast';
import { RemoteControlContainer } from '../../containers/remote-control';
import { SceneSwitch } from '../../containers/scene-switch';
import { ScenesController } from '../../containers/scenes-controller';
import { ScreenShareContainer } from '../../containers/screen-share';
import { StreamWindowsContainer } from '../../containers/stream-window';
import { WhiteboardToolbar } from '../../containers/toolbar';
import { WidgetContainer } from '../../containers/widget';
import { Chat, Watermark, Whiteboard } from '../../containers/widget/slots';
import { OneToOneClassAside as Aside } from '@classroom/infra/capabilities/containers/aside';
import Room from '../room';
import { RemoteControlToolbar } from '../../containers/remote-control/toolbar';
const layoutCls = classnames('edu-room', 'one-on-one-class-room');
const { shareUIStore } = useStore();
return (
<Room>
<FixedAspectRatioRootBox trackMargin={{ top: shareUIStore.navHeight }}>
<SceneSwitch>
<Layout className={layoutCls} direction="col">
<NavigationBar />
<Layout className="flex-grow items-stretch fcr-room-bg h-full">
<Layout
className="flex-grow items-stretch relative"
direction="col"
style={{ paddingTop: 2 }}>
<Whiteboard />
<ScreenShareContainer />
<WhiteboardToolbar />
<ScenesController />
<RemoteControlContainer />
<StreamWindowsContainer />
<RemoteControlToolbar />
</Layout>
<Aside>
<Room1v1StreamsContainer />
<Chat />
</Aside>
</Layout>
<DialogContainer />
<LoadingContainer />
</Layout>
<WidgetContainer />
<ToastContainer />
<Watermark />
</SceneSwitch>
</FixedAspectRatioRootBox>
</Room>
);
};After
import { useStore } from '@classroom/infra/hooks/ui-store';
import classnames from 'classnames';
import { Layout } from '@classroom/ui-kit/components/layout';
import { DialogContainer } from '@classroom/infra/capabilities/containers/dialog';
import { LoadingContainer } from '@classroom/infra/capabilities/containers/loading';
import { NavigationBar } from '@classroom/infra/capabilities/containers/nav';
import { FixedAspectRatioRootBox } from '@classroom/infra/capabilities/containers/root-box/fixed-aspect-ratio';
import { Room1v1StreamsContainer } from '@classroom/infra/capabilities/containers/stream/room-1v1-player';
import { ToastContainer } from '@classroom/infra/capabilities/containers/toast';
import { RemoteControlContainer } from '../../containers/remote-control';
import { SceneSwitch } from '../../containers/scene-switch';
import { ScenesController } from '../../containers/scenes-controller';
import { ScreenShareContainer } from '../../containers/screen-share';
import { StreamWindowsContainer } from '../../containers/stream-window';
import { WhiteboardToolbar } from '../../containers/toolbar';
import { WidgetContainer } from '../../containers/widget';
import { Chat, Watermark, Whiteboard } from '../../containers/widget/slots';
import { OneToOneClassAside as Aside } from '@classroom/infra/capabilities/containers/aside';
import Room from '../room';
import { RemoteControlToolbar } from '../../containers/remote-control/toolbar';
const layoutCls = classnames('edu-room', 'one-on-one-class-room');
const { shareUIStore } = useStore();
return (
<Room>
<FixedAspectRatioRootBox trackMargin={{ top: shareUIStore.navHeight }}>
<SceneSwitch>
<Layout className={layoutCls} direction="col">
<NavigationBar />
<Layout className="flex-grow items-stretch fcr-room-bg h-full">
/** 调整 Layout 中 Content 与 Aside 的顺序。*/
<Aside>
<Room1v1StreamsContainer />
<Chat />
</Aside>
<Layout
className="flex-grow items-stretch relative"
direction="col"
style={{ paddingTop: 2 }}>
<Whiteboard />
<ScreenShareContainer />
<WhiteboardToolbar />
<ScenesController />
<RemoteControlContainer />
<StreamWindowsContainer />
<RemoteControlToolbar />
</Layout>
</Layout>
<DialogContainer />
<LoadingContainer />
</Layout>
<WidgetContainer />
<ToastContainer />
<Watermark />
</SceneSwitch>
</FixedAspectRatioRootBox>
</Room>
);
};Add a logo
If you want to add a logo to the right <Aside>, you need to implement the Logo component first, and then make the following changes in the packages/agora-classroom-sdk/src/infra/capabilities/scenarios/1v1/index.tsx file:
...
<Aside>
<Logo/>
<Room1v1StreamsContainer />
<ChatWidgetPC />
</Aside>
...Change the UI stores
A business component is composed of multiple functional components and depends on UI stores. This section introduces how to edit the UI stores.
UI stores are located in packages/agora-classroom-sdk/src/infra/stores:
| Folder | Description |
|---|---|
/common | The common UI store for all scenarios |
/interactive | The UI store for the Small Classroom scenario |
/lecture | The UI store for the Lecture Hall scenario |
/lecture-h5 | The UI store for the Lecture Hall scenario in H5 |
/one-on-one | The UI store for the One-to-one Classroom scenario |
EduClassroomUIStore in /common is the base class. You can extend this class and rewrite the UI stores for a specific scenario.
The following example shows how to customize the UI store for the Lecture Hall scenario:
import { EduClassroomStore } from 'agora-edu-core';
import { EduClassroomUIStore } from '../common';
import { LectureBoardUIStore } from './board';
import { LectureRosterUIStore } from './roster';
import { LectureRoomStreamUIStore } from './stream';
import { LectrueToolbarUIStore } from './toolbar';
export class EduLectureUIStore extends EduClassroomUIStore {
constructor(store: EduClassroomStore) {
super(store);
// Rewrite Stream UI Store
this._streamUIStore = new LectureRoomStreamUIStore(store, this.shareUIStore);
// Rewrite Roster UI Store
this._rosterUIStore = new LectureRosterUIStore(store, this.shareUIStore);
// Rewrite Board UI Store
this._boardUIStore = new LectureBoardUIStore(store, this.shareUIStore);
// Rewrite Toolbar UI Store
this._toolbarUIStore = new LectrueToolbarUIStore(store, this.shareUIStore);
}
get streamUIStore() {
return this._streamUIStore as LectureRoomStreamUIStore;
}
get rosterUIStore() {
return this._rosterUIStore as LectureRosterUIStore;
}
}Change the teaching tools of the student after the teacher gives permission
If you want to change the teaching tools of the student after the teacher gives the student permission in all scenarios, edit toolbar/index.ts in /common. If you want to apply the above change to only one scenario, create a toolbar.ts file in the folder of this scenario and rewrite the relevant methods.
Taking One-to-one Classroom as an example, edit packages/agora-classroom-sdk/src/infra/stores/one-on-one/toolbar.ts, as follows:
// packages/agora-classroom-sdk/src/infra/stores/one-on-one/toolbar.ts
...
// Extend the base class ToolbarUIStore
export class OneToOneToolbarUIStore extends ToolbarUIStore {
readonly allowedCabinetItems: string[] = [
CabinetItemEnum.Whiteboard,
CabinetItemEnum.ScreenShare,
CabinetItemEnum.Laser,
];
@computed
get teacherTools(): ToolbarItem[] {
let _tools: ToolbarItem[] = [];
if (this.boardApi.mounted && !this.classroomStore.remoteControlStore.isHost) {
_tools = [
ToolbarItem.fromData({
value: 'clicker',
label: 'scaffold.clicker',
icon: 'select',
category: ToolbarItemCategory.Clicker,
}),
ToolbarItem.fromData({
// Set the icon for the selector
value: 'selection',
label: 'scaffold.selector',
icon: 'clicker',
category: ToolbarItemCategory.Selector,
}),
ToolbarItem.fromData({
value: 'pen',
label: 'scaffold.pencil',
icon: 'pen',
category: ToolbarItemCategory.PenPicker,
}),
ToolbarItem.fromData({
value: 'text',
label: 'scaffold.text',
icon: 'text',
category: ToolbarItemCategory.Text,
}),
ToolbarItem.fromData({
value: 'eraser',
label: 'scaffold.eraser',
icon: 'eraser',
category: ToolbarItemCategory.Eraser,
}),
ToolbarItem.fromData({
value: 'hand',
label: 'scaffold.move',
icon: 'hand',
category: ToolbarItemCategory.Hand,
}),
ToolbarItem.fromData({
value: 'save',
label: 'scaffold.save',
icon: 'save-ghost',
category: ToolbarItemCategory.Save,
}),
{
value: 'cloud',
label: 'scaffold.cloud_storage',
icon: 'cloud',
category: ToolbarItemCategory.CloudStorage,
},
{
value: 'tools',
label: 'scaffold.tools',
icon: 'tools',
category: ToolbarItemCategory.Cabinet,
},
];
if (AgoraRteEngineConfig.platform === AgoraRteRuntimePlatform.Electron) {
_tools.splice(
5,
0,
ToolbarItem.fromData({
value: 'slice',
label: 'scaffold.slice',
icon: 'slice',
category: ToolbarItemCategory.Slice,
}),
);
}
} else {
_tools = [
{
value: 'tools',
label: 'scaffold.tools',
icon: 'tools',
category: ToolbarItemCategory.Cabinet,
},
];
}
return _tools;
}
@computed
get studentTools(): ToolbarItem[] {
const { sessionInfo } = EduClassroomConfig.shared;
const whiteboardAuthorized = this.boardApi.grantedUsers.has(sessionInfo.userUuid);
if (!whiteboardAuthorized || this.classroomStore.remoteControlStore.isHost) {
return [];
}
return [
ToolbarItem.fromData({
value: 'clicker',
label: 'scaffold.clicker',
icon: 'select',
category: ToolbarItemCategory.Selector,
}),
ToolbarItem.fromData({
// Set the icon for the selector
value: 'selection',
label: 'scaffold.selector',
icon: 'clicker',
category: ToolbarItemCategory.Clicker,
}),
ToolbarItem.fromData({
value: 'pen',
label: 'scaffold.pencil',
icon: 'pen',
category: ToolbarItemCategory.PenPicker,
}),
ToolbarItem.fromData({
value: 'text',
label: 'scaffold.text',
icon: 'text',
category: ToolbarItemCategory.Text,
}),
ToolbarItem.fromData({
value: 'eraser',
label: 'scaffold.eraser',
icon: 'eraser',
category: ToolbarItemCategory.Eraser,
}),
];
}
}The above settings can override the teaching tools in /common. The final effect is as follows:
Additional examples
Change the background color of the classroom
To change the background color of the classroom, edit packages/agora-classroom-sdk/src/infra/capabilities/containers/root-box/fixed-aspect-ratio.tsx.
const FixedAspectRatioContainer: React.FC<FixedAspectRatioProps> = observer(
({children, minimumWidth = 0, minimumHeight = 0}) => {
const style = useClassroomStyle({minimumHeight, minimumWidth});
const {shareUIStore} = useStore();
return (
<div
// You can use the tailwind class name
className="flex bg-black justify-center items-center h-screen w-screen"
// You can also set CSS properties
style={{backgroundColor: "red"}}>
<div style={style} className={`w-full h-full relative ${shareUIStore.classroomViewportClassName}`}>
{children}
</div>
</div>
);
},
);Change the background color of the whiteboard
To change the background color of the whiteboard, edit packages/agora-plugin-gallery/src/gallery/whiteboard/style.css.
.netless-whiteboard-wrapper {
height: 100%;
width: 100%;
border: 1px solid;
border-radius: 4px;
@apply bg-foreground border-divider;
background: #000; /* Here we set the background color as black */
}Adjust the whiteboard size
To adjust the whiteboard layout, edit packages/agora-classroom-sdk/src/infra/stores/common/board/index.ts. Flexible Classroom will first calculate the width and height of the overall classroom area according to packages/agora-classroom-sdk/src/infra/stores/common/share/index.ts, then calculate the height of the whiteboard container, and finally dynamically set the size of the whiteboard according to the ratio of the whiteboard to the whiteboard container.viewportAspectRatio heightRatio
// packages/agora-classroom-sdk/src/infra/stores/common/share/index.ts
...
// Set Classroom Size
updateClassroomViewportSize() {
...
// Get the current window width and height
const { width, height } = getRootDimensions(this._containerNode);
const aspectRatio = this._viewportAspectRatio;
const curAspectRatio = height / width;
const scopeSize = { height, width };
// Ensure classroom maintains a fixed aspect ratio
if (curAspectRatio > aspectRatio) {
// shrink height
scopeSize.height = width * aspectRatio;
} else if (curAspectRatio < aspectRatio) {
// shrink width
scopeSize.width = height / aspectRatio;
}
...
}
...
// packages/agora-classroom-sdk/src/infra/stores/common/board/index.ts
// Set Whiteboard Scale
...
protected get uiOverrides() {
return {
...super.uiOverrides,
heightRatio: 1
};
}
/**
* Whiteboard container height
* @returns
*/
@computed
get boardAreaHeight() {
// Set the height of the interactive area of the whiteboard (Total minus the height of the navigation bar)
const viewportHeight =
this.shareUIStore.classroomViewportSize.height - this.shareUIStore.navHeight;
// Set Whiteboard Scale
const heightRatio = this.getters.stageVisible ? this.uiOverrides.heightRatio : 1;
// Set whiteboard height
const height = heightRatio * viewportHeight;
return height;
}
...The above changes are applied to all scenarios. If you only want to change the height of the whiteboard in a the One-to-one Classroom scenario, create a board.ts file in packages/agora-classroom-sdk/src/infra/stores/one-on-one with the following code:
// packages/agora-classroom-sdk/src/infra/stores/one-on-one/board.ts
import {BoardUIStore} from "../common/board-ui";
export class OneToOneBoardUIStore extends BoardUIStore {
protected get uiOverrides() {
return {
...super.uiOverrides,
heightRatio: 1,
};
}
}