diff --git a/res/css/_components.scss b/res/css/_components.scss index a1b575a0a1..1b35332711 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -18,6 +18,7 @@ @import "./structures/_RoomSubList.scss"; @import "./structures/_RoomView.scss"; @import "./structures/_SearchBox.scss"; +@import "./structures/_TabbedView.scss"; @import "./structures/_TagPanel.scss"; @import "./structures/_TopLeftMenuButton.scss"; @import "./structures/_UploadBar.scss"; diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss new file mode 100644 index 0000000000..7d42823d17 --- /dev/null +++ b/res/css/structures/_TabbedView.scss @@ -0,0 +1,76 @@ +/* +Copyright 2017 Travis Ralston + +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_TabbedView { + margin: 0; + padding: 0; + display: flex; + width: 100%; + height: 100%; + background-color: $tab-panel-bg-color; +} + +.mx_TabbedView_tabLabels { + width: 300px; + height: 100%; + background-color: $tab-list-bg-color; + color: $tab-list-fg-color; + border-right: 1px solid $tab-border-color; + border-left: 1px solid $tab-border-color; +} + +.mx_TabbedView_tabPanels { + width: calc(100% - 320px); + display: inline-block; + height: 100%; + padding-left: 20px; + scroll-snap-type: block; +} + +.mx_TabbedView_tabLabel { + text-align: center; + vertical-align: middle; + text-transform: uppercase; + cursor: pointer; + display: block; + padding: 20px; + width: calc(100% - 40px); + border-bottom: 1px solid $tab-border-color; +} + +.mx_TabbedView_exit { + padding-top: 10px; + padding-bottom: 10px; +} + +.mx_TabbedView_tabLabel:hover { + font-weight: 700; +} + +.mx_TabbedView_tabLabel_active { + font-weight: 700; + background-color: $tab-list-active-bg-color; + color: $tab-list-active-fg-color; +} + +.mx_TabbedView_tabPanel { + height: 100vh; // 100% of viewport height + scroll-snap-align: start; +} + +.mx_TabbedView_tabPanelContent { + width: 600px; +} \ No newline at end of file diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index c9f62fbe6b..8f369a3b33 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -186,6 +186,14 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; +// Tabbed views +$tab-list-bg-color: $secondary-accent-color; +$tab-list-fg-color: $accent-color; +$tab-list-active-bg-color: $tertiary-accent-color; +$tab-list-active-fg-color: $accent-color; +$tab-border-color: $tertiary-accent-color; +$tab-panel-bg-color: #fff; + // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index dbab909f13..996fe965cf 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -66,6 +66,7 @@ $primary-hairline-color: #e5e5e5; // used for the border of input text fields $input-border-color: #f0f0f0; +$input-border-dark-color: #b8b8b8; $input-darker-bg-color: #c1c9d6; $input-darker-fg-color: #9fa9ba; @@ -181,6 +182,14 @@ $imagebody-giflabel: rgba(0, 0, 0, 0.7); $imagebody-giflabel-border: rgba(0, 0, 0, 0.2); $imagebody-giflabel-color: rgba(255, 255, 255, 1); +// Tabbed views +$tab-list-bg-color: $secondary-accent-color; +$tab-list-fg-color: $accent-color; +$tab-list-active-bg-color: $tertiary-accent-color; +$tab-list-active-fg-color: $accent-color; +$tab-border-color: $tertiary-accent-color; +$tab-panel-bg-color: #fff; + // unused? $progressbar-color: #000; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 25ba980bcf..9733576bd0 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -612,9 +612,7 @@ export default React.createClass({ break; case 'view_user_settings': const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); - Modal.createTrackedDialog('User settings', '', UserSettingsDialog, { - title: _t("Settings"), - }); + Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {}); //this._setPage(PageTypes.UserSettings); //this.notifyNewScreen('settings'); break; diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js new file mode 100644 index 0000000000..44ecee7a95 --- /dev/null +++ b/src/components/structures/TabbedView.js @@ -0,0 +1,165 @@ +/* +Copyright 2017 Travis Ralston +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 * as React from "react"; +import {_t, _td} from '../../languageHandler'; +import GeminiScrollbar from 'react-gemini-scrollbar'; +import PropTypes from "prop-types"; +//import scrollSnapPolyfill from 'css-scroll-snap-polyfill'; + +const DEFAULT_EXIT_STRING = _td("Return to app"); + +/** + * Represents a tab for the TabbedView + */ +export class Tab { + /** + * Creates a new tab + * @param {string} tabLabel The untranslated tab label + * @param {string} tabJsx The JSX for the tab container. + */ + constructor(tabLabel, tabJsx) { + this.label = tabLabel; + this.body = tabJsx; + } +} + +export class TabbedView extends React.Component { + constructor() { + super(); + + // This is used to track when the user has scrolled all the way up or down so we + // don't immediately start flipping between tabs. + this._reachedEndAt = 0; + } + + getInitialState() { + return { + activeTabIndex: 0, + }; + } + + _getActiveTabIndex() { + return this.state ? this.state.activeTabIndex : 0; + } + + /** + * Shows the given tab + * @param {Tab} tab the tab to show + * @private + */ + _setActiveTab(tab) { + const idx = this.props.tabs.indexOf(tab); + if (idx !== -1) { + this.setState({activeTabIndex: idx}); + this._reachedEndAt = 0; // reset scroll timer + } + else console.error("Could not find tab " + tab.label + " in tabs"); + } + + _nextTab() { + let targetIndex = this._getActiveTabIndex() + 1; + if (targetIndex < this.props.tabs.length) { + this.setState({activeTabIndex: targetIndex}); + this._reachedEndAt = 0; // reset scroll timer + } + } + + _previousTab() { + let targetIndex = this._getActiveTabIndex() - 1; + if (targetIndex >= 0) { + this.setState({activeTabIndex: targetIndex}); + this._reachedEndAt = 0; // reset scroll timer + } + } + + _getTabLabel(tab) { + let classes = "mx_TabbedView_tabLabel "; + + const idx = this.props.tabs.indexOf(tab); + if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; + + return ( + this._setActiveTab(tab)}> + {_t(tab.label)} + + ); + } + + _getTabPanel(tab) { + return ( +