mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-31 12:47:58 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 823994fc62 | |||
| cfffadc780 | |||
| 4ae31b3297 | |||
| 954991c7c3 | |||
| 6e2a7f0ca6 | |||
| 24404e4ea2 | |||
| f18d784615 | |||
| 1bfe6b8977 |
@@ -8,6 +8,17 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- 📱(frontend) collapse mobile control bar items on narrow viewports
|
||||
- 📱(frontend) stack idle modal buttons in a column on mobile
|
||||
- 📱(frontend) improve feedback screen responsiveness on mobile
|
||||
- ⬆️(frontend) upgrade @fontsource-variable/atkinson-hyperlegible-next
|
||||
- ⬆️(frontend) upgrade i18next-resources-to-backend from 1.2.1 to 1.2.3
|
||||
- ⬆️(frontend) upgrade @tanstack/react-query from 5.101.1 to 5.101.4
|
||||
|
||||
## [1.28.0] - 2026-08-24
|
||||
|
||||
### Added
|
||||
|
||||
- 📈(frontend) track errors when starting or stopping a recording
|
||||
@@ -35,6 +46,7 @@ and this project adheres to
|
||||
- 🐛(frontend) handle device-in-use errors on Chrome / Windows 10
|
||||
- 🐛(frontend) handle Firefox/Windows AbortError on device start
|
||||
- 🐛(frontend) treat "Timeout starting source" AbortError as device-in-use
|
||||
- 🔇(frontend) suppress leaked WebSocket error events from livekit-client
|
||||
|
||||
## [1.27.0] - 2026-08-14
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
[project]
|
||||
name = "agents"
|
||||
version = "1.27.0"
|
||||
version = "1.28.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"livekit-agents==1.6.7",
|
||||
|
||||
Generated
+1
-1
@@ -9,7 +9,7 @@ resolution-markers = [
|
||||
|
||||
[[package]]
|
||||
name = "agents"
|
||||
version = "1.27.0"
|
||||
version = "1.28.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "livekit-agents" },
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "uv_build"
|
||||
|
||||
[project]
|
||||
name = "meet"
|
||||
version = "1.27.0"
|
||||
version = "1.28.0"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
Generated
+1
-1
@@ -1187,7 +1187,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "meet"
|
||||
version = "1.27.0"
|
||||
version = "1.28.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
|
||||
Generated
+19
-18
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "meet",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "meet",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"dependencies": {
|
||||
"@fontsource-variable/atkinson-hyperlegible-next": "5.2.6",
|
||||
"@fontsource-variable/atkinson-hyperlegible-next": "5.3.0",
|
||||
"@fontsource-variable/lexend": "5.2.11",
|
||||
"@fontsource/opendyslexic": "5.2.5",
|
||||
"@libreaudio/la-call": "0.1.4",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@pandacss/preset-panda": "1.11.3",
|
||||
"@react-types/overlays": "3.10.0",
|
||||
"@remixicon/react": "4.9.0",
|
||||
"@tanstack/react-query": "5.101.1",
|
||||
"@tanstack/react-query": "5.101.4",
|
||||
"@timephy/rnnoise-wasm": "1.0.0",
|
||||
"crisp-sdk-web": "1.1.2",
|
||||
"hoofd": "1.7.3",
|
||||
@@ -27,7 +27,7 @@
|
||||
"i18next": "26.3.6",
|
||||
"i18next-browser-languagedetector": "8.2.1",
|
||||
"i18next-parser": "9.4.0",
|
||||
"i18next-resources-to-backend": "1.2.1",
|
||||
"i18next-resources-to-backend": "1.2.3",
|
||||
"livekit-client": "2.21.0",
|
||||
"posthog-js": "1.404.1",
|
||||
"react": "18.3.1",
|
||||
@@ -767,9 +767,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@fontsource-variable/atkinson-hyperlegible-next": {
|
||||
"version": "5.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource-variable/atkinson-hyperlegible-next/-/atkinson-hyperlegible-next-5.2.6.tgz",
|
||||
"integrity": "sha512-D0Z8peFkRGYACvmWp8Sl8YPGYLBEJbzqapugtsMEYSUUtpQDiZVDHjk9s7bqB4hSCRYCrKuW6V1V+mnHybVnPw==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource-variable/atkinson-hyperlegible-next/-/atkinson-hyperlegible-next-5.3.0.tgz",
|
||||
"integrity": "sha512-UnLzNUy1RWoLDfydAatP4NaRm99X/WbQEph7q/PymJnCFIOOwKOx3pBmp5ys8trO0dM+CKGuJgeZP9fAR4mQpA==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
@@ -2414,9 +2414,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.101.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.1.tgz",
|
||||
"integrity": "sha512-Y6Y92dkXtNqx67m2pMSxUsA3zOCwv862JexZRP8/EPwvKXMPu9m8rv43spiXWzOUIggQ3SQApttALStzhA8B4g==",
|
||||
"version": "5.101.4",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.4.tgz",
|
||||
"integrity": "sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -2435,12 +2435,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.101.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.1.tgz",
|
||||
"integrity": "sha512-ZnONUuQKJe1bJMStXUL1s5uKN9FcfC28j5cK+iDZcdSHtUv1wtin1cGc/Oewhf2Oc4eKY7lggtpvT/AbMmhHew==",
|
||||
"version": "5.101.4",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.4.tgz",
|
||||
"integrity": "sha512-yRg2pfOCxIs4ZJW3XYYHU/WgtD04FHSnfHlpRT7h7pR77hwkdRG4wxbKe4aq6P0RvXUTBSQpQeadS1SUYUe+KA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.101.1"
|
||||
"@tanstack/query-core": "5.101.4"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -6975,9 +6975,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-resources-to-backend": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next-resources-to-backend/-/i18next-resources-to-backend-1.2.1.tgz",
|
||||
"integrity": "sha512-okHbVA+HZ7n1/76MsfhPqDou0fptl2dAlhRDu2ideXloRRduzHsqDOznJBef+R3DFZnbvWoBW+KxJ7fnFjd6Yw==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/i18next-resources-to-backend/-/i18next-resources-to-backend-1.2.3.tgz",
|
||||
"integrity": "sha512-8Y/LLAm5fqZc2ckQxtTWbu75ndjNLzF7mcYl6rhc4g+WBopIsG3YhdYqF5qhJy64tlYhlU2KSSnEgW3gGHLqwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "meet",
|
||||
"private": true,
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "panda codegen && vite",
|
||||
@@ -15,7 +15,7 @@
|
||||
"check": "prettier --check ./src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/atkinson-hyperlegible-next": "5.2.6",
|
||||
"@fontsource-variable/atkinson-hyperlegible-next": "5.3.0",
|
||||
"@fontsource-variable/lexend": "5.2.11",
|
||||
"@fontsource/opendyslexic": "5.2.5",
|
||||
"@libreaudio/la-call": "0.1.4",
|
||||
@@ -26,7 +26,7 @@
|
||||
"@pandacss/preset-panda": "1.11.3",
|
||||
"@react-types/overlays": "3.10.0",
|
||||
"@remixicon/react": "4.9.0",
|
||||
"@tanstack/react-query": "5.101.1",
|
||||
"@tanstack/react-query": "5.101.4",
|
||||
"@timephy/rnnoise-wasm": "1.0.0",
|
||||
"crisp-sdk-web": "1.1.2",
|
||||
"hoofd": "1.7.3",
|
||||
@@ -34,7 +34,7 @@
|
||||
"i18next": "26.3.6",
|
||||
"i18next-browser-languagedetector": "8.2.1",
|
||||
"i18next-parser": "9.4.0",
|
||||
"i18next-resources-to-backend": "1.2.1",
|
||||
"i18next-resources-to-backend": "1.2.3",
|
||||
"livekit-client": "2.21.0",
|
||||
"posthog-js": "1.404.1",
|
||||
"react": "18.3.1",
|
||||
|
||||
@@ -2,6 +2,12 @@ import type { CaptureResult } from 'posthog-js'
|
||||
|
||||
const IGNORED_EXCEPTION_PATTERNS = [
|
||||
/ResizeObserver loop (completed with undelivered notifications|limit exceeded)/,
|
||||
// livekit-client leaks the raw WebSocket error Event as an unhandled
|
||||
// rejection when the signal ws errors after connect (Firefox-heavy,
|
||||
// coincides with signal reconnects). Carries zero diagnostic content —
|
||||
// the close reason is already logged by the SDK.
|
||||
// See: https://github.com/livekit/client-sdk-js/issues/2062
|
||||
/^Event captured as exception with keys: isTrusted$/,
|
||||
]
|
||||
|
||||
const shouldIgnoreException = (value: unknown): boolean =>
|
||||
|
||||
@@ -13,7 +13,7 @@ const controlBarRegion = cva({
|
||||
mobile: {
|
||||
true: {
|
||||
justifyContent: 'center',
|
||||
width: '330px',
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiEmotionLine } from '@remixicon/react'
|
||||
import { ToggleButton } from '@/primitives'
|
||||
@@ -7,6 +6,8 @@ import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKey
|
||||
import { REACTIONS_TOOLBAR_ID } from '../constants'
|
||||
import { useReactionsToolbar } from '../hooks/useReactionsToolbar'
|
||||
import { layoutStore } from '@/stores/layout'
|
||||
import { type ButtonRecipeProps } from '@/primitives/buttonRecipe'
|
||||
import { ToggleButtonProps } from '@/primitives/ToggleButton'
|
||||
|
||||
const focusReactionsToolbar = () => {
|
||||
document
|
||||
@@ -17,35 +18,44 @@ const focusReactionsToolbar = () => {
|
||||
|
||||
export const REACTIONS_TOGGLE_ID = 'reactions-toggle'
|
||||
|
||||
export const ReactionsToggle = () => {
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
export const reactionShortcutHandler = () => {
|
||||
if (layoutStore.showReactionsToolbar) {
|
||||
focusReactionsToolbar()
|
||||
} else {
|
||||
layoutStore.showReactionsToolbar = true
|
||||
}
|
||||
}
|
||||
|
||||
type Props = Pick<NonNullable<ButtonRecipeProps>, 'variant'> & ToggleButtonProps
|
||||
|
||||
export const ReactionsToggle = ({
|
||||
variant = 'primaryDark',
|
||||
onPress,
|
||||
...props
|
||||
}: Props) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
|
||||
|
||||
const { isOpen, toggle } = useReactionsToolbar()
|
||||
|
||||
const handleShortcut = useCallback(() => {
|
||||
if (layoutStore.showReactionsToolbar) {
|
||||
focusReactionsToolbar()
|
||||
} else {
|
||||
layoutStore.showReactionsToolbar = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
useRegisterKeyboardShortcut({
|
||||
id: 'reaction',
|
||||
handler: handleShortcut,
|
||||
handler: reactionShortcutHandler,
|
||||
})
|
||||
|
||||
return (
|
||||
<ToggleButton
|
||||
{...props}
|
||||
id={REACTIONS_TOGGLE_ID}
|
||||
data-attr="reactions-toggle"
|
||||
square
|
||||
variant="primaryDark"
|
||||
variant={variant}
|
||||
aria-label={t('button')}
|
||||
aria-expanded={isOpen}
|
||||
tooltip={t('button')}
|
||||
isSelected={isOpen}
|
||||
onChange={toggle}
|
||||
onPress={onPress}
|
||||
>
|
||||
<RiEmotionLine />
|
||||
</ToggleButton>
|
||||
|
||||
@@ -15,7 +15,8 @@ const Card = styled('div', {
|
||||
marginTop: '1.5rem',
|
||||
borderRadius: '0.25rem',
|
||||
boxShadow: '',
|
||||
minWidth: '380px',
|
||||
width: '100%',
|
||||
maxWidth: '380px',
|
||||
minHeight: '196px',
|
||||
},
|
||||
})
|
||||
@@ -37,8 +38,11 @@ const ratingButtonRecipe = cva({
|
||||
color: 'initial',
|
||||
border: 'none',
|
||||
borderRadius: 0,
|
||||
padding: '0.5rem 0.85rem',
|
||||
padding: { base: '0.5rem 0.25rem', xsm: '0.5rem 0.85rem' },
|
||||
flexGrow: '1',
|
||||
flexBasis: 0,
|
||||
minWidth: 0,
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
variants: {
|
||||
@@ -99,7 +103,9 @@ const OpenFeedback = ({
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<H lvl={3}>{t('question')}</H>
|
||||
<H lvl={3} centered>
|
||||
{t('question')}
|
||||
</H>
|
||||
<TextArea
|
||||
id="feedbackInput"
|
||||
name="feedback"
|
||||
@@ -168,7 +174,9 @@ const RateQuality = ({
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<H lvl={3}>{t('question')}</H>
|
||||
<H lvl={3} centered>
|
||||
{t('question')}
|
||||
</H>
|
||||
<Bar>
|
||||
{[...Array(maxRating)].map((_, index) => (
|
||||
<RACButton
|
||||
@@ -228,7 +236,9 @@ const ConfirmationMessage = ({ onNext }: { onNext: () => void }) => {
|
||||
}}
|
||||
>
|
||||
<VStack gap={0}>
|
||||
<H lvl={3}>{t('heading')}</H>
|
||||
<H lvl={3} centered>
|
||||
{t('heading')}
|
||||
</H>
|
||||
<Text as="p" variant="paragraph" centered>
|
||||
{t('body')}
|
||||
</Text>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { connectionObserverStore } from '@/stores/connectionObserver'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { Stack } from '@/styled-system/jsx'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { navigateTo } from '@/navigation/navigateTo'
|
||||
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
|
||||
@@ -134,7 +134,11 @@ export const IsIdleDisconnectModal = () => {
|
||||
</H>
|
||||
<Description />
|
||||
<Settings />
|
||||
<HStack marginTop="2rem">
|
||||
<Stack
|
||||
direction={{ base: 'column', xsm: 'row' }}
|
||||
align={{ base: 'stretch', xsm: 'center' }}
|
||||
marginTop="2rem"
|
||||
>
|
||||
<Button
|
||||
onPress={() => {
|
||||
connectionObserverStore.isIdleDisconnectModalOpen = false
|
||||
@@ -148,7 +152,7 @@ export const IsIdleDisconnectModal = () => {
|
||||
<Button onPress={close} size="sm" variant="primary">
|
||||
{t('stayButton')}
|
||||
</Button>
|
||||
</HStack>
|
||||
</Stack>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -10,10 +10,18 @@ import {
|
||||
showLowerHandToast,
|
||||
} from '@/features/notifications/utils'
|
||||
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
|
||||
import { type ButtonRecipeProps } from '@/primitives/buttonRecipe'
|
||||
import { ToggleButtonProps } from '@/primitives/ToggleButton'
|
||||
|
||||
const SPEAKING_DETECTION_DELAY = 3000
|
||||
|
||||
export const HandToggle = () => {
|
||||
type Props = Pick<NonNullable<ButtonRecipeProps>, 'variant'> & ToggleButtonProps
|
||||
|
||||
export const HandToggle = ({
|
||||
variant = 'primaryDark',
|
||||
onPress,
|
||||
...props
|
||||
}: Props) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.hand' })
|
||||
|
||||
const room = useRoomContext()
|
||||
@@ -74,12 +82,16 @@ export const HandToggle = () => {
|
||||
})}
|
||||
>
|
||||
<ToggleButton
|
||||
{...props}
|
||||
square
|
||||
variant="primaryDark"
|
||||
variant={variant}
|
||||
aria-label={t(tooltipLabel)}
|
||||
tooltip={t(tooltipLabel)}
|
||||
isSelected={isHandRaised}
|
||||
onPress={handleToggle}
|
||||
onPress={(e) => {
|
||||
handleToggle()
|
||||
onPress?.(e)
|
||||
}}
|
||||
data-attr={`controls-hand-${tooltipLabel}`}
|
||||
>
|
||||
<RiHand />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { supportsScreenSharing } from '@livekit/components-core'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { ControlBarAuxProps } from './ControlBar'
|
||||
import React from 'react'
|
||||
import React, { useLayoutEffect, useRef, useState } from 'react'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { LeaveButton } from '../../components/controls/LeaveButton'
|
||||
import { Track } from 'livekit-client'
|
||||
@@ -26,7 +26,26 @@ import { AudioDevicesControl } from '../../components/controls/Device/AudioDevic
|
||||
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
|
||||
import { openSettingsDialog } from '@/stores/settings'
|
||||
import { ControlBarRegion } from '@/features/layout/components/ControlBarRegion'
|
||||
import { ReactionsToggle } from '@/features/reactions/components/ReactionsToggle'
|
||||
import {
|
||||
ReactionsToggle,
|
||||
reactionShortcutHandler,
|
||||
} from '@/features/reactions/components/ReactionsToggle'
|
||||
import { useSize } from '../../hooks/useResizeObserver'
|
||||
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
|
||||
import { useRaisedHand } from '@/features/rooms/livekit/hooks/useRaisedHand'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
|
||||
// Hand collapses first, then reactions; hidden toggles move into the menu.
|
||||
const COLLAPSIBLE_COUNT = 2
|
||||
|
||||
// Layout-neutral measuring wrapper: inherits the region's gap and refuses to
|
||||
// flex-shrink so measured widths are natural content widths.
|
||||
const measuredRow = css({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 'inherit',
|
||||
flexShrink: 0,
|
||||
})
|
||||
|
||||
export function MobileControlBar({
|
||||
onDeviceError,
|
||||
@@ -36,50 +55,107 @@ export function MobileControlBar({
|
||||
const browserSupportsScreenSharing = supportsScreenSharing()
|
||||
const { toggleEffects } = useSidePanel()
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const { width } = useSize(containerRef)
|
||||
const barRef = useRef<HTMLDivElement>(null)
|
||||
const { width: barWidth } = useSize(barRef)
|
||||
const collapsibleRef = useRef<HTMLDivElement>(null)
|
||||
const { width: collapsibleWidth } = useSize(collapsibleRef)
|
||||
|
||||
const [hiddenCount, setHiddenCount] = useState(0)
|
||||
const calibration = useRef<{ essential: number; slot: number }>()
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (hiddenCount === 0 && collapsibleWidth > 0 && barRef.current) {
|
||||
const gap = parseFloat(getComputedStyle(barRef.current).columnGap) || 0
|
||||
calibration.current = {
|
||||
essential: barWidth - collapsibleWidth - gap,
|
||||
slot: (collapsibleWidth + gap) / COLLAPSIBLE_COUNT,
|
||||
}
|
||||
}
|
||||
if (!calibration.current || width <= 0) return
|
||||
const { essential, slot } = calibration.current
|
||||
const fits = Math.floor((width - essential) / slot)
|
||||
const next = Math.min(
|
||||
COLLAPSIBLE_COUNT,
|
||||
Math.max(0, COLLAPSIBLE_COUNT - fits)
|
||||
)
|
||||
if (next !== hiddenCount) setHiddenCount(next)
|
||||
}, [barWidth, collapsibleWidth, hiddenCount, width, setHiddenCount])
|
||||
|
||||
const hideHand = hiddenCount >= 1
|
||||
const hideReactions = hiddenCount >= 2
|
||||
|
||||
const room = useRoomContext()
|
||||
const { toggleRaisedHand } = useRaisedHand({
|
||||
participant: room.localParticipant,
|
||||
})
|
||||
useRegisterKeyboardShortcut({
|
||||
id: 'raise-hand',
|
||||
handler: toggleRaisedHand,
|
||||
})
|
||||
useRegisterKeyboardShortcut({
|
||||
id: 'reaction',
|
||||
handler: reactionShortcutHandler,
|
||||
})
|
||||
|
||||
const { data } = useConfig()
|
||||
|
||||
const closeMenu = () => setIsMenuOpened(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={css({
|
||||
width: '100vw',
|
||||
display: 'flex',
|
||||
padding: '1.125rem',
|
||||
justifyContent: 'center',
|
||||
})}
|
||||
>
|
||||
<ControlBarRegion mobile>
|
||||
<LeaveButton />
|
||||
<AudioDevicesControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Microphone, error })
|
||||
}
|
||||
hideMenu={true}
|
||||
/>
|
||||
<VideoDeviceControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Camera, error })
|
||||
}
|
||||
hideMenu={true}
|
||||
/>
|
||||
<ReactionsToggle />
|
||||
<HandToggle />
|
||||
<Button
|
||||
id="room-options-trigger"
|
||||
square
|
||||
variant="primaryDark"
|
||||
aria-label={t('options.buttonLabel')}
|
||||
tooltip={t('options.buttonLabel')}
|
||||
onPress={() => setIsMenuOpened(true)}
|
||||
>
|
||||
<RiMore2Line />
|
||||
</Button>
|
||||
</ControlBarRegion>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={css({
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
})}
|
||||
>
|
||||
<ControlBarRegion mobile>
|
||||
<div ref={barRef} className={measuredRow}>
|
||||
<LeaveButton />
|
||||
<AudioDevicesControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Microphone, error })
|
||||
}
|
||||
hideMenu={true}
|
||||
/>
|
||||
<VideoDeviceControl
|
||||
onDeviceError={(error) =>
|
||||
onDeviceError?.({ source: Track.Source.Camera, error })
|
||||
}
|
||||
hideMenu={true}
|
||||
/>
|
||||
{/* Unmounted when empty so it doesn't leave a stray gap. */}
|
||||
{!hideReactions && (
|
||||
<div ref={collapsibleRef} className={measuredRow}>
|
||||
<ReactionsToggle />
|
||||
{!hideHand && <HandToggle />}
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
id="room-options-trigger"
|
||||
square
|
||||
variant="primaryDark"
|
||||
aria-label={t('options.buttonLabel')}
|
||||
tooltip={t('options.buttonLabel')}
|
||||
onPress={() => setIsMenuOpened(true)}
|
||||
>
|
||||
<RiMore2Line />
|
||||
</Button>
|
||||
</div>
|
||||
</ControlBarRegion>
|
||||
</div>
|
||||
</div>
|
||||
<ResponsiveMenu
|
||||
isOpened={isMenuOpened}
|
||||
onClosed={() => setIsMenuOpened(false)}
|
||||
>
|
||||
<ResponsiveMenu isOpened={isMenuOpened} onClosed={closeMenu}>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
@@ -98,6 +174,20 @@ export function MobileControlBar({
|
||||
},
|
||||
})}
|
||||
>
|
||||
{hideReactions && (
|
||||
<ReactionsToggle
|
||||
variant="primaryTextDark"
|
||||
description={true}
|
||||
onPress={closeMenu}
|
||||
/>
|
||||
)}
|
||||
{hideHand && (
|
||||
<HandToggle
|
||||
variant="primaryTextDark"
|
||||
description={true}
|
||||
onPress={closeMenu}
|
||||
/>
|
||||
)}
|
||||
{browserSupportsScreenSharing && (
|
||||
<ScreenShareToggle
|
||||
onDeviceError={(error) =>
|
||||
@@ -105,25 +195,16 @@ export function MobileControlBar({
|
||||
}
|
||||
variant="primaryTextDark"
|
||||
description={true}
|
||||
onPress={() => setIsMenuOpened(false)}
|
||||
onPress={closeMenu}
|
||||
/>
|
||||
)}
|
||||
<ChatToggle
|
||||
description={true}
|
||||
onPress={() => setIsMenuOpened(false)}
|
||||
/>
|
||||
<ParticipantsToggle
|
||||
description={true}
|
||||
onPress={() => setIsMenuOpened(false)}
|
||||
/>
|
||||
<ToolsToggle
|
||||
description={true}
|
||||
onPress={() => setIsMenuOpened(false)}
|
||||
/>
|
||||
<ChatToggle description={true} onPress={closeMenu} />
|
||||
<ParticipantsToggle description={true} onPress={closeMenu} />
|
||||
<ToolsToggle description={true} onPress={closeMenu} />
|
||||
<Button
|
||||
onPress={() => {
|
||||
toggleEffects()
|
||||
setIsMenuOpened(false)
|
||||
closeMenu()
|
||||
}}
|
||||
variant="primaryTextDark"
|
||||
aria-label={t('options.items.effects')}
|
||||
@@ -140,7 +221,7 @@ export function MobileControlBar({
|
||||
aria-label={t('options.items.feedback')}
|
||||
description={true}
|
||||
target="_blank"
|
||||
onPress={() => setIsMenuOpened(false)}
|
||||
onPress={closeMenu}
|
||||
>
|
||||
<RiMegaphoneLine size={20} />
|
||||
</LinkButton>
|
||||
@@ -148,7 +229,7 @@ export function MobileControlBar({
|
||||
<Button
|
||||
onPress={() => {
|
||||
openSettingsDialog()
|
||||
setIsMenuOpened(false)
|
||||
closeMenu()
|
||||
}}
|
||||
variant="primaryTextDark"
|
||||
aria-label={t('options.items.settings')}
|
||||
@@ -157,7 +238,7 @@ export function MobileControlBar({
|
||||
>
|
||||
<RiSettings3Line size={20} />
|
||||
</Button>
|
||||
<CameraSwitchButton onPress={() => setIsMenuOpened(false)} />
|
||||
<CameraSwitchButton onPress={closeMenu} />
|
||||
</div>
|
||||
</div>
|
||||
</ResponsiveMenu>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/primitives'
|
||||
import { Screen } from '@/layout/Screen'
|
||||
import { Center, HStack, styled, VStack } from '@/styled-system/jsx'
|
||||
import { Center, Stack, styled, VStack } from '@/styled-system/jsx'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { Rating } from '@/features/rooms/components/Rating.tsx'
|
||||
import { useLocation } from 'wouter'
|
||||
import { useMemo } from 'react'
|
||||
@@ -14,14 +15,18 @@ const Heading = styled('h1', {
|
||||
fontStyle: 'normal',
|
||||
fontStretch: 'normal',
|
||||
fontOpticalSizing: 'auto',
|
||||
fontSize: '2.3rem',
|
||||
lineHeight: '2.5rem',
|
||||
fontSize: { base: '1.75rem', xsm: '2.3rem' },
|
||||
lineHeight: { base: '2.125rem', xsm: '2.5rem' },
|
||||
letterSpacing: '0',
|
||||
paddingBottom: '2rem',
|
||||
paddingBottom: { base: '1.5rem', xsm: '2rem' },
|
||||
textAlign: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
const buttonClass = css({
|
||||
width: { base: '100%', xsm: 'auto' },
|
||||
})
|
||||
|
||||
enum DisconnectReasonKey {
|
||||
DuplicateIdentity = 'duplicateIdentity',
|
||||
ParticipantRemoved = 'participantRemoved',
|
||||
@@ -54,19 +59,31 @@ const FeedbackRoute = () => {
|
||||
|
||||
return (
|
||||
<Screen layout="centered" footer={false}>
|
||||
<Center>
|
||||
<VStack>
|
||||
<Center width="100%">
|
||||
<VStack width="100%" paddingX="1rem">
|
||||
<Heading>{t(`feedback.heading.${reasonKey || 'normal'}`)}</Heading>
|
||||
<HStack>
|
||||
<Stack
|
||||
direction={{ base: 'column', xsm: 'row' }}
|
||||
width={{ base: '100%', xsm: 'auto' }}
|
||||
maxWidth="380px"
|
||||
>
|
||||
{showBackButton && (
|
||||
<Button variant="secondary" onPress={() => window.history.back()}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className={buttonClass}
|
||||
onPress={() => window.history.back()}
|
||||
>
|
||||
{t('feedback.back')}
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="primary" onPress={() => setLocation('/')}>
|
||||
<Button
|
||||
variant="primary"
|
||||
className={buttonClass}
|
||||
onPress={() => setLocation('/')}
|
||||
>
|
||||
{t('feedback.home')}
|
||||
</Button>
|
||||
</HStack>
|
||||
</Stack>
|
||||
<Rating metadata={metadata} />
|
||||
</VStack>
|
||||
</Center>
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mail_mjml",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@html-to/text-cli": "0.6.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"description": "An util to generate html and text django's templates from mjml templates",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sdk",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sdk",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"license": "ISC",
|
||||
"workspaces": [
|
||||
"./library",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sdk",
|
||||
"version": "1.27.0",
|
||||
"version": "1.28.0",
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
[project]
|
||||
name = "summary"
|
||||
version = "1.27.0"
|
||||
version = "1.28.0"
|
||||
dependencies = [
|
||||
"fastapi[standard]>=0.105.0",
|
||||
"uvicorn>=0.24.0",
|
||||
|
||||
Reference in New Issue
Block a user