Unverified Commit 25d8df56 authored by Kyle Keating's avatar Kyle Keating Committed by GitHub

Merge pull request #1269 from hypothesis/react-selection-tabs

Add react selection-tabs component
parents 8813b8cf 1efb767b
'use strict'; 'use strict';
const classnames = require('classnames');
const propTypes = require('prop-types');
const { createElement } = require('preact');
const { Fragment } = require('preact');
const NewNoteBnt = require('./new-note-btn');
const sessionUtil = require('../util/session-util'); const sessionUtil = require('../util/session-util');
const uiConstants = require('../ui-constants'); const uiConstants = require('../ui-constants');
const useStore = require('../store/use-store');
const { withServices } = require('../util/service-context');
module.exports = { /**
controllerAs: 'vm', * Display name of the tab and annotation count.
//@ngInject */
controller: function($element, store, features, session, settings) { function Tab({
this.TAB_ANNOTATIONS = uiConstants.TAB_ANNOTATIONS; children,
this.TAB_NOTES = uiConstants.TAB_NOTES; count,
this.TAB_ORPHANS = uiConstants.TAB_ORPHANS; isWaitingToAnchor,
onChangeTab,
this.isThemeClean = settings.theme === 'clean'; selected,
type,
this.enableExperimentalNewNoteButton = }) {
settings.enableExperimentalNewNoteButton; return (
<a
this.selectTab = function(type) { className={classnames('selection-tabs__type', {
store.clearSelectedAnnotations(); 'is-selected': selected,
store.selectTab(type); })}
}; onMouseDown={onChangeTab.bind(this, type)}
onTouchStart={onChangeTab.bind(this, type)}
this.showAnnotationsUnavailableMessage = function() { >
return ( {children}
this.selectedTab === this.TAB_ANNOTATIONS && {count > 0 && !isWaitingToAnchor && (
this.totalAnnotations === 0 && <span className="selection-tabs__count"> {count}</span>
!this.isWaitingToAnchorAnnotations )}
); </a>
}; );
}
this.showNotesUnavailableMessage = function() { Tab.propTypes = {
return this.selectedTab === this.TAB_NOTES && this.totalNotes === 0; /**
}; * Child components.
*/
this.showSidebarTutorial = function() { children: propTypes.node.isRequired,
return sessionUtil.shouldShowSidebarTutorial(session.state); /**
}; * The total annotations for this tab.
}, */
bindings: { count: propTypes.number.isRequired,
isLoading: '<', /**
isWaitingToAnchorAnnotations: '<', * Are there any annotations still waiting to anchor?
selectedTab: '<', */
totalAnnotations: '<', isWaitingToAnchor: propTypes.bool.isRequired,
totalNotes: '<', /**
totalOrphans: '<', * Callback when this tab is active with type as a parameter.
}, */
template: require('../templates/selection-tabs.html'), onChangeTab: propTypes.func.isRequired,
/**
* Is this tab currently selected?
*/
selected: propTypes.bool.isRequired,
/**
* The type value for this tab. One of
* 'annotation', 'note', or 'orphan'.
*/
type: propTypes.oneOf(['annotation', 'note', 'orphan']).isRequired,
}; };
/**
* Tabbed display of annotations and notes.
*/
function SelectionTabs({
isWaitingToAnchorAnnotations,
isLoading,
selectedTab,
totalAnnotations,
totalNotes,
totalOrphans,
settings,
session,
}) {
// actions
const store = useStore(store => ({
clearSelectedAnnotations: store.clearSelectedAnnotations,
selectTab: store.selectTab,
}));
const isThemeClean = settings.theme === 'clean';
const selectTab = function(type) {
store.clearSelectedAnnotations();
store.selectTab(type);
};
const showAnnotationsUnavailableMessage =
selectedTab === uiConstants.TAB_ANNOTATIONS &&
totalAnnotations === 0 &&
!isWaitingToAnchorAnnotations;
const showNotesUnavailableMessage =
selectedTab === uiConstants.TAB_NOTES && totalNotes === 0;
const showSidebarTutorial = sessionUtil.shouldShowSidebarTutorial(
session.state
);
return (
<Fragment>
<div
className={classnames('selection-tabs', {
'selection-tabs--theme-clean': isThemeClean,
})}
>
<Tab
count={totalAnnotations}
isWaitingToAnchor={isWaitingToAnchorAnnotations}
selected={selectedTab === uiConstants.TAB_ANNOTATIONS}
type={uiConstants.TAB_ANNOTATIONS}
onChangeTab={selectTab}
>
Annotations
</Tab>
<Tab
count={totalNotes}
isWaitingToAnchor={isWaitingToAnchorAnnotations}
selected={selectedTab === uiConstants.TAB_NOTES}
type={uiConstants.TAB_NOTES}
onChangeTab={selectTab}
>
Page Notes
</Tab>
{totalOrphans > 0 && (
<Tab
count={totalOrphans}
isWaitingToAnchor={isWaitingToAnchorAnnotations}
selected={selectedTab === uiConstants.TAB_ORPHANS}
type={uiConstants.TAB_ORPHANS}
onChangeTab={selectTab}
>
Orphans
</Tab>
)}
</div>
{selectedTab === uiConstants.TAB_NOTES &&
settings.enableExperimentalNewNoteButton && <NewNoteBnt />}
{!isLoading && (
<div className="selection-tabs__empty-message">
{showNotesUnavailableMessage && (
<div className="annotation-unavailable-message">
<p className="annotation-unavailable-message__label">
There are no page notes in this group.
{settings.enableExperimentalNewNoteButton &&
!showSidebarTutorial && (
<div className="annotation-unavailable-message__tutorial">
Create one by clicking the{' '}
<i className="help-icon h-icon-note" /> button.
</div>
)}
</p>
</div>
)}
{showAnnotationsUnavailableMessage && (
<div className="annotation-unavailable-message">
<p className="annotation-unavailable-message__label">
There are no annotations in this group.
{!showSidebarTutorial && (
<div className="annotation-unavailable-message__tutorial">
Create one by selecting some text and clicking the{' '}
<i className="help-icon h-icon-annotate" /> button.
</div>
)}
</p>
</div>
)}
</div>
)}
</Fragment>
);
}
SelectionTabs.propTypes = {
/**
* Are we waiting on any annotations from the server?
*/
isLoading: propTypes.bool.isRequired,
/**
* Are there any annotations still waiting to anchor?
*/
isWaitingToAnchorAnnotations: propTypes.bool.isRequired,
/**
* The currently selected tab (annotations, notes or orphans).
*/
selectedTab: propTypes.oneOf(['annotation', 'note', 'orphan']).isRequired,
/**
* The totals for each respect tab.
*/
totalAnnotations: propTypes.number.isRequired,
totalNotes: propTypes.number.isRequired,
totalOrphans: propTypes.number.isRequired,
// Injected services.
settings: propTypes.object.isRequired,
session: propTypes.object.isRequired,
};
SelectionTabs.injectedProps = ['session', 'settings'];
module.exports = withServices(SelectionTabs);
...@@ -188,7 +188,10 @@ function startAngularApp(config) { ...@@ -188,7 +188,10 @@ function startAngularApp(config) {
'newNoteBtn', 'newNoteBtn',
wrapReactComponent(require('./components/new-note-btn')) wrapReactComponent(require('./components/new-note-btn'))
) )
.component('selectionTabs', require('./components/selection-tabs')) .component(
'selectionTabs',
wrapReactComponent(require('./components/selection-tabs'))
)
.component('sidebarContent', require('./components/sidebar-content')) .component('sidebarContent', require('./components/sidebar-content'))
.component( .component(
'sidebarContentError', 'sidebarContentError',
......
<!-- Tabbed display of annotations and notes. -->
<div class="selection-tabs"
ng-class="{'selection-tabs--theme-clean' : vm.isThemeClean }">
<a class="selection-tabs__type"
href="#"
ng-class="{'is-selected': vm.selectedTab === vm.TAB_ANNOTATIONS}"
h-on-touch="vm.selectTab(vm.TAB_ANNOTATIONS)">
Annotations
<span class="selection-tabs__count"
ng-if="vm.totalAnnotations > 0 && !vm.isWaitingToAnchorAnnotations">
{{ vm.totalAnnotations }}
</span>
</a>
<a class="selection-tabs__type"
href="#"
ng-class="{'is-selected': vm.selectedTab === vm.TAB_NOTES}"
h-on-touch="vm.selectTab(vm.TAB_NOTES)">
Page Notes
<span class="selection-tabs__count"
ng-if="vm.totalNotes > 0 && !vm.isWaitingToAnchorAnnotations">
{{ vm.totalNotes }}
</span>
</a>
<a class="selection-tabs__type selection-tabs__type--orphan"
ng-if="vm.totalOrphans > 0"
href="#"
ng-class="{'is-selected': vm.selectedTab === vm.TAB_ORPHANS}"
h-on-touch="vm.selectTab(vm.TAB_ORPHANS)">
Orphans
<span class="selection-tabs__count"
ng-if="vm.totalOrphans > 0 && !vm.isWaitingToAnchorAnnotations">
{{ vm.totalOrphans }}
</span>
</a>
</div>
<new-note-btn
ng-if="vm.selectedTab === vm.TAB_NOTES && vm.enableExperimentalNewNoteButton">
</new-note-btn>
<div ng-if="!vm.isLoading()" class="selection-tabs__empty-message">
<div ng-if="vm.showNotesUnavailableMessage()" class="annotation-unavailable-message">
<p class="annotation-unavailable-message__label">
There are no page notes in this group.
<br />
<div ng-if="!vm.enableExperimentalNewNoteButton && !vm.showSidebarTutorial()" class="annotation-unavailable-message__tutorial">
Create one by clicking the
<i class="help-icon h-icon-note"></i>
button.
</div>
</p>
</div>
<div ng-if="vm.showAnnotationsUnavailableMessage()" class="annotation-unavailable-message">
<p class="annotation-unavailable-message__label">
There are no annotations in this group.
<br />
<div ng-if="!vm.showSidebarTutorial()" class="annotation-unavailable-message__tutorial">
Create one by selecting some text and clicking the
<i class="help-icon h-icon-annotate"></i> button.
</div>
</p>
</div>
</div>
<selection-tabs <selection-tabs
ng-if="vm.showSelectedTabs()" ng-if="vm.showSelectedTabs()"
is-waiting-to-anchor-annotations="vm.waitingToAnchorAnnotations" is-waiting-to-anchor-annotations="vm.waitingToAnchorAnnotations"
is-loading="vm.isLoading" is-loading="vm.isLoading()"
selected-tab="vm.selectedTab" selected-tab="vm.selectedTab"
total-annotations="vm.totalAnnotations" total-annotations="vm.totalAnnotations"
total-notes="vm.totalNotes" total-notes="vm.totalNotes"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment