diff --git a/res/css/_components.scss b/res/css/_components.scss
index c82dedc069..57a34023c0 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -36,6 +36,7 @@
@import "./views/auth/_LanguageSelector.scss";
@import "./views/auth/_ServerConfig.scss";
@import "./views/auth/_ServerTypeSelector.scss";
+@import "./views/auth/_Welcome.scss";
@import "./views/avatars/_BaseAvatar.scss";
@import "./views/avatars/_MemberStatusMessageAvatar.scss";
@import "./views/context_menus/_MessageContextMenu.scss";
diff --git a/res/css/structures/_HomePage.scss b/res/css/structures/_HomePage.scss
index 5f1e035e99..3aa80f6f59 100644
--- a/res/css/structures/_HomePage.scss
+++ b/res/css/structures/_HomePage.scss
@@ -1,6 +1,7 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
+Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -22,10 +23,3 @@ limitations under the License.
margin-left: auto;
margin-right: auto;
}
-
-.mx_HomePage iframe {
- display: block;
- width: 100%;
- height: 100%;
- border: 0px;
-}
diff --git a/res/css/views/auth/_Welcome.scss b/res/css/views/auth/_Welcome.scss
new file mode 100644
index 0000000000..9043289184
--- /dev/null
+++ b/res/css/views/auth/_Welcome.scss
@@ -0,0 +1,26 @@
+/*
+Copyright 2019 New Vector Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_Welcome {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.mx_Welcome .mx_AuthBody_language {
+ width: 120px;
+ margin-bottom: 10px;
+}
diff --git a/res/css/views/context_menus/_TopLeftMenu.scss b/res/css/views/context_menus/_TopLeftMenu.scss
index 18463da824..f305f0fae3 100644
--- a/res/css/views/context_menus/_TopLeftMenu.scss
+++ b/res/css/views/context_menus/_TopLeftMenu.scss
@@ -27,6 +27,10 @@ limitations under the License.
margin: 5px 0;
padding: 0;
+ li.mx_TopLeftMenu_icon_home::after {
+ mask-image: url('$(res)/img/feather-icons/home.svg');
+ }
+
li.mx_TopLeftMenu_icon_settings::after {
mask-image: url('$(res)/img/feather-icons/settings.svg');
}
diff --git a/res/img/feather-icons/home.svg b/res/img/feather-icons/home.svg
new file mode 100644
index 0000000000..7bb31b23dc
--- /dev/null
+++ b/res/img/feather-icons/home.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Registration.js b/src/Registration.js
index f3a2076ed6..42e172ca0b 100644
--- a/src/Registration.js
+++ b/src/Registration.js
@@ -35,8 +35,10 @@ export const SAFE_LOCALPART_REGEX = /^[a-z0-9=_\-./]+$/;
* on what the HS supports
*
* @param {object} options
- * @param {bool} options.go_home_on_cancel If true, goes to
- * the hame page if the user cancels the action
+ * @param {bool} options.go_home_on_cancel
+ * If true, goes to the home page if the user cancels the action
+ * @param {bool} options.go_welcome_on_cancel
+ * If true, goes to the welcome page if the user cancels the action
*/
export async function startAnyRegistrationFlow(options) {
if (options === undefined) options = {};
@@ -73,6 +75,8 @@ export async function startAnyRegistrationFlow(options) {
dis.dispatch({action: 'start_registration'});
} else if (options.go_home_on_cancel) {
dis.dispatch({action: 'view_home_page'});
+ } else if (options.go_welcome_on_cancel) {
+ dis.dispatch({action: 'view_welcome_page'});
}
},
});
diff --git a/src/components/structures/HomePage.js b/src/components/structures/EmbeddedPage.js
similarity index 59%
rename from src/components/structures/HomePage.js
rename to src/components/structures/EmbeddedPage.js
index 18f1a2ba31..d10b7f8414 100644
--- a/src/components/structures/HomePage.js
+++ b/src/components/structures/EmbeddedPage.js
@@ -1,6 +1,7 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
+Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -26,22 +27,27 @@ import sdk from '../../index';
import { MatrixClient } from 'matrix-js-sdk';
import classnames from 'classnames';
-class HomePage extends React.Component {
- static displayName = 'HomePage';
-
+export default class EmbeddedPage extends React.PureComponent {
static propTypes = {
- // URL to use as the iFrame src. Defaults to /home.html.
- homePageUrl: PropTypes.string,
+ // URL to request embedded page content from
+ url: PropTypes.string,
+ // Class name prefix to apply for a given instance
+ className: PropTypes.string,
+ // Whether to wrap the page in a scrollbar
+ scrollbar: PropTypes.bool,
};
static contextTypes = {
matrixClient: PropTypes.instanceOf(MatrixClient),
};
- state = {
- iframeSrc: '',
+ constructor(props) {
+ super(props);
+
+ this.state = {
page: '',
- };
+ };
+ }
translate(s) {
// default implementation - skins may wish to extend this
@@ -51,22 +57,24 @@ class HomePage extends React.Component {
componentWillMount() {
this._unmounted = false;
- // we use request() to inline the homepage into the react component
+ if (!this.props.url) {
+ return;
+ }
+
+ // we use request() to inline the page into the react component
// so that it can inherit CSS and theming easily rather than mess around
// with iframes and trying to synchronise document.stylesheets.
- const src = this.props.homePageUrl || 'home.html';
-
request(
- { method: "GET", url: src },
+ { method: "GET", url: this.props.url },
(err, response, body) => {
if (this._unmounted) {
return;
}
if (err || response.status < 200 || response.status >= 300) {
- console.warn(`Error loading home page: ${err}`);
- this.setState({ page: _t("Couldn't load home page") });
+ console.warn(`Error loading page: ${err}`);
+ this.setState({ page: _t("Couldn't load page") });
return;
}
@@ -81,28 +89,28 @@ class HomePage extends React.Component {
}
render() {
- const isGuest = this.context.matrixClient.isGuest();
+ const client = this.context.matrixClient;
+ const isGuest = client ? client.isGuest() : true;
+ const className = this.props.className;
const classes = classnames({
- mx_HomePage: true,
- mx_HomePage_guest: isGuest,
+ [className]: true,
+ [`${className}_guest`]: isGuest,
});
- if (this.state.iframeSrc) {
- return (
-
;
}
}
}
-
-module.exports = HomePage;
diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js
index eac4422de0..2303083d98 100644
--- a/src/components/structures/LoggedInView.js
+++ b/src/components/structures/LoggedInView.js
@@ -420,7 +420,7 @@ const LoggedInView = React.createClass({
render: function() {
const LeftPanel = sdk.getComponent('structures.LeftPanel');
const RoomView = sdk.getComponent('structures.RoomView');
- const HomePage = sdk.getComponent('structures.HomePage');
+ const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage');
const GroupView = sdk.getComponent('structures.GroupView');
const MyGroups = sdk.getComponent('structures.MyGroups');
const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar');
@@ -459,8 +459,20 @@ const LoggedInView = React.createClass({
case PageTypes.HomePage:
{
- pageElement = ;
}
break;
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index bb90b2aeb5..5b01912bb7 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -60,27 +60,30 @@ const VIEWS = {
// trying to re-animate a matrix client or register as a guest.
LOADING: 0,
+ // we are showing the welcome view
+ WELCOME: 1,
+
// we are showing the login view
- LOGIN: 1,
+ LOGIN: 2,
// we are showing the registration view
- REGISTER: 2,
+ REGISTER: 3,
// completeing the registration flow
- POST_REGISTRATION: 3,
+ POST_REGISTRATION: 4,
// showing the 'forgot password' view
- FORGOT_PASSWORD: 4,
+ FORGOT_PASSWORD: 5,
// we have valid matrix credentials (either via an explicit login, via the
// initial re-animation/guest registration, or via a registration), and are
// now setting up a matrixclient to talk to it. This isn't an instant
// process because we need to clear out indexeddb. While it is going on we
// show a big spinner.
- LOGGING_IN: 5,
+ LOGGING_IN: 6,
// we are logged in with an active matrix client.
- LOGGED_IN: 6,
+ LOGGED_IN: 7,
};
// Actions that are redirected through the onboarding process prior to being
@@ -354,8 +357,8 @@ export default React.createClass({
});
}).then((loadedSession) => {
if (!loadedSession) {
- // fall back to showing the login screen
- dis.dispatch({action: "start_login"});
+ // fall back to showing the welcome screen
+ dis.dispatch({action: "view_welcome_page"});
}
});
// Note we don't catch errors from this: we catch everything within
@@ -606,6 +609,9 @@ export default React.createClass({
case 'view_group':
this._viewGroup(payload);
break;
+ case 'view_welcome_page':
+ this._viewWelcome();
+ break;
case 'view_home_page':
this._viewHome();
break;
@@ -881,6 +887,13 @@ export default React.createClass({
this.notifyNewScreen('group/' + groupId);
},
+ _viewWelcome() {
+ this.setStateForNewView({
+ view: VIEWS.WELCOME,
+ });
+ this.notifyNewScreen('welcome');
+ },
+
_viewHome: function() {
// The home page requires the "logged in" view, so we'll set that.
this.setStateForNewView({
@@ -954,11 +967,11 @@ export default React.createClass({
}
dis.dispatch({
action: 'require_registration',
- // If the set_mxid dialog is cancelled, view /home because if the browser
- // was pointing at /user/@someone:domain?action=chat, the URL needs to be
- // reset so that they can revisit /user/.. // (and trigger
+ // If the set_mxid dialog is cancelled, view /welcome because if the
+ // browser was pointing at /user/@someone:domain?action=chat, the URL
+ // needs to be reset so that they can revisit /user/.. // (and trigger
// `_chatCreateOrReuse` again)
- go_home_on_cancel: true,
+ go_welcome_on_cancel: true,
});
return;
}
@@ -1180,7 +1193,11 @@ export default React.createClass({
room_id: localStorage.getItem('mx_last_room_id'),
});
} else {
- dis.dispatch({action: 'view_home_page'});
+ if (MatrixClientPeg.get().isGuest) {
+ dis.dispatch({action: 'view_welcome_page'});
+ } else {
+ dis.dispatch({action: 'view_home_page'});
+ }
}
},
@@ -1466,6 +1483,10 @@ export default React.createClass({
dis.dispatch({
action: 'view_user_settings',
});
+ } else if (screen == 'welcome') {
+ dis.dispatch({
+ action: 'view_welcome_page',
+ });
} else if (screen == 'home') {
dis.dispatch({
action: 'view_home_page',
@@ -1849,6 +1870,11 @@ export default React.createClass({
}
}
+ if (this.state.view === VIEWS.WELCOME) {
+ const Welcome = sdk.getComponent('auth.Welcome');
+ return ;
+ }
+
if (this.state.view === VIEWS.REGISTER) {
const Registration = sdk.getComponent('structures.auth.Registration');
return (
diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js
new file mode 100644
index 0000000000..9cc398329d
--- /dev/null
+++ b/src/components/views/auth/Welcome.js
@@ -0,0 +1,47 @@
+/*
+Copyright 2019 New Vector Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import sdk from '../../../index';
+import SdkConfig from '../../../SdkConfig';
+
+export default class Welcome extends React.PureComponent {
+ render() {
+ const AuthPage = sdk.getComponent("auth.AuthPage");
+ const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage');
+ const LanguageSelector = sdk.getComponent('auth.LanguageSelector');
+
+ const pagesConfig = SdkConfig.get().embeddedPages;
+ let pageUrl = null;
+ if (pagesConfig) {
+ pageUrl = pagesConfig.welcomeUrl;
+ }
+ if (!pageUrl) {
+ pageUrl = 'welcome.html';
+ }
+
+ return (
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/src/components/views/context_menus/TopLeftMenu.js b/src/components/views/context_menus/TopLeftMenu.js
index 87b277215b..1d58db3c49 100644
--- a/src/components/views/context_menus/TopLeftMenu.js
+++ b/src/components/views/context_menus/TopLeftMenu.js
@@ -1,5 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
+Copyright 2018, 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import dis from '../../../dispatcher';
import { _t } from '../../../languageHandler';
import LogoutDialog from "../dialogs/LogoutDialog";
import Modal from "../../../Modal";
+import SdkConfig from '../../../SdkConfig';
export class TopLeftMenu extends React.Component {
constructor() {
@@ -27,8 +28,28 @@ export class TopLeftMenu extends React.Component {
this.signOut = this.signOut.bind(this);
}
+ hasHomePage() {
+ const config = SdkConfig.get();
+ const pagesConfig = config.embeddedPages;
+ if (pagesConfig && pagesConfig.homeUrl) {
+ return true;
+ }
+ // This is a deprecated config option for the home page
+ // (despite the name, given we also now have a welcome
+ // page, which is not the same).
+ return !!config.welcomePageUrl;
+ }
+
render() {
+ let homePageSection = null;
+ if (this.hasHomePage()) {
+ homePageSection =
+
{_t("Home")}
+
;
+ }
+
return
+ {homePageSection}
{_t("Settings")}
@@ -38,6 +59,11 @@ export class TopLeftMenu extends React.Component {
;
}
+ viewHomePage() {
+ dis.dispatch({action: 'view_home_page'});
+ this.closeMenu();
+ }
+
openSettings() {
dis.dispatch({action: 'view_user_settings'});
this.closeMenu();
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index c2f19cbdd2..776a7176fd 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1279,6 +1279,7 @@
"Safari and Opera work too.": "Safari and Opera work too.",
"With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!",
"I understand the risks and wish to continue": "I understand the risks and wish to continue",
+ "Couldn't load page": "Couldn't load page",
"You must register to use this functionality": "You must register to use this functionality",
"You must join the room to see its files": "You must join the room to see its files",
"There are no visible files in this room": "There are no visible files in this room",
@@ -1323,7 +1324,6 @@
"Community %(groupId)s not found": "Community %(groupId)s not found",
"This homeserver does not support communities": "This homeserver does not support communities",
"Failed to load %(groupId)s": "Failed to load %(groupId)s",
- "Couldn't load home page": "Couldn't load home page",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Invalid configuration: Cannot supply a default homeserver URL and a default server name",
"Failed to reject invitation": "Failed to reject invitation",
"This room is not public. You will not be able to rejoin without an invite.": "This room is not public. You will not be able to rejoin without an invite.",