@tavus/cvi-ui 0.0.1-beta.2 → 0.0.1-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -33
- package/dev-components/components/README.md +62 -1
- package/dev-components/components/audio-wave/audio-wave.module.css +33 -0
- package/dev-components/components/audio-wave/index.tsx +55 -0
- package/dev-components/components/controls/controls.module.css +75 -73
- package/dev-components/components/controls/index.tsx +2 -2
- package/dev-components/components/conversation-01/conversation.module.css +222 -0
- package/dev-components/components/conversation-01/index.tsx +180 -0
- package/dev-components/components/{hair-check → hair-check-01}/hair-check.module.css +2 -1
- package/dev-components/components/{hair-check → hair-check-01}/index.tsx +1 -1
- package/dist/index.js +412 -104
- package/dist/types/templates/components.d.ts +32 -2
- package/dist/types/templates/jsx/index.d.ts +11 -1
- package/dist/types/templates/tsx/index.d.ts +11 -1
- package/dist/types/utils/version-utils.d.ts +3 -0
- package/package.json +6 -4
- package/src/templates/components.ts +18 -0
- package/src/templates/index.ts +2 -0
- package/src/templates/jsx/components/audio-wave.json +5 -0
- package/src/templates/jsx/components/controls.json +10 -0
- package/src/templates/jsx/components/conversation-01.json +11 -0
- package/src/templates/jsx/components/cvi-provider.json +5 -0
- package/src/templates/jsx/components/hair-check-01.json +10 -0
- package/src/templates/jsx/hooks/cvi-events-hooks.json +5 -0
- package/src/templates/jsx/hooks/use-cvi-call.json +5 -0
- package/src/templates/jsx/hooks/use-local-camera.json +5 -0
- package/src/templates/jsx/hooks/use-local-microphone.json +5 -0
- package/src/templates/jsx/hooks/use-local-screenshare.json +5 -0
- package/src/templates/jsx/hooks/use-remote-participant-ids.json +5 -0
- package/src/templates/jsx/hooks/use-replica-ids.json +5 -0
- package/src/templates/jsx/hooks/use-request-permissions.json +5 -0
- package/src/templates/jsx/hooks/use-start-haircheck.json +5 -0
- package/src/templates/jsx/index.ts +14 -0
- package/src/templates/tsx/components/audio-wave.json +5 -0
- package/src/templates/tsx/components/controls.json +10 -0
- package/src/templates/tsx/components/conversation-01.json +11 -0
- package/src/templates/tsx/components/cvi-provider.json +5 -0
- package/src/templates/tsx/components/hair-check-01.json +10 -0
- package/src/templates/tsx/hooks/cvi-events-hooks.json +5 -0
- package/src/templates/tsx/hooks/use-cvi-call.json +5 -0
- package/src/templates/tsx/hooks/use-local-camera.json +5 -0
- package/src/templates/tsx/hooks/use-local-microphone.json +5 -0
- package/src/templates/tsx/hooks/use-local-screenshare.json +5 -0
- package/src/templates/tsx/hooks/use-remote-participant-ids.json +5 -0
- package/src/templates/tsx/hooks/use-replica-ids.json +5 -0
- package/src/templates/tsx/hooks/use-request-permissions.json +8 -0
- package/src/templates/tsx/hooks/use-start-haircheck.json +5 -0
- package/src/templates/tsx/index.ts +14 -0
- package/src/utils/resolve-components-tree.ts +59 -2
- package/src/utils/update-files.ts +38 -10
- package/src/utils/version-utils.ts +26 -0
- /package/dev-components/hooks/{use-cvi-call.ts → use-cvi-call.tsx} +0 -0
- /package/dev-components/hooks/{use-local-camera.ts → use-local-camera.tsx} +0 -0
- /package/dev-components/hooks/{use-local-microphone.ts → use-local-microphone.tsx} +0 -0
- /package/dev-components/hooks/{use-local-screenshare.ts → use-local-screenshare.tsx} +0 -0
- /package/dev-components/hooks/{use-remote-participant-ids.ts → use-remote-participant-ids.tsx} +0 -0
- /package/dev-components/hooks/{use-replica-ids.ts → use-replica-ids.tsx} +0 -0
- /package/dev-components/hooks/{use-request-permissions.ts → use-request-permissions.tsx} +0 -0
- /package/dev-components/hooks/{use-start-haircheck.ts → use-start-haircheck.tsx} +0 -0
package/README.md
CHANGED
|
@@ -6,49 +6,49 @@ A CLI tool for installing and managing CVI (Conversational Video Interface) comp
|
|
|
6
6
|
|
|
7
7
|
**Initialize the project**:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
```bash
|
|
10
|
+
npx @tavus/cvi-ui@latest init
|
|
11
|
+
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
This will:
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
- Create a `cvi-components.json` configuration file
|
|
16
|
+
- Prompt for TypeScript preference
|
|
17
|
+
- Install the necessary dependencies
|
|
18
18
|
|
|
19
19
|
**Add components to your project**:
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
```bash
|
|
22
|
+
npx @tavus/cvi-ui@latest add conversation
|
|
23
|
+
```
|
|
24
24
|
|
|
25
25
|
**Wrap your app with the CVI provider**:
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
```tsx
|
|
28
|
+
import { CVIProvider } from './components/cvi/components/cvi-provider';
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
function App() {
|
|
31
|
+
return (
|
|
32
|
+
<CVIProvider>
|
|
33
|
+
{/* Your app content */}
|
|
34
|
+
</CVIProvider>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
38
|
|
|
39
39
|
**Add conversation components**:
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
```tsx
|
|
42
|
+
import { Conversation } from './components/cvi/components/conversation';
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
function Call() {
|
|
45
|
+
return (
|
|
46
|
+
<div>
|
|
47
|
+
<Conversation {...conversationProps} />
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
52
|
|
|
53
53
|
## Available Components
|
|
54
54
|
|
|
@@ -59,15 +59,27 @@ A CLI tool for installing and managing CVI (Conversational Video Interface) comp
|
|
|
59
59
|
### UI Components
|
|
60
60
|
|
|
61
61
|
- **`controls`** - Video chat control buttons with device selection capabilities
|
|
62
|
+
|
|
62
63
|
- `MicrophoneButton` - Toggle microphone with device dropdown
|
|
63
|
-
- `CameraButton` - Toggle camera with device dropdown
|
|
64
|
+
- `CameraButton` - Toggle camera with device dropdown
|
|
64
65
|
- `ScreenShareButton` - Toggle screen sharing
|
|
65
66
|
|
|
66
|
-
- **`hair-check`** - Pre-call interface for testing and configuring audio/video devices
|
|
67
|
+
- **`hair-check-01`** - Pre-call interface for testing and configuring audio/video devices
|
|
68
|
+
|
|
67
69
|
- Live camera preview with mirror effect
|
|
68
70
|
- Permission management and device controls
|
|
69
71
|
- Join interface with loading states
|
|
70
72
|
|
|
73
|
+
- **`conversation-01`** - Conversation component for video chat
|
|
74
|
+
|
|
75
|
+
- Video chat with audio wave indicator
|
|
76
|
+
- Device selection and permission management
|
|
77
|
+
- Screen sharing support
|
|
78
|
+
- Error handling
|
|
79
|
+
|
|
80
|
+
- **`audio-wave`** - Audio wave indicator for conversation
|
|
81
|
+
- Shows active speaker audio level
|
|
82
|
+
|
|
71
83
|
### Hooks
|
|
72
84
|
|
|
73
85
|
#### Core Call Management
|
|
@@ -100,4 +112,3 @@ MIT License - see the [LICENSE](LICENSE) file for details.
|
|
|
100
112
|
|
|
101
113
|
- [CVI Documentation](https://docs.tavus.io/sections/conversational-video-interface/cvi-overview)
|
|
102
114
|
- [Tavus Examples](https://github.com/Tavus-Engineering/tavus-examples)
|
|
103
|
-
|
|
@@ -11,6 +11,7 @@ The `Controls` component provides a set of video chat control buttons with integ
|
|
|
11
11
|
- **`MicrophoneButton`**: A button component that toggles microphone on/off with a dropdown for device selection
|
|
12
12
|
- **`CameraButton`**: A button component that toggles camera on/off with a dropdown for device selection
|
|
13
13
|
- **`ScreenShareButton`**: A button component that toggles screen sharing on/off
|
|
14
|
+
- **`SelectDevice`**: A reusable dropdown component for selecting camera and microphone devices
|
|
14
15
|
|
|
15
16
|
#### Usage:
|
|
16
17
|
|
|
@@ -62,7 +63,7 @@ import { MicrophoneButton, CameraButton, ScreenShareButton } from './controls';
|
|
|
62
63
|
- Integration with Daily.co device management system
|
|
63
64
|
- CSS modules for scoped styling
|
|
64
65
|
|
|
65
|
-
### Hair Check
|
|
66
|
+
### Hair Check 01
|
|
66
67
|
|
|
67
68
|
The `HairCheck` component provides a pre-call interface for users to test and configure their audio/video devices before joining a video chat.
|
|
68
69
|
|
|
@@ -99,3 +100,63 @@ import { HairCheck } from './hair-check';
|
|
|
99
100
|
- Fallback user avatar when camera is unavailable
|
|
100
101
|
- Integrated device controls for easy testing
|
|
101
102
|
- Clean, intuitive interface for pre-call setup
|
|
103
|
+
|
|
104
|
+
### Conversation 01
|
|
105
|
+
|
|
106
|
+
The `Conversation` component provides a complete video chat interface for one-to-one conversations with AI replicas, featuring main video display, self-view preview, and integrated controls.
|
|
107
|
+
|
|
108
|
+
#### Features:
|
|
109
|
+
|
|
110
|
+
- **Main Video Display**: Large video area showing the AI replica or screen share
|
|
111
|
+
- **Self-View Preview**: Small preview window showing local camera feed
|
|
112
|
+
- **Screen Sharing Support**: Automatic switching between replica video and screen share
|
|
113
|
+
- **Device Controls**: Integrated microphone, camera, and screen share controls
|
|
114
|
+
- **Error Handling**: Graceful handling of camera/microphone permission errors
|
|
115
|
+
- **Responsive Layout**: Adaptive design for different screen sizes
|
|
116
|
+
|
|
117
|
+
#### Usage:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { Conversation } from './conversation-01';
|
|
121
|
+
|
|
122
|
+
<Conversation
|
|
123
|
+
conversation={conversationData}
|
|
124
|
+
onLeave={() => handleLeaveCall()}
|
|
125
|
+
/>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### Props:
|
|
129
|
+
|
|
130
|
+
- `conversation` (ConversationData): Object containing conversation details
|
|
131
|
+
- `conversation_id` (string): Unique identifier for the conversation
|
|
132
|
+
- `conversation_name` (string): Display name for the conversation
|
|
133
|
+
- `status` ('active' | 'ended' | 'error'): Current conversation status
|
|
134
|
+
- `conversation_url` (string): Daily.co room URL for joining
|
|
135
|
+
- `replica_id` (string | null): ID of the AI replica participant
|
|
136
|
+
- `persona_id` (string | null): ID of the persona being used
|
|
137
|
+
- `created_at` (string): Timestamp of conversation creation
|
|
138
|
+
- `onLeave` (function): Callback when user leaves the conversation
|
|
139
|
+
|
|
140
|
+
### Audio Wave
|
|
141
|
+
|
|
142
|
+
The `AudioWave` component provides real-time audio level visualization for video chat participants, displaying animated bars that respond to audio input levels.
|
|
143
|
+
|
|
144
|
+
#### Features:
|
|
145
|
+
|
|
146
|
+
- **Real-time Audio Visualization**: Three animated bars that respond to audio levels
|
|
147
|
+
- **Active Speaker Detection**: Visual distinction between active and inactive speakers
|
|
148
|
+
- **Performance Optimized**: Uses `requestAnimationFrame` for smooth animations
|
|
149
|
+
- **Responsive Design**: Compact circular design that fits well in video previews
|
|
150
|
+
- **Audio Level Scaling**: Intelligent volume scaling for consistent visual feedback
|
|
151
|
+
|
|
152
|
+
#### Usage:
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { AudioWave } from './audio-wave';
|
|
156
|
+
|
|
157
|
+
<AudioWave id={participantId} />
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Props:
|
|
161
|
+
|
|
162
|
+
- `id` (string): The participant's session ID to monitor audio levels for
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
overflow: hidden;
|
|
3
|
+
border: 1px solid white;
|
|
4
|
+
width: 1.5rem;
|
|
5
|
+
height: 1.5rem;
|
|
6
|
+
border-radius: 9999px;
|
|
7
|
+
will-change: transform;
|
|
8
|
+
transform: translateZ(0);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.waveContainer {
|
|
12
|
+
display: flex;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
align-items: center;
|
|
15
|
+
gap: 0.125rem;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.bar {
|
|
21
|
+
width: 0.25rem;
|
|
22
|
+
height: 0.25rem;
|
|
23
|
+
background-color: white;
|
|
24
|
+
border-radius: 9999px;
|
|
25
|
+
transition: height 200ms ease-out;
|
|
26
|
+
will-change: height;
|
|
27
|
+
transform: translateZ(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.barInactive {
|
|
31
|
+
width: 0.25rem !important;
|
|
32
|
+
height: 0.25rem !important;
|
|
33
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { useCallback, useRef, memo } from "react";
|
|
2
|
+
import { useActiveSpeakerId } from "@daily-co/daily-react";
|
|
3
|
+
import { useAudioLevelObserver } from "@daily-co/daily-react";
|
|
4
|
+
import styles from "./audio-wave.module.css";
|
|
5
|
+
|
|
6
|
+
export const AudioWave = memo(({ id }: { id: string }) => {
|
|
7
|
+
const activeSpeakerId = useActiveSpeakerId();
|
|
8
|
+
const isActiveSpeaker = activeSpeakerId === id;
|
|
9
|
+
|
|
10
|
+
const leftBarRef = useRef<HTMLDivElement>(null);
|
|
11
|
+
const centerBarRef = useRef<HTMLDivElement>(null);
|
|
12
|
+
const rightBarRef = useRef<HTMLDivElement>(null);
|
|
13
|
+
const animationFrameRef = useRef<number | undefined>(undefined);
|
|
14
|
+
|
|
15
|
+
useAudioLevelObserver(
|
|
16
|
+
id,
|
|
17
|
+
useCallback((volume) => {
|
|
18
|
+
// Cancel any pending animation frame to prevent accumulation
|
|
19
|
+
if (animationFrameRef.current) {
|
|
20
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Use requestAnimationFrame to batch DOM updates
|
|
24
|
+
animationFrameRef.current = requestAnimationFrame(() => {
|
|
25
|
+
const scaledVolume = Number(Math.max(0.01, volume).toFixed(2));
|
|
26
|
+
if (leftBarRef.current && centerBarRef.current && rightBarRef.current) {
|
|
27
|
+
leftBarRef.current.style.height = `${20 + scaledVolume * 40}%`;
|
|
28
|
+
centerBarRef.current.style.height = `${20 + scaledVolume * 130}%`;
|
|
29
|
+
rightBarRef.current.style.height = `${20 + scaledVolume * 40}%`;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}, []),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className={styles.container}>
|
|
37
|
+
<div className={styles.waveContainer}>
|
|
38
|
+
<div
|
|
39
|
+
ref={leftBarRef}
|
|
40
|
+
className={`${styles.bar} ${!isActiveSpeaker ? styles.barInactive : ''}`}
|
|
41
|
+
/>
|
|
42
|
+
<div
|
|
43
|
+
ref={centerBarRef}
|
|
44
|
+
className={`${styles.bar} ${!isActiveSpeaker ? styles.barInactive : ''}`}
|
|
45
|
+
/>
|
|
46
|
+
<div
|
|
47
|
+
ref={rightBarRef}
|
|
48
|
+
className={`${styles.bar} ${!isActiveSpeaker ? styles.barInactive : ''}`}
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
AudioWave.displayName = 'AudioWave';
|
|
@@ -1,113 +1,115 @@
|
|
|
1
1
|
/* SelectDevice styles */
|
|
2
2
|
.selectDevice {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
height: 3rem;
|
|
4
|
+
width: 5.5rem;
|
|
5
|
+
border-radius: 9999px;
|
|
6
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
7
|
+
padding: 0 0.75rem;
|
|
8
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
9
|
+
backdrop-filter: blur(10px);
|
|
10
|
+
color: transparent;
|
|
11
|
+
padding-right: 2rem; /* space for arrow */
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
-webkit-appearance: none;
|
|
14
|
+
-moz-appearance: none;
|
|
15
|
+
appearance: none;
|
|
16
|
+
cursor: pointer;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
.selectDevice::-ms-expand {
|
|
17
|
-
|
|
20
|
+
display: none;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
.selectDevice option {
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
color: transparent;
|
|
25
|
+
background-color: transparent;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
.selectDevice:focus {
|
|
26
|
-
|
|
29
|
+
outline: none;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
/* Device button container styles */
|
|
30
33
|
.deviceButtonContainer {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
position: relative;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
border-radius: 9999px;
|
|
39
|
+
backdrop-filter: blur(4px);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/* Device button styles */
|
|
40
43
|
.deviceButton {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
position: absolute;
|
|
45
|
+
left: 0;
|
|
46
|
+
top: 0;
|
|
47
|
+
z-index: 10;
|
|
48
|
+
height: 3rem;
|
|
49
|
+
width: 3rem;
|
|
50
|
+
border-radius: 9999px;
|
|
51
|
+
background-color: white;
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
border: 1px solid transparent;
|
|
56
|
+
cursor: pointer;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
.deviceButtonIcon {
|
|
56
|
-
|
|
60
|
+
display: flex;
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
.deviceButton:disabled {
|
|
60
|
-
|
|
64
|
+
opacity: 0.5;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
/* Screen reader only text */
|
|
64
68
|
.srOnly {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: 1px;
|
|
71
|
+
height: 1px;
|
|
72
|
+
padding: 0;
|
|
73
|
+
margin: -1px;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
clip: rect(0, 0, 0, 0);
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
border-width: 0;
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
/* Controls container */
|
|
77
81
|
.controlsContainer {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/* End call button */
|
|
85
|
-
.endCallButton {
|
|
86
|
-
height: 3rem;
|
|
87
|
-
width: 3rem;
|
|
88
|
-
border-radius: 9999px;
|
|
89
|
-
background-color: #EF4444;
|
|
90
|
-
display: flex;
|
|
91
|
-
align-items: center;
|
|
92
|
-
justify-content: center;
|
|
82
|
+
display: flex;
|
|
83
|
+
gap: 1rem;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
align-items: center;
|
|
93
86
|
}
|
|
94
87
|
|
|
95
88
|
.selectDeviceContainer {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
position: relative;
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
99
92
|
}
|
|
100
93
|
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
.selectArrow {
|
|
95
|
+
position: absolute;
|
|
96
|
+
right: 1rem;
|
|
97
|
+
pointer-events: none;
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
height: 100%;
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
103
|
+
.screenShareButton {
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
position: relative;
|
|
106
|
+
height: 3rem;
|
|
107
|
+
width: 3rem;
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
border-radius: 9999px;
|
|
112
|
+
backdrop-filter: blur(4px);
|
|
113
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
114
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
115
|
+
}
|
|
@@ -144,7 +144,7 @@ export const CameraButton = memo(() => {
|
|
|
144
144
|
disabled={!isCamReady || !currentCam}
|
|
145
145
|
className={styles.deviceButton}
|
|
146
146
|
>
|
|
147
|
-
<span>
|
|
147
|
+
<span className={styles.deviceButtonIcon}>
|
|
148
148
|
{isCamMuted ? (
|
|
149
149
|
<svg
|
|
150
150
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -218,7 +218,7 @@ export const ScreenShareButton = memo(() => {
|
|
|
218
218
|
<button
|
|
219
219
|
type="button"
|
|
220
220
|
onClick={onToggleScreenshare}
|
|
221
|
-
className={styles.
|
|
221
|
+
className={`${styles.deviceButtonContainer} ${styles.screenShareButton}`}
|
|
222
222
|
>
|
|
223
223
|
<span>
|
|
224
224
|
{isScreenSharing ? (
|