Skip to content

Commit

Permalink
feat(layer-tabs): add collapsible layer-selector, highlight selected … (
Browse files Browse the repository at this point in the history
#123)

* feat(layer-tabs): add collapsible layer-selector, highlight selected layers

* feat(layer-tabs): remove list-style

* refactor(layer-tabs): change classnames
  • Loading branch information
KatvonRivia authored and pwambach committed Oct 7, 2019
1 parent 753e948 commit 2ed8363
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/scripts/actions/set-selected-layer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const SET_SELECTED_LAYER_ID = 'SET_SELECTED_LAYER_ID';

export type LayerId = string;
export type LayerId = string | null;

export interface SetSelectedLayerIdAction {
type: typeof SET_SELECTED_LAYER_ID;
Expand Down
1 change: 1 addition & 0 deletions src/scripts/components/app/app.styl
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

.app
height: 100%
font-family: Arial, Helvetica, sans-serif
16 changes: 13 additions & 3 deletions src/scripts/components/layer-list/layer-list.styl
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@
padding: 0
margin: 0
background-color: #fff
list-style: none

.layerItem
padding: 15px
font-size: 1.1em

.layerItem:hover,
.layerItem:focus
background-color: #e0f1ff

.layerItemSelected,
.layerItemSelected:hover
.layerItemSelected:focus
background-color:#a8d7ff

.subLayerItem
margin: 5px
padding: 15px
font-size: 1em

.layerItem:hover,
.layerItem:focus
background-color: #e0f1ff
.subLayerItemSelected
background-color: #a8d7ff

20 changes: 16 additions & 4 deletions src/scripts/components/layer-list/layer-list.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import React, {FunctionComponent, MouseEvent} from 'react';
import cx from 'classnames';
import {Layer} from '../../actions/fetch-layers';
import styles from './layer-list.styl';

interface Props {
layers: Layer[];
selected: string;
selected: string | null;
onSelect: (id: string) => void;
}

const LayerList: FunctionComponent<Props> = ({layers, onSelect}) => (
const LayerList: FunctionComponent<Props> = ({layers, selected, onSelect}) => (
<ul className={styles.layerList}>
{layers.map(layer => {
const layerClickHandler = () => {
if (layer.subLayers.length === 0) {
onSelect(layer.id);
}
};
const isSelected = selected === layer.id;
const layerItemClasses = cx(
styles.layerItem,
isSelected && styles.layerItemSelected
);

return (
<li
className={styles.layerItem}
className={layerItemClasses}
key={layer.id}
onClick={() => layerClickHandler()}>
{layer.name}
Expand All @@ -31,9 +37,15 @@ const LayerList: FunctionComponent<Props> = ({layers, onSelect}) => (
event.stopPropagation();
onSelect(subLayer.id);
};
const isSubSelected = selected === subLayer.id;
const subLayerItemClasses = cx(
styles.subLayerItem,
isSubSelected && styles.subLayerItemSelected
);

return (
<li
className={styles.subLayerItem}
className={subLayerItemClasses}
key={subLayer.id}
onClick={event => subLayerClickHandler(event)}>
{subLayer.name}
Expand Down
38 changes: 30 additions & 8 deletions src/scripts/components/layer-selector/layer-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {FunctionComponent, useEffect, useState} from 'react';
import {useSelector, useDispatch} from 'react-redux';
import {layersSelector} from '../../reducers/layers';
import {selectedLayerIdSelector} from '../../reducers/selected-layer-id';
import fetchLayers from '../../actions/fetch-layers';
import {setSelectedLayerIdAction} from '../../actions/set-selected-layer';
import LayerList from '../layer-list/layer-list';
Expand All @@ -9,6 +10,7 @@ import styles from './layer-selector.styl';

const LayerSelector: FunctionComponent<{}> = () => {
const layers = useSelector(layersSelector);
const layerIds = useSelector(selectedLayerIdSelector);
const dispatch = useDispatch();
const tabs = [
{
Expand All @@ -22,7 +24,27 @@ const LayerSelector: FunctionComponent<{}> = () => {
];

const [activeTabId, setActiveTabId] = useState(tabs[0].id);
const [isOpen, setIsOpen] = useState(false);
const isMainTabSelected = activeTabId === tabs[0].id;
const selectedLayer = isMainTabSelected ? layerIds.main : layerIds.compare;

const onTabClick = (id: string) => {
setActiveTabId(id);

if (!isOpen) {
setIsOpen(true);
return;
}

if (activeTabId === id) {
setIsOpen(false);
}
};

const onLayerClick = (id: string) => {
const newId = selectedLayer === id ? null : id;
dispatch(setSelectedLayerIdAction(newId, isMainTabSelected));
};

useEffect(() => {
dispatch(fetchLayers());
Expand All @@ -33,15 +55,15 @@ const LayerSelector: FunctionComponent<{}> = () => {
<Tabs
tabs={tabs}
activeTabId={activeTabId}
onTabChanged={id => setActiveTabId(id)}
/>
<LayerList
layers={layers}
selected={'layer1'}
onSelect={id =>
dispatch(setSelectedLayerIdAction(id, isMainTabSelected))
}
onTabChanged={id => onTabClick(id)}
/>
{isOpen && (
<LayerList
layers={layers}
selected={selectedLayer}
onSelect={id => onLayerClick(id)}
/>
)}
</div>
);
};
Expand Down
9 changes: 6 additions & 3 deletions src/scripts/components/tab/tab.styl
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
.btn
.tab
width: 50%
padding: 20px
border-radius: 10px 10px 0 0
font-size: 1.3em
outline: 0

.btnInactive
background-color: #141414
color: #fff
border: 1px solid #ccc

.tabActive
background-color: #fff
color: #141414
border: 1px solid #ccc
10 changes: 5 additions & 5 deletions src/scripts/components/tab/tab.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {FunctionComponent} from 'react';
import cx from 'classnames';
import styles from './tab.styl';
import classNames from 'classnames';

interface Props {
id: string;
Expand All @@ -14,11 +14,11 @@ const Tab: FunctionComponent<Props> = ({
onSelectTabId,
children
}) => {
const btnClass = classNames(styles.btn, {
[styles.btnInactive]: activeTabId !== id
});
const isActive = activeTabId === id;
const tabClasses = cx(styles.tab, isActive && styles.tabActive);

return (
<button className={btnClass} onClick={() => onSelectTabId(id)}>
<button className={tabClasses} onClick={() => onSelectTabId(id)}>
{children}
</button>
);
Expand Down
5 changes: 4 additions & 1 deletion src/scripts/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export type Action = FetchLayersSuccessAction | SetSelectedLayerIdAction;

const initialState: State = {
layers: [],
selectedLayer: []
selectedLayer: {
main: null,
compare: null
}
};

function reducer(state: State = initialState, action: Action): State {
Expand Down
19 changes: 14 additions & 5 deletions src/scripts/reducers/selected-layer-id.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import {SET_SELECTED_LAYER_ID, LayerId} from '../actions/set-selected-layer';
import {Action, State} from './index';

export type SelectedLayersState = LayerId[];
export interface SelectedLayersState {
main: LayerId | null;
compare: LayerId | null;
}

const initialState = {
main: null,
compare: null
};

function selectedLayerReducer(
state: SelectedLayersState = [],
state: SelectedLayersState = initialState,
action: Action
): SelectedLayersState {
switch (action.type) {
case SET_SELECTED_LAYER_ID:
const newState = [...state];
newState[action.isPrimary ? 0 : 1] = action.layerId;
const newState = {...state};
const key = action.isPrimary ? 'main' : 'compare';
newState[key] = action.layerId;
return newState;
default:
return state;
}
}
export function selectedLayerIdSelector(state: State) {
export function selectedLayerIdSelector(state: State): SelectedLayersState {
return state.selectedLayer;
}
export default selectedLayerReducer;

0 comments on commit 2ed8363

Please sign in to comment.