fix(subtitles): Styles.

- Move the styles from css to tss-react ones
 - Dynamic fontSize based on the visible area of the page
 - Remove the gaps in the background when a line is wrapped.
 - Change the text color to white.
 - Remove transparency.
pull/15049/head jitsi-meet_9706
Hristo Terezov 9 months ago
parent 2364344046
commit 2d56dbe249
  1. 26
      css/_transcription-subtitles.scss
  2. 1
      css/main.scss
  3. 13
      react/features/base/ui/functions.web.ts
  4. 4
      react/features/display-name/components/web/DisplayNameBadge.tsx
  5. 8
      react/features/display-name/components/web/StageParticipantNameLabel.tsx
  6. 26
      react/features/display-name/components/web/styles.ts
  7. 74
      react/features/subtitles/components/web/Captions.tsx
  8. 4
      react/features/subtitles/constants.ts
  9. 16
      react/features/subtitles/functions.web.ts
  10. 1
      react/features/toolbox/constants.ts

@ -1,26 +0,0 @@
.transcription-subtitles {
bottom: $newToolbarSize + 40px;
font-size: 16px;
font-weight: 1000;
left: 50%;
max-width: 50vw;
opacity: 0.80;
overflow-wrap: break-word;
pointer-events: none;
position: absolute;
text-shadow: 0px 0px 1px rgba(0,0,0,0.3),
0px 1px 1px rgba(0,0,0,0.3),
1px 0px 1px rgba(0,0,0,0.3),
0px 0px 1px rgba(0,0,0,0.3);
transform: translateX(-50%);
z-index: 7;
&.lifted {
// Lift subtitle above toolbar+dominant speaker box.
bottom: $newToolbarSize + 36px + 40px;
}
span {
background: black;
}
}

@ -61,7 +61,6 @@ $flagsImagePath: "../images/";
@import 'filmstrip/vertical_filmstrip_overrides';
@import 'unsupported-browser/main';
@import 'deep-linking/main';
@import 'transcription-subtitles';
@import '_meetings_list.scss';
@import 'navigate_section_list';
@import 'third-party-branding/google';

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { adaptV4Theme, createTheme } from '@mui/material/styles';
import { Theme, adaptV4Theme, createTheme } from '@mui/material/styles';
import { ITypography, IPalette as Palette1 } from '../ui/types';
@ -107,3 +107,14 @@ export function operatesWithEnterKey(element: Element): boolean {
return false;
}
/**
* Returns a common spacing from the bottom of the page for floating elements over the video space.
*
* @param {Theme} theme - The current theme.
* @param {boolean} isToolbarVisible - Whether the toolbar is visible or not.
* @returns {number}
*/
export function getVideospaceFloatingElementsBottomSpacing(theme: Theme, isToolbarVisible: boolean) {
return parseInt(isToolbarVisible ? theme.spacing(12) : theme.spacing(6), 10);
}

@ -1,6 +1,8 @@
import React from 'react';
import { makeStyles } from 'tss-react/mui';
import { DISPLAY_NAME_VERTICAL_PADDING } from './styles';
const useStyles = makeStyles()(theme => {
const { text01 } = theme.palette;
@ -11,7 +13,7 @@ const useStyles = makeStyles()(theme => {
color: text01,
maxWidth: '50%',
overflow: 'hidden',
padding: '2px 16px',
padding: `${DISPLAY_NAME_VERTICAL_PADDING / 2}px 16px`,
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}

@ -10,20 +10,22 @@ import {
isWhiteboardParticipant
} from '../../../base/participants/functions';
import { withPixelLineHeight } from '../../../base/styles/functions.web';
import { getVideospaceFloatingElementsBottomSpacing } from '../../../base/ui/functions.web';
import { getLargeVideoParticipant } from '../../../large-video/functions';
import { isToolboxVisible } from '../../../toolbox/functions.web';
import { isLayoutTileView } from '../../../video-layout/functions.web';
import DisplayNameBadge from './DisplayNameBadge';
import { getStageParticipantTypography } from './styles';
const useStyles = makeStyles()(theme => {
return {
badgeContainer: {
...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
...withPixelLineHeight(getStageParticipantTypography(theme)),
alignItems: 'center',
display: 'inline-flex',
justifyContent: 'center',
marginBottom: theme.spacing(7),
marginBottom: getVideospaceFloatingElementsBottomSpacing(theme, false),
transition: 'margin-bottom 0.3s',
pointerEvents: 'none',
position: 'absolute',
@ -33,7 +35,7 @@ const useStyles = makeStyles()(theme => {
zIndex: 1
},
containerElevated: {
marginBottom: theme.spacing(12)
marginBottom: getVideospaceFloatingElementsBottomSpacing(theme, true)
}
};
});

@ -0,0 +1,26 @@
import { Theme } from '@mui/material';
/**
* The vertical padding for the display name.
*/
export const DISPLAY_NAME_VERTICAL_PADDING = 4;
/**
* Returns the typography for stage participant display name badge.
*
* @param {Theme} theme - The current theme.
* @returns {ITypographyType}
*/
export function getStageParticipantTypography(theme: Theme) {
return theme.typography.bodyShortRegularLarge;
}
/**
* Returns the height + padding for stage participant display name badge.
*
* @param {Theme} theme - The current theme.
* @returns {number}
*/
export function getStageParticipantNameLabelHeight(theme: Theme) {
return getStageParticipantTypography(theme).lineHeight ?? 0 + DISPLAY_NAME_VERTICAL_PADDING;
}

@ -1,25 +1,85 @@
import { Theme } from '@mui/material';
import React, { ReactElement } from 'react';
import { connect } from 'react-redux';
import { withStyles } from 'tss-react/mui';
import { IReduxState } from '../../../app/types';
import { getLocalParticipant } from '../../../base/participants/functions';
import { getVideospaceFloatingElementsBottomSpacing } from '../../../base/ui/functions.web';
import { getStageParticipantNameLabelHeight } from '../../../display-name/components/web/styles';
import { getLargeVideoParticipant } from '../../../large-video/functions';
import { isLayoutTileView } from '../../../video-layout/functions.web';
import { calculateSubtitlesFontSize } from '../../functions.web';
import {
AbstractCaptions,
type IAbstractCaptionsProps,
_abstractMapStateToProps
} from '../AbstractCaptions';
interface IProps extends IAbstractCaptionsProps {
/**
* The height of the visible area.
*/
_clientHeight?: number;
/**
* Whether the subtitles container is lifted above the invite box.
*/
_isLifted: boolean | undefined;
/**
* An object containing the CSS classes.
*/
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
}
const styles = (theme: Theme, props: IProps) => {
const { _isLifted = false, _clientHeight } = props;
const fontSize = calculateSubtitlesFontSize(_clientHeight);
const padding = Math.ceil(0.2 * fontSize);
// Currently the subtitles position are not affected by the toolbar visibility.
let bottom = getVideospaceFloatingElementsBottomSpacing(theme, true);
// This is the case where we display the onstage participant display name
// below the subtitles.
if (_isLifted) {
// 10px is the space between the onstage participant display name label and subtitles. We also need
// to add the padding of the subtitles because it will decrease the gap between the label and subtitles.
bottom += getStageParticipantNameLabelHeight(theme) + 10 + padding;
}
return {
transcriptionSubtitles: {
bottom,
fontSize: `${fontSize}px`,
left: '50%',
maxWidth: '50vw',
overflowWrap: 'break-word' as const,
pointerEvents: 'none' as const,
position: 'absolute' as const,
textShadow: `
0px 0px 1px rgba(0,0,0,0.3),
0px 1px 1px rgba(0,0,0,0.3),
1px 0px 1px rgba(0,0,0,0.3),
0px 0px 1px rgba(0,0,0,0.3)`,
transform: 'translateX(-50%)',
zIndex: 7, // The popups are with z-index 8. This z-index has to be lower.
lineHeight: 1.2,
span: {
color: '#fff',
background: 'black',
// without this when the text is wrapped on 2+ lines there will be a gap in the background:
padding: `${padding}px 0px`
}
}
};
};
/**
* React {@code Component} which can display speech-to-text results from
* Jigasi as subtitles.
@ -53,12 +113,10 @@ class Captions extends AbstractCaptions<IProps> {
* @returns {ReactElement} - The subtitles container.
*/
_renderSubtitlesContainer(paragraphs: Array<ReactElement>): ReactElement {
const className = this.props._isLifted
? 'transcription-subtitles lifted'
: 'transcription-subtitles';
const classes = withStyles.getClasses(this.props);
return (
<div className = { className } >
<div className = { classes.transcriptionSubtitles } >
{ paragraphs }
</div>
);
@ -77,11 +135,13 @@ function mapStateToProps(state: IReduxState) {
const isTileView = isLayoutTileView(state);
const largeVideoParticipant = getLargeVideoParticipant(state);
const localParticipant = getLocalParticipant(state);
const { clientHeight } = state['features/base/responsive-ui'];
return {
..._abstractMapStateToProps(state),
_isLifted: Boolean(largeVideoParticipant && largeVideoParticipant?.id !== localParticipant?.id && !isTileView)
_isLifted: Boolean(largeVideoParticipant && largeVideoParticipant?.id !== localParticipant?.id && !isTileView),
_clientHeight: clientHeight
};
}
export default connect(mapStateToProps)(Captions);
export default connect(mapStateToProps)(withStyles(Captions, styles));

@ -0,0 +1,4 @@
/**
* The minimum font size for subtitles.
*/
export const MIN_SUBTITLES_FONT_SIZE = 16;

@ -1,5 +1,7 @@
/* eslint-disable max-params, max-len */
import { MIN_SUBTITLES_FONT_SIZE } from './constants';
/**
* Logs when about the received transcription chunk.
*
@ -17,3 +19,17 @@ export const notifyTranscriptionChunkReceived = (transcriptMessageID: string, la
participant,
...text
});
/**
* Calculates the font size for the subtitles.
*
* @param {number} clientHeight - The height of the visible area of the window.
* @returns {number}
*/
export function calculateSubtitlesFontSize(clientHeight?: number) {
if (typeof clientHeight === 'undefined') {
return MIN_SUBTITLES_FONT_SIZE;
}
return Math.max(Math.floor(clientHeight * 0.04), MIN_SUBTITLES_FONT_SIZE);
}

@ -84,7 +84,6 @@ export const ZINDEX_DIALOG_PORTAL = 302;
*/
export const SPINNER_COLOR = '#929292';
/**
* The list of all possible UI buttons.
*

Loading…
Cancel
Save