Skip to content

Commit a91e365

Browse files
authored
feat(composite): Custom Recording layouts (#1986)
Adds support for custom recording layouts. 🎫 Ticket: https://linear.app/stream/issue/REACT-638/
1 parent 53ce975 commit a91e365

File tree

6 files changed

+79
-32
lines changed

6 files changed

+79
-32
lines changed

sample-apps/react/egress-composite/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"dependencies": {
1414
"@emotion/css": "^11.13.5",
1515
"@sentry/react": "^10.19.0",
16+
"@skooldev/skool-stream-layout": "^1.0.9",
1617
"@stream-io/video-react-sdk": "workspace:^",
1718
"clsx": "^2.0.0",
1819
"js-base64": "^3.7.8",

sample-apps/react/egress-composite/src/ConfigurationContext.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ export type ConfigurationValue = {
135135
'layout.spotlight.participants_bar_limit'?: 'dynamic' | number; // ✅
136136

137137
custom_actions?: CustomActions;
138+
// used for customer-specific layouts that aren't yet available for
139+
// selection through our dashboard UI. In this case, customers can enable
140+
// them by specifying their identifier in call recording's advanced options.
141+
custom_layout_override?: Layout;
142+
custom_screen_share_layout_override?: ScreenshareLayout;
138143
};
139144
} & {
140145
setOptionsOverride: Dispatch<
@@ -201,6 +206,11 @@ export const applyConfigurationDefaults = (
201206
...rest
202207
} = configuration;
203208

209+
// apply overrides
210+
rest.layout = options.custom_layout_override ?? rest.layout;
211+
rest.screenshare_layout =
212+
options.custom_screen_share_layout_override ?? rest.screenshare_layout;
213+
204214
return {
205215
api_key,
206216
token,

sample-apps/react/egress-composite/src/components/layouts/index.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { ComponentType } from 'react';
2+
3+
import { DominantSpeaker, DominantSpeakerScreenShare } from './DominantSpeaker';
4+
import { PaginatedGrid } from './PaginatedGrid';
5+
import { Spotlight } from './Spotlight';
6+
7+
// NOTE: with the current setup of the app, using this layout breaks in DEV mode.
8+
// The reason for it seems to be yarn and how `workspace:^` versions are resolved.
9+
// This app and the skool layout package both depend on `@stream-io/video-react-sdk`
10+
// and this causes some resolution conflict internally.
11+
//
12+
// The production builds don't seem to be affected, and we have a workaround for dev.
13+
// The workaround is to modify the egress-composite/package.json with
14+
// `"@stream-io/video-react-sdk": "x.y.z"` (where x.y.z) is the previously released version
15+
// e.g.: current: 1.25.1 -> x.y.z should be 1.25.0
16+
import { SkoolStreamLayout } from '@skooldev/skool-stream-layout';
17+
18+
export const DEFAULT_LAYOUT: Layout = 'spotlight';
19+
export const DEFAULT_SCREENSHARE_LAYOUT: ScreenshareLayout = 'spotlight';
20+
21+
export type Layout =
22+
| 'grid'
23+
| 'single-participant'
24+
| 'spotlight'
25+
| 'mobile'
26+
| 'dominant-speaker'
27+
// custom layouts
28+
| 'skool';
29+
30+
// NOTE: should always be a subset of the Layout type
31+
export type ScreenshareLayout =
32+
| 'single-participant'
33+
| 'spotlight'
34+
| 'dominant-speaker'
35+
// custom layouts
36+
| 'skool';
37+
38+
const CustomSkoolStreamLayout = () => {
39+
return <SkoolStreamLayout excludeLocalParticipant />;
40+
};
41+
42+
export const layoutMap: Record<
43+
Layout,
44+
// normal & screen share view
45+
[ComponentType, ComponentType] | [ComponentType]
46+
> = {
47+
'single-participant': [DominantSpeaker, DominantSpeakerScreenShare],
48+
'dominant-speaker': [DominantSpeaker, DominantSpeakerScreenShare],
49+
mobile: [DominantSpeaker, DominantSpeakerScreenShare],
50+
grid: [PaginatedGrid],
51+
spotlight: [Spotlight, Spotlight],
52+
53+
// custom layouts
54+
skool: [CustomSkoolStreamLayout, CustomSkoolStreamLayout],
55+
};

sample-apps/react/egress-composite/src/main.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { CompositeApp } from './CompositeApp';
1010

1111
import '@stream-io/video-react-sdk/dist/css/styles.css';
12+
import '@skooldev/skool-stream-layout/dist/styles.css';
1213
// Uncomment this line to test your own custom CSS
1314
// import cssUrl from '../public/example/custom.css?url';
1415

yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7059,6 +7059,17 @@ __metadata:
70597059
languageName: node
70607060
linkType: hard
70617061

7062+
"@skooldev/skool-stream-layout@npm:^1.0.9":
7063+
version: 1.0.9
7064+
resolution: "@skooldev/skool-stream-layout@npm:1.0.9"
7065+
peerDependencies:
7066+
"@stream-io/video-react-sdk": ^1.25.0
7067+
react: ^17 || ^18 || ^19
7068+
react-dom: ^17 || ^18 || ^19
7069+
checksum: 10/0ff2dcc31481516021c1d5946a09771c64fe82218a8fc93f29fe20b30d52f91ca0eb5be4a4738d1c4971d7c7e9542646c9fa5ed0ebf8874fb5bb974524153d3a
7070+
languageName: node
7071+
linkType: hard
7072+
70627073
"@stream-io/audio-filters-web@workspace:^, @stream-io/audio-filters-web@workspace:packages/audio-filters-web":
70637074
version: 0.0.0-use.local
70647075
resolution: "@stream-io/audio-filters-web@workspace:packages/audio-filters-web"
@@ -7115,6 +7126,7 @@ __metadata:
71157126
"@playwright/test": "npm:^1.56.0"
71167127
"@sentry/react": "npm:^10.19.0"
71177128
"@sentry/vite-plugin": "npm:^4.3.0"
7129+
"@skooldev/skool-stream-layout": "npm:^1.0.9"
71187130
"@stream-io/video-react-sdk": "workspace:^"
71197131
"@types/react": "npm:~19.1.17"
71207132
"@types/react-dom": "npm:~19.1.11"

0 commit comments

Comments
 (0)