From bb22ab84fc10e054dd17abbf548f7fc85d3582a4 Mon Sep 17 00:00:00 2001 From: KDSBrowne <kert.browne85@gmail.com> Date: Mon, 10 Aug 2020 12:51:06 +0000 Subject: [PATCH] add download link to current presentation toast --- .../ui/components/presentation/component.jsx | 57 +++++++++++++++++-- .../ui/components/presentation/styles.scss | 49 ++++++++++++---- .../components/status-notifier/component.jsx | 5 +- .../ui/components/status-notifier/styles.scss | 22 +------ .../imports/ui/components/toast/styles.scss | 23 ++++++-- .../ui/stylesheets/variables/typography.scss | 1 + bigbluebutton-html5/private/locales/en.json | 1 + 7 files changed, 116 insertions(+), 42 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/presentation/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/component.jsx index cda84f25cc..e084ee858f 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/component.jsx @@ -11,6 +11,7 @@ import AnnotationGroupContainer from '../whiteboard/annotation-group/container'; import PresentationOverlayContainer from './presentation-overlay/container'; import Slide from './slide/component'; import { styles } from './styles.scss'; +import toastStyles from '/imports/ui/components/toast/styles'; import MediaService, { shouldEnableSwapLayout } from '../media/service'; import PresentationCloseButton from './presentation-close-button/component'; import DownloadPresentationButton from './download-presentation-button/component'; @@ -29,6 +30,10 @@ const intlMessages = defineMessages({ id: 'app.presentation.notificationLabel', description: 'label displayed in toast when presentation switches', }, + downloadLabel: { + id: 'app.presentation.downloadLabel', + description: 'label for downloadable presentations', + }, }); const ALLOW_FULLSCREEN = Meteor.settings.public.app.allowFullscreen; @@ -131,6 +136,7 @@ class PresentationArea extends PureComponent { restoreOnUpdate, layoutContextDispatch, layoutContextState, + userIsPresenter, } = this.props; const { numUsersVideo } = layoutContextState; @@ -172,16 +178,36 @@ class PresentationArea extends PureComponent { } } - if (prevProps.currentPresentation.name !== currentPresentation.name) { + const downloadableOn = !prevProps.currentPresentation.downloadable + && currentPresentation.downloadable; + + const shouldCloseToast = !(currentPresentation.downloadable && !userIsPresenter); + + if ( + prevProps.currentPresentation.name !== currentPresentation.name + || (downloadableOn && !userIsPresenter) + ) { if (this.currentPresentationToastId) { - return toast.update(this.currentPresentationToastId, { + toast.update(this.currentPresentationToastId, { + autoClose: shouldCloseToast, render: this.renderCurrentPresentationToast(), }); + } else { + this.currentPresentationToastId = toast(this.renderCurrentPresentationToast(), { + onClose: () => { this.currentPresentationToastId = null; }, + autoClose: shouldCloseToast, + className: toastStyles.actionToast, + }); } + } + + const downloadableOff = prevProps.currentPresentation.downloadable + && !currentPresentation.downloadable; - this.currentPresentationToastId = toast(this.renderCurrentPresentationToast(), { - onClose: () => { this.currentPresentationToastId = null; }, + if (this.currentPresentationToastId && downloadableOff) { + toast.update(this.currentPresentationToastId, { autoClose: true, + render: this.renderCurrentPresentationToast(), }); } @@ -670,7 +696,10 @@ class PresentationArea extends PureComponent { } renderCurrentPresentationToast() { - const { intl, currentPresentation } = this.props; + const { + intl, currentPresentation, userIsPresenter, downloadPresentationUri, + } = this.props; + const { downloadable } = currentPresentation; return ( <div className={styles.innerToastWrapper}> @@ -679,10 +708,28 @@ class PresentationArea extends PureComponent { <Icon iconName="presentation" /> </div> </div> + <div className={styles.toastTextContent} data-test="toastSmallMsg"> <div>{`${intl.formatMessage(intlMessages.changeNotification)}`}</div> <div className={styles.presentationName}>{`${currentPresentation.name}`}</div> </div> + + {downloadable && !userIsPresenter + ? ( + <span className={styles.toastDownload}> + <div className={toastStyles.separator} /> + <a + className={styles.downloadBtn} + aria-label={`${intl.formatMessage(intlMessages.downloadLabel)} ${currentPresentation.name}`} + href={downloadPresentationUri} + target="_blank" + rel="noopener noreferrer" + > + {intl.formatMessage(intlMessages.downloadLabel)} + </a> + </span> + ) : null + } </div> ); } diff --git a/bigbluebutton-html5/imports/ui/components/presentation/styles.scss b/bigbluebutton-html5/imports/ui/components/presentation/styles.scss index d7efec3bc5..fdf85c3c89 100644 --- a/bigbluebutton-html5/imports/ui/components/presentation/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/presentation/styles.scss @@ -4,6 +4,7 @@ :root { --innerToastWidth: 17rem; --iconWrapperSize: 2rem; + --toast-icon-side: 40px; } .enter { @@ -93,14 +94,17 @@ } .innerToastWrapper { - display: flex; - flex-direction: row; width: var(--innerToastWidth); } .toastTextContent { position: relative; overflow: hidden; + margin-top: var(--sm-padding-y); + + > div:first-of-type { + font-weight: bold; + } } .presentationName { @@ -108,6 +112,13 @@ overflow: hidden; } +.toastMessage { + font-size: var(--font-size-small); + margin-top: var(--toast-margin); + overflow: hidden; + text-overflow: ellipsis; +} + .toastIcon { margin-right: var(--sm-padding-x); [dir="rtl"] & { @@ -118,21 +129,37 @@ .iconWrapper { background-color: var(--color-primary); - width: var(--iconWrapperSize); - height: var(--iconWrapperSize); + width: var(--toast-icon-side); + height: var(--toast-icon-side); border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; > i { position: relative; - left: var(--md-padding-y); - top: var(--sm-padding-y); - font-size: var(--font-size-base); color: var(--color-white); + font-size: var(--font-size-larger); + } +} + +.toastDownload { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; - [dir="rtl"] & { - left: 0; - right: var(--md-padding-y); - } + a { + color: var(--color-primary); + cursor: pointer; + text-decoration: none; + + &:focus, + &:hover, + &:active { + color: var(--color-primary); + box-shadow: 0; + } } } diff --git a/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx b/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx index a337150da8..78f822c1fb 100644 --- a/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx @@ -5,6 +5,7 @@ import { toast } from 'react-toastify'; import Icon from '/imports/ui/components/icon/component'; import Button from '/imports/ui/components/button/component'; import { ENTER } from '/imports/utils/keyCodes'; +import toastStyles from '/imports/ui/components/toast/styles'; import { styles } from './styles'; const messages = defineMessages({ @@ -71,7 +72,7 @@ class StatusNotifier extends Component { autoClose: false, closeOnClick: false, closeButton: false, - className: styles.raisedHandsToast, + className: toastStyles.actionToast, }); } break; @@ -161,7 +162,7 @@ class StatusNotifier extends Component { <div>{intl.formatMessage(messages.raisedHandsTitle)}</div> {formattedRaisedHands} </div> - <div className={styles.separator} /> + <div className={toastStyles.separator} /> <Button className={styles.clearBtn} label={intl.formatMessage(messages.lowerHandsLabel)} diff --git a/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss b/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss index 5f396dfcc9..d5f4978fdc 100644 --- a/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/status-notifier/styles.scss @@ -3,7 +3,6 @@ :root { --iconWrapperSize: 40px; - --icon-offset: .6rem; --innerToastWidth: 17rem; --toast-margin: .5rem; --toast-icon-side: 40px; @@ -87,23 +86,6 @@ padding: 5px 0; } -.raisedHandsToast { - display: flex; - position: relative; - margin-bottom: var(--sm-padding-x); - padding: var(--md-padding-x); - border-radius: var(--border-radius); - box-shadow: 0 var(--border-size-small) 10px 0 rgba(0, 0, 0, 0.1), 0 var(--border-size) 15px 0 rgba(0, 0, 0, 0.05); - justify-content: space-between; - color: var(--color-text); - background-color: var(--color-white); - -webkit-animation-duration: 0.75s; - animation-duration: 0.75s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; - max-width: var(--toast-max-width); -} - .avatar:hover, .avatar:focus { border: solid var(--border-size) var(--color-gray-lighter); @@ -118,8 +100,8 @@ > i { position: relative; color: var(--color-white); - top: var(--icon-offset); - left: var(--icon-offset); + top: var(--toast-margin); + left: var(--toast-margin); font-size: var(--font-size-xl); [dir="rtl"] & { diff --git a/bigbluebutton-html5/imports/ui/components/toast/styles.scss b/bigbluebutton-html5/imports/ui/components/toast/styles.scss index a5ff879223..854bfffeb7 100755 --- a/bigbluebutton-html5/imports/ui/components/toast/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/toast/styles.scss @@ -144,21 +144,28 @@ } } -.toast { +.toast , +.actionToast { position: relative; margin-bottom: var(--sm-padding-x); - padding: var(--md-padding-x); + padding: 12px; border-radius: var(--border-radius); box-shadow: 0 var(--border-size-small) 10px 0 rgba(0, 0, 0, 0.1), 0 var(--border-size) 15px 0 rgba(0, 0, 0, 0.05); display: flex; justify-content: space-between; - cursor: pointer; color: var(--color-text); - background-color: var(--background); + -webkit-animation-duration: 0.75s; animation-duration: 0.75s; + -webkit-animation-fill-mode: both; animation-fill-mode: both; max-width: var(--toast-max-width); + min-width: var(--toast-max-width); width: var(--toast-max-width); +} + +.toast { + cursor: pointer; + background-color: var(--background); &:hover, &:focus { @@ -166,6 +173,14 @@ } } +.actionToast { + background-color: var(--color-white); + + i.close { + left: none !important; + } +} + .body { margin: auto auto; flex: 1; diff --git a/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss b/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss index bf83f8da39..492a95241e 100644 --- a/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss +++ b/bigbluebutton-html5/imports/ui/stylesheets/variables/typography.scss @@ -7,6 +7,7 @@ --font-size-base: 1rem; --font-size-xl: 1.75rem; + --font-size-larger: 1.5rem; --font-size-large: 1.25rem; --font-size-md: 0.95rem; --font-size-small: 0.875rem; diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json index cc6ff15f39..6457c594cf 100755 --- a/bigbluebutton-html5/private/locales/en.json +++ b/bigbluebutton-html5/private/locales/en.json @@ -135,6 +135,7 @@ "app.meeting.alertBreakoutEndsUnderMinutesSingular": "Breakout is closing in one minute.", "app.presentation.hide": "Hide presentation", "app.presentation.notificationLabel": "Current presentation", + "app.presentation.downloadLabel": "Download", "app.presentation.slideContent": "Slide Content", "app.presentation.startSlideContent": "Slide content start", "app.presentation.endSlideContent": "Slide content end", -- GitLab