Commit bcfd2588 authored by Imran Salam's avatar Imran Salam
Browse files

implement browser tabs and grey out browser navigator icon when drawer opened

parent ca1e18a1
......@@ -4,6 +4,7 @@
@include flex;
background: $ens-light-grey;
box-shadow: 0 2px 3px $ens-grey;
height: 32px;
padding: 7px 0 3px 0;
position: relative;
z-index: 200;
......
......@@ -2,11 +2,14 @@ import React, { FunctionComponent, Fragment } from 'react';
import { connect } from 'react-redux';
import { browserInfoConfig } from '../browserConfig';
import { TrackType } from '../track-panel/trackPanelConfig';
import {
toggleBrowserNav,
updateDefaultChrLocation,
updateChrLocation,
toggleGenomeSelector
toggleGenomeSelector,
selectBrowserTab
} from '../browserActions';
import { ChrLocation } from '../browserState';
import {
......@@ -15,7 +18,8 @@ import {
getBrowserActivated,
getDefaultChrLocation,
getGenomeSelectorActive,
getDrawerOpened
getDrawerOpened,
getSelectedBrowserTab
} from '../browserSelectors';
import { RootState } from 'src/rootReducer';
......@@ -32,9 +36,11 @@ type StateProps = {
defaultChrLocation: ChrLocation;
drawerOpened: boolean;
genomeSelectorActive: boolean;
selectedBrowserTab: TrackType;
};
type DispatchProps = {
selectBrowserTab: (selectedBrowserTab: TrackType) => void;
toggleBrowserNav: () => void;
toggleGenomeSelector: (genomeSelectorActive: boolean) => void;
updateChrLocation: (chrLocation: ChrLocation) => void;
......@@ -65,11 +71,21 @@ export const BrowserBar: FunctionComponent<BrowserBarProps> = (
const getBrowserNavIcon = () => {
if (props.browserNavOpened === true) {
return navigator.icon.selected;
} else if (props.drawerOpened === true) {
return navigator.icon.grey;
} else {
return navigator.icon.default;
}
};
const toggleNavigator = () => {
if (props.drawerOpened === true) {
return;
}
props.toggleBrowserNav();
};
return (
<div className={styles.browserBar}>
<div className={getBrowserInfoClasses()}>
......@@ -118,17 +134,19 @@ export const BrowserBar: FunctionComponent<BrowserBarProps> = (
/>
{props.genomeSelectorActive ? null : (
<dd className={styles.navigator}>
<button
title={navigator.description}
onClick={props.toggleBrowserNav}
>
<button title={navigator.description} onClick={toggleNavigator}>
<img src={getBrowserNavIcon()} alt={navigator.description} />
</button>
</dd>
)}
</dl>
</div>
<BrowserTabs />
<BrowserTabs
drawerOpened={props.drawerOpened}
genomeSelectorActive={props.genomeSelectorActive}
selectBrowserTab={props.selectBrowserTab}
selectedBrowserTab={props.selectedBrowserTab}
/>
</div>
);
};
......@@ -139,10 +157,12 @@ const mapStateToProps = (state: RootState): StateProps => ({
chrLocation: getChrLocation(state),
defaultChrLocation: getDefaultChrLocation(state),
drawerOpened: getDrawerOpened(state),
genomeSelectorActive: getGenomeSelectorActive(state)
genomeSelectorActive: getGenomeSelectorActive(state),
selectedBrowserTab: getSelectedBrowserTab(state)
});
const mapDispatchToProps: DispatchProps = {
selectBrowserTab,
toggleBrowserNav,
toggleGenomeSelector,
updateChrLocation,
......
......@@ -10,11 +10,15 @@
}
.browserTab {
button {
color: $ens-blue;
}
}
.browserTabActive {
button {
color: inherit;
}
}
.browserTabArrow {
......@@ -31,7 +35,7 @@
right: calc(60% - 6px);
transform-origin: 0 0;
transform: rotate(-45deg);
top: 21px;
top: 24px;
width: 0;
}
}
import React, { FunctionComponent } from 'react';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { TrackType } from '../track-panel/trackPanelConfig';
import styles from './BrowserTabs.scss';
type BrowserTabsProps = {};
type BrowserTabsProps = {
drawerOpened: boolean;
genomeSelectorActive: boolean;
selectBrowserTab: (selectedBrowserTab: TrackType) => void;
selectedBrowserTab: TrackType;
};
type ClickHandlers = {
[key: string]: () => void;
};
const BrowserTabs: FunctionComponent<BrowserTabsProps> = (
props: BrowserTabsProps
) => {
const initClickHandlers: ClickHandlers = {};
const [clickHandlers, setClickHandlers] = useState(initClickHandlers);
const getBrowserTabClasses = (trackType: TrackType) => {
let classNames = styles.browserTab;
if (props.selectedBrowserTab === trackType) {
classNames += ` ${styles.browserTabActive}`;
if (props.drawerOpened === false) {
classNames += ` ${styles.browserTabArrow}`;
}
}
return classNames;
};
useEffect(() => {
const callbacks: ClickHandlers = {};
Object.values(TrackType).forEach((value: TrackType) => {
callbacks[value] = () => {
if (props.genomeSelectorActive === true) {
return;
}
props.selectBrowserTab(value);
};
});
setClickHandlers(callbacks);
}, [props.genomeSelectorActive]);
return (
<dl className={`${styles.browserTabs} show-for-large`}>
<dd>
<button className={styles.browserTabActive}>Genomic</button>
</dd>
<dd>
<button>Variation</button>
</dd>
<dd>
<button>Expression</button>
{Object.values(TrackType).map((value: TrackType) => (
<dd
className={getBrowserTabClasses(value)}
key={value}
onClick={clickHandlers[value]}
>
<button>{value}</button>
</dd>
))}
</dl>
);
};
......
import { createAction } from 'typesafe-actions';
import { BrowserNavStates, ChrLocation } from './browserState';
import { TrackType } from './track-panel/trackPanelConfig';
export const updateBrowserActivated = createAction(
'browser/update-browser-activated',
......@@ -68,3 +69,10 @@ export const toggleGenomeSelector = createAction(
return (genomeSelectorActive: boolean) => resolve(genomeSelectorActive);
}
);
export const selectBrowserTab = createAction(
'select-browser-tab',
(resolve) => {
return (selectedBrowserTab: TrackType) => resolve(selectedBrowserTab);
}
);
......@@ -3,6 +3,7 @@ import resetGreyIcon from 'static/img/browser/reset-grey.svg';
import navigatorIcon from 'static/img/browser/navigator.svg';
import navigatorSelectedIcon from 'static/img/browser/navigator-selected.svg';
import navigatorGreyIcon from 'static/img/browser/navigator-grey.svg';
import navigateUpIcon from 'static/img/browser/navigate-up.svg';
import navigateUpOffIcon from 'static/img/browser/navigate-up-off.svg';
......@@ -53,6 +54,7 @@ export const browserInfoConfig: BrowserInfoType = {
description: 'toggle browser navigation',
icon: {
default: navigatorIcon,
grey: navigatorGreyIcon,
selected: navigatorSelectedIcon
},
name: 'navigator'
......
......@@ -50,6 +50,8 @@ export default (
};
case getType(browser.toggleGenomeSelector):
return { ...state, genomeSelectorActive: action.payload };
case getType(browser.selectBrowserTab):
return { ...state, selectedBrowserTab: action.payload };
default:
return state;
}
......
......@@ -4,6 +4,7 @@ import {
BrowserNavStates,
ChrLocation
} from './browserState';
import { TrackType } from './track-panel/trackPanelConfig';
export const getBrowserActivated = (state: RootState): boolean =>
state.browser.browserActivated;
......@@ -40,3 +41,6 @@ export const getTrackPanelModalView = (state: RootState): string =>
export const getGenomeSelectorActive = (state: RootState): boolean =>
state.browser.genomeSelectorActive;
export const getSelectedBrowserTab = (state: RootState): TrackType =>
state.browser.selectedBrowserTab;
import { TrackType } from './track-panel/trackPanelConfig';
export enum BrowserOpenState {
EXPANDED = 'expanded',
SEMI_EXPANDED = 'semiExpanded',
......@@ -26,6 +28,7 @@ export type BrowserState = Readonly<{
drawerOpened: boolean;
drawerView: string;
genomeSelectorActive: boolean;
selectedBrowserTab: TrackType;
trackPanelModalOpened: boolean;
trackPanelModalView: string;
trackPanelOpened: boolean;
......@@ -41,6 +44,7 @@ export const defaultState: BrowserState = {
drawerOpened: false,
drawerView: '',
genomeSelectorActive: false,
selectedBrowserTab: TrackType.GENOMIC,
trackPanelModalOpened: false,
trackPanelModalView: '',
trackPanelOpened: true
......
......@@ -8,6 +8,7 @@ import { connect } from 'react-redux';
import TrackPanelBar from './track-panel-bar/TrackPanelBar';
import TrackPanelList from './track-panel-list/TrackPanelList';
import TrackPanelModal from './track-panel-modal/TrackPanelModal';
import { RootState } from 'src/rootReducer';
......@@ -25,15 +26,16 @@ import {
getTrackPanelOpened,
getBrowserActivated,
getTrackPanelModalOpened,
getTrackPanelModalView
getTrackPanelModalView,
getSelectedBrowserTab
} from '../browserSelectors';
import { getLaunchbarExpanded } from 'src/header/headerSelectors';
import { getBreakpointWidth } from 'src/globalSelectors';
import { BreakpointWidth } from 'src/globalConfig';
import { TrackType } from './trackPanelConfig';
import styles from './TrackPanel.scss';
import TrackPanelModal from './track-panel-modal/TrackPanelModal';
type StateProps = {
browserActivated: boolean;
......@@ -41,6 +43,7 @@ type StateProps = {
drawerView: string;
breakpointWidth: BreakpointWidth;
launchbarExpanded: boolean;
selectedBrowserTab: TrackType;
trackPanelModalOpened: boolean;
trackPanelModalView: string;
trackPanelOpened: boolean;
......@@ -91,6 +94,7 @@ const TrackPanel: FunctionComponent<TrackPanelProps> = (
browserRef={props.browserRef}
drawerView={props.drawerView}
launchbarExpanded={props.launchbarExpanded}
selectedBrowserTab={props.selectedBrowserTab}
toggleDrawer={props.toggleDrawer}
updateDrawerView={props.changeDrawerView}
/>
......@@ -115,6 +119,7 @@ const mapStateToProps = (state: RootState): StateProps => ({
drawerOpened: getDrawerOpened(state),
drawerView: getDrawerView(state),
launchbarExpanded: getLaunchbarExpanded(state),
selectedBrowserTab: getSelectedBrowserTab(state),
trackPanelModalOpened: getTrackPanelModalOpened(state),
trackPanelModalView: getTrackPanelModalView(state),
trackPanelOpened: getTrackPanelOpened(state)
......
import React, { FunctionComponent, RefObject, useCallback } from 'react';
import React, {
FunctionComponent,
RefObject,
useCallback,
useState,
useEffect
} from 'react';
import TrackPanelListItem from './TrackPanelListItem';
import {
TrackPanelCategory,
TrackPanelItem,
trackPanelConfig
trackPanelConfig,
TrackType
} from '../trackPanelConfig';
import styles from './TrackPanelList.scss';
......@@ -13,6 +20,7 @@ type TrackPanelListProps = {
browserRef: RefObject<HTMLDivElement>;
drawerView: string;
launchbarExpanded: boolean;
selectedBrowserTab: TrackType;
toggleDrawer: (drawerOpened: boolean) => void;
updateDrawerView: (drawerView: string) => void;
};
......@@ -20,6 +28,19 @@ type TrackPanelListProps = {
const TrackPanelList: FunctionComponent<TrackPanelListProps> = (
props: TrackPanelListProps
) => {
const [trackCategories, setTrackCategories] = useState(
trackPanelConfig.categories
);
useEffect(() => {
setTrackCategories(
trackPanelConfig.categories.filter(
(category: TrackPanelCategory) =>
category.types.indexOf(props.selectedBrowserTab) > -1
)
);
}, [props.selectedBrowserTab]);
const changeDrawerView = useCallback(
(currentTrack: string) => {
const { drawerView, toggleDrawer, updateDrawerView } = props;
......@@ -61,7 +82,7 @@ const TrackPanelList: FunctionComponent<TrackPanelListProps> = (
<section>
<dl>{getTrackListItem(trackPanelConfig.main)}</dl>
</section>
{trackPanelConfig.categories.map((category: TrackPanelCategory) => (
{trackCategories.map((category: TrackPanelCategory) => (
<section key={category.name}>
<h4>{category.name}</h4>
<dl>
......
......@@ -21,9 +21,16 @@ export type TrackPanelItem = {
selectedInfo?: string;
};
export enum TrackType {
GENOMIC = 'Genomic',
VARIATION = 'Variation',
EXPRESSION = 'Expression'
}
export type TrackPanelCategory = {
name: string;
trackList: TrackPanelItem[];
types: TrackType[];
};
export type TrackPanelIcon = {
......@@ -76,7 +83,8 @@ export const trackPanelConfig: TrackPanelConfig = {
label: 'Other genes',
name: 'gene-other-rev'
}
]
],
types: [TrackType.GENOMIC]
},
{
name: 'Assembly',
......@@ -91,19 +99,59 @@ export const trackPanelConfig: TrackPanelConfig = {
label: '%GC',
name: 'gc'
}
]
],
types: [TrackType.GENOMIC]
},
{
name: 'Comparative genomics',
trackList: []
trackList: [],
types: [TrackType.GENOMIC]
},
{
name: 'Short variants',
trackList: [
{
id: 201,
label: '1000 Genomes all SNPs & indels',
name: 'snps-and-indels'
}
],
types: [TrackType.VARIATION]
},
{
name: 'Somatic variants',
trackList: [],
types: [TrackType.VARIATION]
},
{
name: 'Structural variants',
trackList: [],
types: [TrackType.VARIATION]
},
{
name: 'Experiment design',
trackList: []
trackList: [],
types: [TrackType.EXPRESSION, TrackType.GENOMIC, TrackType.VARIATION]
},
{
name: 'References & evidence',
trackList: []
trackList: [],
types: [TrackType.GENOMIC]
},
{
name: 'Regulatory features',
trackList: [],
types: [TrackType.EXPRESSION]
},
{
name: 'Gene expression correlations',
trackList: [],
types: [TrackType.EXPRESSION]
},
{
name: 'Other regulatory regions',
trackList: [],
types: [TrackType.EXPRESSION]
}
],
main: {
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 28 28" style="enable-background:new 0 0 28 28;" xml:space="preserve">
<style type="text/css">
.st0{fill:#B7C0C8;}
</style>
<path class="st0" d="M13.2,24.5c-6.2-9-7.3-9.9-7.3-13.2c0-4.5,3.7-8.2,8.2-8.2s8.2,3.7,8.2,8.2c0,3.3-1.1,4.2-7.3,13.2
C14.4,25,13.6,25,13.2,24.5L13.2,24.5z M14,14.7c1.9,0,3.4-1.5,3.4-3.4S15.9,7.9,14,7.9s-3.4,1.5-3.4,3.4S12.1,14.7,14,14.7z"/>
</svg>
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