Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 505572e9d0 | |||
| 69d92e6f30 | |||
| c47e830b40 | |||
| d7f1b7b94c | |||
| 8072d2c950 | |||
| 726f9097f9 |
+2
-1
@@ -25,7 +25,8 @@ and this project adheres to
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🐛(frontend) remove unexpected F2 tooltip when clicking video screen
|
||||
- 🐛(frontend) remove unexpected F2 tooltip when clicking video screen
|
||||
- 🩹(frontend) icon font loading to avoid text/icon flickering
|
||||
|
||||
## [1.2.0] - 2026-01-05
|
||||
|
||||
|
||||
@@ -6,6 +6,22 @@
|
||||
<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">
|
||||
<!-- Font URLs are resolved and replaced by Vite during the build process. Font loading failures will not break the application. -->
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
crossorigin="anonymous"
|
||||
href="/node_modules/@fontsource/material-icons-outlined/files/material-icons-outlined-latin-400-normal.woff2"
|
||||
type="font/woff2"
|
||||
/>
|
||||
<!-- Font URLs are resolved and replaced by Vite during the build process. Font loading failures will not break the application. -->
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
crossorigin="anonymous"
|
||||
href="/node_modules/@fontsource-variable/material-symbols-outlined/files/material-symbols-outlined-latin-wght-normal.woff2"
|
||||
type="font/woff2"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>%VITE_APP_TITLE%</title>
|
||||
</head>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { css, cx } from '@/styled-system/css'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { Spinner } from '@/primitives/Spinner'
|
||||
import { Button, Text } from '@/primitives'
|
||||
import { Button, Icon, Text } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RecordingStatuses } from '../hooks/useRecordingStatuses'
|
||||
import { ReactNode, useEffect, useRef, useState } from 'react'
|
||||
@@ -141,31 +141,23 @@ export const ControlsButton = ({
|
||||
})}
|
||||
onPress={() => openSidePanel()}
|
||||
>
|
||||
<span
|
||||
className={cx(
|
||||
'material-icons',
|
||||
css({
|
||||
color: 'primary.500',
|
||||
marginRight: '1rem',
|
||||
})
|
||||
)}
|
||||
>
|
||||
info
|
||||
</span>
|
||||
<Icon
|
||||
className={css({
|
||||
color: 'primary.500',
|
||||
marginRight: '1rem',
|
||||
})}
|
||||
name="info"
|
||||
/>
|
||||
<Text variant={'smNote'}>
|
||||
{parseLineBreaks(t('button.anotherModeStarted'))}
|
||||
</Text>
|
||||
<span
|
||||
className={cx(
|
||||
'material-icons',
|
||||
css({
|
||||
color: 'primary.500',
|
||||
marginLeft: 'auto',
|
||||
})
|
||||
)}
|
||||
>
|
||||
chevron_right
|
||||
</span>
|
||||
<Icon
|
||||
className={css({
|
||||
color: 'primary.500',
|
||||
marginLeft: 'auto',
|
||||
})}
|
||||
name="chevron_right"
|
||||
/>
|
||||
</RACButton>
|
||||
)}
|
||||
<Button
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { H, Text } from '@/primitives'
|
||||
import { H, Text, Icon } from '@/primitives'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { LoginButton } from '@/components/LoginButton'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
@@ -24,9 +24,7 @@ export const LoginPrompt = ({ heading, body }: LoginPromptProps) => {
|
||||
})}
|
||||
>
|
||||
<HStack justify="start" alignItems="center" marginBottom="0.5rem">
|
||||
<span className="material-symbols" aria-hidden={true}>
|
||||
login
|
||||
</span>
|
||||
<Icon type="symbols" name="login" />
|
||||
<H lvl={3} margin={false} padding={false}>
|
||||
{heading}
|
||||
</H>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Spinner } from '@/primitives/Spinner'
|
||||
import { Icon } from '@/primitives'
|
||||
|
||||
interface RecordingStatusIconProps {
|
||||
isStarted: boolean
|
||||
@@ -14,8 +15,8 @@ export const RecordingStatusIcon = ({
|
||||
}
|
||||
|
||||
if (isTranscriptActive) {
|
||||
return <span className="material-symbols">speech_to_text</span>
|
||||
return <Icon type="symbols" name="speech_to_text" />
|
||||
}
|
||||
|
||||
return <span className="material-symbols">screen_record</span>
|
||||
return <Icon type="symbols" name="screen_record" />
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, H, Text } from '@/primitives'
|
||||
import { Button, Icon, H, Text } from '@/primitives'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
@@ -59,7 +59,7 @@ export const RequestRecording = ({
|
||||
})}
|
||||
>
|
||||
<HStack justify="start" alignItems="center" marginBottom="0.5rem">
|
||||
<span className="material-symbols">person_raised_hand</span>
|
||||
<Icon type="symbols" name="person_raised_hand" />
|
||||
<H lvl={3} margin={false} padding={false}>
|
||||
{heading}
|
||||
</H>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { css } from '@/styled-system/css'
|
||||
import { ReactNode } from 'react'
|
||||
import { Icon } from '@/primitives'
|
||||
|
||||
type RowPosition = 'first' | 'middle' | 'last' | 'single'
|
||||
|
||||
@@ -45,7 +46,7 @@ export const RowWrapper = ({
|
||||
})}
|
||||
>
|
||||
{/* fixme - doesn't handle properly material-symbols */}
|
||||
<span className="material-icons">{iconName}</span>
|
||||
<Icon name={iconName} />
|
||||
</div>
|
||||
<div
|
||||
className={css({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { A, Div, Text } from '@/primitives'
|
||||
import { A, Div, Icon, Text } from '@/primitives'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { Button as RACButton } from 'react-aria-components'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -87,7 +87,7 @@ const ToolButton = ({
|
||||
alignItems: 'center',
|
||||
})}
|
||||
>
|
||||
<span className="material-symbols">chevron_forward</span>
|
||||
<Icon type="symbols" name="chevron_forward" />
|
||||
</div>
|
||||
</RACButton>
|
||||
)
|
||||
@@ -163,7 +163,7 @@ export const Tools = () => {
|
||||
</Text>
|
||||
{isTranscriptEnabled && (
|
||||
<ToolButton
|
||||
icon={<span className="material-symbols">speech_to_text</span>}
|
||||
icon={<Icon type="symbols" name="speech_to_text" />}
|
||||
title={t('tools.transcript.title')}
|
||||
description={t('tools.transcript.body')}
|
||||
onPress={() => openTranscript()}
|
||||
@@ -171,7 +171,7 @@ export const Tools = () => {
|
||||
)}
|
||||
{isScreenRecordingEnabled && (
|
||||
<ToolButton
|
||||
icon={<span className="material-symbols">mode_standby</span>}
|
||||
icon={<Icon type="symbols" name="mode_standby" />}
|
||||
title={t('tools.screenRecording.title')}
|
||||
description={t('tools.screenRecording.body')}
|
||||
onPress={() => openScreenRecording()}
|
||||
|
||||
@@ -22,6 +22,11 @@ const Heading = styled('h1', {
|
||||
},
|
||||
})
|
||||
|
||||
enum DisconnectReasonKey {
|
||||
DuplicateIdentity = 'duplicateIdentity',
|
||||
ParticipantRemoved = 'participantRemoved',
|
||||
}
|
||||
|
||||
export const FeedbackRoute = () => {
|
||||
const { t } = useTranslation('rooms')
|
||||
const [, setLocation] = useLocation()
|
||||
@@ -32,21 +37,25 @@ export const FeedbackRoute = () => {
|
||||
if (!state?.reason) return
|
||||
switch (state.reason) {
|
||||
case DisconnectReason.DUPLICATE_IDENTITY:
|
||||
return 'duplicateIdentity'
|
||||
return DisconnectReasonKey.DuplicateIdentity
|
||||
case DisconnectReason.PARTICIPANT_REMOVED:
|
||||
return 'participantRemoved'
|
||||
return DisconnectReasonKey.ParticipantRemoved
|
||||
}
|
||||
}, [])
|
||||
|
||||
const showBackButton = reasonKey !== DisconnectReasonKey.ParticipantRemoved
|
||||
|
||||
return (
|
||||
<Screen layout="centered" footer={false}>
|
||||
<Center>
|
||||
<VStack>
|
||||
<Heading>{t(`feedback.heading.${reasonKey || 'normal'}`)}</Heading>
|
||||
<HStack>
|
||||
<Button variant="secondary" onPress={() => window.history.back()}>
|
||||
{t('feedback.back')}
|
||||
</Button>
|
||||
{showBackButton && (
|
||||
<Button variant="secondary" onPress={() => window.history.back()}>
|
||||
{t('feedback.back')}
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="primary" onPress={() => setLocation('/')}>
|
||||
{t('feedback.home')}
|
||||
</Button>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Dialog, type DialogProps } from '@/primitives'
|
||||
import { Tab, Tabs, TabList } from '@/primitives/Tabs.tsx'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { text } from '@/primitives/Text.tsx'
|
||||
import { Icon } from '@/primitives/Icon'
|
||||
import { Heading } from 'react-aria-components'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
@@ -106,7 +107,7 @@ export const SettingsDialogExtended = (props: SettingsDialogExtended) => {
|
||||
</Tab>
|
||||
{isAdminOrOwner && (
|
||||
<Tab icon highlight id={SettingsDialogExtendedKey.TRANSCRIPTION}>
|
||||
<span className="material-symbols">speech_to_text</span>
|
||||
<Icon type="symbols" name="speech_to_text" />
|
||||
{isWideScreen &&
|
||||
t(`tabs.${SettingsDialogExtendedKey.TRANSCRIPTION}`)}
|
||||
</Tab>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { cva, RecipeVariantProps } from '@/styled-system/css'
|
||||
import { ComponentPropsWithoutRef } from 'react'
|
||||
|
||||
const iconRecipe = cva({
|
||||
base: {
|
||||
fontWeight: 'normal',
|
||||
fontStyle: 'normal',
|
||||
display: 'inline-block',
|
||||
lineHeight: 1,
|
||||
textTransform: 'none',
|
||||
letterSpacing: 'normal',
|
||||
wordWrap: 'normal',
|
||||
whiteSpace: 'nowrap',
|
||||
direction: 'ltr',
|
||||
},
|
||||
variants: {
|
||||
type: {
|
||||
icons: {
|
||||
fontFamily: 'Material Icons Outlined',
|
||||
webkitFontSmoothing: 'antialiased',
|
||||
mozOsxFontSmoothing: 'grayscale',
|
||||
textRendering: 'optimizeLegibility',
|
||||
fontFeatureSettings: '"liga"',
|
||||
},
|
||||
symbols: {
|
||||
fontFamily: 'Material Symbols Outlined Variable',
|
||||
},
|
||||
},
|
||||
size: {
|
||||
sm: {
|
||||
fontSize: '18px',
|
||||
},
|
||||
md: {
|
||||
fontSize: '24px',
|
||||
},
|
||||
lg: {
|
||||
fontSize: '32px',
|
||||
},
|
||||
xl: {
|
||||
fontSize: '40px',
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
type: 'icons',
|
||||
size: 'md',
|
||||
},
|
||||
})
|
||||
|
||||
export type IconRecipeProps = RecipeVariantProps<typeof iconRecipe>
|
||||
|
||||
export type IconProps = IconRecipeProps &
|
||||
ComponentPropsWithoutRef<'span'> & {
|
||||
name: string
|
||||
}
|
||||
|
||||
export const Icon = ({ name, ...props }: IconProps) => {
|
||||
const [variantProps, componentProps] = iconRecipe.splitVariantProps(props)
|
||||
const { className, ...remainingComponentProps } = componentProps
|
||||
|
||||
return (
|
||||
<span
|
||||
translate="no"
|
||||
aria-hidden="true"
|
||||
className={[iconRecipe(variantProps), className].join(' ')}
|
||||
{...remainingComponentProps}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -30,3 +30,4 @@ export { Ul } from './Ul'
|
||||
export { VerticallyOffCenter } from './VerticallyOffCenter'
|
||||
export { TextArea } from './TextArea'
|
||||
export { Switch } from './Switch'
|
||||
export { Icon } from './Icon'
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
@import '@fontsource/material-icons-outlined';
|
||||
|
||||
.material-icons,
|
||||
.material-symbols {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: 'Material Icons Outlined';
|
||||
}
|
||||
|
||||
.material-symbols {
|
||||
font-family: 'Material Symbols Outlined Variable';
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
@import './livekit.css';
|
||||
@import './icons.css';
|
||||
@layer reset, base, tokens, recipes, utilities;
|
||||
html,
|
||||
body,
|
||||
@@ -54,3 +53,36 @@ body:has(.lk-video-conference) #crisp-chatbox > * > div[role='button'] {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generated using the Advanced installation guidelines from
|
||||
* https://fontsource.org/fonts/material-icons-outlined/install
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Material Icons Outlined';
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-weight: 400;
|
||||
src: url(@fontsource/material-icons-outlined/files/material-icons-outlined-latin-400-normal.woff2)
|
||||
format('woff2');
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
|
||||
U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
|
||||
U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* Generated using the Advanced installation guidelines from
|
||||
* https://fontsource.org/fonts/material-symbols-outlined/install
|
||||
*/
|
||||
/* material-symbols-outlined-latin-wght-normal */
|
||||
@font-face {
|
||||
font-family: 'Material Symbols Outlined Variable';
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-weight: 100 700;
|
||||
src: url(@fontsource-variable/material-symbols-outlined/files/material-symbols-outlined-latin-wght-normal.woff2)
|
||||
format('woff2-variations');
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
|
||||
U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
|
||||
U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user