Compare commits

...

6 Commits

Author SHA1 Message Date
lebaudantoine e5e6e266b0 💄(frontend) replace switch text with icons for font-size independence
Replace text elements in switch components with proper icons to eliminate
dependency on font size variations and ensure consistent visual
appearance.

Improves component reliability across different font scaling scenarios
and provides clearer visual indicators that remain legible regardless of
user font preferences or system scaling settings.
2025-09-08 21:47:56 +02:00
lebaudantoine 8f05a987df 💄(frontend) narrow lobby column width on prejoin screen
Reduce lobby column width on prejoin screen for better visual balance
and improved layout proportions.
2025-09-08 21:47:56 +02:00
lebaudantoine cef3e98ec1 🐛(frontend) fix favicon issues with comprehensive icon set for Safari
Add extensive list of favicon formats and sizes to resolve display
issues specifically affecting Safari browser, ensuring proper icon rendering
across all devices and platforms.
2025-09-08 21:47:56 +02:00
lebaudantoine 6b31719b1b (frontend) add quick action to open transcription menu
Implement quick access button to open the transcription menu directly,
providing faster navigation to transcript controls and settings.
2025-09-08 21:47:56 +02:00
lebaudantoine 175a64001a (frontend) add quick action to open recording menu
Implement quick access button to open the recording menu directly,
providing faster navigation to recording controls and settings.
2025-09-08 21:47:56 +02:00
lebaudantoine d46d70e73b 🚸(frontend) display recording duration limit in recording panel
Add information to recording panel indicating maximum recording
duration when time limits are configured to prevent user confusion
and help with session planning.
2025-09-08 21:47:56 +02:00
21 changed files with 139 additions and 32 deletions
+4 -1
View File
@@ -2,7 +2,10 @@
<html lang="en" data-lk-theme="visio-light">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/assets/icon.svg" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%VITE_APP_TITLE%</title>
</head>
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg width="160" height="160" viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.61135 59.6951C5 62.832 5 66.6949 5 73.1656V88.7307C5 96.7588 5 100.773 6.16756 104.366C7.20062 107.546 8.89041 110.472 11.1274 112.957C13.6555 115.765 17.1318 117.772 24.0842 121.786L37.564 129.568C43.7169 133.121 47.1472 135.101 50.4165 136.054V88.0288C50.4165 85.6281 49.1052 83.4192 46.9976 82.2696L5.61135 59.6951Z" fill="#C9191E"/>
<path d="M118.313 66.7489V91.7898C118.313 95.2521 119.818 98.5435 122.436 100.809L140.459 116.406C141.513 117.298 142.608 118.028 143.744 118.596C144.92 119.123 146.056 119.387 147.151 119.387C149.503 119.387 151.389 118.616 152.809 117.075C154.269 115.493 154.999 113.445 154.999 110.93V47.6577C154.999 45.1431 154.269 43.1151 152.809 41.5738C151.389 39.992 149.503 39.2011 147.151 39.2011C146.056 39.2011 144.92 39.4647 143.744 39.992C142.608 40.5193 141.513 41.2494 140.459 42.1822L122.45 57.7172C119.823 59.983 118.313 63.28 118.313 66.7489Z" fill="#000091"/>
<path d="M11.6345 50.7522C11.1333 50.4788 10.6078 50.2937 10.0757 50.1915C10.4114 49.7628 10.7622 49.3452 11.1276 48.9394C13.6558 46.1315 17.132 44.1245 24.0845 40.1105L37.5643 32.3279C44.5167 28.3139 47.993 26.3069 51.6887 25.5213C54.9587 24.8262 58.3383 24.8262 61.6083 25.5213C65.304 26.3069 68.7803 28.3139 75.7327 32.3279L89.0535 40.0187C89.1066 40.0492 89.1597 40.0798 89.2129 40.1105C96.1653 44.1245 99.6416 46.1316 102.17 48.9394C104.407 51.4238 106.096 54.3506 107.13 57.5301C108.297 61.1235 108.297 65.1375 108.297 73.1656V88.7307C108.297 96.7588 108.297 100.773 107.13 104.366C106.096 107.546 104.407 110.473 102.17 112.957C99.6416 115.765 96.1655 117.772 89.2133 121.785C89.1537 121.82 89.0936 121.855 89.0341 121.889L75.7327 129.568C68.7803 133.582 65.304 135.589 61.6083 136.375C61.4564 136.407 61.3043 136.438 61.1519 136.467L61.1519 88.0288C61.1519 81.6997 57.6948 75.8761 52.1386 72.8455L11.6345 50.7522Z" fill="#000091"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

+1
View File
@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
@@ -23,6 +23,8 @@ import posthog from 'posthog-js'
import { useSnapshot } from 'valtio/index'
import { Spinner } from '@/primitives/Spinner'
import { useConfig } from '@/api/useConfig'
import humanizeDuration from 'humanize-duration'
import i18n from 'i18next'
export const ScreenRecordingSidePanel = () => {
const { data } = useConfig()
@@ -189,7 +191,7 @@ export const ScreenRecordingSidePanel = () => {
</H>
<Text
variant="note"
wrap={'pretty'}
wrap="balance"
centered
className={css({
textStyle: 'sm',
@@ -198,7 +200,18 @@ export const ScreenRecordingSidePanel = () => {
marginTop: '0.25rem',
})}
>
{t('start.body')} <br />{' '}
{t('start.body', {
duration_message: data?.recording?.max_duration
? t('durationMessage', {
max_duration: humanizeDuration(
data?.recording?.max_duration,
{
language: i18n.language,
}
),
})
: '',
})}{' '}
{data?.support?.help_article_recording && (
<A href={data.support.help_article_recording} target="_blank">
{t('start.linkMore')}
@@ -25,6 +25,8 @@ import posthog from 'posthog-js'
import { useSnapshot } from 'valtio/index'
import { Spinner } from '@/primitives/Spinner'
import { useConfig } from '@/api/useConfig'
import humanizeDuration from 'humanize-duration'
import i18n from 'i18next'
export const TranscriptSidePanel = () => {
const { data } = useConfig()
@@ -263,7 +265,7 @@ export const TranscriptSidePanel = () => {
</H>
<Text
variant="note"
wrap={'pretty'}
wrap="balance"
centered
className={css({
textStyle: 'sm',
@@ -272,7 +274,18 @@ export const TranscriptSidePanel = () => {
marginTop: '0.25rem',
})}
>
{t('start.body')} <br />{' '}
{t('start.body', {
duration_message: data?.recording?.max_duration
? t('durationMessage', {
max_duration: humanizeDuration(
data?.recording?.max_duration,
{
language: i18n.language,
}
),
})
: '',
})}{' '}
{data?.support?.help_article_transcript && (
<A
href={data.support.help_article_transcript}
@@ -474,7 +474,7 @@ export const Join = ({
width: '100%',
flexDirection: 'column',
flexGrow: 1,
gap: { base: '1rem', sm: '2rem', lg: 0 },
gap: { base: '1rem', sm: '2rem', lg: '2rem' },
lg: {
flexDirection: 'row',
},
@@ -771,7 +771,7 @@ export const Join = ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flex: '0 0 448px',
flex: '0 0 360px',
position: 'relative',
margin: '1rem 1rem 1rem 0.5rem',
})}
@@ -5,6 +5,8 @@ import { SettingsMenuItem } from './SettingsMenuItem'
import { FeedbackMenuItem } from './FeedbackMenuItem'
import { EffectsMenuItem } from './EffectsMenuItem'
import { SupportMenuItem } from './SupportMenuItem'
import { TranscriptMenuItem } from './TranscriptMenuItem'
import { ScreenRecordingMenuItem } from './ScreenRecordingMenuItem'
// @todo try refactoring it to use MenuList component
export const OptionsMenuItems = () => {
@@ -16,6 +18,8 @@ export const OptionsMenuItems = () => {
}}
>
<MenuSection>
<TranscriptMenuItem />
<ScreenRecordingMenuItem />
<FullScreenMenuItem />
<EffectsMenuItem />
</MenuSection>
@@ -0,0 +1,32 @@
import { RiRecordCircleLine } from '@remixicon/react'
import { MenuItem } from 'react-aria-components'
import { useTranslation } from 'react-i18next'
import { menuRecipe } from '@/primitives/menuRecipe'
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
import { RecordingMode, useHasRecordingAccess } from '@/features/recording'
import { FeatureFlags } from '@/features/analytics/enums'
export const ScreenRecordingMenuItem = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
const { isScreenRecordingOpen, openScreenRecording, toggleTools } =
useSidePanel()
const hasScreenRecordingAccess = useHasRecordingAccess(
RecordingMode.ScreenRecording,
FeatureFlags.ScreenRecording
)
if (!hasScreenRecordingAccess) return null
return (
<MenuItem
className={menuRecipe({ icon: true, variant: 'dark' }).item}
onAction={() =>
!isScreenRecordingOpen ? openScreenRecording() : toggleTools()
}
>
<RiRecordCircleLine size={20} />
{t('screenRecording')}
</MenuItem>
)
}
@@ -0,0 +1,29 @@
import { RiFileTextLine } from '@remixicon/react'
import { MenuItem } from 'react-aria-components'
import { useTranslation } from 'react-i18next'
import { menuRecipe } from '@/primitives/menuRecipe'
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
import { RecordingMode, useHasRecordingAccess } from '@/features/recording'
import { FeatureFlags } from '@/features/analytics/enums'
export const TranscriptMenuItem = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
const { isTranscriptOpen, openTranscript, toggleTools } = useSidePanel()
const hasTranscriptAccess = useHasRecordingAccess(
RecordingMode.Transcript,
FeatureFlags.Transcript
)
if (!hasTranscriptAccess) return null
return (
<MenuItem
className={menuRecipe({ icon: true, variant: 'dark' }).item}
onAction={() => (!isTranscriptOpen ? openTranscript() : toggleTools())}
>
<RiFileTextLine size={20} />
{t('transcript')}
</MenuItem>
)
}
+8 -4
View File
@@ -206,6 +206,8 @@
"items": {
"feedback": "Feedback geben",
"settings": "Einstellungen",
"screenRecording": "Aufzeichnung",
"transcript": "Transkription",
"username": "Ihren Namen aktualisieren",
"effects": "Effekte anwenden",
"switchCamera": "Kamera wechseln",
@@ -303,7 +305,7 @@
"transcript": {
"start": {
"heading": "Dieses Gespräch transkribieren",
"body": "Dieses Gespräch automatisch transkribieren und die Zusammenfassung in Docs erhalten.",
"body": "Dieses Gespräch automatisch transkribieren {{duration_message}} und die Zusammenfassung in Docs erhalten.",
"button": "Transkription starten",
"loading": "Transkription wird gestartet",
"linkMore": "Mehr erfahren"
@@ -334,12 +336,13 @@
"start": "Die Transkription konnte nicht gestartet werden. Bitte versuche es in einem Moment erneut."
},
"button": "OK"
}
},
"durationMessage": "(begrenzt auf {{max_duration}}) "
},
"screenRecording": {
"start": {
"heading": "Dieses Gespräch aufzeichnen",
"body": "Zeichne dieses Gespräch auf, um es später anzusehen. Du erhältst die Videoaufnahme per E-Mail.",
"body": "Zeichne dieses Gespräch auf, um es später anzusehen {{duration_message}}. Du erhältst die Videoaufnahme per E-Mail.",
"button": "Aufzeichnung starten",
"loading": "Aufzeichnung wird gestartet",
"linkMore": "Mehr erfahren"
@@ -365,7 +368,8 @@
"start": "Die Aufzeichnung konnte nicht gestartet werden. Bitte versuche es in einem Moment erneut."
},
"button": "OK"
}
},
"durationMessage": "(begrenzt auf {{max_duration}})"
},
"admin": {
"description": "Diese Einstellungen für Organisatoren ermöglichen dir die Kontrolle über dein Meeting. Nur Organisatoren haben Zugriff auf diese Optionen.",
+8 -4
View File
@@ -206,6 +206,8 @@
"items": {
"feedback": "Give us feedback",
"settings": "Settings",
"screenRecording": "Screen recording",
"transcript": "Transcription",
"username": "Update Your Name",
"effects": "Apply effects",
"switchCamera": "Switch camera",
@@ -303,7 +305,7 @@
"transcript": {
"start": {
"heading": "Transcribe this call",
"body": "Automatically transcribe this call and receive the summary in Docs.",
"body": "Automatically transcribe this call {{duration_message}} and receive the summary in Docs.",
"button": "Start transcription",
"loading": "Transcription starting",
"linkMore": "Learn more"
@@ -334,12 +336,13 @@
"start": "We were unable to start the transcription. Please try again in a moment."
},
"button": "OK"
}
},
"durationMessage": "(limited to {{max_duration}}) "
},
"screenRecording": {
"start": {
"heading": "Record this call",
"body": "Record this call to watch it later and receive the video recording by email.",
"body": "Record this call to watch it later {{duration_message}} and receive the video recording by email.",
"button": "Start recording",
"loading": "Recording starting",
"linkMore": "Learn more"
@@ -365,7 +368,8 @@
"start": "We were unable to start the recording. Please try again in a moment."
},
"button": "OK"
}
},
"durationMessage": "(limited to {{max_duration}}) "
},
"admin": {
"description": "These organizer settings allow you to maintain control of your meeting. Only organizers can access these controls.",
+8 -4
View File
@@ -206,6 +206,8 @@
"items": {
"feedback": "Partager votre avis",
"settings": "Paramètres",
"screenRecording": "Enregistrement",
"transcript": "Transcription",
"username": "Choisir votre nom",
"effects": "Effets d'arrière-plan",
"switchCamera": "Changer de caméra",
@@ -303,7 +305,7 @@
"transcript": {
"start": {
"heading": "Transcrire cet appel",
"body": "Transcrivez cet appel automatiquement et recevez le compte rendu dans Docs.",
"body": "Transcrivez cet appel automatiquement {{duration_message}} et recevez le compte rendu dans Docs.",
"button": "Démarrer la transcription",
"loading": "Démarrage de la transcription",
"linkMore": "En savoir plus"
@@ -334,12 +336,13 @@
"start": "Nous n'avons pas pu démarrer la transcription. Veuillez réessayer dans quelques instants."
},
"button": "OK"
}
},
"durationMessage": "(limité à {{max_duration}}) "
},
"screenRecording": {
"start": {
"heading": "Enregistrer cet appel",
"body": "Enregistrez cet appel pour plus tard et recevez l'enregistrement vidéo par mail.",
"body": "Enregistrez cet appel pour plus tard {{duration_message}} et recevez l'enregistrement vidéo par mail.",
"button": "Démarrer l'enregistrement",
"loading": "Démarrage de l'enregistrement",
"linkMore": "En savoir plus"
@@ -365,7 +368,8 @@
"start": "Nous n'avons pas pu démarrer l'enregistrement. Veuillez réessayer dans quelques instants."
},
"button": "OK"
}
},
"durationMessage": "(limité à {{max_duration}}) "
},
"admin": {
"description": "Ces paramètres organisateur vous permettent de garder le contrôle de votre réunion. Seuls les organisateurs peuvent accéder à ces commandes.",
+8 -4
View File
@@ -206,6 +206,8 @@
"items": {
"feedback": "Geef ons feedback",
"settings": "Instellingen",
"transcript": "Transcriptie",
"screenRecording": "Schermopname",
"username": "Verander uw naam",
"effects": "Pas effecten toe",
"switchCamera": "Selecteer camera",
@@ -303,7 +305,7 @@
"transcript": {
"start": {
"heading": "Transcribeer dit gesprek",
"body": "Transcribeer dit gesprek automatisch en ontvang het verslag in Docs.",
"body": "Transcribeer dit gesprek automatisch {{duration_message}} en ontvang het verslag in Docs.",
"button": "Transcriptie starten",
"loading": "Transcriptie begint",
"linkMore": "Meer informatie"
@@ -334,12 +336,13 @@
"start": "We konden de transcriptie niet starten. Probeer het over enkele ogenblikken opnieuw."
},
"button": "Opnieuw proberen"
}
},
"durationMessage": "(beperkt tot {{max_duration}}) "
},
"screenRecording": {
"start": {
"heading": "Dit gesprek opnemen",
"body": "Neem dit gesprek op om het later terug te kijken. Je ontvangt de video-opname per e-mail.",
"body": "Neem dit gesprek op om het later terug te kijken {{duration_message}}. Je ontvangt de video-opname per e-mail.",
"button": "Opname starten",
"loading": "Opname gestarten",
"linkMore": "Meer informatie"
@@ -365,7 +368,8 @@
"start": "We konden de opname niet starten. Probeer het over enkele ogenblikken opnieuw."
},
"button": "Opnieuw proberen"
}
},
"durationMessage": "(beperkt tot {{max_duration}})"
},
"admin": {
"description": "Deze organisatorinstellingen geven u controle over uw vergadering. Alleen organisatoren hebben toegang tot deze bedieningselementen.",
+5 -4
View File
@@ -4,6 +4,7 @@ import {
} from 'react-aria-components'
import { styled } from '@/styled-system/jsx'
import { StyledVariantProps } from '@/styled-system/types'
import { RiCheckLine, RiCloseFill } from '@remixicon/react'
export const StyledSwitch = styled(RACSwitch, {
base: {
@@ -37,7 +38,7 @@ export const StyledSwitch = styled(RACSwitch, {
position: 'absolute',
display: 'block',
top: '50%',
right: '0.25rem',
right: '0.1rem',
transform: 'translateY(-50%)',
color: 'primary.800',
fontSize: '0.75rem',
@@ -50,7 +51,7 @@ export const StyledSwitch = styled(RACSwitch, {
position: 'absolute',
display: 'block',
top: '50%',
left: '0.375rem',
left: '0.13rem',
transform: 'translateY(-50%)',
color: 'white',
fontSize: '0.70rem',
@@ -110,10 +111,10 @@ export const Switch = ({ children, ...props }: SwitchProps) => (
<>
<div className="indicator">
<span className="checkmark" aria-hidden="true">
<RiCheckLine size={16} />
</span>
<span className="cross" aria-hidden="true">
<RiCloseFill size={16} />
</span>
</div>
{typeof children === 'function' ? children(renderProps) : children}