Skip to content

Commit

Permalink
Move panel toggles to control headers
Browse files Browse the repository at this point in the history
Do this by extending annotatedHeader to take an optional toggle, then
using it for all available panels.

Simplify headers and translations to just the panel name (e.g. Tree)
instead of "Show <panel name>" / "<panel name> Options".

Repurpose and move the section "Panel Options" to the top as "Layout".
Conditionally render that entire section including the header.

This also adds a section for the entropy panel to maintain its
toggle-ability. This is an empty section because it does not have any
sidebar options.
  • Loading branch information
victorlin committed Oct 18, 2023
1 parent 302ce86 commit 66f82bd
Show file tree
Hide file tree
Showing 20 changed files with 221 additions and 165 deletions.
28 changes: 16 additions & 12 deletions src/components/controls/annotatedHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,29 @@ import { FaInfoCircle } from "react-icons/fa";
import {StyledTooltip, HeaderIconContainer, HeaderContainer, HeaderTitle} from "./styles";

type Props = {
toggle?: JSX.Element
title: string
tooltip: JSX.Element
mobile: boolean
}

export const AnnotatedHeader = ({title, tooltip, mobile}: Props) => {
export const AnnotatedHeader = ({toggle=undefined, title, tooltip, mobile}: Props) => {
return (
<HeaderContainer>
<HeaderTitle>{title}</HeaderTitle>
{tooltip && !mobile && (
<>
<HeaderIconContainer data-tip data-for={title}>
<FaInfoCircle/>
</HeaderIconContainer>
<StyledTooltip place="bottom" type="dark" effect="solid" id={title}>
{tooltip}
</StyledTooltip>
</>
)}
<div>
<HeaderTitle>{title}</HeaderTitle>
{tooltip && !mobile && (
<>
<HeaderIconContainer data-tip data-for={title}>
<FaInfoCircle/>
</HeaderIconContainer>
<StyledTooltip place="bottom" type="dark" effect="solid" id={title}>
{tooltip}
</StyledTooltip>
</>
)}
</div>
{toggle !== undefined && toggle}
</HeaderContainer>
);
};
Expand Down
116 changes: 75 additions & 41 deletions src/components/controls/controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import GeoResolution from "./geo-resolution";
import TransmissionLines from './transmission-lines';
import NormalizeFrequencies from "./frequency-normalization";
import AnimationOptions from "./animation-options";
import PanelToggles from "./panel-toggles";
import { PanelSection } from "./panelSection";
import ToggleTangle from "./toggle-tangle";
import Language from "./language";
import { ControlsContainer } from "./styles";
import FilterData, {FilterInfo} from "./filter";
import {TreeOptionsInfo, MapOptionsInfo, AnimationOptionsInfo, PanelOptionsInfo,
ExplodeTreeInfo, FrequencyInfo, MeasurementsOptionsInfo} from "./miscInfoText";
import {TreeInfo, MapInfo, AnimationOptionsInfo, PanelLayoutInfo,
ExplodeTreeInfo, EntropyInfo, FrequencyInfo, MeasurementsInfo} from "./miscInfoText";
import { AnnotatedHeader } from "./annotatedHeader";
import MeasurementsOptions from "./measurementsOptions";
import { RootState } from "../../store";
Expand All @@ -35,12 +35,10 @@ type Props = {
function Controls({ mobileDisplay }: Props) {
const { t } = useTranslation();

const panelsAvailable = useSelector((state: RootState) => state.controls.panelsAvailable);
const panelsToDisplay = useSelector((state: RootState) => state.controls.panelsToDisplay);

const treeOn = panelsToDisplay.includes("tree");
const mapOn = panelsToDisplay.includes("map");
const frequenciesOn = panelsToDisplay.includes("frequencies");
const measurementsOn = panelsToDisplay.includes("measurements");
const showTreeToo = useSelector((state: RootState) => state.controls.showTreeToo);
const canTogglePanelLayout = useSelector((state: RootState) => state.controls.canTogglePanelLayout);

return (
<ControlsContainer>
Expand All @@ -54,52 +52,88 @@ function Controls({ mobileDisplay }: Props) {
<ColorBy />

<AnnotatedHeader title={t("sidebar:Filter Data")} tooltip={FilterInfo} mobile={mobileDisplay}/>
<FilterData measurementsOn={measurementsOn} />

{treeOn &&
<span>
<AnnotatedHeader title={t("sidebar:Tree Options")} tooltip={TreeOptionsInfo} mobile={mobileDisplay}/>
<ChooseLayout />
<ChooseMetric />
<ChooseBranchLabelling />
<ChooseTipLabel />
<ChooseSecondTree />
<ChooseExplodeAttr tooltip={ExplodeTreeInfo} mobile={mobileDisplay} />
<ToggleTangle />
</span>
<FilterData measurementsOn={panelsToDisplay.includes("measurements")} />

{canTogglePanelLayout &&
<>
{/* FIXME: update translations */}
<AnnotatedHeader title={t("sidebar:Layout")} tooltip={PanelLayoutInfo} mobile={mobileDisplay} />
<PanelLayout />
</>
}
{!canTogglePanelLayout &&
<span style={{ marginTop: "10px" }}></span>
}

{panelsAvailable.includes("tree") &&
<PanelSection
panel="tree"
title={t("sidebar:Tree")}
tooltip={TreeInfo}
mobile={mobileDisplay}
options={<>
<ChooseLayout />
<ChooseMetric />
<ChooseBranchLabelling />
<ChooseTipLabel />
<ChooseSecondTree />
<ChooseExplodeAttr tooltip={ExplodeTreeInfo} mobile={mobileDisplay} />
<ToggleTangle />
</>}
/>
}

{panelsAvailable.includes("measurements") &&
<PanelSection
panel="measurements"
title={t("sidebar:Measurements")}
tooltip={MeasurementsInfo}
mobile={mobileDisplay}
options={<MeasurementsOptions />}
/>
}

{measurementsOn &&
<span style={{ marginTop: "10px" }}>
<AnnotatedHeader title={t("sidebar:Measurements Options")} tooltip={MeasurementsOptionsInfo} mobile={mobileDisplay}/>
<MeasurementsOptions />
</span>
{/* Prevent the map from being toggled on when a second tree is visible.
It is hidden by logic elsewhere.
*/}
{panelsAvailable.includes("map") && !showTreeToo &&
<PanelSection
panel="map"
title={t("sidebar:Map")}
tooltip={MapInfo}
mobile={mobileDisplay}
options={<>
<GeoResolution />
<TransmissionLines />
</>}
/>
}

{mapOn &&
<span style={{ marginTop: "10px" }}>
<AnnotatedHeader title={t("sidebar:Map Options")} tooltip={MapOptionsInfo} mobile={mobileDisplay}/>
<GeoResolution />
<TransmissionLines />
</span>
{panelsAvailable.includes("entropy") &&
<PanelSection
panel="entropy"
title={t("sidebar:Entropy")}
tooltip={EntropyInfo}
mobile={mobileDisplay}
options={<></>}
/>
}

{frequenciesOn &&
<span style={{ marginTop: "10px" }}>
<AnnotatedHeader title={t("sidebar:Frequency Options")} tooltip={FrequencyInfo} mobile={mobileDisplay}/>
<NormalizeFrequencies />
</span>
{panelsAvailable.includes("frequencies") &&
<PanelSection
panel="frequencies"
title={t("sidebar:Frequency")}
tooltip={FrequencyInfo}
mobile={mobileDisplay}
options={<NormalizeFrequencies />}
/>
}

<span style={{ marginTop: "10px" }}>
<AnnotatedHeader title={t("sidebar:Animation Options")} tooltip={AnimationOptionsInfo} mobile={mobileDisplay}/>
<AnimationOptions />
</span>

<span style={{ paddingTop: "10px" }} />
<AnnotatedHeader title={t("sidebar:Panel Options")} tooltip={PanelOptionsInfo} mobile={mobileDisplay}/>
<PanelLayout />
<PanelToggles />
<Language />
</ControlsContainer>
);
Expand Down
18 changes: 11 additions & 7 deletions src/components/controls/miscInfoText.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";


export const TreeOptionsInfo = (
export const TreeInfo = (
<>
Change various options relating to how the tree is displayed.
The exact options available depend on the dataset and specific analysis performed.
Expand All @@ -12,7 +12,7 @@ export const TreeOptionsInfo = (
);


export const MapOptionsInfo = (
export const MapInfo = (
<>
Change various options relating to how the map is displayed.
<br/>
Expand All @@ -27,11 +27,15 @@ export const AnimationOptionsInfo = (
</>
);

export const PanelOptionsInfo = (
export const PanelLayoutInfo = (
<>
Control which panels are being displayed and whether to show the tree and the map side-by-side (<em>grid</em>) or expanded (<em>full</em>).
<br/>
Note that what options are available here are dataset specific!
Control whether to show the tree and the map side-by-side (<em>grid</em>) or expanded (<em>full</em>).
</>
);

export const EntropyInfo = (
<>
FIXME: Add some info text that describes the entropy panel.
</>
);

Expand All @@ -42,7 +46,7 @@ export const FrequencyInfo = (
</>
);

export const MeasurementsOptionsInfo = (
export const MeasurementsInfo = (
<>
Change collection of measurements and various display options for the collection.
</>
Expand Down
6 changes: 1 addition & 5 deletions src/components/controls/panel-layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,12 @@ const PanelsGridIcon = withTheme(icons.PanelsGrid);
@connect((state) => {
return {
panelLayout: state.controls.panelLayout,
canTogglePanelLayout: state.controls.canTogglePanelLayout
};
})
class PanelLayouts extends React.Component {
render() {
const { t } = this.props;
// const mapAndTree = this.props.panels !== undefined && this.props.panels.indexOf("map") !== -1 && this.props.panels.indexOf("tree") !== -1;
if (!this.props.canTogglePanelLayout) {
return null;
}

return (
<div style={{marginTop: 0, marginBottom: 10}}>
<PanelsFullIcon width={22} selected={this.props.panelLayout === "full"}/>
Expand Down
31 changes: 31 additions & 0 deletions src/components/controls/panel-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// A slider toggle to adjust the state of a panel via dispatch.

import React from "react";
import { useAppDispatch } from "../../hooks";

import Toggle from "./toggle";
import { togglePanelDisplay } from "../../actions/panelDisplay";

type Props = {
panel: string
on: boolean
}

const PanelToggle = ({ panel, on }: Props) => {
const dispatch = useAppDispatch();

// There is no slider label since the title in the annotated header acts as a
// visual label.
// FIXME: Add a hidden label?

return (
<Toggle
display={true}
on={on}
callback={() => dispatch(togglePanelDisplay(panel))}
label=""
/>
);
};

export default PanelToggle;
38 changes: 0 additions & 38 deletions src/components/controls/panel-toggles.tsx

This file was deleted.

33 changes: 33 additions & 0 deletions src/components/controls/panelSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { useSelector } from "react-redux";
import { AnnotatedHeader } from "./annotatedHeader";
import { PanelSectionContainer } from "./styles";
import PanelToggle from "./panel-toggle";
import { RootState } from "../../store";

type Props = {
panel: string
title: string
tooltip: JSX.Element
options: JSX.Element
mobile: boolean
}

export const PanelSection = ({ panel, title, tooltip, options, mobile }: Props) => {

const panelsToDisplay = useSelector((state: RootState) => state.controls.panelsToDisplay);

const panelOn = panelsToDisplay.includes(panel)

return (
<PanelSectionContainer>
<AnnotatedHeader
toggle={<PanelToggle panel={panel} on={panelOn} />}
title={title}
tooltip={tooltip}
mobile={mobile}
/>
{panelOn && options}
</PanelSectionContainer>
);
};
Loading

0 comments on commit 66f82bd

Please sign in to comment.