Merge pull request #18825 from GuiLeme/plugin-sdk-navbar
feat(plugin): extensible area navigation bar (above presentation on the presentation area)
This commit is contained in:
commit
3b531125dc
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import withShortcutHelper from '/imports/ui/components/shortcut-help/service';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import * as PluginSdk from 'bigbluebutton-html-plugin-sdk';
|
||||
import Styled from './styles';
|
||||
import RecordingIndicator from './recording-indicator/container';
|
||||
import TalkingIndicatorContainer from '/imports/ui/components/nav-bar/talking-indicator/container';
|
||||
@ -13,6 +14,7 @@ import TimerIndicatorContainer from '/imports/ui/components/timer/indicator/cont
|
||||
import browserInfo from '/imports/utils/browserInfo';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import { PANELS, ACTIONS } from '../layout/enums';
|
||||
import Button from '/imports/ui/components/common/button/component';
|
||||
import { isEqual } from 'radash';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
@ -45,6 +47,9 @@ const propTypes = {
|
||||
breakoutNum: PropTypes.number,
|
||||
breakoutName: PropTypes.string,
|
||||
meetingName: PropTypes.string,
|
||||
pluginNavBarItems: PropTypes.arrayOf(PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
})).isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -53,6 +58,70 @@ const defaultProps = {
|
||||
shortcuts: '',
|
||||
};
|
||||
|
||||
const renderPluginItems = (pluginItems) => (
|
||||
<>
|
||||
{
|
||||
pluginItems.map((pluginItem) => {
|
||||
let returnComponent;
|
||||
switch (pluginItem.type) {
|
||||
case PluginSdk.NavBarItemType.BUTTON:
|
||||
returnComponent = (
|
||||
<Styled.PluginComponentWrapper
|
||||
key={pluginItem.id}
|
||||
>
|
||||
<Button
|
||||
icon={pluginItem.icon}
|
||||
label={pluginItem.label}
|
||||
aria-label={pluginItem.tooltip}
|
||||
color="primary"
|
||||
tooltip={pluginItem.tooltip}
|
||||
onClick={pluginItem.onClick}
|
||||
/>
|
||||
</Styled.PluginComponentWrapper>
|
||||
);
|
||||
break;
|
||||
case PluginSdk.NavBarItemType.INFO:
|
||||
returnComponent = (
|
||||
<Styled.PluginComponentWrapper
|
||||
key={pluginItem.id}
|
||||
tooltip={pluginItem.tooltip}
|
||||
>
|
||||
<Styled.PluginInfoComponent>
|
||||
{pluginItem.label}
|
||||
</Styled.PluginInfoComponent>
|
||||
</Styled.PluginComponentWrapper>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
returnComponent = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pluginItem.hasSeparator) {
|
||||
switch (pluginItem.position) {
|
||||
case PluginSdk.NavBarItemPosition.RIGHT:
|
||||
returnComponent = (
|
||||
<>
|
||||
{returnComponent}
|
||||
<Styled.PluginSeparatorWrapper>|</Styled.PluginSeparatorWrapper>
|
||||
</>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
returnComponent = (
|
||||
<>
|
||||
<Styled.PluginSeparatorWrapper>|</Styled.PluginSeparatorWrapper>
|
||||
{returnComponent}
|
||||
</>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return returnComponent;
|
||||
})
|
||||
}
|
||||
</>
|
||||
);
|
||||
class NavBar extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -62,6 +131,7 @@ class NavBar extends Component {
|
||||
}
|
||||
|
||||
this.handleToggleUserList = this.handleToggleUserList.bind(this);
|
||||
this.splitPluginItems = this.splitPluginItems.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -156,6 +226,31 @@ class NavBar extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
splitPluginItems() {
|
||||
const { pluginNavBarItems } = this.props;
|
||||
|
||||
return pluginNavBarItems.reduce((result, item) => {
|
||||
switch (item.position) {
|
||||
case PluginSdk.NavBarItemPosition.LEFT:
|
||||
result.leftPluginItems.push(item);
|
||||
break;
|
||||
case PluginSdk.NavBarItemPosition.CENTER:
|
||||
result.centerPluginItems.push(item);
|
||||
break;
|
||||
case PluginSdk.NavBarItemPosition.RIGHT:
|
||||
result.rightPluginItems.push(item);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}, {
|
||||
leftPluginItems: [],
|
||||
centerPluginItems: [],
|
||||
rightPluginItems: [],
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
hasUnreadMessages,
|
||||
@ -189,6 +284,8 @@ class NavBar extends Component {
|
||||
}
|
||||
});
|
||||
|
||||
const { leftPluginItems, centerPluginItems, rightPluginItems } = this.splitPluginItems();
|
||||
|
||||
return (
|
||||
<Styled.Navbar
|
||||
id="Navbar"
|
||||
@ -233,6 +330,7 @@ class NavBar extends Component {
|
||||
&& <Styled.ArrowRight iconName="right_arrow" />}
|
||||
{isExpanded && document.dir === 'rtl'
|
||||
&& <Styled.ArrowRight iconName="right_arrow" />}
|
||||
{renderPluginItems(leftPluginItems)}
|
||||
</Styled.Left>
|
||||
<Styled.Center>
|
||||
<Styled.PresentationTitle data-test="presentationTitle">
|
||||
@ -242,8 +340,10 @@ class NavBar extends Component {
|
||||
amIModerator={amIModerator}
|
||||
currentUserId={currentUserId}
|
||||
/>
|
||||
{renderPluginItems(centerPluginItems)}
|
||||
</Styled.Center>
|
||||
<Styled.Right>
|
||||
{renderPluginItems(rightPluginItems)}
|
||||
{ConnectionStatusService.isEnabled() ? <ConnectionStatusButton /> : null}
|
||||
<SettingsDropdownContainer amIModerator={amIModerator} />
|
||||
</Styled.Right>
|
||||
|
@ -12,6 +12,7 @@ import { UsersContext } from '/imports/ui/components/components-data/users-conte
|
||||
import NotesService from '/imports/ui/components/notes/service';
|
||||
import NavBar from './component';
|
||||
import { layoutSelectInput, layoutSelectOutput, layoutDispatch } from '../layout/context';
|
||||
import { PluginsContext } from '/imports/ui/components/components-data/plugin-context/context';
|
||||
import { PANELS } from '/imports/ui/components/layout/enums';
|
||||
|
||||
const PUBLIC_CONFIG = Meteor.settings.public;
|
||||
@ -31,6 +32,7 @@ const checkUnreadMessages = ({
|
||||
const NavBarContainer = ({ children, ...props }) => {
|
||||
const usingChatContext = useContext(ChatContext);
|
||||
const usingUsersContext = useContext(UsersContext);
|
||||
const { pluginsProvidedAggregatedState } = useContext(PluginsContext);
|
||||
const usingGroupChatContext = useContext(GroupChatContext);
|
||||
const { chats: groupChatsMessages } = usingChatContext;
|
||||
const { users } = usingUsersContext;
|
||||
@ -62,6 +64,13 @@ const NavBarContainer = ({ children, ...props }) => {
|
||||
|
||||
if (hideNavBar || navBar.display === false) return null;
|
||||
|
||||
let pluginNavBarItems = [];
|
||||
if (pluginsProvidedAggregatedState.navBarItems) {
|
||||
pluginNavBarItems = [
|
||||
...pluginsProvidedAggregatedState.navBarItems,
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<NavBar
|
||||
{...{
|
||||
@ -76,6 +85,7 @@ const NavBarContainer = ({ children, ...props }) => {
|
||||
isExpanded,
|
||||
activeChats,
|
||||
currentUserId: Auth.userID,
|
||||
pluginNavBarItems,
|
||||
...rest,
|
||||
}}
|
||||
style={{ ...navBar }}
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
colorDanger,
|
||||
colorGrayDark,
|
||||
colorBackground,
|
||||
colorGray,
|
||||
} from '/imports/ui/stylesheets/styled-components/palette';
|
||||
import { fontSizeBase } from '/imports/ui/stylesheets/styled-components/typography';
|
||||
import { phoneLandscape, smallOnly } from '/imports/ui/stylesheets/styled-components/breakpoints';
|
||||
@ -79,6 +80,28 @@ const PresentationTitle = styled.h1`
|
||||
}
|
||||
`;
|
||||
|
||||
const PluginInfoComponent = styled.h1`
|
||||
font-weight: 400;
|
||||
color: ${colorWhite};
|
||||
font-size: ${fontSizeBase};
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 30vw;
|
||||
`;
|
||||
|
||||
const PluginComponentWrapper = styled.div`
|
||||
margin: 0 .5rem;
|
||||
`;
|
||||
|
||||
const PluginSeparatorWrapper = styled.div`
|
||||
color: ${colorGray};
|
||||
font-size: ${fontSizeBase};
|
||||
margin: 0 1rem;
|
||||
`;
|
||||
|
||||
const Right = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -128,4 +151,7 @@ export default {
|
||||
Right,
|
||||
Bottom,
|
||||
NavbarToggleButton,
|
||||
PluginInfoComponent,
|
||||
PluginComponentWrapper,
|
||||
PluginSeparatorWrapper,
|
||||
};
|
||||
|
@ -11,6 +11,7 @@ import ActionButtonDropdownPluginStateContainer from './action-button-dropdown/c
|
||||
import AudioSettingsDropdownPluginStateContainer from './audio-settings-dropdown/container';
|
||||
import ActionBarPluginStateContainer from './action-bar/container';
|
||||
import PresentationDropdownPluginStateContainer from './presentation-dropdown/container';
|
||||
import NavBarPluginStateContainer from './nav-bar/container';
|
||||
|
||||
const pluginProvidedStateMap: PluginsProvidedStateMap = {};
|
||||
|
||||
@ -21,6 +22,7 @@ const pluginProvidedStateContainers: PluginProvidedStateContainerChild[] = [
|
||||
AudioSettingsDropdownPluginStateContainer,
|
||||
ActionBarPluginStateContainer,
|
||||
PresentationDropdownPluginStateContainer,
|
||||
NavBarPluginStateContainer,
|
||||
];
|
||||
|
||||
function generateItemWithId<T extends PluginSdk.PluginProvidedUiItemDescriptor>(
|
||||
|
@ -0,0 +1,54 @@
|
||||
import { useEffect, useState, useContext } from 'react';
|
||||
import * as PluginSdk from 'bigbluebutton-html-plugin-sdk';
|
||||
|
||||
import {
|
||||
PluginProvidedStateContainerChildProps, PluginProvidedState,
|
||||
PluginProvidedStateContainerChild,
|
||||
} from '../../types';
|
||||
import { PluginsContext } from '../../../components-data/plugin-context/context';
|
||||
|
||||
const NavBarPluginStateContainer = ((
|
||||
props: PluginProvidedStateContainerChildProps,
|
||||
) => {
|
||||
const {
|
||||
uuid,
|
||||
generateItemWithId,
|
||||
pluginProvidedStateMap,
|
||||
pluginApi,
|
||||
} = props;
|
||||
const [
|
||||
navBarItems,
|
||||
setNavBarItems,
|
||||
] = useState<PluginSdk.NavBarItem[]>([]);
|
||||
|
||||
const {
|
||||
pluginsProvidedAggregatedState,
|
||||
setPluginsProvidedAggregatedState,
|
||||
} = useContext(PluginsContext);
|
||||
|
||||
useEffect(() => {
|
||||
// Change this plugin provided toolbar items
|
||||
pluginProvidedStateMap[uuid].navBarItems = navBarItems;
|
||||
|
||||
// Update context with computed aggregated list of all plugin provided toolbar items
|
||||
const aggregatedNavBarItems = ([] as PluginSdk.NavBarItem[]).concat(
|
||||
...Object.values(pluginProvidedStateMap)
|
||||
.map((pps: PluginProvidedState) => pps.navBarItems),
|
||||
);
|
||||
|
||||
setPluginsProvidedAggregatedState(
|
||||
{
|
||||
...pluginsProvidedAggregatedState,
|
||||
navBarItems: aggregatedNavBarItems,
|
||||
},
|
||||
);
|
||||
}, [navBarItems]);
|
||||
|
||||
pluginApi.setNavBarItems = (items: PluginSdk.NavBarItem[]) => {
|
||||
const itemsWithId = items.map(generateItemWithId) as PluginSdk.NavBarItem[];
|
||||
return setNavBarItems(itemsWithId);
|
||||
};
|
||||
return null;
|
||||
}) as PluginProvidedStateContainerChild;
|
||||
|
||||
export default NavBarPluginStateContainer;
|
@ -33,6 +33,7 @@ export interface PluginProvidedState {
|
||||
audioSettingsDropdownItems: PluginSdk.AudioSettingsDropdownItem[];
|
||||
actionsBarItems: PluginSdk.ActionsBarItem[];
|
||||
presentationDropdownItems: PluginSdk.PresentationDropdownItem[];
|
||||
navBarItems: PluginSdk.NavBarItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
6
bigbluebutton-html5/package-lock.json
generated
6
bigbluebutton-html5/package-lock.json
generated
@ -3754,9 +3754,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bigbluebutton-html-plugin-sdk": {
|
||||
"version": "0.0.11",
|
||||
"resolved": "https://registry.npmjs.org/bigbluebutton-html-plugin-sdk/-/bigbluebutton-html-plugin-sdk-0.0.11.tgz",
|
||||
"integrity": "sha512-mpZ6a7f5mhCSzdJbWZYUgoF+dj6598BidshBOMBFhZEzZjLUEGHkIjoac6yUHnjYOOLXcIttwYC07PwQlK8qDQ=="
|
||||
"version": "0.0.12",
|
||||
"resolved": "https://registry.npmjs.org/bigbluebutton-html-plugin-sdk/-/bigbluebutton-html-plugin-sdk-0.0.12.tgz",
|
||||
"integrity": "sha512-w22ghyDfIYAVXRgu2GnrSjLZicouNOTK1v9Lwy5o7EpoR3YSLsTV9e7h7zmQuz5M4cgwFcs7KcllIcg83poYrg=="
|
||||
},
|
||||
"bintrees": {
|
||||
"version": "1.0.2",
|
||||
|
@ -45,7 +45,7 @@
|
||||
"autoprefixer": "^10.4.4",
|
||||
"axios": "^0.21.3",
|
||||
"babel-runtime": "~6.26.0",
|
||||
"bigbluebutton-html-plugin-sdk": "0.0.11",
|
||||
"bigbluebutton-html-plugin-sdk": "0.0.12",
|
||||
"bowser": "^2.11.0",
|
||||
"browser-bunyan": "^1.8.0",
|
||||
"classnames": "^2.2.6",
|
||||
|
Loading…
Reference in New Issue
Block a user