feat(dynamic-branding): Add custom theme branding (#10335)
- apply theming to various buttons
This commit is contained in:
parent
61025edb74
commit
8ebca64af1
68
config.js
68
config.js
|
@ -896,25 +896,55 @@ var config = {
|
|||
If there is no url set or there are missing fields, the defaults are applied.
|
||||
The config file should be in JSON.
|
||||
None of the fields are mandatory and the response must have the shape:
|
||||
{
|
||||
// The domain url to apply (will replace the domain in the sharing conference link/embed section)
|
||||
inviteDomain: 'example-company.org,
|
||||
// The hex value for the colour used as background
|
||||
backgroundColor: '#fff',
|
||||
// The url for the image used as background
|
||||
backgroundImageUrl: 'https://example.com/background-img.png',
|
||||
// The anchor url used when clicking the logo image
|
||||
logoClickUrl: 'https://example-company.org',
|
||||
// The url used for the image used as logo
|
||||
logoImageUrl: 'https://example.com/logo-img.png',
|
||||
// Overwrite for pool of background images for avatars
|
||||
avatarBackgrounds: ['url(https://example.com/avatar-background-1.png)', '#FFF'],
|
||||
// The lobby/prejoin screen background
|
||||
premeetingBackground: 'url(https://example.com/premeeting-background.png)',
|
||||
// A list of images that can be used as video backgrounds.
|
||||
// When this field is present, the default images will be replaced with those provided.
|
||||
virtualBackgrounds: ['https://example.com/img.jpg']
|
||||
}
|
||||
{
|
||||
// The domain url to apply (will replace the domain in the sharing conference link/embed section)
|
||||
inviteDomain: 'example-company.org,
|
||||
// The hex value for the colour used as background
|
||||
backgroundColor: '#fff',
|
||||
// The url for the image used as background
|
||||
backgroundImageUrl: 'https://example.com/background-img.png',
|
||||
// The anchor url used when clicking the logo image
|
||||
logoClickUrl: 'https://example-company.org',
|
||||
// The url used for the image used as logo
|
||||
logoImageUrl: 'https://example.com/logo-img.png',
|
||||
// Overwrite for pool of background images for avatars
|
||||
avatarBackgrounds: ['url(https://example.com/avatar-background-1.png)', '#FFF'],
|
||||
// The lobby/prejoin screen background
|
||||
premeetingBackground: 'url(https://example.com/premeeting-background.png)',
|
||||
// A list of images that can be used as video backgrounds.
|
||||
// When this field is present, the default images will be replaced with those provided.
|
||||
virtualBackgrounds: ['https://example.com/img.jpg'],
|
||||
// Object containing a theme's properties. It also supports partial overwrites of the main theme.
|
||||
// For a list of all possible theme tokens and their current defaults, please check:
|
||||
// https://github.com/jitsi/jitsi-meet/tree/master/resources/custom-theme/custom-theme.json
|
||||
// For a short explanations on each of the tokens, please check:
|
||||
// https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/ui/Tokens.js
|
||||
// IMPORTANT!: This is work in progress so many of the various tokens are not yet applied in code
|
||||
// or they are partially applied.
|
||||
customTheme: {
|
||||
palette: {
|
||||
ui01: "orange !important",
|
||||
ui02: "maroon",
|
||||
surface02: 'darkgreen',
|
||||
ui03: "violet",
|
||||
ui04: "magenta",
|
||||
ui05: "blueviolet",
|
||||
field02Hover: 'red',
|
||||
action01: 'green',
|
||||
action01Hover: 'lightgreen',
|
||||
action02Disabled: 'beige',
|
||||
success02: 'cadetblue',
|
||||
action02Hover: 'aliceblue'
|
||||
},
|
||||
typography: {
|
||||
labelRegular: {
|
||||
fontSize: 25,
|
||||
lineHeight: 30,
|
||||
fontWeight: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// dynamicBrandingUrl: '',
|
||||
|
||||
|
|
|
@ -77,14 +77,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.toolbox-button {
|
||||
color: $toolbarButtonColor;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: $newToolbarSize;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.toolbar-button-with-badge {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
@ -115,86 +107,6 @@
|
|||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||||
}
|
||||
|
||||
.toolbox-content-items {
|
||||
background: $newToolbarBackgroundColor;
|
||||
border-radius: 6px;
|
||||
margin: 0 auto;
|
||||
padding: 6px;
|
||||
text-align: center;
|
||||
pointer-events: all;
|
||||
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
|
||||
|
||||
>div {
|
||||
margin-left: 8px;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-menu {
|
||||
font-size: 14px;
|
||||
list-style-type: none;
|
||||
padding: 8px 0;
|
||||
background-color: $menuBG;
|
||||
|
||||
.profile-text {
|
||||
max-width: 150px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-menu-item {
|
||||
align-items: center;
|
||||
color: $overflowMenuItemColor;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
height: 40px;
|
||||
line-height: 24px;
|
||||
padding: 8px 16px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background: $overflowMenuItemBackground;
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
}
|
||||
&.disabled {
|
||||
cursor: initial;
|
||||
color: #929292;
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #929292;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&.unclickable:hover {
|
||||
background: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.beta-tag {
|
||||
background: #36383C;
|
||||
border-radius: 3px;
|
||||
|
@ -205,73 +117,12 @@
|
|||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.overflow-menu-item-icon {
|
||||
margin-right: 16px;
|
||||
|
||||
i {
|
||||
display: inline;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
i:hover {
|
||||
background-color: initial;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.overflow-menu-hr {
|
||||
border-top: 1px solid #4C4D50;
|
||||
border-bottom: 0;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
display: flex;
|
||||
border-radius: 3px;
|
||||
flex-direction: column;
|
||||
font-size: 24px;
|
||||
height: $newToolbarSize;
|
||||
justify-content: center;
|
||||
width: $newToolbarSize;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background: $newToolbarButtonHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 320px) {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: $newToolbarButtonToggleColor;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: initial !important;
|
||||
background-color: #36383c !important;
|
||||
|
||||
svg {
|
||||
fill: #929292 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hangup-button {
|
||||
background-color: $hangupColor;
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
.copy-button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 8px 8px 16px;
|
||||
margin-top: 5px;
|
||||
width: calc(100% - 24px);
|
||||
height: 24px;
|
||||
|
||||
background: #0376DA;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: #278ADF;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&-content {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 292px;
|
||||
margin-right: 16px;
|
||||
|
||||
&.selected {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&.clicked {
|
||||
background: #31B76A;
|
||||
}
|
||||
|
||||
& > div > svg > path {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ $flagsImagePath: "../images/";
|
|||
@import 'inlay';
|
||||
@import 'reload_overlay/reload_overlay';
|
||||
@import 'mini_toolbox';
|
||||
@import 'buttons/copy.scss';
|
||||
@import 'modals/desktop-picker/desktop-picker';
|
||||
@import 'modals/device-selection/device-selection';
|
||||
@import 'modals/dialog';
|
||||
|
|
|
@ -138,7 +138,6 @@
|
|||
|
||||
.toolbox-content-items {
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
|
|
@ -2,14 +2,67 @@
|
|||
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { withStyles } from '@material-ui/styles';
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Icon, IconCheck, IconCopy } from '../../base/icons';
|
||||
import { withPixelLineHeight } from '../styles/functions.web';
|
||||
import { copyText } from '../util';
|
||||
|
||||
|
||||
const styles = theme => {
|
||||
return {
|
||||
copyButton: {
|
||||
...withPixelLineHeight(theme.typography.bodyLongRegular),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '8px 8px 8px 16px',
|
||||
marginTop: 5,
|
||||
width: 'calc(100% - 24px)',
|
||||
height: 24,
|
||||
|
||||
background: theme.palette.action01,
|
||||
cursor: 'pointer',
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action01Hover,
|
||||
fontWeight: 600
|
||||
},
|
||||
|
||||
'&.clicked': {
|
||||
background: theme.palette.success02
|
||||
},
|
||||
|
||||
'& > div > svg > path': {
|
||||
fill: theme.palette.text01
|
||||
}
|
||||
},
|
||||
content: {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
maxWidth: 292,
|
||||
marginRight: 16,
|
||||
|
||||
'&.selected': {
|
||||
fontWeight: 600
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let mounted;
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: Object,
|
||||
|
||||
/**
|
||||
* Css class to apply on container.
|
||||
*/
|
||||
|
@ -46,10 +99,18 @@ type Props = {
|
|||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
function CopyButton({ className, displayedText, textToCopy, textOnHover, textOnCopySuccess, id }: Props) {
|
||||
function CopyButton({ classes, className, displayedText, textToCopy, textOnHover, textOnCopySuccess, id }: Props) {
|
||||
const [ isClicked, setIsClicked ] = useState(false);
|
||||
const [ isHovered, setIsHovered ] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
mounted = true;
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Click handler for the element.
|
||||
*
|
||||
|
@ -64,7 +125,10 @@ function CopyButton({ className, displayedText, textToCopy, textOnHover, textOnC
|
|||
setIsClicked(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setIsClicked(false);
|
||||
// avoid: Can't perform a React state update on an unmounted component
|
||||
if (mounted) {
|
||||
setIsClicked(false);
|
||||
}
|
||||
}, 2500);
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +176,7 @@ function CopyButton({ className, displayedText, textToCopy, textOnHover, textOnC
|
|||
if (isClicked) {
|
||||
return (
|
||||
<>
|
||||
<div className = 'copy-button-content selected'>
|
||||
<div className = { clsx(classes.content, 'selected') }>
|
||||
<span role = { 'alert' }>{ textOnCopySuccess }</span>
|
||||
</div>
|
||||
<Icon src = { IconCheck } />
|
||||
|
@ -122,8 +186,8 @@ function CopyButton({ className, displayedText, textToCopy, textOnHover, textOnC
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className = 'copy-button-content'>
|
||||
{isHovered ? textOnHover : displayedText}
|
||||
<div className = { `${classes.copyButton}-content` }>
|
||||
{ isHovered ? textOnHover : displayedText }
|
||||
</div>
|
||||
<Icon src = { IconCopy } />
|
||||
</>
|
||||
|
@ -133,7 +197,7 @@ function CopyButton({ className, displayedText, textToCopy, textOnHover, textOnC
|
|||
return (
|
||||
<div
|
||||
aria-label = { textOnHover }
|
||||
className = { `${className} copy-button${isClicked ? ' clicked' : ''}` }
|
||||
className = { clsx(className, classes.copyButton, isClicked ? ' clicked' : '') }
|
||||
id = { id }
|
||||
onBlur = { onHoverOut }
|
||||
onClick = { onClick }
|
||||
|
@ -152,4 +216,4 @@ CopyButton.defaultProps = {
|
|||
className: ''
|
||||
};
|
||||
|
||||
export default CopyButton;
|
||||
export default withStyles(styles)(CopyButton);
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
// @flow
|
||||
|
||||
import { withStyles } from '@material-ui/styles';
|
||||
import clsx from 'clsx';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { Icon, IconArrowDown } from '../../../icons';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
|
||||
type Props = {
|
||||
|
||||
|
@ -11,6 +14,11 @@ type Props = {
|
|||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: Object,
|
||||
|
||||
/**
|
||||
* Text css class of the button.
|
||||
*/
|
||||
|
@ -78,6 +86,91 @@ type Props = {
|
|||
ariaDropDownLabel?: string
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the styles for the component.
|
||||
*
|
||||
* @param {Object} theme - The current UI theme.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
const styles = theme => {
|
||||
return {
|
||||
actionButton: {
|
||||
...withPixelLineHeight(theme.typography.bodyLongBold),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
boxSizing: 'border-box',
|
||||
color: theme.palette.text01,
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block',
|
||||
marginBottom: '16px',
|
||||
padding: '7px 16px',
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
|
||||
'&.primary': {
|
||||
background: theme.palette.action01,
|
||||
border: '1px solid #0376DA',
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action01Hover
|
||||
}
|
||||
},
|
||||
|
||||
'&.secondary': {
|
||||
background: theme.palette.action02,
|
||||
border: '1px solid transparent'
|
||||
},
|
||||
|
||||
'&.text': {
|
||||
width: 'auto',
|
||||
fontSize: '13px',
|
||||
margin: '0',
|
||||
padding: '0'
|
||||
},
|
||||
|
||||
'&.disabled': {
|
||||
background: theme.palette.action01Disabled,
|
||||
border: '1px solid #5E6D7A',
|
||||
color: '#AFB6BC',
|
||||
cursor: 'initial',
|
||||
|
||||
'.icon': {
|
||||
'& > svg': {
|
||||
fill: '#AFB6BC'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
[theme.breakpoints.down('400')]: {
|
||||
fontSize: 16,
|
||||
marginBottom: 8,
|
||||
padding: '11px 16px'
|
||||
}
|
||||
},
|
||||
options: {
|
||||
borderRadius: theme.shape.borderRadius / 2,
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
width: 36,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: '#0262B6'
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
pointerEvents: 'none'
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Button used for pre meeting actions.
|
||||
*
|
||||
|
@ -85,6 +178,7 @@ type Props = {
|
|||
*/
|
||||
function ActionButton({
|
||||
children,
|
||||
classes,
|
||||
className = '',
|
||||
disabled,
|
||||
hasOptions,
|
||||
|
@ -115,11 +209,18 @@ function ActionButton({
|
|||
}
|
||||
}, [ onOptionsClick, disabled ]);
|
||||
|
||||
const containerClasses = clsx(
|
||||
classes.actionButton,
|
||||
className && className,
|
||||
type,
|
||||
disabled && 'disabled'
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
aria-disabled = { disabled }
|
||||
aria-label = { ariaLabel }
|
||||
className = { `action-btn ${className} ${type} ${disabled ? 'disabled' : ''}` }
|
||||
className = { containerClasses }
|
||||
data-testid = { testId ? testId : undefined }
|
||||
onClick = { disabled ? undefined : onClick }
|
||||
onKeyPress = { onKeyPressHandler }
|
||||
|
@ -132,7 +233,7 @@ function ActionButton({
|
|||
aria-haspopup = 'true'
|
||||
aria-label = { ariaDropDownLabel }
|
||||
aria-pressed = { ariaPressed }
|
||||
className = 'options'
|
||||
className = { classes.options }
|
||||
data-testid = 'prejoin.joinOptions'
|
||||
onClick = { disabled ? undefined : onOptionsClick }
|
||||
onKeyPress = { onOptionsKeyPressHandler }
|
||||
|
@ -148,4 +249,4 @@ function ActionButton({
|
|||
);
|
||||
}
|
||||
|
||||
export default ActionButton;
|
||||
export default withStyles(styles)(ActionButton);
|
||||
|
|
|
@ -370,3 +370,12 @@ export const typography = {
|
|||
letterSpacing: 0
|
||||
}
|
||||
};
|
||||
|
||||
export const breakpoints = {
|
||||
values: {
|
||||
'0': 0,
|
||||
'320': 320,
|
||||
'400': 400,
|
||||
'480': 480
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { font, colors, colorMap, spacing, shape, typography } from '../Tokens';
|
||||
import { font, colors, colorMap, spacing, shape, typography, breakpoints } from '../Tokens';
|
||||
import { createWebTheme } from '../functions';
|
||||
|
||||
export default createWebTheme({
|
||||
|
@ -10,10 +10,5 @@ export default createWebTheme({
|
|||
spacing,
|
||||
shape,
|
||||
typography,
|
||||
breakpoints: {
|
||||
values: {
|
||||
'0': 0,
|
||||
'480': 480
|
||||
}
|
||||
}
|
||||
breakpoints
|
||||
});
|
||||
|
|
|
@ -15,7 +15,7 @@ import { formatCommonClasses } from '../functions';
|
|||
const useStyles = makeStyles(theme =>
|
||||
createStyles({
|
||||
'@global': {
|
||||
...formatCommonClasses(commonStyles),
|
||||
...formatCommonClasses(commonStyles(theme)),
|
||||
...getGlobalStyles(theme)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,10 +3,17 @@
|
|||
import { ThemeProvider } from '@material-ui/core/styles';
|
||||
import * as React from 'react';
|
||||
|
||||
import { connect } from '../../../base/redux';
|
||||
|
||||
import BaseTheme from './BaseTheme';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The default theme or theme set through advanced branding.
|
||||
*/
|
||||
_theme: Object,
|
||||
|
||||
/**
|
||||
* The children of the component.
|
||||
*/
|
||||
|
@ -19,6 +26,22 @@ type Props = {
|
|||
* @param {Object} props - The props of the component.
|
||||
* @returns {React.ReactNode}
|
||||
*/
|
||||
export default function JitsiThemeProvider(props: Props) {
|
||||
return <ThemeProvider theme = { BaseTheme }>{ props.children }</ThemeProvider>;
|
||||
function JitsiThemeProvider(props: Props) {
|
||||
return <ThemeProvider theme = { props._theme }>{ props.children }</ThemeProvider>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const { muiBrandedTheme } = state['features/dynamic-branding'];
|
||||
|
||||
return {
|
||||
_theme: muiBrandedTheme || BaseTheme
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(JitsiThemeProvider);
|
||||
|
|
|
@ -6,19 +6,153 @@
|
|||
*
|
||||
*/
|
||||
export const commonClassName = {
|
||||
emptyList: 'empty-list'
|
||||
emptyList: 'empty-list',
|
||||
overflowMenuItem: 'overflow-menu-item',
|
||||
overflowMenuItemIcon: 'overflow-menu-item-icon',
|
||||
toolboxIcon: 'toolbox-icon',
|
||||
toolboxButton: 'toolbox-button',
|
||||
toolboxContentItems: 'toolbox-content-items'
|
||||
};
|
||||
|
||||
/**
|
||||
* An object containing the declaration of the common, reusable CSS classes.
|
||||
* Returns an object containing the declaration of the common, reusable CSS classes.
|
||||
*
|
||||
* @param {Object} theme -The theme.
|
||||
*
|
||||
* @returns {Object} - The common styles.
|
||||
*/
|
||||
export const commonStyles = {
|
||||
// '.empty-list'
|
||||
[commonClassName.emptyList]: {
|
||||
listStyleType: 'none',
|
||||
margin: 0,
|
||||
padding: 0
|
||||
}
|
||||
export const commonStyles = (theme: Object) => {
|
||||
return {
|
||||
// '.empty-list'
|
||||
[commonClassName.emptyList]: {
|
||||
listStyleType: 'none',
|
||||
margin: 0,
|
||||
padding: 0
|
||||
},
|
||||
[commonClassName.overflowMenuItem]: {
|
||||
alignItems: 'center',
|
||||
color: theme.palette.text01,
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
fontSize: 14,
|
||||
fontWeight: 400,
|
||||
height: 40,
|
||||
lineHeight: '24px',
|
||||
padding: '8px 16px',
|
||||
boxSizing: 'border-box',
|
||||
'& > div': {
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
},
|
||||
|
||||
'&.unclickable': {
|
||||
cursor: 'default'
|
||||
},
|
||||
|
||||
'&.disabled': {
|
||||
cursor: 'initial',
|
||||
color: theme.palette.text03,
|
||||
|
||||
'&:hover': {
|
||||
background: 'none'
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.text03
|
||||
}
|
||||
},
|
||||
|
||||
'@media (hover: hover) and (pointer: fine)': {
|
||||
'&:hover': {
|
||||
background: theme.palette.action02Hover
|
||||
},
|
||||
'&.unclickable:hover': {
|
||||
background: 'inherit'
|
||||
}
|
||||
}
|
||||
},
|
||||
[commonClassName.overflowMenuItemIcon]: {
|
||||
marginRight: '16px',
|
||||
|
||||
'& i': {
|
||||
display: 'inline',
|
||||
fontSize: 24
|
||||
},
|
||||
|
||||
'@media (hover: hover) and (pointer: fine)': {
|
||||
'&i:hover': {
|
||||
backgroundColor: 'initial'
|
||||
}
|
||||
},
|
||||
|
||||
'& img': {
|
||||
maxWidth: 24,
|
||||
maxHeight: 24
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.text01,
|
||||
height: 20,
|
||||
width: 20
|
||||
}
|
||||
},
|
||||
[commonClassName.toolboxIcon]: {
|
||||
display: 'flex',
|
||||
borderRadius: 3,
|
||||
flexDirection: 'column',
|
||||
fontSize: 24,
|
||||
height: 48,
|
||||
justifyContent: 'center',
|
||||
width: 48,
|
||||
|
||||
'@media (hover: hover) and (pointer: fine)': {
|
||||
'&:hover': {
|
||||
background: theme.palette.action02Hover
|
||||
}
|
||||
},
|
||||
[theme.breakpoints.down('320')]: {
|
||||
height: 36,
|
||||
width: 36
|
||||
},
|
||||
|
||||
'&.toggled': {
|
||||
background: theme.palette.ui02
|
||||
},
|
||||
|
||||
'&.disabled': {
|
||||
cursor: 'initial !important',
|
||||
backgroundColor: `${theme.palette.action02Disabled} !important`,
|
||||
|
||||
'& svg': {
|
||||
fill: `${theme.palette.text03} !important`
|
||||
}
|
||||
}
|
||||
},
|
||||
[commonClassName.toolboxButton]: {
|
||||
color: theme.palette.text01,
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block',
|
||||
lineHeight: '48px',
|
||||
textAlign: 'center'
|
||||
},
|
||||
[commonClassName.toolboxContentItems]: {
|
||||
background: theme.palette.ui01,
|
||||
borderRadius: 6,
|
||||
margin: '0 auto',
|
||||
padding: 6,
|
||||
textAlign: 'center',
|
||||
pointerEvents: 'all',
|
||||
boxShadow: '0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15)',
|
||||
|
||||
'& > div': {
|
||||
marginLeft: 8,
|
||||
|
||||
'&:first-child': {
|
||||
marginLeft: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,7 @@ import { createColorTokens } from './utils';
|
|||
* @param {Object} arg - The ui tokens.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function createWebTheme({ font, colors, colorMap, shape, spacing, typography }: Object) {
|
||||
export function createWebTheme({ font, colors, colorMap, shape, spacing, typography, breakpoints }: Object) {
|
||||
return createMuiTheme({
|
||||
props: {
|
||||
// disable ripple effect on buttons globally
|
||||
|
@ -27,7 +27,8 @@ export function createWebTheme({ font, colors, colorMap, shape, spacing, typogra
|
|||
typography: {
|
||||
font,
|
||||
...typography
|
||||
}
|
||||
},
|
||||
breakpoints
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -46,3 +47,4 @@ export function formatCommonClasses(stylesObj: Object) {
|
|||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// @flow
|
||||
import { createMuiTheme } from '@material-ui/core/styles';
|
||||
|
||||
import { loadConfig } from '../base/lib-jitsi-meet';
|
||||
import { font, colors, colorMap, spacing, shape, typography, breakpoints } from '../base/ui/Tokens';
|
||||
import { createColorTokens } from '../base/ui/utils';
|
||||
|
||||
/**
|
||||
* Extracts the fqn part from a path, where fqn represents
|
||||
|
@ -45,3 +49,89 @@ export async function getDynamicBrandingUrl() {
|
|||
export function isDynamicBrandingDataLoaded(state: Object) {
|
||||
return state['features/dynamic-branding'].customizationReady;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates MUI branding theme based on the custom theme json.
|
||||
*
|
||||
* @param {Object} customTheme - The branded custom theme.
|
||||
* @returns {Object} - The MUI theme.
|
||||
*/
|
||||
export function createMuiBrandingTheme(customTheme: Object) {
|
||||
const {
|
||||
palette: customPalette,
|
||||
shape: customShape,
|
||||
typography: customTypography,
|
||||
breakpoints: customBreakpoints,
|
||||
spacing: customSpacing
|
||||
} = customTheme;
|
||||
|
||||
const newPalette = createColorTokens(colorMap, colors);
|
||||
|
||||
if (customPalette) {
|
||||
overwriteRecurrsive(newPalette, customPalette);
|
||||
}
|
||||
|
||||
const newShape = { ...shape };
|
||||
|
||||
if (customShape) {
|
||||
overwriteRecurrsive(newShape, customShape);
|
||||
}
|
||||
|
||||
const newTypography = {
|
||||
font: { ...font },
|
||||
...typography
|
||||
};
|
||||
|
||||
if (customTypography) {
|
||||
overwriteRecurrsive(newTypography, customTypography);
|
||||
}
|
||||
|
||||
const newBreakpoints = { ...breakpoints };
|
||||
|
||||
if (customBreakpoints) {
|
||||
overwriteRecurrsive(newBreakpoints, customBreakpoints);
|
||||
}
|
||||
|
||||
let newSpacing = [ ...spacing ];
|
||||
|
||||
if (customSpacing && customSpacing.length) {
|
||||
newSpacing = customSpacing;
|
||||
}
|
||||
|
||||
return createMuiTheme({
|
||||
props: {
|
||||
// disable ripple effect on buttons globally
|
||||
MuiButtonBase: {
|
||||
disableRipple: true
|
||||
}
|
||||
},
|
||||
|
||||
// use token spacing array
|
||||
spacing: newSpacing
|
||||
}, {
|
||||
palette: newPalette,
|
||||
shape: newShape,
|
||||
typography: newTypography,
|
||||
breakpoints: newBreakpoints
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites recursively values from object 2 into object 1 based on common keys.
|
||||
* (Merges object2 into object1).
|
||||
*
|
||||
* @param {Object} obj1 - The object holding the merged values.
|
||||
* @param {Object} obj2 - The object to compare to and take values from.
|
||||
* @returns {void}
|
||||
*/
|
||||
function overwriteRecurrsive(obj1: Object, obj2: Object) {
|
||||
Object.keys(obj2).forEach(key => {
|
||||
if (obj1.hasOwnProperty(key)) {
|
||||
if (typeof obj1[key] === 'object') {
|
||||
overwriteRecurrsive(obj1[key], obj2[key]);
|
||||
} else {
|
||||
obj1[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
import { APP_WILL_MOUNT } from '../base/app';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import { SET_DYNAMIC_BRANDING_DATA } from './actionTypes';
|
||||
import { fetchCustomBrandingData } from './actions';
|
||||
import { createMuiBrandingTheme } from './functions';
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
|
@ -12,6 +14,13 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
store.dispatch(fetchCustomBrandingData());
|
||||
break;
|
||||
}
|
||||
case SET_DYNAMIC_BRANDING_DATA: {
|
||||
const { customTheme } = action.value;
|
||||
|
||||
if (customTheme) {
|
||||
action.value.muiBrandedTheme = createMuiBrandingTheme(customTheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
|
|
|
@ -100,6 +100,14 @@ const DEFAULT_STATE = {
|
|||
*/
|
||||
logoImageUrl: '',
|
||||
|
||||
/**
|
||||
* The generated MUI branded theme based on the custom theme json.
|
||||
*
|
||||
* @public
|
||||
* @type {boolean}
|
||||
*/
|
||||
muiBrandedTheme: undefined,
|
||||
|
||||
/**
|
||||
* The lobby/prejoin background.
|
||||
*
|
||||
|
@ -140,6 +148,7 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
|||
inviteDomain,
|
||||
logoClickUrl,
|
||||
logoImageUrl,
|
||||
muiBrandedTheme,
|
||||
premeetingBackground,
|
||||
virtualBackgrounds
|
||||
} = action.value;
|
||||
|
@ -153,6 +162,7 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
|||
inviteDomain,
|
||||
logoClickUrl,
|
||||
logoImageUrl,
|
||||
muiBrandedTheme,
|
||||
premeetingBackground,
|
||||
customizationFailed: false,
|
||||
customizationReady: true,
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
// @flow
|
||||
|
||||
import { withStyles } from '@material-ui/styles';
|
||||
import React from 'react';
|
||||
|
||||
import { Icon } from '../../base/icons';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The css classes generated from theme.
|
||||
*/
|
||||
classes: Object,
|
||||
|
||||
/**
|
||||
* Attribute used in automated testing.
|
||||
*/
|
||||
dataTestId: string,
|
||||
|
||||
/**
|
||||
* The button's icon.
|
||||
*/
|
||||
icon: HTMLElement,
|
||||
|
||||
/**
|
||||
* The button's label.
|
||||
*/
|
||||
label: string,
|
||||
|
||||
/**
|
||||
* Function to be called when button is clicked.
|
||||
*/
|
||||
onButtonClick: Function,
|
||||
|
||||
/**
|
||||
* Function to be called on key pressed.
|
||||
*/
|
||||
onKeyPressed: Function,
|
||||
|
||||
/**
|
||||
* Used for translation.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the styles for the component.
|
||||
*
|
||||
* @param {Object} theme - The current UI theme.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
const styles = theme => {
|
||||
return {
|
||||
prejoinPreviewDropdownBtn: {
|
||||
alignItems: 'center',
|
||||
color: '#1C2025',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
height: 40,
|
||||
fontSize: 15,
|
||||
lineHeight: 24,
|
||||
padding: '0 16px',
|
||||
backgroundColor: theme.palette.field02,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.field02Hover
|
||||
}
|
||||
},
|
||||
prejoinPreviewDropdownIcon: {
|
||||
display: 'inline-block',
|
||||
marginRight: 16,
|
||||
|
||||
'& > svg': {
|
||||
fill: '#1C2025'
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Buttons used for pre meeting actions.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
const DropdownButton = ({
|
||||
classes,
|
||||
dataTestId,
|
||||
icon,
|
||||
onButtonClick,
|
||||
onKeyPressed,
|
||||
label
|
||||
}: Props) => (
|
||||
<div
|
||||
className = { classes.prejoinPreviewDropdownBtn }
|
||||
data-testid = { dataTestId }
|
||||
onClick = { onButtonClick }
|
||||
onKeyPress = { onKeyPressed }
|
||||
role = 'button'
|
||||
tabIndex = { 0 }>
|
||||
<Icon
|
||||
className = { classes.prejoinPreviewDropdownIcon }
|
||||
size = { 24 }
|
||||
src = { icon } />
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default withStyles(styles)(DropdownButton);
|
|
@ -6,7 +6,7 @@ import React, { Component } from 'react';
|
|||
import { getRoomName } from '../../base/conference';
|
||||
import { isNameReadOnly } from '../../base/config';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Icon, IconArrowDown, IconArrowUp, IconPhone, IconVolumeOff } from '../../base/icons';
|
||||
import { IconArrowDown, IconArrowUp, IconPhone, IconVolumeOff } from '../../base/icons';
|
||||
import { isVideoMutedByUser } from '../../base/media';
|
||||
import { ActionButton, InputField, PreMeetingScreen } from '../../base/premeeting';
|
||||
import { connect } from '../../base/redux';
|
||||
|
@ -24,6 +24,7 @@ import {
|
|||
isJoinByPhoneDialogVisible
|
||||
} from '../functions';
|
||||
|
||||
import DropdownButton from './DropdownButton';
|
||||
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
||||
|
||||
type Props = {
|
||||
|
@ -327,32 +328,18 @@ class Prejoin extends Component<Props, State> {
|
|||
<div className = 'prejoin-preview-dropdown-container'>
|
||||
<InlineDialog
|
||||
content = { <div className = 'prejoin-preview-dropdown-btns'>
|
||||
<div
|
||||
className = 'prejoin-preview-dropdown-btn'
|
||||
data-testid = 'prejoin.joinWithoutAudio'
|
||||
onClick = { joinConferenceWithoutAudio }
|
||||
onKeyPress = { _onJoinConferenceWithoutAudioKeyPress }
|
||||
role = 'button'
|
||||
tabIndex = { 0 }>
|
||||
<Icon
|
||||
className = 'prejoin-preview-dropdown-icon'
|
||||
size = { 24 }
|
||||
src = { IconVolumeOff } />
|
||||
{ t('prejoin.joinWithoutAudio') }
|
||||
</div>
|
||||
{hasJoinByPhoneButton && <div
|
||||
className = 'prejoin-preview-dropdown-btn'
|
||||
onClick = { _showDialog }
|
||||
onKeyPress = { _showDialogKeyPress }
|
||||
role = 'button'
|
||||
tabIndex = { 0 }>
|
||||
<Icon
|
||||
className = 'prejoin-preview-dropdown-icon'
|
||||
data-testid = 'prejoin.joinByPhone'
|
||||
size = { 24 }
|
||||
src = { IconPhone } />
|
||||
{ t('prejoin.joinAudioByPhone') }
|
||||
</div>}
|
||||
<DropdownButton
|
||||
dataTestId = 'prejoin.joinWithoutAudio'
|
||||
icon = { IconVolumeOff }
|
||||
label = { t('prejoin.joinWithoutAudio') }
|
||||
onButtonClick = { joinConferenceWithoutAudio }
|
||||
onKeyPressed = { _onJoinConferenceWithoutAudioKeyPress } />
|
||||
{hasJoinByPhoneButton && <DropdownButton
|
||||
dataTestId = 'prejoin.joinByPhone'
|
||||
icon = { IconPhone }
|
||||
label = { t('prejoin.joinAudioByPhone') }
|
||||
onButtonClick = { _showDialog }
|
||||
onKeyPressed = { _showDialogKeyPress } />}
|
||||
</div> }
|
||||
isOpen = { showJoinByPhoneButtons }
|
||||
onClose = { _onDropdownClose }>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut';
|
||||
|
@ -224,6 +225,11 @@ type Props = {
|
|||
*/
|
||||
_virtualSource: Object,
|
||||
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: Object,
|
||||
|
||||
/**
|
||||
* Invoked to active other features of the app.
|
||||
*/
|
||||
|
@ -248,6 +254,17 @@ type Props = {
|
|||
|
||||
declare var APP: Object;
|
||||
|
||||
const styles = theme => {
|
||||
return {
|
||||
overflowMenu: {
|
||||
fontSize: 14,
|
||||
listStyleType: 'none',
|
||||
padding: '8px 0',
|
||||
backgroundColor: theme.palette.ui03
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the conference toolbox on React/Web.
|
||||
*
|
||||
|
@ -1200,10 +1217,11 @@ class Toolbox extends Component<Props> {
|
|||
const {
|
||||
_isMobile,
|
||||
_overflowMenuVisible,
|
||||
_reactionsEnabled,
|
||||
_toolbarButtons,
|
||||
classes,
|
||||
showDominantSpeakerName,
|
||||
t,
|
||||
_reactionsEnabled
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
const toolbarAccLabel = 'toolbar.accessibilityLabel.moreActionsMenu';
|
||||
|
@ -1240,7 +1258,7 @@ class Toolbox extends Component<Props> {
|
|||
}>
|
||||
<ul
|
||||
aria-label = { t(toolbarAccLabel) }
|
||||
className = 'overflow-menu'
|
||||
className = { classes.overflowMenu }
|
||||
id = 'overflow-menu'
|
||||
onKeyDown = { this._onEscKey }
|
||||
role = 'menu'>
|
||||
|
@ -1346,4 +1364,4 @@ function _mapStateToProps(state, ownProps) {
|
|||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(Toolbox));
|
||||
export default translate(connect(_mapStateToProps)(withStyles(styles)(Toolbox)));
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
{
|
||||
"spacing": [ 0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128 ],
|
||||
"breakpoints": {
|
||||
"values": {
|
||||
"0": 0,
|
||||
"320": 320,
|
||||
"400": 400,
|
||||
"480": 480
|
||||
}
|
||||
},
|
||||
"palette": {
|
||||
"uiBackground": "#040404",
|
||||
"ui01": "#141414",
|
||||
"ui02": "#292929",
|
||||
"ui03": "#3D3D3D",
|
||||
"ui04": "#525252",
|
||||
"ui05": "#666",
|
||||
"action01": "#0056E0",
|
||||
"screen01Header": "#17A0DB",
|
||||
"action01Hover": "#246FE5",
|
||||
"action01Active": "#0045B3",
|
||||
"action01Focus": "#99BBF3",
|
||||
"action01Disabled": "#00225A",
|
||||
"action02": "#3D3D3D",
|
||||
"action02Hover": "#525252",
|
||||
"action02Active": "#292929",
|
||||
"action02Focus": "#858585",
|
||||
"action02Disabled": "#141414",
|
||||
"action03": "transparent",
|
||||
"action03Hover": "#525252",
|
||||
"action03Active": "#292929",
|
||||
"action03Focus": "#858585",
|
||||
"action03Disabled": "transparent",
|
||||
"actionDanger": "#CB2233",
|
||||
"actionDangerHover": "#E04757",
|
||||
"actionDangerActive": "#A21B29",
|
||||
"actionDangerFocus": "#EAA7AD",
|
||||
"actionDangerDisabled": "#7A141F",
|
||||
"bottomSheet": "#111111",
|
||||
"text01": "#FFF",
|
||||
"text02": "#C2C2C2",
|
||||
"text03": "#858585",
|
||||
"text04": "#AAAAAA",
|
||||
"textError": "#E04757",
|
||||
"icon01": "#FFF",
|
||||
"icon02": "#C2C2C2",
|
||||
"icon03": "#858585",
|
||||
"iconError": "#E04757",
|
||||
"field01": "#040404",
|
||||
"field01Hover": "#292929",
|
||||
"field01Focus": "#0056E0",
|
||||
"field01Disabled": "#525252",
|
||||
"field02": "#FFF",
|
||||
"dividerColor": "#AAAAAA",
|
||||
"field02Hover": "#CCDDF9",
|
||||
"field02Focus": "#0056E0",
|
||||
"field02Disabled": "#666",
|
||||
"section01": "#E0E0E0",
|
||||
"section01Active": "#0045B3",
|
||||
"section01Inactive": "#040404",
|
||||
"border01": "#A3A3A3",
|
||||
"border02": "#666",
|
||||
"border03": "#3D3D3D",
|
||||
"borderError": "#E04757",
|
||||
"link01": "#669AEC",
|
||||
"link01Hover": "#99BBF3",
|
||||
"link01Active": "#246FE5",
|
||||
"success01": "#1EC26A",
|
||||
"success02": "#1EC26A",
|
||||
"warning01": "#F8AE1A",
|
||||
"warning02": "#ED9E1B"
|
||||
},
|
||||
"typography": {
|
||||
"font": {
|
||||
"weightRegular": "400",
|
||||
"weightSemiBold": "600"
|
||||
},
|
||||
"labelRegular": {
|
||||
"fontSize": 12,
|
||||
"lineHeight": 16,
|
||||
"fontWeight": "400",
|
||||
"letterSpacing": 0.16
|
||||
},
|
||||
"labelBold": {
|
||||
"fontSize": 12,
|
||||
"lineHeight": 16,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0.16
|
||||
},
|
||||
"labelButton": {
|
||||
"fontSize": 14,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"labelButtonLarge": {
|
||||
"fontSize": 16,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"bodyShortRegular": {
|
||||
"fontSize": 14,
|
||||
"lineHeight": 18,
|
||||
"fontWeight": "400",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"bodyShortBold": {
|
||||
"fontSize": 14,
|
||||
"lineHeight": 18,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"bodyShortRegularLarge": {
|
||||
"fontSize": 16,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "400",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"bodyShortBoldLarge": {
|
||||
"fontSize": 16,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"bodyLongRegular": {
|
||||
"fontSize": 14,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "400",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"bodyLongBold": {
|
||||
"fontSize": 14,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading1": {
|
||||
"fontSize": 54,
|
||||
"lineHeight": 64,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading2": {
|
||||
"fontSize": 42,
|
||||
"lineHeight": 50,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading3": {
|
||||
"fontSize": 32,
|
||||
"lineHeight": 40,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading4": {
|
||||
"fontSize": 28,
|
||||
"lineHeight": 36,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading5": {
|
||||
"fontSize": 20,
|
||||
"lineHeight": 28,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading6": {
|
||||
"fontSize": 16,
|
||||
"lineHeight": 26,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
},
|
||||
"heading7": {
|
||||
"fontSize": 14,
|
||||
"lineHeight": 24,
|
||||
"fontWeight": "600",
|
||||
"letterSpacing": 0
|
||||
}
|
||||
},
|
||||
"shape": {
|
||||
"borderRadius": 6,
|
||||
"boxShadow": "inset 0px -1px 0px rgba(255, 255, 255, 0.15)"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue