@fraku/video 0.0.1 → 0.0.2

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.
Files changed (43) hide show
  1. package/package.json +2 -3
  2. package/src/App.tsx +0 -7
  3. package/src/components/ZoomVideoPlugin/ZoomVideoPlugin.stories.tsx +0 -50
  4. package/src/components/ZoomVideoPlugin/ZoomVideoPlugin.tsx +0 -253
  5. package/src/components/ZoomVideoPlugin/components/ButtonsDock/ButtonsDock.tsx +0 -353
  6. package/src/components/ZoomVideoPlugin/components/ButtonsDock/DockButton.tsx +0 -90
  7. package/src/components/ZoomVideoPlugin/components/ButtonsDock/MenuItemTemplate.tsx +0 -35
  8. package/src/components/ZoomVideoPlugin/components/ButtonsDock/index.ts +0 -1
  9. package/src/components/ZoomVideoPlugin/components/MobileIconButton/MobileIconButton.tsx +0 -30
  10. package/src/components/ZoomVideoPlugin/components/MobileIconButton/index.ts +0 -1
  11. package/src/components/ZoomVideoPlugin/components/Overlay/Overlay.tsx +0 -74
  12. package/src/components/ZoomVideoPlugin/components/Overlay/index.ts +0 -1
  13. package/src/components/ZoomVideoPlugin/components/ParticipantsList.tsx +0 -52
  14. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/SettingsContent.tsx +0 -19
  15. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/SettingsMenu.tsx +0 -30
  16. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/SettingsOverlay.tsx +0 -52
  17. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/Tabs/AudioSettings.tsx +0 -191
  18. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/Tabs/BackgroundSettings.tsx +0 -47
  19. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/Tabs/DropdownItemTemplate.tsx +0 -20
  20. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/Tabs/DropdownValueTemplate.tsx +0 -12
  21. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/Tabs/VideoSettings.tsx +0 -30
  22. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/context.ts +0 -20
  23. package/src/components/ZoomVideoPlugin/components/SettingsOverlay/index.ts +0 -1
  24. package/src/components/ZoomVideoPlugin/components/Video.tsx +0 -35
  25. package/src/components/ZoomVideoPlugin/constants.ts +0 -4
  26. package/src/components/ZoomVideoPlugin/context.ts +0 -86
  27. package/src/components/ZoomVideoPlugin/hooks/useClientMessages.ts +0 -142
  28. package/src/components/ZoomVideoPlugin/hooks/useDeviceSize.ts +0 -24
  29. package/src/components/ZoomVideoPlugin/hooks/useStartVideoOptions.ts +0 -14
  30. package/src/components/ZoomVideoPlugin/hooks/useZoomVideoPlayer.tsx +0 -142
  31. package/src/components/ZoomVideoPlugin/index.ts +0 -2
  32. package/src/components/ZoomVideoPlugin/lib/platforms.ts +0 -17
  33. package/src/components/ZoomVideoPlugin/pages/AfterSession.tsx +0 -14
  34. package/src/components/ZoomVideoPlugin/pages/MainSession.tsx +0 -53
  35. package/src/components/ZoomVideoPlugin/pages/PanelistsSession.tsx +0 -97
  36. package/src/components/ZoomVideoPlugin/pages/PreSessionConfiguration.tsx +0 -154
  37. package/src/components/ZoomVideoPlugin/types.global.d.ts +0 -15
  38. package/src/components/ZoomVideoPlugin/types.ts +0 -23
  39. package/src/global.d.ts +0 -46
  40. package/src/index.css +0 -4
  41. package/src/index.ts +0 -4
  42. package/src/main.tsx +0 -10
  43. package/src/vite-env.d.ts +0 -12
@@ -1,90 +0,0 @@
1
- import React from 'react'
2
- import cn from 'classnames'
3
-
4
- type DockButtonProps = {
5
- className?: string
6
- // Main action (always required)
7
- mainIcon: string
8
- mainLabel?: string
9
- mainTitle?: string
10
- onMainClick: (e: React.MouseEvent<HTMLButtonElement>) => void
11
- // Optional secondary action
12
- showSecondary?: boolean
13
- secondaryIcon?: string
14
- secondaryTitle?: string
15
- onSecondaryClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
16
- }
17
-
18
- /**
19
- * Renders a customizable dock button component with optional main and secondary actions.
20
- *
21
- * @param className - Additional CSS class names to apply to the container.
22
- * @param mainIcon - The CSS class for the main icon to display.
23
- * @param mainLabel - Optional label text for the main button.
24
- * @param mainTitle - The title attribute for the main button (for accessibility/tooltips).
25
- * @param onMainClick - Click handler for the main button action.
26
- * @param showSecondary - Flag to indicate if the secondary button should be displayed.
27
- * @param secondaryIcon - Optional CSS class for the secondary icon to display.
28
- * @param secondaryTitle - The title attribute for the secondary button (for accessibility/tooltips).
29
- * @param onSecondaryClick - Optional click handler for the secondary button action.
30
- *
31
- * @returns A dock button component with main and optional secondary actions.
32
- */
33
- const DockButton = ({
34
- className,
35
- mainIcon,
36
- mainLabel,
37
- mainTitle,
38
- onMainClick,
39
- secondaryIcon,
40
- secondaryTitle,
41
- onSecondaryClick,
42
- showSecondary = false
43
- }: DockButtonProps) => {
44
- const hasLabel = Boolean(mainLabel)
45
- const hasSecondary = showSecondary && secondaryIcon && onSecondaryClick
46
-
47
- return (
48
- <div
49
- className={cn(
50
- 'flex items-center bg-neutral-85 h-40 rounded-full',
51
- {
52
- 'justify-center min-w-40': !hasLabel && !hasSecondary,
53
- 'justify-between gap-12 px-4': hasSecondary,
54
- 'px-12': hasLabel && !hasSecondary
55
- },
56
- className
57
- )}
58
- >
59
- {/* Main action */}
60
- <button
61
- className={cn('dock-button-main flex items-center justify-center', {
62
- 'p-8 h-full': hasSecondary,
63
- 'w-full h-40': !hasSecondary
64
- })}
65
- onClick={onMainClick}
66
- title={mainTitle}
67
- type="button"
68
- >
69
- <span className="flex items-center justify-center w-24 h-24">
70
- <i className={mainIcon} aria-hidden="true" />
71
- </span>
72
- {hasLabel && <span className="ml-4">{mainLabel}</span>}
73
- </button>
74
-
75
- {/* Secondary action (optional) */}
76
- {hasSecondary && (
77
- <button
78
- className="dock-button-secondary flex items-center justify-center w-32 h-full hover:bg-neutral-95 rounded-full"
79
- onClick={onSecondaryClick}
80
- title={secondaryTitle}
81
- type="button"
82
- >
83
- <i className={secondaryIcon} aria-hidden="true" />
84
- </button>
85
- )}
86
- </div>
87
- )
88
- }
89
-
90
- export default DockButton
@@ -1,35 +0,0 @@
1
- import { MenuItem, MenuItemOptions } from 'primereact/menuitem'
2
-
3
- type Props = {
4
- item: MenuItem
5
- options: MenuItemOptions
6
- activeItem: string | undefined
7
- }
8
-
9
- const MenuItemTemplate = ({ item, options, activeItem }: Props) => {
10
- const isActive = item.id === activeItem
11
-
12
- return (
13
- <div className="p-menuitem-content" data-pc-section="content">
14
- <a
15
- aria-label={item.label}
16
- className={options.className}
17
- data-test={item?.data?.dataTestId}
18
- data-pc-section="action"
19
- href="#"
20
- onClick={options.onClick}
21
- >
22
- {isActive && (
23
- <span className={options.iconClassName} data-pc-section="icon">
24
- <i className="fa-regular fa-check" aria-hidden="true" />
25
- </span>
26
- )}
27
- <span className={options.labelClassName} data-pc-section="label">
28
- {item.label}
29
- </span>
30
- </a>
31
- </div>
32
- )
33
- }
34
-
35
- export default MenuItemTemplate
@@ -1 +0,0 @@
1
- export { default } from './ButtonsDock'
@@ -1,30 +0,0 @@
1
- import cn from 'classnames'
2
-
3
- type MobileIconButtonProps = {
4
- className?: string
5
- icon: string
6
- onClick: () => void
7
- title?: string
8
- id?: string
9
- }
10
-
11
- const MobileIconButton = ({ className, icon, onClick, title, id }: MobileIconButtonProps) => {
12
- return (
13
- <button
14
- aria-label={title}
15
- className={cn(
16
- 'flex items-center justify-start gap-4 w-full h-40 px-8 rounded-l border border-neutral-80 hover:bg-neutral-85',
17
- className
18
- )}
19
- id={id}
20
- onClick={onClick}
21
- >
22
- <span className="flex items-center justify-center w-24 h-24">
23
- <i className={icon} aria-hidden="true" />
24
- </span>
25
- <span className="flex-1 text-left">{title}</span>
26
- </button>
27
- )
28
- }
29
-
30
- export default MobileIconButton
@@ -1 +0,0 @@
1
- export { default } from './MobileIconButton'
@@ -1,74 +0,0 @@
1
- import { Dialog } from 'primereact/dialog'
2
- import { Sidebar } from 'primereact/sidebar'
3
- import { Breakpoint } from '../../hooks/useDeviceSize'
4
-
5
- type OverlayProps = {
6
- breakpoint: Breakpoint
7
- children: React.ReactNode
8
- className?: string
9
- header?: string | React.ReactNode
10
- onHide: () => void
11
- width?: string | number
12
- visible: boolean
13
- }
14
-
15
- const Overlay = ({
16
- breakpoint,
17
- children,
18
- onHide,
19
- className,
20
- visible = false,
21
- width = '50vw',
22
- header = ''
23
- }: OverlayProps) => {
24
- const isTablet = breakpoint < Breakpoint.Desktop
25
-
26
- if (isTablet) {
27
- return (
28
- <Sidebar
29
- blockScroll
30
- className={className}
31
- closeIcon={<i className="fa-regular fa-xmark fa-lg" aria-hidden="true" />}
32
- header={header}
33
- onHide={onHide}
34
- position="bottom"
35
- pt={{
36
- header: { className: 'border-b border-neutral-80 font-bold text-l' },
37
- root: { className: '[&_.p-sidebar-content]:px-0 h-fit' },
38
- content: { className: 'p-0' }
39
- }}
40
- visible={visible}
41
- >
42
- {children}
43
- </Sidebar>
44
- )
45
- }
46
-
47
- return (
48
- <Dialog
49
- blockScroll
50
- className={className}
51
- closable
52
- closeIcon={<i className="fa-regular fa-xmark fa-lg" aria-hidden="true" />}
53
- contentStyle={{ padding: '0' }}
54
- dismissableMask
55
- draggable
56
- focusOnShow={false}
57
- header={header}
58
- headerStyle={{
59
- borderBottom: '1px solid var(--neutral-80)',
60
- padding: '16px'
61
- }}
62
- onHide={onHide}
63
- pt={{
64
- headerTitle: { className: '!font-bold !text-l' }
65
- }}
66
- style={{ width }}
67
- visible={visible}
68
- >
69
- {children}
70
- </Dialog>
71
- )
72
- }
73
-
74
- export default Overlay
@@ -1 +0,0 @@
1
- export { default } from './Overlay'
@@ -1,52 +0,0 @@
1
- import type { Participant, VideoClient } from '@zoom/videosdk'
2
- import cn from 'classnames'
3
- import { ReactSetter } from '../types'
4
-
5
- type Props = {
6
- participants: Participant[]
7
- setIsCamOn: ReactSetter<boolean>
8
- setIsMicOn: ReactSetter<boolean>
9
- zmClient: typeof VideoClient
10
- }
11
-
12
- const ParticipantsList = ({ zmClient, setIsCamOn, setIsMicOn, participants }: Props) => {
13
- return (
14
- <ul className="flex flex-col gap-8 w-full self-start">
15
- {participants.map((user) => {
16
- const isCurrentUser = user.userId === zmClient?.getCurrentUserInfo()?.userId
17
- return (
18
- <li key={user.userId} className="flex items-center justify-between gap-16 p-4 rounded shadow-medium w-full">
19
- <span className="truncate flex gap-4">
20
- <span className="truncate">{user.displayName}</span>
21
- <span className="truncate">id: {user.userId}</span>
22
- <span className="text-sm">{isCurrentUser ? '(You)' : ''}</span>
23
- </span>
24
- <div className="flex items-center gap-8">
25
- <button
26
- onClick={() => setIsCamOn((prev) => !prev)}
27
- title={user.bVideoOn ? 'Stop Video' : 'Start Video'}
28
- disabled={!isCurrentUser}
29
- className={cn('w-24', { 'opacity-32 cursor-not-allowed': !isCurrentUser })}
30
- >
31
- <i className={`fa-regular ${user.bVideoOn ? 'fa-video' : 'fa-video-slash'}`} aria-hidden="true" />
32
- </button>
33
- <button
34
- onClick={() => setIsMicOn((prev) => !prev)}
35
- title={user.muted || !user.audio ? 'Unmute' : 'Mute'}
36
- disabled={!isCurrentUser}
37
- className={cn('w-24', { 'opacity-32 cursor-not-allowed': !isCurrentUser })}
38
- >
39
- <i
40
- className={`fa-regular ${user.muted || !user.audio ? 'fa-microphone-slash' : 'fa-microphone'}`}
41
- aria-hidden="true"
42
- />
43
- </button>
44
- </div>
45
- </li>
46
- )
47
- })}
48
- </ul>
49
- )
50
- }
51
-
52
- export default ParticipantsList
@@ -1,19 +0,0 @@
1
- import { useSettingsOverlayContext } from './context'
2
- import AudioSettings from './Tabs/AudioSettings'
3
- import BackgroundSettings from './Tabs/BackgroundSettings'
4
- import VideoSettings from './Tabs/VideoSettings'
5
-
6
- const settingsRegistry = {
7
- Audio: AudioSettings,
8
- Video: VideoSettings,
9
- Background: BackgroundSettings
10
- }
11
-
12
- const SettingsContent = () => {
13
- const { selectedSettingsTab } = useSettingsOverlayContext()
14
-
15
- const ActiveComponent = settingsRegistry[selectedSettingsTab]
16
- return ActiveComponent ? <ActiveComponent /> : null
17
- }
18
-
19
- export default SettingsContent
@@ -1,30 +0,0 @@
1
- import cn from 'classnames'
2
- import MobileIconButton from '../MobileIconButton'
3
- import { SettingsTab, useSettingsOverlayContext } from './context'
4
-
5
- const tabs: { id: SettingsTab; icon: string; title: string }[] = [
6
- { id: SettingsTab.Audio, icon: 'fa-regular fa-microphone', title: 'Audio' },
7
- { id: SettingsTab.Video, icon: 'fa-regular fa-video', title: 'Video' },
8
- { id: SettingsTab.Background, icon: 'fa-regular fa-image', title: 'Fondos' }
9
- ]
10
-
11
- const SettingsMenu = () => {
12
- const { selectedSettingsTab, setSelectedSettingsTab } = useSettingsOverlayContext()
13
-
14
- return (
15
- <div className="flex flex-col sm:flex-row md:flex-col w-full p-16 md:p-0 gap-16 md:gap-0 md:w-fit md:min-w-[200px] md:flex-shrink-0 overflow-visible">
16
- {tabs.map(({ id, icon, title }) => (
17
- <MobileIconButton
18
- key={id}
19
- className={cn('font-bold md:rounded-none md:border-0', { 'bg-neutral-95': selectedSettingsTab === id })}
20
- icon={icon}
21
- id={id}
22
- onClick={() => setSelectedSettingsTab(id)}
23
- title={title}
24
- />
25
- ))}
26
- </div>
27
- )
28
- }
29
-
30
- export default SettingsMenu
@@ -1,52 +0,0 @@
1
- import { useEffect, useMemo, useState } from 'react'
2
- import { Breakpoint } from '../../hooks/useDeviceSize'
3
- import Overlay from '../Overlay'
4
- import { SETTINGS_OVERLAY_WIDTH } from '../../constants'
5
- import SettingsMenu from './SettingsMenu'
6
- import SettingsContent from './SettingsContent'
7
- import { settingsOverlayContext, SettingsOverlayContextProps, SettingsTab } from './context'
8
-
9
- type Props = {
10
- breakpoint: Breakpoint
11
- visible: boolean
12
- onHide: () => void
13
- defaultTab?: SettingsTab
14
- }
15
-
16
- const SettingsOverlay = ({ visible, onHide, breakpoint, defaultTab = SettingsTab.Audio }: Props) => {
17
- const [selectedSettingsTab, setSelectedSettingsTab] = useState<SettingsTab>(defaultTab)
18
-
19
- useEffect(() => {
20
- if (visible) setSelectedSettingsTab(defaultTab)
21
- }, [defaultTab, visible])
22
-
23
- const contextVal = useMemo<SettingsOverlayContextProps>(
24
- () => ({
25
- selectedSettingsTab,
26
- setSelectedSettingsTab
27
- }),
28
- [selectedSettingsTab]
29
- )
30
-
31
- return (
32
- <Overlay
33
- visible={visible}
34
- onHide={onHide}
35
- header="Settings"
36
- breakpoint={breakpoint}
37
- width={SETTINGS_OVERLAY_WIDTH}
38
- className="min-w-[30vw] min-h-[30vh] max-h-[60vh] h-full [&_.p-dialog-content]:overflow-hidden"
39
- >
40
- <settingsOverlayContext.Provider value={contextVal}>
41
- <div className="flex flex-col md:flex-row divide-y md:divide-y-0 md:divide-x divide-neutral-80 h-full">
42
- <SettingsMenu />
43
- <div className="flex-1 overflow-y-auto p-12">
44
- <SettingsContent />
45
- </div>
46
- </div>
47
- </settingsOverlayContext.Provider>
48
- </Overlay>
49
- )
50
- }
51
-
52
- export default SettingsOverlay
@@ -1,191 +0,0 @@
1
- import { useState, useCallback, useRef, useEffect } from 'react'
2
- import { ProgressBar } from 'primereact/progressbar'
3
- import cn from 'classnames'
4
- import { Dropdown } from 'primereact/dropdown'
5
- import { useZoomVideoContext } from '../../../context'
6
- import DropdownValueTemplate from './DropdownValueTemplate'
7
- import DropdownItemTemplate from './DropdownItemTemplate'
8
-
9
- const UPDATE_INTERVAL_MS = 300
10
-
11
- const AudioSettings = () => {
12
- const {
13
- activeAudioOutput,
14
- activeMicrophone,
15
- audioOutputList,
16
- localAudio,
17
- micList,
18
- switchActiveAudioOutput,
19
- switchActiveMicrophone
20
- } = useZoomVideoContext()
21
-
22
- const [micLevel, setMicLevel] = useState<number>(0)
23
- const [speakerLevel, setSpeakerLevel] = useState<number>(0)
24
- const [micState, setMicState] = useState<'idle' | 'recording' | 'playing'>('idle')
25
-
26
- const micListOptions = micList.map((mic) => ({
27
- label: mic.label || `Micrófono ${mic.deviceId}`,
28
- value: mic.deviceId
29
- }))
30
-
31
- const speakerOptions = audioOutputList.map((spk) => ({
32
- label: spk.label || `Altavoz ${spk.deviceId}`,
33
- value: spk.deviceId
34
- }))
35
-
36
- const micTesterRef = useRef<any>(null)
37
- const lastUpdateMicRef = useRef<number>(0)
38
- const handleMicTest = useCallback(async () => {
39
- if (!localAudio) return
40
-
41
- if (micTesterRef.current) {
42
- micTesterRef.current.stop?.()
43
- micTesterRef.current = null
44
- setMicState('idle')
45
- setMicLevel(0)
46
- return
47
- }
48
-
49
- const tester = localAudio.testMicrophone({
50
- microphoneId: activeMicrophone,
51
- speakerId: activeAudioOutput,
52
- recordAndPlay: true,
53
- onAnalyseFrequency: (v: number) => {
54
- const now = Date.now()
55
- // only update every UPDATE_INTERVAL_MS ms
56
- if (now - lastUpdateMicRef.current > UPDATE_INTERVAL_MS) {
57
- lastUpdateMicRef.current = now
58
- setMicLevel(v)
59
- }
60
- },
61
- onStartRecording: () => setMicState('recording'),
62
- onStartPlayRecording: () => setMicState('playing'),
63
- onStopPlayRecording: () => {
64
- setMicState('idle')
65
- micTesterRef.current = null
66
- setMicLevel(0)
67
- }
68
- })
69
-
70
- micTesterRef.current = tester
71
- setMicState('recording')
72
- }, [localAudio, activeMicrophone, activeAudioOutput])
73
-
74
- const speakerTesterRef = useRef<any>(null)
75
- const lastUpdateSpeakerRef = useRef<number>(0)
76
- const handleSpeakerTest = useCallback(async () => {
77
- if (!localAudio) return
78
- if (speakerTesterRef.current) {
79
- speakerTesterRef.current.destroy?.()
80
- speakerTesterRef.current = null
81
- setSpeakerLevel(0)
82
- return
83
- }
84
- const tester = localAudio.testSpeaker({
85
- speakerId: activeAudioOutput,
86
- onAnalyseFrequency: (v: number) => {
87
- const now = Date.now()
88
- // only update every UPDATE_INTERVAL_MS ms
89
- if (now - lastUpdateSpeakerRef.current > UPDATE_INTERVAL_MS) {
90
- lastUpdateSpeakerRef.current = now
91
- setSpeakerLevel(v)
92
- }
93
- }
94
- })
95
- speakerTesterRef.current = tester
96
- }, [localAudio, activeAudioOutput])
97
-
98
- useEffect(() => {
99
- return () => {
100
- micTesterRef.current?.stop?.()
101
- speakerTesterRef.current?.destroy?.()
102
- }
103
- }, [])
104
-
105
- return (
106
- <div className="flex flex-col">
107
- {/* Microphone Section */}
108
- <p className="text-s font-bold">Micrófono</p>
109
- <p className="text-s mb-8 text-neutral-40">Selecciona un método de entrada de audio</p>
110
- <Dropdown
111
- className="mb-16 w-full"
112
- itemTemplate={(option) => <DropdownItemTemplate option={option} isActive={option.value === activeMicrophone} />}
113
- placeholder="Selecciona un micrófono"
114
- options={micListOptions}
115
- onChange={async (e) => await switchActiveMicrophone(e.value)}
116
- value={activeMicrophone}
117
- valueTemplate={(option) => <DropdownValueTemplate option={option} icon="fa-regular fa-microphone" />}
118
- />
119
-
120
- {/* Microphone Test Header */}
121
- <div className="mt-4 mb-8">
122
- <p className="text-s font-bold">Prueba de micrófono</p>
123
- <div className="mt-4 self-start">
124
- <p className="text-s text-neutral-40 text-start">
125
- {micState === 'idle' && 'Graba una muestra de tu voz y escúchela para verificar el funcionamiento.'}
126
- {micState === 'recording' && 'Grabando la voz... espera unos segundos.'}
127
- {micState === 'playing' && 'Reproduciendo grabación...'}
128
- </p>
129
- </div>
130
- </div>
131
-
132
- <button
133
- type="button"
134
- onClick={handleMicTest}
135
- className={cn(
136
- 'w-fit rounded-l p-8 font-semibold transition-all duration-200 border hover:border-neutral-70 text-white',
137
- {
138
- 'bg-neutral-60': micState === 'recording' || micState === 'playing',
139
- 'bg-neutral-50': micState === 'idle'
140
- }
141
- )}
142
- >
143
- {micState === 'recording' && 'Detener grabación'}
144
- {micState === 'playing' && 'Detener reproducción'}
145
- {micState === 'idle' && 'Probar micrófono'}
146
- </button>
147
-
148
- {/* Status message */}
149
- <ProgressBar
150
- value={micState === 'idle' ? 0 : micLevel}
151
- showValue={false}
152
- className="w-full mt-4 h-8 rounded-m border border-neutral-80"
153
- />
154
-
155
- {/* Speaker Section */}
156
- <div className="mt-32">
157
- <p className="text-s font-bold">Altavoz</p>
158
- <p className="text-s mb-8 text-neutral-40">Selecciona un método de salida de audio</p>
159
- <Dropdown
160
- className="mb-16 w-full"
161
- itemTemplate={(option) => (
162
- <DropdownItemTemplate option={option} isActive={option.value === activeAudioOutput} />
163
- )}
164
- options={speakerOptions}
165
- placeholder="Selecciona un altavoz"
166
- onChange={async (e) => await switchActiveAudioOutput(e.value)}
167
- value={activeAudioOutput}
168
- valueTemplate={(option) => <DropdownValueTemplate option={option} icon="fa-regular fa-volume" />}
169
- />
170
-
171
- <button
172
- type="button"
173
- onClick={handleSpeakerTest}
174
- className={cn(
175
- 'w-fit rounded-l p-8 font-semibold transition-all duration-200 border hover:border-neutral-70 text-white',
176
- speakerTesterRef.current ? 'bg-neutral-60' : 'bg-neutral-50'
177
- )}
178
- >
179
- {speakerTesterRef.current ? 'Detener prueba de altavoz' : 'Probar altavoz'}
180
- </button>
181
- <ProgressBar
182
- value={speakerLevel}
183
- showValue={false}
184
- className="w-full mt-8 h-8 rounded-m border border-neutral-80"
185
- />
186
- </div>
187
- </div>
188
- )
189
- }
190
-
191
- export default AudioSettings
@@ -1,47 +0,0 @@
1
- import cn from 'classnames'
2
- import { useZoomVideoContext } from '../../../context'
3
-
4
- const BackgroundSettings = () => {
5
- const { isBlurred, setIsBlurred } = useZoomVideoContext()
6
-
7
- const options = [
8
- {
9
- label: 'Ninguno',
10
- icon: 'fa-ban',
11
- isActive: !isBlurred
12
- },
13
- {
14
- label: 'Desenfocar',
15
- icon: 'fa-droplet',
16
- isActive: isBlurred
17
- }
18
- ]
19
-
20
- return (
21
- <div className="flex flex-col">
22
- <p className="text-s font-bold mb-8">Fondo</p>
23
- <div className="flex gap-12">
24
- {options.map(({ label, icon, isActive }) => {
25
- return (
26
- <button
27
- key={label}
28
- type="button"
29
- onClick={() => setIsBlurred((prev: boolean) => (isActive ? prev : !prev))}
30
- className={cn(
31
- 'w-full h-80 flex flex-col items-center justify-center gap-8 border rounded-l bg-white font-bold transition-colors ease-in-out',
32
- isActive ? '!border-neutral-60 border-2' : 'border-neutral-80 hover:border-neutral-70'
33
- )}
34
- >
35
- <span className="flex items-center justify-center w-24 h-24">
36
- <i className={cn('fa-regular fa-xl', icon)} aria-hidden="true" />
37
- </span>
38
- <span>{label}</span>
39
- </button>
40
- )
41
- })}
42
- </div>
43
- </div>
44
- )
45
- }
46
-
47
- export default BackgroundSettings
@@ -1,20 +0,0 @@
1
- const DropdownItemTemplate = ({
2
- option,
3
- isActive
4
- }: {
5
- option: { label: string; value: string }
6
- isActive: boolean
7
- }) => {
8
- return (
9
- <div className="flex items-center gap-4">
10
- {isActive && (
11
- <span className="flex items-center justify-center w-24 h-24">
12
- <i className="fa-regular fa-check" aria-hidden="true" />
13
- </span>
14
- )}
15
- <span className="mr-2">{option.label}</span>
16
- </div>
17
- )
18
- }
19
-
20
- export default DropdownItemTemplate
@@ -1,12 +0,0 @@
1
- const DropdownValueTemplate = ({ option, icon }: { option: { label: string; value: string }; icon: string }) => {
2
- return (
3
- <div className="flex items-center gap-4 font-semibold text-neutral-50">
4
- <span className="flex items-center justify-center w-24 h-24">
5
- <i className={icon} aria-hidden="true" />
6
- </span>
7
- <span className="truncate">{option.label}</span>
8
- </div>
9
- )
10
- }
11
-
12
- export default DropdownValueTemplate