♻️(frontend) refactor audio/video tabs to share common layout components
Extract shared layout components from audio and video tabs to eliminate code duplication and improve maintainability. Creates reusable layout components that both tabs can utilize, reducing redundancy and ensuring consistent styling and behavior across settings tabs.
This commit is contained in:
committed by
aleb_the_flash
parent
c330ec6ff4
commit
2215b621f4
@@ -1,4 +1,4 @@
|
||||
import { DialogProps, Field, H, Switch, Text } from '@/primitives'
|
||||
import { DialogProps, Field, Switch, Text } from '@/primitives'
|
||||
|
||||
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||
import {
|
||||
@@ -9,78 +9,11 @@ import {
|
||||
import { isSafari } from '@/utils/livekit'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SoundTester } from '@/components/SoundTester'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { ReactNode } from 'react'
|
||||
import { css } from '@/styled-system/css'
|
||||
import posthog from 'posthog-js'
|
||||
import { useNoiseReductionAvailable } from '@/features/rooms/livekit/hooks/useNoiseReductionAvailable'
|
||||
|
||||
type RowWrapperProps = {
|
||||
heading: string
|
||||
children: ReactNode[]
|
||||
beta?: boolean
|
||||
}
|
||||
|
||||
const BetaBadge = () => (
|
||||
<span
|
||||
className={css({
|
||||
content: '"Beta"',
|
||||
display: 'block',
|
||||
letterSpacing: '-0.02rem',
|
||||
padding: '0 0.25rem',
|
||||
backgroundColor: '#E8EDFF',
|
||||
color: '#0063CB',
|
||||
fontSize: '12px',
|
||||
fontWeight: 500,
|
||||
margin: '0 0 0.9375rem 0.3125rem',
|
||||
lineHeight: '1rem',
|
||||
borderRadius: '4px',
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
marginTop: { base: '10px', sm: '5px' },
|
||||
})}
|
||||
>
|
||||
Beta
|
||||
</span>
|
||||
)
|
||||
|
||||
const RowWrapper = ({ heading, children, beta }: RowWrapperProps) => {
|
||||
return (
|
||||
<>
|
||||
<HStack>
|
||||
<H lvl={2}>{heading}</H>
|
||||
{beta && <BetaBadge />}
|
||||
</HStack>
|
||||
<HStack
|
||||
gap={0}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 215px',
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
{children[0]}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '10rem',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
paddingLeft: '1.5rem',
|
||||
}}
|
||||
>
|
||||
{children[1]}
|
||||
</div>
|
||||
</HStack>
|
||||
</>
|
||||
)
|
||||
}
|
||||
import posthog from 'posthog-js'
|
||||
import { RowWrapper } from './layout/RowWrapper'
|
||||
|
||||
export type AudioTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { DialogProps, Field, H } from '@/primitives'
|
||||
import { DialogProps, Field } from '@/primitives'
|
||||
|
||||
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||
import { useMediaDeviceSelect, useRoomContext } from '@livekit/components-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { css } from '@/styled-system/css'
|
||||
import {
|
||||
createLocalVideoTrack,
|
||||
@@ -16,44 +15,7 @@ import {
|
||||
} from 'livekit-client'
|
||||
import { BackgroundProcessorFactory } from '@/features/rooms/livekit/components/blur'
|
||||
import { VideoResolution } from '@/stores/userChoices'
|
||||
|
||||
type RowWrapperProps = {
|
||||
heading: string
|
||||
children: ReactNode[]
|
||||
}
|
||||
|
||||
const RowWrapper = ({ heading, children }: RowWrapperProps) => {
|
||||
return (
|
||||
<>
|
||||
<H lvl={2}>{heading}</H>
|
||||
<HStack
|
||||
gap={0}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 215px',
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
{children[0]}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '10rem',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
paddingLeft: '1.5rem',
|
||||
}}
|
||||
>
|
||||
{children[1]}
|
||||
</div>
|
||||
</HStack>
|
||||
</>
|
||||
)
|
||||
}
|
||||
import { RowWrapper } from './layout/RowWrapper'
|
||||
|
||||
export type VideoTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
@@ -212,104 +174,65 @@ export const VideoTab = ({ id }: VideoTabProps) => {
|
||||
)}
|
||||
</div>
|
||||
</RowWrapper>
|
||||
<H lvl={2}>{t('resolution.heading')}</H>
|
||||
<HStack
|
||||
gap={0}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 215px',
|
||||
minWidth: 0,
|
||||
<RowWrapper heading={t('resolution.heading')}>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('resolution.publish.label')}
|
||||
items={[
|
||||
{
|
||||
value: 'h720',
|
||||
label: `${t('resolution.publish.items.high')} (720p)`,
|
||||
},
|
||||
{
|
||||
value: 'h360',
|
||||
label: `${t('resolution.publish.items.medium')} (360p)`,
|
||||
},
|
||||
{
|
||||
value: 'h180',
|
||||
label: `${t('resolution.publish.items.low')} (180p)`,
|
||||
},
|
||||
]}
|
||||
selectedKey={videoPublishResolution}
|
||||
onSelectionChange={async (key) => {
|
||||
await handleVideoResolutionChange(key as VideoResolution)
|
||||
}}
|
||||
>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('resolution.publish.label')}
|
||||
items={[
|
||||
{
|
||||
value: 'h720',
|
||||
label: `${t('resolution.publish.items.high')} (720p)`,
|
||||
},
|
||||
{
|
||||
value: 'h360',
|
||||
label: `${t('resolution.publish.items.medium')} (360p)`,
|
||||
},
|
||||
{
|
||||
value: 'h180',
|
||||
label: `${t('resolution.publish.items.low')} (180p)`,
|
||||
},
|
||||
]}
|
||||
selectedKey={videoPublishResolution}
|
||||
onSelectionChange={async (key) => {
|
||||
await handleVideoResolutionChange(key as VideoResolution)
|
||||
}}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '10rem',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
paddingLeft: '1.5rem',
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
<HStack
|
||||
gap={0}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 215px',
|
||||
minWidth: 0,
|
||||
<></>
|
||||
</RowWrapper>
|
||||
<RowWrapper>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('resolution.subscribe.label')}
|
||||
items={[
|
||||
{
|
||||
value: VideoQuality.HIGH.toString(),
|
||||
label: t('resolution.subscribe.items.high'),
|
||||
},
|
||||
{
|
||||
value: VideoQuality.MEDIUM.toString(),
|
||||
label: t('resolution.subscribe.items.medium'),
|
||||
},
|
||||
{
|
||||
value: VideoQuality.LOW.toString(),
|
||||
label: t('resolution.subscribe.items.low'),
|
||||
},
|
||||
]}
|
||||
selectedKey={videoSubscribeQuality?.toString()}
|
||||
onSelectionChange={(key) => {
|
||||
if (key == undefined) return
|
||||
const selectedQuality = Number(String(key))
|
||||
saveVideoSubscribeQuality(selectedQuality)
|
||||
updateExistingRemoteVideoQuality(selectedQuality)
|
||||
}}
|
||||
>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('resolution.subscribe.label')}
|
||||
items={[
|
||||
{
|
||||
value: VideoQuality.HIGH.toString(),
|
||||
label: t('resolution.subscribe.items.high'),
|
||||
},
|
||||
{
|
||||
value: VideoQuality.MEDIUM.toString(),
|
||||
label: t('resolution.subscribe.items.medium'),
|
||||
},
|
||||
{
|
||||
value: VideoQuality.LOW.toString(),
|
||||
label: t('resolution.subscribe.items.low'),
|
||||
},
|
||||
]}
|
||||
selectedKey={videoSubscribeQuality?.toString()}
|
||||
onSelectionChange={(key) => {
|
||||
if (key == undefined) return
|
||||
const selectedQuality = Number(String(key))
|
||||
saveVideoSubscribeQuality(selectedQuality)
|
||||
updateExistingRemoteVideoQuality(selectedQuality)
|
||||
}}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '10rem',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
paddingLeft: '1.5rem',
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
<></>
|
||||
</RowWrapper>
|
||||
</TabPanel>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { H } from '@/primitives'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { css } from '@/styled-system/css'
|
||||
|
||||
export type RowWrapperProps = {
|
||||
heading?: string
|
||||
children: ReactNode[]
|
||||
beta?: boolean
|
||||
}
|
||||
|
||||
const BetaBadge = () => (
|
||||
<span
|
||||
className={css({
|
||||
content: '"Beta"',
|
||||
display: 'block',
|
||||
letterSpacing: '-0.02rem',
|
||||
padding: '0 0.25rem',
|
||||
backgroundColor: '#E8EDFF',
|
||||
color: '#0063CB',
|
||||
fontSize: '12px',
|
||||
fontWeight: 500,
|
||||
margin: '0 0 0.9375rem 0.3125rem',
|
||||
lineHeight: '1rem',
|
||||
borderRadius: '4px',
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
marginTop: { base: '10px', sm: '5px' },
|
||||
})}
|
||||
>
|
||||
Beta
|
||||
</span>
|
||||
)
|
||||
|
||||
export const RowWrapper = ({ heading, children, beta }: RowWrapperProps) => {
|
||||
return (
|
||||
<>
|
||||
{heading && (
|
||||
<HStack>
|
||||
<H lvl={2}>{heading}</H>
|
||||
{beta && <BetaBadge />}
|
||||
</HStack>
|
||||
)}
|
||||
<HStack
|
||||
gap={0}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 215px',
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
{children[0]}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '10rem',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
paddingLeft: '1.5rem',
|
||||
}}
|
||||
>
|
||||
{children[1]}
|
||||
</div>
|
||||
</HStack>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user