Introduce unsupported browser page
This commit is contained in:
parent
57ba702dda
commit
2e81b8493e
3
Makefile
3
Makefile
|
@ -8,7 +8,6 @@ OUTPUT_DIR = .
|
|||
STYLES_BUNDLE = css/all.bundle.css
|
||||
STYLES_DESTINATION = css/all.css
|
||||
STYLES_MAIN = css/main.scss
|
||||
STYLES_UNSUPPORTED_BROWSER = css/unsupported_browser.scss
|
||||
WEBPACK = ./node_modules/.bin/webpack
|
||||
|
||||
all: update-deps compile deploy clean
|
||||
|
@ -47,7 +46,6 @@ deploy-lib-jitsi-meet:
|
|||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-css:
|
||||
$(NODE_SASS) css/unsupported_browser.scss css/unsupported_browser.css ; \
|
||||
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
|
||||
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
|
||||
rm $(STYLES_BUNDLE)
|
||||
|
@ -59,6 +57,5 @@ source-package:
|
|||
mkdir -p source_package/jitsi-meet/css && \
|
||||
cp -r *.js *.html connection_optimization favicon.ico fonts images libs sounds LICENSE lang source_package/jitsi-meet && \
|
||||
cp css/all.css source_package/jitsi-meet/css && \
|
||||
cp css/unsupported_browser.css source_package/jitsi-meet/css && \
|
||||
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
|
||||
rm -rf source_package
|
||||
|
|
|
@ -131,6 +131,6 @@ $linkHoverFontColor: #287ade;
|
|||
/**
|
||||
* Landing
|
||||
*/
|
||||
$landingButtonBgColor: #ff9a00;
|
||||
$landingTextColor: #4a4a4a;
|
||||
$primaryLandingButtonBgColor: #17a0db;
|
||||
$unsupportedBrowserButtonBgColor: #ff9a00;
|
||||
$unsupportedBrowserTextColor: #4a4a4a;
|
||||
$primaryUnsupportedBrowserButtonBgColor: #17a0db;
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
@import '404';
|
||||
@import 'policy';
|
||||
@import 'filmstrip';
|
||||
@import 'landing';
|
||||
@import 'unsupported-browser/mobile-browser-page';
|
||||
@import 'unsupported-browser/unsupported_browser';
|
||||
|
||||
/* Modules END */
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
.landing {
|
||||
.mobile-browser-page {
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
padding: 35px 0;
|
||||
width: 100vw;
|
||||
|
||||
&__body {
|
||||
color: $landingTextColor;
|
||||
color: $unsupportedBrowserTextColor;
|
||||
margin: auto;
|
||||
max-width: 40em;
|
||||
text-align: center;
|
||||
|
@ -44,25 +44,25 @@
|
|||
max-width: 300px;
|
||||
width: 98%;
|
||||
@include border-radius(8px);
|
||||
background-color: $landingButtonBgColor;
|
||||
background-color: $unsupportedBrowserButtonBgColor;
|
||||
font-size: 1.5em;
|
||||
font-weight: 300;
|
||||
letter-spacing: 0.5px;
|
||||
text-shadow: 0px 1px 2px $landingTextColor;
|
||||
text-shadow: 0px 1px 2px $unsupportedBrowserTextColor;
|
||||
|
||||
// Disable standard button effects.
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
|
||||
&:active {
|
||||
background-color: $landingButtonBgColor;
|
||||
background-color: $unsupportedBrowserButtonBgColor;
|
||||
}
|
||||
|
||||
&_primary {
|
||||
background-color: $primaryLandingButtonBgColor;
|
||||
background-color: $primaryUnsupportedBrowserButtonBgColor;
|
||||
|
||||
&:active {
|
||||
background-color: $primaryLandingButtonBgColor;
|
||||
background-color: $primaryUnsupportedBrowserButtonBgColor;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
.browser {
|
||||
display: inline-block;
|
||||
margin: 1em 7px;
|
||||
width: 138px;
|
||||
vertical-align: middle;
|
||||
color: #929391;
|
||||
font-size: 20px;
|
||||
|
||||
&__button {
|
||||
background-color: #62c82a;
|
||||
border: 1px solid #3c8117;
|
||||
border-radius: 10px;
|
||||
color: #FFFFFF;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
width: 115px;
|
||||
height: 26px;
|
||||
padding-top: 13px;
|
||||
margin: 15px auto 0px auto;
|
||||
}
|
||||
|
||||
&__link {
|
||||
color: #087dba;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-list
|
||||
{
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
margin: 20px auto 0px auto;
|
||||
|
||||
&_chrome {
|
||||
width: 78px;
|
||||
height: 78px;
|
||||
background-image: url('../../images/chrome.png');
|
||||
}
|
||||
|
||||
&_chromium {
|
||||
width: 77px;
|
||||
height: 78px;
|
||||
background-image: url('../../images/chromium.png');
|
||||
}
|
||||
|
||||
&_firefox {
|
||||
width: 86px;
|
||||
height: 80px;
|
||||
background-image: url('../../images/firefox.png');
|
||||
}
|
||||
|
||||
&_opera {
|
||||
width: 73px;
|
||||
height: 78px;
|
||||
background-image: url('../../images/opera.png');
|
||||
}
|
||||
|
||||
&_ie {
|
||||
width: 80px;
|
||||
height: 78px;
|
||||
background-image: url('../../images/ie.png');
|
||||
}
|
||||
|
||||
&_safari {
|
||||
width: 78px;
|
||||
height: 79px;
|
||||
background-image: url('../../images/safari.png');
|
||||
}
|
||||
}
|
||||
|
||||
&__text
|
||||
{
|
||||
line-height: 1.2em;
|
||||
|
||||
&_small {
|
||||
font-size: small;
|
||||
}
|
||||
}
|
||||
|
||||
&__tile {
|
||||
width: 138px;
|
||||
height: 163px;
|
||||
margin-top: 5px;
|
||||
background-color: #e8e8e8;
|
||||
border: 1px solid #cfcfcf;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.unsupported-browser {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width:500px;
|
||||
height: 565px;
|
||||
overflow:hidden;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
top: 0; left: 0; bottom: 0; right: 0;
|
||||
|
||||
&__page {
|
||||
display:inline-block;
|
||||
font-size: 28px;
|
||||
vertical-align:middle;
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin: 0 auto;
|
||||
width: 20em;
|
||||
}
|
||||
|
||||
&-wrapper {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
@import 'variables';
|
||||
|
||||
body {
|
||||
width:100%;
|
||||
height:100%;
|
||||
background-color: white;
|
||||
color: #424242;
|
||||
font-family: $baseFontFamily;
|
||||
font-size: 28px;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
#wrap{
|
||||
display: block;
|
||||
position: absolute;
|
||||
width:500px;
|
||||
height: 565px;
|
||||
overflow:hidden;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
top: 0; left: 0; bottom: 0; right: 0;
|
||||
}
|
||||
.firefox{
|
||||
font-size: 11pt;
|
||||
color: #c8c8c8;
|
||||
width: 468px;
|
||||
text-align: center;
|
||||
margin: 30px auto 0px auto;
|
||||
padding-left: 15px;
|
||||
}
|
||||
#text{
|
||||
display:inline-block;
|
||||
font-size: 28px;
|
||||
/* width: 568px; */
|
||||
vertical-align:middle;
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #087dba;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.browser {
|
||||
width: 138px;
|
||||
height: 163px;
|
||||
margin-top: 5px;
|
||||
background-color: #e8e8e8;
|
||||
border: 1px solid #cfcfcf;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.browser_wrapper
|
||||
{
|
||||
width: 138px;
|
||||
/* height: 188px; */
|
||||
vertical-align: middle;
|
||||
color: #929391;
|
||||
font-size: 20px;
|
||||
float: left;
|
||||
margin-left: 15px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.browser_text
|
||||
{
|
||||
height: 2em;
|
||||
}
|
||||
.supported_browsers
|
||||
{
|
||||
margin: 0px auto 0px auto;
|
||||
/* width: 660px; */
|
||||
}
|
||||
|
||||
.clear
|
||||
{
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.button
|
||||
{
|
||||
background-color: #62c82a;
|
||||
border: 1px solid #3c8117;
|
||||
border-radius: 10px;
|
||||
color: #FFFFFF;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
width: 115px;
|
||||
height: 26px;
|
||||
padding-top: 13px;
|
||||
margin: 15px auto 0px auto;
|
||||
}
|
||||
|
||||
.logo
|
||||
{
|
||||
margin: 20px auto 0px auto;
|
||||
}
|
||||
|
||||
#chrome_logo
|
||||
{
|
||||
width: 78px;
|
||||
height: 78px;
|
||||
background-image: url('../images/chrome.png');
|
||||
}
|
||||
#chromium_logo
|
||||
{
|
||||
width: 77px;
|
||||
height: 78px;
|
||||
background-image: url('../images/chromium.png');
|
||||
}
|
||||
#firefox_logo
|
||||
{
|
||||
width: 86px;
|
||||
height: 80px;
|
||||
background-image: url('../images/firefox.png');
|
||||
}
|
||||
|
||||
#opera_logo
|
||||
{
|
||||
width: 73px;
|
||||
height: 78px;
|
||||
background-image: url('../images/opera.png');
|
||||
}
|
||||
|
||||
#safari_logo
|
||||
{
|
||||
width: 78px;
|
||||
height: 79px;
|
||||
background-image: url('../images/safari.png');
|
||||
}
|
||||
|
||||
#ie_logo
|
||||
{
|
||||
width: 80px;
|
||||
height: 78px;
|
||||
background-image: url('../images/ie.png');
|
||||
}
|
||||
|
|
@ -6,19 +6,10 @@ import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
|||
import {
|
||||
_getRoomAndDomainFromUrlString,
|
||||
_getRouteToRender,
|
||||
areRoutesEqual,
|
||||
init
|
||||
} from './functions';
|
||||
import './reducer';
|
||||
|
||||
/**
|
||||
* Variable saving current route of the app. Later it will be extracted as
|
||||
* a property of the class with Router specific logic.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
let currentRoute = {};
|
||||
|
||||
/**
|
||||
* Temporary solution. Should dispatch actions related to initial settings of
|
||||
* the app like setting log levels, reading the config parameters from query
|
||||
|
@ -73,8 +64,8 @@ export function appNavigate(urlOrRoom) {
|
|||
.then(() => {
|
||||
const link = typeof room === 'undefined'
|
||||
&& typeof domain === 'undefined'
|
||||
? urlOrRoom
|
||||
: room;
|
||||
? urlOrRoom
|
||||
: room;
|
||||
|
||||
dispatch(_setRoomAndNavigate(link));
|
||||
});
|
||||
|
@ -153,9 +144,6 @@ function _setRoomAndNavigate(newRoom) {
|
|||
const { app } = state['features/app'];
|
||||
const newRoute = _getRouteToRender(state);
|
||||
|
||||
if (!areRoutesEqual(newRoute, currentRoute)) {
|
||||
currentRoute = newRoute;
|
||||
app._navigate(newRoute);
|
||||
}
|
||||
app._navigate(newRoute);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
localParticipantJoined,
|
||||
localParticipantLeft
|
||||
} from '../../base/participants';
|
||||
import { RouteRegistry } from '../../base/navigator';
|
||||
|
||||
import {
|
||||
appNavigate,
|
||||
|
@ -31,7 +32,7 @@ export class AbstractApp extends Component {
|
|||
* The URL, if any, with which the app was launched.
|
||||
*/
|
||||
url: React.PropTypes.string
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new App instance.
|
||||
|
@ -210,33 +211,38 @@ export class AbstractApp extends Component {
|
|||
* @returns {void}
|
||||
*/
|
||||
_navigate(route) {
|
||||
let nextState = {
|
||||
...this.state,
|
||||
route
|
||||
};
|
||||
const currentRoute = this.state.route || {};
|
||||
|
||||
// The Web App was using react-router so it utilized react-router's
|
||||
// onEnter. During the removal of react-router, modifications were
|
||||
// minimized by preserving the onEnter interface:
|
||||
// (1) Router would provide its nextState to the Route's onEnter. As the
|
||||
// role of Router is now this AbstractApp, provide its nextState.
|
||||
// (2) A replace function would be provided to the Route in case it
|
||||
// chose to redirect to another path.
|
||||
this._onRouteEnter(route, nextState, pathname => {
|
||||
// FIXME In order to minimize the modifications related to the
|
||||
// removal of react-router, the Web implementation is provided
|
||||
// bellow because the replace function is used on Web only at the
|
||||
// time of this writing. Provide a platform-agnostic implementation.
|
||||
// It should likely find the best Route matching the specified
|
||||
// pathname and navigate to it.
|
||||
window.location.pathname = pathname;
|
||||
if (!RouteRegistry.areRoutesEqual(route, currentRoute)) {
|
||||
let nextState = {
|
||||
...this.state,
|
||||
route
|
||||
};
|
||||
|
||||
// Do not proceed with the route because it chose to redirect to
|
||||
// another path.
|
||||
nextState = undefined;
|
||||
});
|
||||
// The Web App was using react-router so it utilized react-router's
|
||||
// onEnter. During the removal of react-router, modifications were
|
||||
// minimized by preserving the onEnter interface:
|
||||
// (1) Router would provide its nextState to the Route's onEnter.
|
||||
// As the role of Router is now this AbstractApp, provide its
|
||||
// nextState.
|
||||
// (2) A replace function would be provided to the Route in case it
|
||||
// chose to redirect to another path.
|
||||
this._onRouteEnter(route, nextState, pathname => {
|
||||
// FIXME In order to minimize the modifications related to the
|
||||
// removal of react-router, the Web implementation is provided
|
||||
// bellow because the replace function is used on Web only at
|
||||
// the time of this writing. Provide a platform-agnostic
|
||||
// implementation. It should likely find the best Route matching
|
||||
// the specified pathname and navigate to it.
|
||||
window.location.pathname = pathname;
|
||||
|
||||
nextState && this.setState(nextState);
|
||||
// Do not proceed with the route because it chose to redirect to
|
||||
// another path.
|
||||
nextState = undefined;
|
||||
});
|
||||
|
||||
nextState && this.setState(nextState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@ import { isRoomValid } from '../base/conference';
|
|||
import { RouteRegistry } from '../base/navigator';
|
||||
import { Platform } from '../base/react';
|
||||
import { Conference } from '../conference';
|
||||
import { Landing } from '../unsupported-browser';
|
||||
import { MobileBrowserPage } from '../unsupported-browser';
|
||||
import { WelcomePage } from '../welcome';
|
||||
|
||||
import URLProcessor from '../../../modules/config/URLProcessor';
|
||||
|
@ -33,37 +33,19 @@ export function _getRouteToRender(stateOrGetState) {
|
|||
? stateOrGetState()
|
||||
: stateOrGetState;
|
||||
|
||||
// If landing was shown, there is no need to show it again.
|
||||
const { landingIsShown } = state['features/unsupported-browser'];
|
||||
// If mobile browser page was shown, there is no need to show it again.
|
||||
const { mobileBrowserPageIsShown } = state['features/unsupported-browser'];
|
||||
const { room } = state['features/base/conference'];
|
||||
const component = isRoomValid(room) ? Conference : WelcomePage;
|
||||
const route = RouteRegistry.getRouteByComponent(component);
|
||||
|
||||
// We're using spread operator here to create copy of the route registered
|
||||
// in registry. If we overwrite some of its properties (like 'component')
|
||||
// they will stay unchanged in the registry.
|
||||
const route = { ...RouteRegistry.getRouteByComponent(component) };
|
||||
|
||||
if ((OS === 'android' || OS === 'ios') && !landingIsShown) {
|
||||
route.component = Landing;
|
||||
if ((OS === 'android' || OS === 'ios') && !mobileBrowserPageIsShown) {
|
||||
route.component = MobileBrowserPage;
|
||||
}
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method checking whether route objects are equal by value. Returns true if
|
||||
* and only if key values of the first object are equal to key values of
|
||||
* the second one.
|
||||
*
|
||||
* @param {Object} newRoute - New route object to be compared.
|
||||
* @param {Object} oldRoute - Old route object to be compared.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function areRoutesEqual(newRoute, oldRoute) {
|
||||
return Object.keys(newRoute)
|
||||
.every(key => newRoute[key] === oldRoute[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary solution. Later we'll get rid of global APP and set its properties
|
||||
* in redux store.
|
||||
|
|
|
@ -11,6 +11,20 @@
|
|||
* without needing to create additional inter-feature dependencies.
|
||||
*/
|
||||
class RouteRegistry {
|
||||
/**
|
||||
* Method checking whether route objects are equal by value. Returns true if
|
||||
* and only if key values of the first object are equal to key values of
|
||||
* the second one.
|
||||
*
|
||||
* @param {Object} newRoute - New route object to be compared.
|
||||
* @param {Object} oldRoute - Old route object to be compared.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
areRoutesEqual(newRoute, oldRoute) {
|
||||
return Object.keys(newRoute)
|
||||
.every(key => newRoute[key] === oldRoute[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new RouteRegistry instance.
|
||||
*/
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { Symbol } from '../base/react';
|
||||
|
||||
/**
|
||||
* The type of the Redux action which signals that a mobile landing is shown.
|
||||
* The type of the Redux action which signals that a mobile browser page
|
||||
* is shown.
|
||||
*
|
||||
* {
|
||||
* type: LANDING_IS_SHOWN
|
||||
* type: MOBILE_BROWSER_PAGE_IS_SHOWN
|
||||
* }
|
||||
*/
|
||||
export const LANDING_IS_SHOWN = Symbol('LANDING_IS_SHOWN');
|
||||
// eslint-disable-next-line max-len
|
||||
export const MOBILE_BROWSER_PAGE_IS_SHOWN = Symbol('MOBILE_BROWSER_PAGE_IS_SHOWN');
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { LANDING_IS_SHOWN } from './actionTypes';
|
||||
import { MOBILE_BROWSER_PAGE_IS_SHOWN } from './actionTypes';
|
||||
import './reducer';
|
||||
|
||||
/**
|
||||
* Returns an action that mobile landing is shown
|
||||
* and there is no need to show it on other pages.
|
||||
* Returns an action that mobile browser page is shown and there is no need
|
||||
* to show it on other pages.
|
||||
*
|
||||
* @returns {{
|
||||
* type: LANDING_IS_SHOWN
|
||||
* type: MOBILE_BROWSER_PAGE_IS_SHOWN
|
||||
* }}
|
||||
*/
|
||||
export function landingIsShown() {
|
||||
export function mobileBrowserPageIsShown() {
|
||||
return {
|
||||
type: LANDING_IS_SHOWN
|
||||
type: MOBILE_BROWSER_PAGE_IS_SHOWN
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { connect } from 'react-redux';
|
|||
import { Platform } from '../../base/react';
|
||||
|
||||
import { appNavigate } from '../../app';
|
||||
import { landingIsShown } from '../actions';
|
||||
import { mobileBrowserPageIsShown } from '../actions';
|
||||
|
||||
/**
|
||||
* The map of platforms to URLs at which the mobile app for the associated
|
||||
|
@ -16,14 +16,14 @@ const URLS = {
|
|||
};
|
||||
|
||||
/**
|
||||
* React component representing mobile landing page.
|
||||
* React component representing mobile browser page.
|
||||
*
|
||||
* @class Landing
|
||||
* @class MobileBrowserPage
|
||||
*/
|
||||
class Landing extends Component {
|
||||
class MobileBrowserPage extends Component {
|
||||
|
||||
/**
|
||||
* Constructor of Landing component.
|
||||
* Constructor of MobileBrowserPage component.
|
||||
*
|
||||
* @param {Object} props - The read-only React Component props with which
|
||||
* the new instance is to be initialized.
|
||||
|
@ -36,14 +36,14 @@ class Landing extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Landing component's property types.
|
||||
* Mobile browser page component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
dispatch: React.PropTypes.func,
|
||||
room: React.PropTypes.string
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* React lifecycle method triggered after component is mounted.
|
||||
|
@ -51,7 +51,7 @@ class Landing extends Component {
|
|||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.props.dispatch(landingIsShown());
|
||||
this.props.dispatch(mobileBrowserPageIsShown());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,21 +90,25 @@ class Landing extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Renders landing component.
|
||||
* Renders component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { btnText } = this.state;
|
||||
const primaryButtonClasses = 'landing__button landing__button_primary';
|
||||
const blockPrefix = 'mobile-browser-page';
|
||||
const textClasses = `${blockPrefix}__text ${blockPrefix}__text_small`;
|
||||
let primaryButtonClasses = `${blockPrefix}__button`;
|
||||
|
||||
primaryButtonClasses += `${blockPrefix}__button_primary`;
|
||||
|
||||
return (
|
||||
<div className = 'landing'>
|
||||
<div className = 'landing__body'>
|
||||
<div className = { blockPrefix }>
|
||||
<div className = { `${blockPrefix}__body` }>
|
||||
<img
|
||||
className = 'landing__logo'
|
||||
className = { `${blockPrefix}__logo` }
|
||||
src = '/images/logo-blue.svg' />
|
||||
<p className = 'landing__text'>
|
||||
<p className = { `${blockPrefix}__text` }>
|
||||
You need <strong>Jitsi Meet</strong> to join a
|
||||
conversation on your mobile
|
||||
</p>
|
||||
|
@ -113,13 +117,13 @@ class Landing extends Component {
|
|||
Download the App
|
||||
</button>
|
||||
</a>
|
||||
<p className = 'landing__text landing__text_small'>
|
||||
<p className = { textClasses }>
|
||||
or if you already have it
|
||||
<br />
|
||||
<strong>then</strong>
|
||||
</p>
|
||||
<button
|
||||
className = 'landing__button'
|
||||
className = 'mobile-browser-page__button'
|
||||
onClick = { this._onClickJoin }>
|
||||
{ btnText }
|
||||
</button>
|
||||
|
@ -130,7 +134,7 @@ class Landing extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated Landing's props.
|
||||
* Maps (parts of) the Redux state to the associated MobileBrowserPage's props.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {{
|
||||
|
@ -143,4 +147,4 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Landing);
|
||||
export default connect(mapStateToProps)(MobileBrowserPage);
|
|
@ -0,0 +1,117 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
/**
|
||||
* Array of all supported browsers.
|
||||
*/
|
||||
const SUPPORTED_BROWSERS = [
|
||||
{
|
||||
link: 'http://google.com/chrome',
|
||||
name: 'chrome',
|
||||
plugin: false,
|
||||
title: 'Chrome 44+'
|
||||
}, {
|
||||
link: 'http://www.chromium.org/',
|
||||
name: 'chromium',
|
||||
plugin: false,
|
||||
title: 'Chromium 44+'
|
||||
}, {
|
||||
link: 'http://www.opera.com',
|
||||
name: 'opera',
|
||||
plugin: false,
|
||||
title: 'Opera 32+'
|
||||
}, {
|
||||
link: 'http://www.getfirefox.com/',
|
||||
name: 'firefox',
|
||||
plugin: false,
|
||||
title: 'Firefox and Iceweasel 40+'
|
||||
}, {
|
||||
link: 'https://temasys.atlassian.net/wiki/display/TWPP/WebRTC+Plugins',
|
||||
name: 'ie',
|
||||
plugin: 'Temasys 0.8.854+',
|
||||
title: 'IE'
|
||||
}, {
|
||||
link: 'https://temasys.atlassian.net/wiki/display/TWPP/WebRTC+Plugins',
|
||||
name: 'safari',
|
||||
plugin: 'Temasys 0.8.854+',
|
||||
title: 'Safari'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* React component representing unsupported browser page.
|
||||
*
|
||||
* @class UnsupportedBrowserPage
|
||||
*/
|
||||
export default class UnsupportedBrowserPage extends Component {
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<div className = 'unsupported-browser-wrapper'>
|
||||
<div className = 'unsupported-browser'>
|
||||
<div className = 'unsupported-browser__content'>
|
||||
<h2 className = 'unsupported-browser__title'>
|
||||
This application is currently only supported by
|
||||
</h2>
|
||||
{ this._getSupportedBrowsersLayout() }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates layout for the list of supported browsers.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
* @private
|
||||
*/
|
||||
_getSupportedBrowsersLayout() {
|
||||
return (
|
||||
<div className = 'browser-list'>
|
||||
{ SUPPORTED_BROWSERS.map(this._getSupportedBrowser) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that generated layout for supported browser object.
|
||||
*
|
||||
* @param {Object} browser - Object containing information about supported
|
||||
* browser.
|
||||
* @returns {ReactElement}
|
||||
* @private
|
||||
*/
|
||||
_getSupportedBrowser(browser) {
|
||||
let pluginHtml = null;
|
||||
const logoClassName = `browser__logo browser__logo_${browser.name}`;
|
||||
|
||||
// Browsers not supporting WebRTC could support application
|
||||
// with Temasys plugin installed.
|
||||
if (browser.plugin) {
|
||||
const className = 'browser__text_small';
|
||||
|
||||
pluginHtml = <p className = { className }>({ browser.plugin })</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className = 'browser'>
|
||||
<div className = 'browser__text'>
|
||||
{ browser.title }
|
||||
{ pluginHtml }
|
||||
</div>
|
||||
<div className = 'browser__tile'>
|
||||
<div className = { logoClassName } />
|
||||
<a
|
||||
className = 'browser__link'
|
||||
href = { browser.link }>
|
||||
<div className = 'browser__button'>DOWNLOAD</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
export { default as Landing } from './Landing';
|
||||
export { default as MobileBrowserPage } from './MobileBrowserPage';
|
||||
export { default as UnsupportedBrowserPage } from './UnsupportedBrowserPage';
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import { LANDING_IS_SHOWN } from './actionTypes';
|
||||
import { MOBILE_BROWSER_PAGE_IS_SHOWN } from './actionTypes';
|
||||
|
||||
ReducerRegistry.register(
|
||||
'features/unsupported-browser',
|
||||
(state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case LANDING_IS_SHOWN:
|
||||
case MOBILE_BROWSER_PAGE_IS_SHOWN:
|
||||
return {
|
||||
...state,
|
||||
|
||||
/**
|
||||
* Flag that shows that mobile landing is shown.
|
||||
* Flag that shows that mobile browser page is shown.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
landingIsShown: true
|
||||
mobileBrowserPageIsShown: true
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Jitsi Meet: Unsupported Browser</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/unsupported_browser.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- wrap starts here -->
|
||||
<div id="wrap">
|
||||
<div id="text">
|
||||
<p>This application is currently only supported by</p>
|
||||
|
||||
<div class="supported_browsers">
|
||||
<div class="browser_wrapper">
|
||||
Chrome 44+
|
||||
<div class="browser">
|
||||
<div class="logo" id="chrome_logo"></div>
|
||||
<a href="http://google.com/chrome"><div class="button">DOWNLOAD</div></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="browser_wrapper">
|
||||
Chromium 44+
|
||||
<div class="browser">
|
||||
<div class="logo" id="chromium_logo"></div>
|
||||
<a href="http://www.chromium.org/"><div class="button">DOWNLOAD</div></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="browser_wrapper">
|
||||
Opera 32+
|
||||
<div class="browser">
|
||||
<div class="logo" id="opera_logo"></div>
|
||||
<a href="http://www.opera.com"><div class="button">DOWNLOAD</div></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="browser_wrapper">
|
||||
<div class="browser_text">
|
||||
Firefox and Iceweasel 40+</div>
|
||||
<div class="browser">
|
||||
<div class="logo" id="firefox_logo"></div>
|
||||
<a href="http://www.getfirefox.com/"><div class="button">DOWNLOAD</div></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="browser_wrapper">
|
||||
<div class="browser_text">
|
||||
IE <br /> <span style="font-size: small">(Temasys 0.8.854+)</span></div>
|
||||
<div class="browser">
|
||||
<div class="logo" id="ie_logo"></div>
|
||||
<a href="https://temasys.atlassian.net/wiki/display/TWPP/WebRTC+Plugins"><div class="button">DOWNLOAD</div></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="browser_wrapper">
|
||||
<div class="browser_text">
|
||||
Safari <br /> <span style="font-size: small">(Temasys 0.8.854+)</span></div>
|
||||
<div class="browser">
|
||||
<div class="logo" id="safari_logo"></div>
|
||||
<a href="https://temasys.atlassian.net/wiki/display/TWPP/WebRTC+Plugins"><div class="button">DOWNLOAD</div></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<!-- wrap ends here -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue