Compare commits
12 Commits
fixci
...
transcript-menu
| Author | SHA1 | Date | |
|---|---|---|---|
| 9333d72538 | |||
| 5ecb05ba57 | |||
| f7d07f77a7 | |||
| 7a22831cb9 | |||
| 1a409da941 | |||
| db8626adcc | |||
| eaf2c4d021 | |||
| bad5d1de3f | |||
| 5e31ca727a | |||
| 5f42fcd159 | |||
| 985b621e14 | |||
| d2d66fb8b6 |
@@ -116,10 +116,10 @@ const config: Config = {
|
||||
'80%': { transform: 'rotate(20deg)' },
|
||||
'100%': { transform: 'rotate(0)' },
|
||||
},
|
||||
pulse_mic: {
|
||||
'0%': { color: 'primary', opacity: '1' },
|
||||
'50%': { color: 'primary', opacity: '0.8' },
|
||||
'100%': { color: 'primary', opacity: '1' },
|
||||
pulse_background: {
|
||||
'0%': { opacity: '1' },
|
||||
'50%': { opacity: '0.65' },
|
||||
'100%': { opacity: '1' },
|
||||
},
|
||||
},
|
||||
tokens: defineTokens({
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useConfig } from '@/api/useConfig.ts'
|
||||
|
||||
export const useIsAnalyticsEnabled = () => {
|
||||
const { data } = useConfig()
|
||||
return !!data?.analytics?.id
|
||||
}
|
||||
@@ -121,7 +121,13 @@ const OpenFeedback = ({
|
||||
>
|
||||
{t('submit')}
|
||||
</Button>
|
||||
<Button invisible size="sm" fullWidth onPress={onNext}>
|
||||
<Button
|
||||
invisible
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
fullWidth
|
||||
onPress={onNext}
|
||||
>
|
||||
{t('skip')}
|
||||
</Button>
|
||||
</VStack>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { css } from '@/styled-system/css'
|
||||
import { RiRecordCircleLine } from '@remixicon/react'
|
||||
import { Text } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
|
||||
export const RecordingStateToast = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'recording' })
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
if (!room?.isRecording) return
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
position: 'fixed',
|
||||
top: '10px',
|
||||
left: '10px',
|
||||
paddingY: '0.25rem',
|
||||
paddingX: '0.25rem 0.35rem',
|
||||
backgroundColor: 'primaryDark.200',
|
||||
borderColor: 'primaryDark.400',
|
||||
border: '1px solid',
|
||||
color: 'white',
|
||||
borderRadius: '4px',
|
||||
gap: '0.5rem',
|
||||
})}
|
||||
>
|
||||
<RiRecordCircleLine
|
||||
size={20}
|
||||
className={css({
|
||||
color: 'white',
|
||||
backgroundColor: 'danger.700',
|
||||
padding: '3px',
|
||||
borderRadius: '3px',
|
||||
})}
|
||||
/>
|
||||
<Text variant={'sm'}>{t('label')}</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { useSidePanel } from '../hooks/useSidePanel'
|
||||
import { ReactNode } from 'react'
|
||||
import { Effects } from './Effects'
|
||||
import { Chat } from '../prefabs/Chat'
|
||||
import { Transcript } from './Transcript'
|
||||
|
||||
type StyledSidePanelProps = {
|
||||
title: string
|
||||
@@ -106,6 +107,7 @@ export const SidePanel = () => {
|
||||
isEffectsOpen,
|
||||
isChatOpen,
|
||||
isSidePanelOpen,
|
||||
isTranscriptOpen,
|
||||
} = useSidePanel()
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' })
|
||||
|
||||
@@ -127,6 +129,9 @@ export const SidePanel = () => {
|
||||
<Panel isOpen={isChatOpen}>
|
||||
<Chat />
|
||||
</Panel>
|
||||
<Panel isOpen={isTranscriptOpen}>
|
||||
<Transcript />
|
||||
</Panel>
|
||||
</StyledSidePanel>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Button, Div, H, Text } from '@/primitives'
|
||||
|
||||
import thirdSlide from '@/assets/intro-slider/3_resume.png'
|
||||
import { css } from '@/styled-system/css'
|
||||
|
||||
import { useHasTranscriptAccess } from '../hooks/useHasTranscriptAccess'
|
||||
import { RiRecordCircleLine, RiStopCircleLine } from '@remixicon/react'
|
||||
import { useRoomId } from '@/features/rooms/livekit/hooks/useRoomId'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
import {
|
||||
RecordingMode,
|
||||
useStartRecording,
|
||||
} from '@/features/rooms/api/startRecording'
|
||||
import { useStopRecording } from '@/features/rooms/api/stopRecording'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { RoomEvent } from 'livekit-client'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export const Transcript = () => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'transcript' })
|
||||
|
||||
const hasTranscriptAccess = useHasTranscriptAccess()
|
||||
|
||||
const roomId = useRoomId()
|
||||
|
||||
const { mutateAsync: startRecordingRoom } = useStartRecording()
|
||||
const { mutateAsync: stopRecordingRoom } = useStopRecording()
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
useEffect(() => {
|
||||
const handleRecordingStatusChanged = () => {
|
||||
setIsLoading(false)
|
||||
}
|
||||
room.on(RoomEvent.RecordingStatusChanged, handleRecordingStatusChanged)
|
||||
return () => {
|
||||
room.off(RoomEvent.RecordingStatusChanged, handleRecordingStatusChanged)
|
||||
}
|
||||
}, [room])
|
||||
|
||||
const handleTranscript = async () => {
|
||||
if (!roomId) {
|
||||
console.warn('No room ID found')
|
||||
return
|
||||
}
|
||||
try {
|
||||
setIsLoading(true)
|
||||
if (room.isRecording) {
|
||||
await stopRecordingRoom({ id: roomId })
|
||||
} else {
|
||||
await startRecordingRoom({ id: roomId, mode: RecordingMode.Transcript })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to handle transcript:', error)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasTranscriptAccess) return
|
||||
|
||||
return (
|
||||
<Div
|
||||
display="flex"
|
||||
overflowY="scroll"
|
||||
padding="0 1.5rem"
|
||||
flexGrow={1}
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<img src={thirdSlide} alt={'wip'} />
|
||||
{room.isRecording ? (
|
||||
<>
|
||||
<H lvl={2}>{t('stop.heading')}</H>
|
||||
<Text variant="sm" centered wrap="balance">
|
||||
{t('stop.body')}
|
||||
</Text>
|
||||
<div className={css({ height: '2rem' })} />
|
||||
<Button isDisabled={isLoading} onPress={() => handleTranscript()}>
|
||||
<RiStopCircleLine style={{ marginRight: '0.5rem' }} />{' '}
|
||||
{t('stop.button')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<H lvl={2}>{t('start.heading')}</H>
|
||||
<Text variant="sm" centered wrap="balance">
|
||||
{t('start.body')}
|
||||
</Text>
|
||||
<div className={css({ height: '2rem' })} />
|
||||
<Button isDisabled={isLoading} onPress={() => handleTranscript()}>
|
||||
<RiRecordCircleLine style={{ marginRight: '0.5rem' }} />{' '}
|
||||
{t('start.button')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Div>
|
||||
)
|
||||
}
|
||||
-2
@@ -10,7 +10,6 @@ import { DialogState } from './OptionsButton'
|
||||
import { Separator } from '@/primitives/Separator'
|
||||
import { useSidePanel } from '../../../hooks/useSidePanel'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe.ts'
|
||||
import { TranscriptMenuItem } from './TranscriptMenuItem'
|
||||
|
||||
// @todo try refactoring it to use MenuList component
|
||||
export const OptionsMenuItems = ({
|
||||
@@ -35,7 +34,6 @@ export const OptionsMenuItems = ({
|
||||
<RiAccountBoxLine size={20} />
|
||||
{t('effects')}
|
||||
</MenuItem>
|
||||
<TranscriptMenuItem />
|
||||
</Section>
|
||||
<Separator />
|
||||
<Section>
|
||||
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
import { RiRecordCircleLine, RiStopCircleLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe'
|
||||
import { MenuItem } from 'react-aria-components'
|
||||
import {
|
||||
RecordingMode,
|
||||
useStartRecording,
|
||||
} from '@/features/rooms/api/startRecording'
|
||||
import { useStopRecording } from '@/features/rooms/api/stopRecording'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
|
||||
export const TranscriptMenuItem = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
|
||||
|
||||
const apiRoomData = useRoomData()
|
||||
|
||||
const { mutateAsync: startRecordingRoom } = useStartRecording()
|
||||
const { mutateAsync: stopRecordingRoom } = useStopRecording()
|
||||
|
||||
const { data } = useConfig()
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
const handleTranscript = async () => {
|
||||
const roomId = apiRoomData?.livekit?.room
|
||||
|
||||
if (!roomId) {
|
||||
console.warn('No room ID found')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (room.isRecording) {
|
||||
await stopRecordingRoom({ id: roomId })
|
||||
} else {
|
||||
await startRecordingRoom({ id: roomId, mode: RecordingMode.Transcript })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to handle transcript:', error)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!data?.recording?.is_enabled ||
|
||||
!data?.recording?.available_modes?.includes(RecordingMode.Transcript) ||
|
||||
!apiRoomData?.is_administrable
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
className={menuRecipe({ icon: true }).item}
|
||||
onAction={async () => await handleTranscript()}
|
||||
>
|
||||
{room.isRecording ? (
|
||||
<>
|
||||
<RiRecordCircleLine size={20} />
|
||||
{t('transcript.stop')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RiStopCircleLine size={20} />
|
||||
{t('transcript.start')}
|
||||
</>
|
||||
)}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
+6
-3
@@ -84,9 +84,12 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
||||
<RiMicOffFill color={'gray'} />
|
||||
) : (
|
||||
<RiMicFill
|
||||
style={{
|
||||
animation: isSpeaking ? 'pulse_mic 800ms infinite' : undefined,
|
||||
}}
|
||||
className={css({
|
||||
color: isSpeaking ? 'primaryDark.300' : 'primaryDark.50',
|
||||
animation: isSpeaking
|
||||
? 'pulse_background 800ms infinite'
|
||||
: undefined,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { ToggleButton } from '@/primitives'
|
||||
import { RiBardLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSidePanel } from '../../hooks/useSidePanel'
|
||||
import { useHasTranscriptAccess } from '../../hooks/useHasTranscriptAccess'
|
||||
import { css } from '@/styled-system/css'
|
||||
|
||||
export const TranscriptToggle = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.transcript' })
|
||||
|
||||
const { isTranscriptOpen, toggleTranscript } = useSidePanel()
|
||||
const tooltipLabel = isTranscriptOpen ? 'open' : 'closed'
|
||||
|
||||
const hasTranscriptAccess = useHasTranscriptAccess()
|
||||
|
||||
if (!hasTranscriptAccess) return
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
})}
|
||||
>
|
||||
<ToggleButton
|
||||
square
|
||||
variant="primaryTextDark"
|
||||
aria-label={t(tooltipLabel)}
|
||||
tooltip={t(tooltipLabel)}
|
||||
isSelected={isTranscriptOpen}
|
||||
onPress={() => toggleTranscript()}
|
||||
>
|
||||
<RiBardLine />
|
||||
</ToggleButton>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useFeatureFlagEnabled } from 'posthog-js/react'
|
||||
import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled'
|
||||
import { useIsTranscriptEnabled } from './useIsTranscriptEnabled'
|
||||
import { useIsAdminOrOwner } from './useIsAdminOrOwner'
|
||||
|
||||
export const useHasTranscriptAccess = () => {
|
||||
const featureEnabled = useFeatureFlagEnabled('transcription-summary')
|
||||
const isAnalyticsEnabled = useIsAnalyticsEnabled()
|
||||
const isTranscriptEnabled = useIsTranscriptEnabled()
|
||||
const isAdminOrOwner = useIsAdminOrOwner()
|
||||
|
||||
return (
|
||||
(featureEnabled || !isAnalyticsEnabled) &&
|
||||
isAdminOrOwner &&
|
||||
isTranscriptEnabled
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useRoomData } from './useRoomData'
|
||||
|
||||
export const useIsAdminOrOwner = () => {
|
||||
const apiRoomData = useRoomData()
|
||||
return apiRoomData?.is_administrable
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { RecordingMode } from '@/features/rooms/api/startRecording'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
|
||||
export const useIsTranscriptEnabled = () => {
|
||||
const { data } = useConfig()
|
||||
|
||||
return (
|
||||
data?.recording?.is_enabled &&
|
||||
data?.recording?.available_modes?.includes(RecordingMode.Transcript)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useRoomData } from './useRoomData'
|
||||
|
||||
export const useRoomId = () => {
|
||||
const apiRoomData = useRoomData()
|
||||
return apiRoomData?.livekit?.room
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export enum PanelId {
|
||||
PARTICIPANTS = 'participants',
|
||||
EFFECTS = 'effects',
|
||||
CHAT = 'chat',
|
||||
TRANSCRIPT = 'transcript',
|
||||
}
|
||||
|
||||
export const useSidePanel = () => {
|
||||
@@ -14,6 +15,7 @@ export const useSidePanel = () => {
|
||||
const isParticipantsOpen = activePanelId == PanelId.PARTICIPANTS
|
||||
const isEffectsOpen = activePanelId == PanelId.EFFECTS
|
||||
const isChatOpen = activePanelId == PanelId.CHAT
|
||||
const isTranscriptOpen = activePanelId == PanelId.TRANSCRIPT
|
||||
const isSidePanelOpen = !!activePanelId
|
||||
|
||||
const toggleParticipants = () => {
|
||||
@@ -28,14 +30,20 @@ export const useSidePanel = () => {
|
||||
layoutStore.activePanelId = isEffectsOpen ? null : PanelId.EFFECTS
|
||||
}
|
||||
|
||||
const toggleTranscript = () => {
|
||||
layoutStore.activePanelId = isTranscriptOpen ? null : PanelId.TRANSCRIPT
|
||||
}
|
||||
|
||||
return {
|
||||
activePanelId,
|
||||
toggleParticipants,
|
||||
toggleChat,
|
||||
toggleEffects,
|
||||
toggleTranscript,
|
||||
isChatOpen,
|
||||
isParticipantsOpen,
|
||||
isEffectsOpen,
|
||||
isSidePanelOpen,
|
||||
isTranscriptOpen,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ import { HandToggle } from '../components/controls/HandToggle'
|
||||
import { SelectToggleDevice } from '../components/controls/SelectToggleDevice'
|
||||
import { LeaveButton } from '../components/controls/LeaveButton'
|
||||
import { ScreenShareToggle } from '../components/controls/ScreenShareToggle'
|
||||
import { SupportToggle } from '../components/controls/SupportToggle'
|
||||
import { TranscriptToggle } from '../components/controls/TranscriptToggle'
|
||||
|
||||
import { css } from '@/styled-system/css'
|
||||
import { SupportToggle } from '@/features/rooms/livekit/components/controls/SupportToggle.tsx'
|
||||
|
||||
/** @public */
|
||||
export type ControlBarControls = {
|
||||
@@ -156,6 +158,7 @@ export function ControlBar({
|
||||
>
|
||||
<ChatToggle />
|
||||
<ParticipantsToggle />
|
||||
<TranscriptToggle />
|
||||
<SupportToggle />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,7 @@ import { FocusLayout } from '../components/FocusLayout'
|
||||
import { ParticipantTile } from '../components/ParticipantTile'
|
||||
import { SidePanel } from '../components/SidePanel'
|
||||
import { useSidePanel } from '../hooks/useSidePanel'
|
||||
import { RecordingStateToast } from '../components/RecordingStateToast'
|
||||
|
||||
const LayoutWrapper = styled(
|
||||
'div',
|
||||
@@ -212,6 +213,7 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
|
||||
)}
|
||||
<RoomAudioRenderer />
|
||||
<ConnectionStateToast />
|
||||
<RecordingStateToast />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,6 +71,10 @@
|
||||
"open": "",
|
||||
"closed": ""
|
||||
},
|
||||
"transcript": {
|
||||
"open": "",
|
||||
"closed": ""
|
||||
},
|
||||
"support": ""
|
||||
},
|
||||
"options": {
|
||||
@@ -79,11 +83,7 @@
|
||||
"feedbacks": "",
|
||||
"settings": "",
|
||||
"username": "",
|
||||
"effects": "",
|
||||
"transcript": {
|
||||
"start": "",
|
||||
"stop": ""
|
||||
}
|
||||
"effects": ""
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
@@ -102,18 +102,32 @@
|
||||
"heading": {
|
||||
"participants": "",
|
||||
"effects": "",
|
||||
"chat": ""
|
||||
"chat": "",
|
||||
"transcript": ""
|
||||
},
|
||||
"content": {
|
||||
"participants": "",
|
||||
"effects": "",
|
||||
"chat": ""
|
||||
"chat": "",
|
||||
"transcript": ""
|
||||
},
|
||||
"closeButton": ""
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": ""
|
||||
},
|
||||
"transcript": {
|
||||
"start": {
|
||||
"heading": "",
|
||||
"body": "",
|
||||
"button": ""
|
||||
},
|
||||
"stop": {
|
||||
"heading": "",
|
||||
"body": "",
|
||||
"button": ""
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"submit": "",
|
||||
"question": "",
|
||||
@@ -150,5 +164,8 @@
|
||||
"raisedHands": "",
|
||||
"lowerParticipantHand": "",
|
||||
"lowerParticipantsHand": ""
|
||||
},
|
||||
"recording": {
|
||||
"label": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
"open": "Hide everyone",
|
||||
"closed": "See everyone"
|
||||
},
|
||||
"transcript": {
|
||||
"open": "Hide AI assistant",
|
||||
"closed": "Show AI assistant"
|
||||
},
|
||||
"support": "Support"
|
||||
},
|
||||
"options": {
|
||||
@@ -78,11 +82,7 @@
|
||||
"feedbacks": "Give us feedbacks",
|
||||
"settings": "Settings",
|
||||
"username": "Update Your Name",
|
||||
"effects": "Apply effects",
|
||||
"transcript": {
|
||||
"start": "Start meeting transcription",
|
||||
"stop": "Stop ongoing transcription"
|
||||
}
|
||||
"effects": "Apply effects"
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
@@ -101,18 +101,32 @@
|
||||
"heading": {
|
||||
"participants": "Participants",
|
||||
"effects": "Effects",
|
||||
"chat": "Messages in the chat"
|
||||
"chat": "Messages in the chat",
|
||||
"transcript": "AI Assistant"
|
||||
},
|
||||
"content": {
|
||||
"participants": "participants",
|
||||
"effects": "effects",
|
||||
"chat": "messages"
|
||||
"chat": "messages",
|
||||
"transcript": "AI assistant"
|
||||
},
|
||||
"closeButton": "Hide {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "The messages are visible to participants only at the time they are sent. All messages are deleted at the end of the call."
|
||||
},
|
||||
"transcript": {
|
||||
"start": {
|
||||
"heading": "Start the Assistant!",
|
||||
"body": "The assistant automatically starts recording your meeting audio (limited to 1 hour). At the end, you'll receive a clear and concise summary of the discussion directly via email.",
|
||||
"button": "Start"
|
||||
},
|
||||
"stop": {
|
||||
"heading": "Recording in Progress...",
|
||||
"body": "Your meeting is currently being recorded. You will receive a summary via email once the meeting ends.",
|
||||
"button": "Stop Recording"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"submit": "Submit",
|
||||
"question": "What do you think about the quality of your call?",
|
||||
@@ -149,5 +163,8 @@
|
||||
"raisedHands": "Raised hands",
|
||||
"lowerParticipantHand": "Lower {{name}}'s hand",
|
||||
"lowerParticipantsHand": "Lower all hands"
|
||||
},
|
||||
"recording": {
|
||||
"label": "Recording"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
"open": "Masquer les participants",
|
||||
"closed": "Afficher les participants"
|
||||
},
|
||||
"transcript": {
|
||||
"open": "Masquer l'assistant IA",
|
||||
"closed": "Afficher l'assistant IA"
|
||||
},
|
||||
"support": "Support"
|
||||
},
|
||||
"options": {
|
||||
@@ -78,11 +82,7 @@
|
||||
"feedbacks": "Partager votre avis",
|
||||
"settings": "Paramètres",
|
||||
"username": "Choisir votre nom",
|
||||
"effects": "Appliquer des effets",
|
||||
"transcript": {
|
||||
"start": "Démarrer la transcription",
|
||||
"stop": "Arrêter la transcription en cours"
|
||||
}
|
||||
"effects": "Appliquer des effets"
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
@@ -101,18 +101,32 @@
|
||||
"heading": {
|
||||
"participants": "Participants",
|
||||
"effects": "Effets",
|
||||
"chat": "Messages dans l'appel"
|
||||
"chat": "Messages dans l'appel",
|
||||
"transcript": "Assistant IA"
|
||||
},
|
||||
"content": {
|
||||
"participants": "les participants",
|
||||
"effects": "les effets",
|
||||
"chat": "les messages"
|
||||
"chat": "les messages",
|
||||
"transcript": "l'assistant IA"
|
||||
},
|
||||
"closeButton": "Masquer {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "Les messages sont visibles par les participants uniquement au moment de\nleur envoi. Tous les messages sont supprimés à la fin de l'appel."
|
||||
},
|
||||
"transcript": {
|
||||
"start": {
|
||||
"heading": "Démarrer l'assistant !",
|
||||
"body": "L'assistant démarre automatiquement l'enregistrement sonore de votre réunion (limité à 1h). À la fin, vous recevrez un résumé clair et concis des échanges directement par e-mail.",
|
||||
"button": "Démarrer"
|
||||
},
|
||||
"stop": {
|
||||
"heading": "Enregistrement en cours …",
|
||||
"body": "L'enregistrement de votre réunion est en cours. Vous recevrez un compte-rendu par email une fois la réunion terminée.",
|
||||
"button": "Arrêter l'enregistrement"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"submit": "Envoyer",
|
||||
"question": "Que pensez-vous de la qualité de votre appel ?",
|
||||
@@ -149,5 +163,8 @@
|
||||
"raisedHands": "Mains levées",
|
||||
"lowerParticipantHand": "Baisser la main de {{name}}",
|
||||
"lowerParticipantsHand": "Baisser la main de tous les participants"
|
||||
},
|
||||
"recording": {
|
||||
"label": "Enregistrement"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,14 @@ export const text = cva({
|
||||
textAlign: 'inherit',
|
||||
},
|
||||
},
|
||||
wrap: {
|
||||
balance: {
|
||||
textWrap: 'balance',
|
||||
},
|
||||
pretty: {
|
||||
textWrap: 'pretty',
|
||||
},
|
||||
},
|
||||
bold: {
|
||||
true: {
|
||||
fontWeight: 'bold',
|
||||
|
||||
Reference in New Issue
Block a user