diff --git a/src/frontend/panda.config.ts b/src/frontend/panda.config.ts
index ed740179..921691c0 100644
--- a/src/frontend/panda.config.ts
+++ b/src/frontend/panda.config.ts
@@ -397,6 +397,12 @@ const config: Config = {
lineHeight: '1.25rem',
},
},
+ xs: {
+ value: {
+ fontSize: '0.825rem',
+ lineHeight: '1.15rem',
+ },
+ },
badge: {
value: {
fontSize: '0.75rem',
diff --git a/src/frontend/src/features/rooms/livekit/components/Info.tsx b/src/frontend/src/features/rooms/livekit/components/Info.tsx
new file mode 100644
index 00000000..a0aadaae
--- /dev/null
+++ b/src/frontend/src/features/rooms/livekit/components/Info.tsx
@@ -0,0 +1,75 @@
+import { useTranslation } from 'react-i18next'
+import { useEffect, useState } from 'react'
+import { VStack } from '@/styled-system/jsx'
+import { css } from '@/styled-system/css'
+import { RiCheckLine, RiFileCopyLine } from '@remixicon/react'
+import { Button, Div, Text } from '@/primitives'
+import { getRouteUrl } from '@/navigation/getRouteUrl'
+import { useRoomData } from '../hooks/useRoomData'
+
+export const Info = () => {
+ const { t } = useTranslation('rooms', { keyPrefix: 'info' })
+
+ const [isCopied, setIsCopied] = useState(false)
+
+ useEffect(() => {
+ if (isCopied) {
+ const timeout = setTimeout(() => setIsCopied(false), 3000)
+ return () => clearTimeout(timeout)
+ }
+ }, [isCopied])
+
+ const data = useRoomData()
+ const roomUrl = getRouteUrl('room', data?.slug)
+
+ return (
+
+
+
+ {t('roomInformation.title')}
+
+
+ {roomUrl}
+
+
+
+
+ )
+}
diff --git a/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx b/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx
index c437123b..57db8dda 100644
--- a/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx
+++ b/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx
@@ -12,6 +12,7 @@ import { Chat } from '../prefabs/Chat'
import { Effects } from './effects/Effects'
import { Admin } from './Admin'
import { Tools } from './Tools'
+import { Info } from './Info'
type StyledSidePanelProps = {
title: string
@@ -133,6 +134,7 @@ export const SidePanel = () => {
isSidePanelOpen,
isToolsOpen,
isAdminOpen,
+ isInfoOpen,
isSubPanelOpen,
activeSubPanelId,
} = useSidePanel()
@@ -167,6 +169,9 @@ export const SidePanel = () => {
+
+
+
)
}
diff --git a/src/frontend/src/features/rooms/livekit/components/controls/InfoToggle.tsx b/src/frontend/src/features/rooms/livekit/components/controls/InfoToggle.tsx
new file mode 100644
index 00000000..2f61921b
--- /dev/null
+++ b/src/frontend/src/features/rooms/livekit/components/controls/InfoToggle.tsx
@@ -0,0 +1,41 @@
+import { useTranslation } from 'react-i18next'
+import { RiInformationLine } from '@remixicon/react'
+import { css } from '@/styled-system/css'
+import { ToggleButton } from '@/primitives'
+import { useSidePanel } from '../../hooks/useSidePanel'
+import { ToggleButtonProps } from '@/primitives/ToggleButton'
+
+export const InfoToggle = ({
+ onPress,
+ ...props
+}: Partial) => {
+ const { t } = useTranslation('rooms', { keyPrefix: 'controls.info' })
+
+ const { isInfoOpen, toggleInfo } = useSidePanel()
+ const tooltipLabel = isInfoOpen ? 'open' : 'closed'
+
+ return (
+
+ {
+ toggleInfo()
+ onPress?.(e)
+ }}
+ data-attr={`controls-info-${tooltipLabel}`}
+ {...props}
+ >
+
+
+
+ )
+}
diff --git a/src/frontend/src/features/rooms/livekit/hooks/useSidePanel.ts b/src/frontend/src/features/rooms/livekit/hooks/useSidePanel.ts
index ed23512e..96b125e9 100644
--- a/src/frontend/src/features/rooms/livekit/hooks/useSidePanel.ts
+++ b/src/frontend/src/features/rooms/livekit/hooks/useSidePanel.ts
@@ -7,6 +7,7 @@ export enum PanelId {
CHAT = 'chat',
TOOLS = 'tools',
ADMIN = 'admin',
+ INFO = 'info',
}
export enum SubPanelId {
@@ -24,6 +25,7 @@ export const useSidePanel = () => {
const isChatOpen = activePanelId == PanelId.CHAT
const isToolsOpen = activePanelId == PanelId.TOOLS
const isAdminOpen = activePanelId == PanelId.ADMIN
+ const isInfoOpen = activePanelId == PanelId.INFO
const isTranscriptOpen = activeSubPanelId == SubPanelId.TRANSCRIPT
const isScreenRecordingOpen = activeSubPanelId == SubPanelId.SCREEN_RECORDING
const isSidePanelOpen = !!activePanelId
@@ -54,6 +56,11 @@ export const useSidePanel = () => {
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
}
+ const toggleInfo = () => {
+ layoutStore.activePanelId = isInfoOpen ? null : PanelId.INFO
+ if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
+ }
+
const openTranscript = () => {
layoutStore.activeSubPanelId = SubPanelId.TRANSCRIPT
layoutStore.activePanelId = PanelId.TOOLS
@@ -72,6 +79,7 @@ export const useSidePanel = () => {
toggleEffects,
toggleTools,
toggleAdmin,
+ toggleInfo,
openTranscript,
openScreenRecording,
isSubPanelOpen,
@@ -81,6 +89,7 @@ export const useSidePanel = () => {
isSidePanelOpen,
isToolsOpen,
isAdminOpen,
+ isInfoOpen,
isTranscriptOpen,
isScreenRecordingOpen,
}
diff --git a/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/MoreOptions.tsx b/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/MoreOptions.tsx
index 8715b95b..811b3a80 100644
--- a/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/MoreOptions.tsx
+++ b/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/MoreOptions.tsx
@@ -2,6 +2,7 @@ import { css } from '@/styled-system/css'
import { ChatToggle } from '../../components/controls/ChatToggle'
import { ParticipantsToggle } from '../../components/controls/Participants/ParticipantsToggle'
import { ToolsToggle } from '../../components/controls/ToolsToggle'
+import { InfoToggle } from '../../components/controls/InfoToggle'
import { AdminToggle } from '../../components/AdminToggle'
import { useSize } from '../../hooks/useResizeObserver'
import { useState, RefObject } from 'react'
@@ -18,6 +19,7 @@ const NavigationControls = ({
tooltipType = 'instant',
}: Partial) => (
<>
+
diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json
index 17c44a96..3cff09c6 100644
--- a/src/frontend/src/locales/de/rooms.json
+++ b/src/frontend/src/locales/de/rooms.json
@@ -91,6 +91,10 @@
}
}
},
+ "info": {
+ "open": "",
+ "closed": ""
+ },
"hand": {
"raise": "",
"lower": ""
@@ -171,7 +175,8 @@
"transcript": "",
"screenRecording": "",
"admin": "",
- "tools": ""
+ "tools": "",
+ "info": ""
},
"content": {
"participants": "",
@@ -180,7 +185,8 @@
"transcript": "",
"screenRecording": "",
"admin": "",
- "tools": ""
+ "tools": "",
+ "info": ""
},
"closeButton": ""
},
@@ -201,6 +207,16 @@
}
}
},
+ "info": {
+ "roomInformation": {
+ "title": "",
+ "button": {
+ "ariaLabel": "",
+ "copy": "",
+ "copied": ""
+ }
+ }
+ },
"transcript": {
"start": {
"heading": "",
diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json
index 739cfa40..0e35f5af 100644
--- a/src/frontend/src/locales/en/rooms.json
+++ b/src/frontend/src/locales/en/rooms.json
@@ -90,6 +90,10 @@
}
}
},
+ "info": {
+ "open": "Hide information",
+ "closed": "Show information"
+ },
"hand": {
"raise": "Raise hand",
"lower": "Lower hand"
@@ -170,7 +174,8 @@
"transcript": "Transcription",
"screenRecording": "Recording",
"admin": "Admin settings",
- "tools": "More tools"
+ "tools": "More tools",
+ "info": "Meeting information"
},
"content": {
"participants": "participants",
@@ -179,7 +184,8 @@
"transcript": "transcription",
"screenRecording": "recording",
"admin": "admin settings",
- "tools": "more tools"
+ "tools": "more tools",
+ "info": "meeting information"
},
"closeButton": "Hide {{content}}"
},
@@ -200,6 +206,16 @@
}
}
},
+ "info": {
+ "roomInformation": {
+ "title": "Connection Information",
+ "button": {
+ "ariaLabel": "Copy your meeting address",
+ "copy": "Copy address",
+ "copied": "Address copied"
+ }
+ }
+ },
"transcript": {
"start": {
"heading": "Transcribe this call",
diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json
index 5f23e211..645f3d4b 100644
--- a/src/frontend/src/locales/fr/rooms.json
+++ b/src/frontend/src/locales/fr/rooms.json
@@ -90,6 +90,10 @@
}
}
},
+ "info": {
+ "open": "Masquer les informations",
+ "closed": "Afficher les informations"
+ },
"hand": {
"raise": "Lever la main",
"lower": "Baisser la main"
@@ -170,7 +174,8 @@
"transcript": "Transcription",
"screenRecording": "Enregistrement",
"admin": "Commandes de l'organisateur",
- "tools": "Plus d'outils"
+ "tools": "Plus d'outils",
+ "info": "Informations sur la réunion"
},
"content": {
"participants": "les participants",
@@ -179,7 +184,8 @@
"transcript": "transcription",
"screenRecording": "enregistrement",
"admin": "commandes de l'organisateur",
- "tools": "plus d'outils"
+ "tools": "plus d'outils",
+ "info": "informations sur la réunion"
},
"closeButton": "Masquer {{content}}"
},
@@ -200,6 +206,16 @@
}
}
},
+ "info": {
+ "roomInformation": {
+ "title": "Informations de connexions",
+ "button": {
+ "ariaLabel": "Copier l'adresse de votre réunion",
+ "copy": "Copier l'adresse",
+ "copied": "Adresse copiée"
+ }
+ }
+ },
"transcript": {
"start": {
"heading": "Transcrire cet appel",
diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json
index da3d8d87..9ee85b85 100644
--- a/src/frontend/src/locales/nl/rooms.json
+++ b/src/frontend/src/locales/nl/rooms.json
@@ -90,6 +90,10 @@
}
}
},
+ "info": {
+ "open": "Informatie verbergen",
+ "closed": "Informatie tonen"
+ },
"hand": {
"raise": "Hand opsteken",
"lower": "Hand laten zakken"
@@ -170,7 +174,8 @@
"transcript": "Transcriptie",
"screenRecording": "Schermopname",
"admin": "Beheerdersbediening",
- "tools": "Meer tools"
+ "tools": "Meer tools",
+ "info": "Vergaderinformatie"
},
"content": {
"participants": "deelnemers",
@@ -179,7 +184,8 @@
"screenRecording": "transcriptie",
"transcript": "schermopname",
"admin": "beheerdersbediening",
- "tools": "meer tools"
+ "tools": "meer tools",
+ "info": "vergaderinformatie"
},
"closeButton": "Verberg {{content}}"
},
@@ -200,6 +206,16 @@
}
}
},
+ "info": {
+ "roomInformation": {
+ "title": "Verbindingsinformatie",
+ "button": {
+ "ariaLabel": "Kopieer je vergaderadres",
+ "copy": "Adres kopiëren",
+ "copied": "Adres gekopieerd"
+ }
+ }
+ },
"transcript": {
"start": {
"heading": "Transcribeer dit gesprek",
diff --git a/src/frontend/src/primitives/Text.tsx b/src/frontend/src/primitives/Text.tsx
index a7de86ef..bd430025 100644
--- a/src/frontend/src/primitives/Text.tsx
+++ b/src/frontend/src/primitives/Text.tsx
@@ -57,6 +57,10 @@ export const text = cva({
color: 'default.subtle-text',
textStyle: 'sm',
},
+ xsNote: {
+ color: 'default.subtle-text',
+ textStyle: 'xs',
+ },
inherits: {},
},
centered: {