diff --git a/browser/components/loop/content/js/panel.js b/browser/components/loop/content/js/panel.js index ac6aa8650fd..407367e439e 100644 --- a/browser/components/loop/content/js/panel.js +++ b/browser/components/loop/content/js/panel.js @@ -22,6 +22,57 @@ loop.panel = (function(_, mozL10n) { */ var router; + var TabView = React.createClass({displayName: 'TabView', + getInitialState: function() { + return { + selectedTab: "call" + }; + }, + + handleSelectTab: function(event) { + var tabName = event.target.dataset.tabName; + this.setState({selectedTab: tabName}); + + if (this.props.onSelect) { + this.props.onSelect(tabName); + } + }, + + render: function() { + var cx = React.addons.classSet; + var tabButtons = []; + var tabs = []; + React.Children.forEach(this.props.children, function(tab, i) { + var tabName = tab.props.name; + var isSelected = (this.state.selectedTab == tabName); + tabButtons.push( + React.DOM.li({className: cx({selected: isSelected}), + key: i, + 'data-tab-name': tabName, + onClick: this.handleSelectTab} + ) + ); + tabs.push( + React.DOM.div({key: i, className: cx({tab: true, selected: isSelected})}, + tab.props.children + ) + ); + }, this); + return ( + React.DOM.div({className: "tab-view-container"}, + React.DOM.ul({className: "tab-view"}, tabButtons), + tabs + ) + ); + } + }); + + var Tab = React.createClass({displayName: 'Tab', + render: function() { + return null; + } + }); + /** * Dropdown menu mixin. * @type {Object} @@ -424,10 +475,17 @@ loop.panel = (function(_, mozL10n) { return ( React.DOM.div(null, NotificationListView({notifications: this.props.notifications}), - CallUrlResult({client: this.props.client, - notifications: this.props.notifications, - callUrl: this.props.callUrl}), - ToSView(null), + TabView({onSelect: this.selectTab}, + Tab({name: "call"}, + CallUrlResult({client: this.props.client, + notifications: this.props.notifications, + callUrl: this.props.callUrl}), + ToSView(null) + ), + Tab({name: "contacts"}, + React.DOM.span(null, "contacts") + ) + ), React.DOM.div({className: "footer"}, AvailabilityDropdown(null), AuthLink(null), diff --git a/browser/components/loop/content/js/panel.jsx b/browser/components/loop/content/js/panel.jsx index 902c343e957..1791f69aa5d 100644 --- a/browser/components/loop/content/js/panel.jsx +++ b/browser/components/loop/content/js/panel.jsx @@ -22,6 +22,57 @@ loop.panel = (function(_, mozL10n) { */ var router; + var TabView = React.createClass({ + getInitialState: function() { + return { + selectedTab: "call" + }; + }, + + handleSelectTab: function(event) { + var tabName = event.target.dataset.tabName; + this.setState({selectedTab: tabName}); + + if (this.props.onSelect) { + this.props.onSelect(tabName); + } + }, + + render: function() { + var cx = React.addons.classSet; + var tabButtons = []; + var tabs = []; + React.Children.forEach(this.props.children, function(tab, i) { + var tabName = tab.props.name; + var isSelected = (this.state.selectedTab == tabName); + tabButtons.push( +
  • +
  • + ); + tabs.push( +
    + {tab.props.children} +
    + ); + }, this); + return ( +
    + + {tabs} +
    + ); + } + }); + + var Tab = React.createClass({ + render: function() { + return null; + } + }); + /** * Dropdown menu mixin. * @type {Object} @@ -424,10 +475,17 @@ loop.panel = (function(_, mozL10n) { return (
    - - + + + + + + + contacts + +
    diff --git a/browser/components/loop/content/shared/css/panel.css b/browser/components/loop/content/shared/css/panel.css index b751c77e17b..436316b5774 100644 --- a/browser/components/loop/content/shared/css/panel.css +++ b/browser/components/loop/content/shared/css/panel.css @@ -4,12 +4,6 @@ /* Panel styles */ .panel { - /* XXX force proper content positioning by adding extra margin space - * taken away by reset.css - */ - margin-top: 7px; - margin-bottom: 7px; - /* hide the extra margin space that the panel resizer now wants to show */ overflow: hidden; } @@ -18,6 +12,74 @@ margin-bottom: 1em; } +.tab-view, +.tab-view > li { + margin: 0; + padding: 0; + border: 0; + vertical-align: baseline; +} + +.tab-view { + display: flex; + flex-direction: row; + padding: 10px; + border-bottom: 1px solid #ccc; + background: #fafafa; + border-top-right-radius: 2px; + border-top-left-radius: 2px; + list-style: none; +} + +.tab-view > li { + flex: 1; + text-align: center; + color: #ccc; + border-right: 1px solid #ccc; + padding: 0 10px; + height: 16px; + cursor: pointer; + background-repeat: no-repeat; + background-size: 16px 16px; + background-position: center; +} + +.tab-view > li[data-tab-name="call"] { + background-image: url("../img/icons-16x16.svg#precall"); +} + +.tab-view > li[data-tab-name="call"]:hover { + background-image: url("../img/icons-16x16.svg#precall-hover"); +} + +.tab-view > li[data-tab-name="call"].selected { + background-image: url("../img/icons-16x16.svg#precall-active"); +} + +.tab-view > li[data-tab-name="contacts"] { + background-image: url("../img/icons-16x16.svg#contacts"); +} + +.tab-view > li[data-tab-name="contacts"]:hover { + background-image: url("../img/icons-16x16.svg#contacts-hover"); +} + +.tab-view > li[data-tab-name="contacts"].selected { + background-image: url("../img/icons-16x16.svg#contacts-active"); +} + +.tab-view > li:last-child { + border-right: 0; +} + +.tab { + display: none; +} + +.tab.selected { + display: block; +} + .share { background: #fbfbfb; } diff --git a/browser/components/loop/content/shared/img/icons-16x16.svg b/browser/components/loop/content/shared/img/icons-16x16.svg new file mode 100644 index 00000000000..901570ce12e --- /dev/null +++ b/browser/components/loop/content/shared/img/icons-16x16.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browser/components/loop/jar.mn b/browser/components/loop/jar.mn index d1761edc2fc..20d36890bf9 100644 --- a/browser/components/loop/jar.mn +++ b/browser/components/loop/jar.mn @@ -44,7 +44,8 @@ browser.jar: content/browser/loop/shared/img/svg/glyph-account-16x16.svg (content/shared/img/svg/glyph-account-16x16.svg) content/browser/loop/shared/img/svg/glyph-signin-16x16.svg (content/shared/img/svg/glyph-signin-16x16.svg) content/browser/loop/shared/img/svg/glyph-signout-16x16.svg (content/shared/img/svg/glyph-signout-16x16.svg) - content/browser/loop/shared/img/audio-call-avatar.svg (content/shared/img/audio-call-avatar.svg) + content/browser/loop/shared/img/audio-call-avatar.svg (content/shared/img/audio-call-avatar.svg) + content/browser/loop/shared/img/icons-16x16.svg (content/shared/img/icons-16x16.svg) # Shared scripts content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)