From 82d38838ed8a6645b3515dba097d43599cd58b9e Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Tue, 12 Sep 2023 11:40:50 -0700 Subject: [PATCH 01/14] PanelToggles: Add context to implicit behavior --- src/components/controls/panel-toggles.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/controls/panel-toggles.tsx b/src/components/controls/panel-toggles.tsx index 023ea9bae..eb74afb80 100644 --- a/src/components/controls/panel-toggles.tsx +++ b/src/components/controls/panel-toggles.tsx @@ -16,9 +16,13 @@ export default function PanelToggles() { const showTreeToo = useSelector((state: RootState) => state.controls.showTreeToo); const panels = panelsAvailable.slice(); + + // Prevent the map from being toggled on when a second tree is visible. + // It is hidden by logic elsewhere. if (showTreeToo && panels.indexOf("map") !== -1) { panels.splice(panels.indexOf("map"), 1); } + return <> {panels.map((n) => ( Date: Fri, 29 Sep 2023 11:59:45 -0700 Subject: [PATCH 02/14] AnnotatedHeader: Convert to TypeScript The component was written to allow tooltip as optional, so make that explicit. Other props should be required. --- src/components/controls/annotatedHeader.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/controls/annotatedHeader.tsx b/src/components/controls/annotatedHeader.tsx index fb766a64b..a2ad33202 100644 --- a/src/components/controls/annotatedHeader.tsx +++ b/src/components/controls/annotatedHeader.tsx @@ -4,7 +4,12 @@ import { FaInfoCircle } from "react-icons/fa"; import {StyledTooltip, HeaderIconContainer, HeaderContainer} from "./styles"; import { RootState } from "../../store"; -export const AnnotatedHeader = ({title, tooltip}) => { +type Props = { + title: string + tooltip?: JSX.Element +} + +export const AnnotatedHeader = ({title, tooltip=undefined}: Props) => { const mobile = useSelector((state: RootState) => state.general.mobileDisplay); return ( From 46ed345330cf4389eba4436fb731fb4e2c31140f Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:34:22 -0700 Subject: [PATCH 03/14] AnnotatedHeader: Use separate styled component for font-related styles This keeps the styling closer to where it is used. --- src/components/controls/annotatedHeader.tsx | 4 ++-- src/components/controls/styles.js | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/controls/annotatedHeader.tsx b/src/components/controls/annotatedHeader.tsx index a2ad33202..5c297066d 100644 --- a/src/components/controls/annotatedHeader.tsx +++ b/src/components/controls/annotatedHeader.tsx @@ -1,7 +1,7 @@ import React from "react"; import { useSelector } from "react-redux"; import { FaInfoCircle } from "react-icons/fa"; -import {StyledTooltip, HeaderIconContainer, HeaderContainer} from "./styles"; +import {StyledTooltip, HeaderIconContainer, HeaderContainer, HeaderTitle} from "./styles"; import { RootState } from "../../store"; type Props = { @@ -14,7 +14,7 @@ export const AnnotatedHeader = ({title, tooltip=undefined}: Props) => { return ( - {title} + {title} {tooltip && !mobile && ( <> diff --git a/src/components/controls/styles.js b/src/components/controls/styles.js index 45555053f..40c22bb23 100644 --- a/src/components/controls/styles.js +++ b/src/components/controls/styles.js @@ -24,12 +24,15 @@ export const ControlsContainer = styled.div` export const HeaderContainer = styled.div` display: flex; justify-content: space-between; - font-family: ${(props) => props.theme["font-family"]}; - font-size: 16px; line-height: 28px; min-height: 28px; /* needed for safari, else the div height is 0 */ margin-top: 15px; margin-bottom: 5px; +`; + +export const HeaderTitle = styled.span` + font-family: ${(props) => props.theme["font-family"]}; + font-size: 16px; font-weight: 500; color: ${(props) => props.theme.color}; `; From 620bfedb4109430a0c1dea48950af9b927c317cf Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:17:23 -0700 Subject: [PATCH 04/14] Make Language its own controls section Previously, it looked like language was a part of Panel Options. --- src/components/controls/controls.tsx | 3 +++ src/components/controls/language.js | 35 +++++++++++----------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/components/controls/controls.tsx b/src/components/controls/controls.tsx index df0690c0d..de7a4e640 100644 --- a/src/components/controls/controls.tsx +++ b/src/components/controls/controls.tsx @@ -94,6 +94,9 @@ function Controls({ treeOn, mapOn, frequenciesOn, measurementsOn }: Props) { + + + ); diff --git a/src/components/controls/language.js b/src/components/controls/language.js index e1d163eda..c0fc34245 100644 --- a/src/components/controls/language.js +++ b/src/components/controls/language.js @@ -1,11 +1,9 @@ import React from "react"; import { connect } from "react-redux"; -import { withTranslation } from "react-i18next"; import i18n from "i18next"; import { controlsWidth } from "../../util/globals"; import { analyticsControlsEvent } from "../../util/googleAnalytics"; -import { SidebarSubtitle } from "./styles"; import { CHANGE_LANGUAGE } from "../../actions/types"; import CustomSelect from "./customSelect"; @@ -62,29 +60,22 @@ class Language extends React.Component { } render() { - const { t } = this.props; const selectOptions = this.getlanguageOptions(); return ( - <> - - {t("sidebar:Language")} - -
- value === this.props.language)} - options={selectOptions} - isClearable={false} - isSearchable={false} - isMulti={false} - onChange={(opt) => {this.changeLanguage(opt.value);}} - /> -
- +
+ value === this.props.language)} + options={selectOptions} + isClearable={false} + isSearchable={false} + isMulti={false} + onChange={(opt) => {this.changeLanguage(opt.value);}} + /> +
); } } -const WithTranslation = withTranslation()(Language); -export default WithTranslation; +export default Language; From a0ebda5f604db318e0323db867c32612d351db50 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:02:23 -0700 Subject: [PATCH 05/14] Determine panel visibility states in controls component Instead of determining in the sidebar and passing down as props. --- src/components/controls/controls.tsx | 18 ++++++++++-------- src/components/main/sidebar.tsx | 8 +------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/components/controls/controls.tsx b/src/components/controls/controls.tsx index de7a4e640..cfc6d4379 100644 --- a/src/components/controls/controls.tsx +++ b/src/components/controls/controls.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useSelector } from "react-redux"; import { useTranslation } from 'react-i18next'; import ColorBy, {ColorByInfo} from "./color-by"; @@ -25,17 +26,18 @@ import {TreeOptionsInfo, MapOptionsInfo, AnimationOptionsInfo, PanelOptionsInfo, ExplodeTreeInfo, FrequencyInfo, MeasurementsOptionsInfo} from "./miscInfoText"; import { AnnotatedHeader } from "./annotatedHeader"; import MeasurementsOptions from "./measurementsOptions"; +import { RootState } from "../../store"; -type Props = { - treeOn: boolean - mapOn: boolean - frequenciesOn: boolean - measurementsOn: boolean -} - -function Controls({ treeOn, mapOn, frequenciesOn, measurementsOn }: Props) { +function Controls() { const { t } = useTranslation(); + 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"); + return ( diff --git a/src/components/main/sidebar.tsx b/src/components/main/sidebar.tsx index 99f755df6..4a442764c 100644 --- a/src/components/main/sidebar.tsx +++ b/src/components/main/sidebar.tsx @@ -13,7 +13,6 @@ export const Sidebar = ( { width, height, displayNarrative, narrativeTitle, navBarHandler} ) => { const sidebarOpen = useSelector((state: RootState) => state.controls.sidebarOpen); - const panelsToDisplay = useSelector((state: RootState) => state.controls.panelsToDisplay); return ( @@ -27,12 +26,7 @@ export const Sidebar = ( {displayNarrative ? ( ) : ( - + )} From 8a96a0903d98b46efc4815470280b9d5d1dcc35f Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:39:37 -0800 Subject: [PATCH 06/14] tsconfig: Disable exactOptionalPropertyTypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disabling this makes typed prop drilling more readable by not requiring a conditional for optional props¹. ¹ https://stackoverflow.com/a/48816255 --- tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 37a8d7705..4b8fa23c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,7 +34,6 @@ Visit https://aka.ms/tsconfig.json for a detailed list of options. "noImplicitAny": false, /* Allow implicit any to make incremental TypeScript adoption easier. */ "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ From ce518c57839aa6e1b023b091ded80e47d3bbe55a Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:27:42 -0700 Subject: [PATCH 07/14] Prepare for panel-specific header changes Split AnnotatedHeader into AnnotatedTitle and ControlHeader. A future commit will introduce PanelHeader. This places the header info icon immediately to the right of the title, instead of the far right side (to make room for the upcoming panel visibility toggle). --- ...annotatedHeader.tsx => annotatedTitle.tsx} | 23 +++++++++++++------ src/components/controls/choose-dataset.js | 4 ++-- src/components/controls/controlHeader.tsx | 21 +++++++++++++++++ src/components/controls/controls.tsx | 22 +++++++++--------- src/components/controls/styles.js | 10 ++++++-- 5 files changed, 58 insertions(+), 22 deletions(-) rename src/components/controls/{annotatedHeader.tsx => annotatedTitle.tsx} (54%) create mode 100644 src/components/controls/controlHeader.tsx diff --git a/src/components/controls/annotatedHeader.tsx b/src/components/controls/annotatedTitle.tsx similarity index 54% rename from src/components/controls/annotatedHeader.tsx rename to src/components/controls/annotatedTitle.tsx index 5c297066d..d185430bb 100644 --- a/src/components/controls/annotatedHeader.tsx +++ b/src/components/controls/annotatedTitle.tsx @@ -1,19 +1,29 @@ import React from "react"; import { useSelector } from "react-redux"; import { FaInfoCircle } from "react-icons/fa"; -import {StyledTooltip, HeaderIconContainer, HeaderContainer, HeaderTitle} from "./styles"; +import {TitleAndIconContainer, StyledTooltip, HeaderIconContainer, HeaderTitle} from "./styles"; import { RootState } from "../../store"; +/** Title to display for the control. */ +export type Title = string; + +/** Informational tooltip element to display on hover. */ +export type Tooltip = JSX.Element; + type Props = { - title: string - tooltip?: JSX.Element + title: Title + tooltip?: Tooltip } -export const AnnotatedHeader = ({title, tooltip=undefined}: Props) => { +/** + * A title and tooltip to be shown in a control header. + * The tooltip is not shown on mobile. + */ +export const AnnotatedTitle = ({title, tooltip=undefined}: Props) => { const mobile = useSelector((state: RootState) => state.general.mobileDisplay); return ( - + {title} {tooltip && !mobile && ( <> @@ -25,7 +35,6 @@ export const AnnotatedHeader = ({title, tooltip=undefined}: Props) => { )} - + ); }; - diff --git a/src/components/controls/choose-dataset.js b/src/components/controls/choose-dataset.js index c3f0c7bac..134fcfe12 100644 --- a/src/components/controls/choose-dataset.js +++ b/src/components/controls/choose-dataset.js @@ -2,7 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import { withTranslation } from "react-i18next"; import ChooseDatasetSelect from "./choose-dataset-select"; -import { AnnotatedHeader } from "./annotatedHeader"; +import { ControlHeader } from "./controlHeader"; // const DroppedFiles = withTheme((props) => { // /* TODO: this shouldn't be in the auspice src, rather injected as an extension when needed */ @@ -54,7 +54,7 @@ class ChooseDataset extends React.Component { return ( <> - + {options.map((option, optionIdx) => ( { + return ( + + + + ); +}; diff --git a/src/components/controls/controls.tsx b/src/components/controls/controls.tsx index cfc6d4379..db1f97e0b 100644 --- a/src/components/controls/controls.tsx +++ b/src/components/controls/controls.tsx @@ -24,7 +24,7 @@ import { ControlsContainer } from "./styles"; import FilterData, {FilterInfo} from "./filter"; import {TreeOptionsInfo, MapOptionsInfo, AnimationOptionsInfo, PanelOptionsInfo, ExplodeTreeInfo, FrequencyInfo, MeasurementsOptionsInfo} from "./miscInfoText"; -import { AnnotatedHeader } from "./annotatedHeader"; +import { ControlHeader } from "./controlHeader"; import MeasurementsOptions from "./measurementsOptions"; import { RootState } from "../../store"; @@ -42,19 +42,19 @@ function Controls() { - + - + - + {treeOn && - + @@ -67,14 +67,14 @@ function Controls() { {measurementsOn && - + } {mapOn && - + @@ -82,23 +82,23 @@ function Controls() { {frequenciesOn && - + } - + - + - + ); diff --git a/src/components/controls/styles.js b/src/components/controls/styles.js index 40c22bb23..b48dfe3a8 100644 --- a/src/components/controls/styles.js +++ b/src/components/controls/styles.js @@ -30,6 +30,11 @@ export const HeaderContainer = styled.div` margin-bottom: 5px; `; +export const TitleAndIconContainer = styled.span` + display: flex; + align-items: center; +`; + export const HeaderTitle = styled.span` font-family: ${(props) => props.theme["font-family"]}; font-size: 16px; @@ -38,8 +43,9 @@ export const HeaderTitle = styled.span` `; export const HeaderIconContainer = styled.span` - padding-top: 4px; - padding-right: 3px; + display: inline-flex; + font-size: 16px; + padding-left: 6px; cursor: help; color: #888; `; From e441dae3041cd294c414d2ac5aa3d80f8e260220 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Fri, 29 Sep 2023 13:24:22 -0700 Subject: [PATCH 08/14] Move panel toggles to control headers Do this with some new panel-specific components that build upon the existing AnnotatedTitle and Toggle components. Simplify headers and translations to just the panel name (e.g. Tree) instead of "Show " / " Options". Conditionally render the entire "Panel Options" 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. --- src/components/controls/annotatedTitle.tsx | 4 +- src/components/controls/controlHeader.tsx | 2 +- src/components/controls/controls.tsx | 108 +++++++++++++-------- src/components/controls/miscInfoText.js | 25 +++-- src/components/controls/panel-layout.js | 6 +- src/components/controls/panel-toggles.tsx | 38 -------- src/components/controls/panelHeader.tsx | 42 ++++++++ src/components/controls/panelSection.tsx | 37 +++++++ src/components/controls/styles.js | 19 ++++ src/locales/ar/sidebar.json | 8 +- src/locales/de/sidebar.json | 8 +- src/locales/en/sidebar.json | 8 +- src/locales/es/sidebar.json | 8 +- src/locales/fr/sidebar.json | 8 +- src/locales/it/sidebar.json | 8 +- src/locales/ja/sidebar.json | 8 +- src/locales/lt/sidebar.json | 8 +- src/locales/pl/sidebar.json | 8 +- src/locales/pt/sidebar.json | 8 +- src/locales/ru/sidebar.json | 8 +- src/locales/tr/sidebar.json | 8 +- 21 files changed, 223 insertions(+), 154 deletions(-) delete mode 100644 src/components/controls/panel-toggles.tsx create mode 100644 src/components/controls/panelHeader.tsx create mode 100644 src/components/controls/panelSection.tsx diff --git a/src/components/controls/annotatedTitle.tsx b/src/components/controls/annotatedTitle.tsx index d185430bb..d08c58cc7 100644 --- a/src/components/controls/annotatedTitle.tsx +++ b/src/components/controls/annotatedTitle.tsx @@ -27,7 +27,9 @@ export const AnnotatedTitle = ({title, tooltip=undefined}: Props) => { {title} {tooltip && !mobile && ( <> - + event.stopPropagation()}> diff --git a/src/components/controls/controlHeader.tsx b/src/components/controls/controlHeader.tsx index e57a73404..345589b4b 100644 --- a/src/components/controls/controlHeader.tsx +++ b/src/components/controls/controlHeader.tsx @@ -8,7 +8,7 @@ type Props = { } /** - * A header used by all controls, containing an informative title. + * A header used by all non-panel controls, containing an informative title. */ export const ControlHeader = ({title, tooltip=undefined }: Props) => { return ( diff --git a/src/components/controls/controls.tsx b/src/components/controls/controls.tsx index db1f97e0b..09c96f207 100644 --- a/src/components/controls/controls.tsx +++ b/src/components/controls/controls.tsx @@ -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, PanelOptionsInfo, + ExplodeTreeInfo, EntropyInfo, FrequencyInfo, MeasurementsInfo} from "./miscInfoText"; import { ControlHeader } from "./controlHeader"; import MeasurementsOptions from "./measurementsOptions"; import { RootState } from "../../store"; @@ -31,12 +31,10 @@ import { RootState } from "../../store"; function Controls() { 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 ( @@ -50,41 +48,66 @@ function Controls() { - - - {treeOn && - - - - - - - - - - + + + + + {panelsAvailable.includes("tree") && + + + + + + + + + } + /> } - {measurementsOn && - - - - + {panelsAvailable.includes("measurements") && + } + /> } - {mapOn && - - - - - + {/* Prevent the map from being toggled on when a second tree is visible. + It is hidden by logic elsewhere. + */} + {panelsAvailable.includes("map") && !showTreeToo && + + + + } + /> } - {frequenciesOn && - - - - + {panelsAvailable.includes("entropy") && + + } + + {panelsAvailable.includes("frequencies") && + } + /> } @@ -92,10 +115,13 @@ function Controls() { - - - - + {canTogglePanelLayout && + <> + + + + + } diff --git a/src/components/controls/miscInfoText.js b/src/components/controls/miscInfoText.js index eb2bafb91..92a61e591 100644 --- a/src/components/controls/miscInfoText.js +++ b/src/components/controls/miscInfoText.js @@ -1,9 +1,10 @@ import React from "react"; -export const TreeOptionsInfo = ( +export const TreeInfo = ( <> - Change various options relating to how the tree is displayed. + This panel displays the evolutionary relationships among samples, illustrating their genetic relatedness and inferred ancestry. +
The exact options available depend on the dataset and specific analysis performed.
If Branch Length is available, you can choose to display the tree branches in terms of (nucleotide) divergence or (inferred) time. @@ -12,9 +13,9 @@ export const TreeOptionsInfo = ( ); -export const MapOptionsInfo = ( +export const MapInfo = ( <> - Change various options relating to how the map is displayed. + This panel displays the geographical distribution of samples.
The geographic resolution chooses the metadata values which define where samples are placed on the map. This can be the same as the selected color-by but is often not! @@ -29,21 +30,29 @@ export const AnimationOptionsInfo = ( export const PanelOptionsInfo = ( <> - Control which panels are being displayed and whether to show the tree and the map side-by-side (grid) or expanded (full). -
- Note that what options are available here are dataset specific! + Control whether to show the tree and the map side-by-side (grid) or expanded (full). + +); + +export const EntropyInfo = ( + <> + This panel displays the observed diversity across the current genome or a selected CDS. All options are in the panel itself. ); export const FrequencyInfo = ( <> + This panel displays the prevalence of a characteristic over time, determined by the color-by. +
Normalize frequencies controls whether the vertical axis represents the entire dataset or only the samples currently visible (e.g. due to filtering). This option is not available when data is limited to prevent numerical issues. ); -export const MeasurementsOptionsInfo = ( +export const MeasurementsInfo = ( <> + This panel displays multidimensional data such as serological experimental results that are linked to samples in the tree. +
Change collection of measurements and various display options for the collection. ); diff --git a/src/components/controls/panel-layout.js b/src/components/controls/panel-layout.js index 61df20d95..c2cf1ead5 100644 --- a/src/components/controls/panel-layout.js +++ b/src/components/controls/panel-layout.js @@ -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 (
diff --git a/src/components/controls/panel-toggles.tsx b/src/components/controls/panel-toggles.tsx deleted file mode 100644 index eb74afb80..000000000 --- a/src/components/controls/panel-toggles.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import { useSelector } from "react-redux"; -import { useAppDispatch } from "../../hooks"; -import { useTranslation } from 'react-i18next'; - -import Toggle from "./toggle"; -import { togglePanelDisplay } from "../../actions/panelDisplay"; -import { RootState } from "../../store"; - -export default function PanelToggles() { - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - - const panelsAvailable = useSelector((state: RootState) => state.controls.panelsAvailable); - const panelsToDisplay = useSelector((state: RootState) => state.controls.panelsToDisplay); - const showTreeToo = useSelector((state: RootState) => state.controls.showTreeToo); - - const panels = panelsAvailable.slice(); - - // Prevent the map from being toggled on when a second tree is visible. - // It is hidden by logic elsewhere. - if (showTreeToo && panels.indexOf("map") !== -1) { - panels.splice(panels.indexOf("map"), 1); - } - - return <> - {panels.map((n) => ( - dispatch(togglePanelDisplay(n))} - label={t("sidebar:Show " + n)} - style={{ paddingBottom: "10px" }} - /> - ))} - -} diff --git a/src/components/controls/panelHeader.tsx b/src/components/controls/panelHeader.tsx new file mode 100644 index 000000000..d156269b8 --- /dev/null +++ b/src/components/controls/panelHeader.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import { useAppDispatch } from "../../hooks"; +import { togglePanelDisplay } from "../../actions/panelDisplay"; +import { HeaderContainer } from "./styles"; +import Toggle from "./toggle"; +import { AnnotatedTitle, Title, Tooltip } from "./annotatedTitle"; + +/** Panel identifier used internally. */ +export type PanelId = string; + +type Props = { + panel: PanelId + title: Title + tooltip?: Tooltip + + /** Indicates panel visibility. */ + panelIsVisible: boolean +} + +/** + * A header used by all panel controls, containing an interactive title. + */ +export const PanelHeader = ({ panel, title, tooltip, panelIsVisible }: Props) => { + const dispatch = useAppDispatch(); + + function togglePanelVisibility() { + dispatch(togglePanelDisplay(panel)) + } + + return ( + + + + + ); +}; diff --git a/src/components/controls/panelSection.tsx b/src/components/controls/panelSection.tsx new file mode 100644 index 000000000..7dc6594b8 --- /dev/null +++ b/src/components/controls/panelSection.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { PanelSectionContainer } from "./styles"; +import { Title, Tooltip } from "./annotatedTitle"; +import { PanelHeader, PanelId } from "./panelHeader"; +import { RootState } from "../../store"; + +type Props = { + panel: PanelId + title: Title + tooltip?: Tooltip + + /** Element that contains panel-specific options. */ + options?: JSX.Element +} + +/** + * A controls section for panel-specific customization. + */ +export const PanelSection = ({ panel, title, tooltip, options=undefined }: Props) => { + + const panelsToDisplay = useSelector((state: RootState) => state.controls.panelsToDisplay); + + const panelIsVisible = panelsToDisplay.includes(panel) + + return ( + + + {panelIsVisible && options} + + ); +}; diff --git a/src/components/controls/styles.js b/src/components/controls/styles.js index b48dfe3a8..f36456e24 100644 --- a/src/components/controls/styles.js +++ b/src/components/controls/styles.js @@ -30,6 +30,25 @@ export const HeaderContainer = styled.div` margin-bottom: 5px; `; +export const PanelSectionContainer = styled.div` + // Less padding is necessary on the top because there is already some space + // from HeaderContainer's top margin. + padding-top: 2px; + padding-bottom: 8px; + + // Add borders to delineate panel sections from other sections. + // TODO: Rename unselectedBackground to alternateBackground. + // https://github.com/nextstrain/auspice/pull/1704#discussion_r1385917481 + border-top: 1px solid ${(props) => props.theme.unselectedBackground}; + border-bottom: 1px solid ${(props) => props.theme.unselectedBackground}; + + // Don't add a top border when there is already a bottom border from a sibling + // above. + & + & { + border-top: none; + } +`; + export const TitleAndIconContainer = styled.span` display: flex; align-items: center; diff --git a/src/locales/ar/sidebar.json b/src/locales/ar/sidebar.json index 003bdaffa..259b74ef3 100644 --- a/src/locales/ar/sidebar.json +++ b/src/locales/ar/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "مجموعة بيانات", "Date Range": "النطاق الزمني", "Color By": "اللون حسب", - "Tree Options": "خيارات الشجرة", "Layout": "التخطيط", "rectangular": "مستطيل", "radial": "شعاعي", @@ -15,15 +14,14 @@ "Branch Labels": "تسميات الفروع", "Search Strains": "البحث على السلالات", "Second Tree": "الشجرة الثانية", - "Map Options": "خيارات الخريطة", "Geographic resolution": "دقة الخريطة", "Animation Speed": "سرعة الحركة", "Loop animation": "حركة متكررة", "Animate cumulative history": "تحريك التاريخ التراكمي", "Panel Options": "خيارات اللوحة", - "Show tree": "اظهار الشجرة", - "Show map": "اظهار الخريطة", - "Show entropy": "اظهار الانتروبيا", + "Tree": "الشجرة", + "Map": "الخريطة", + "Entropy": "الانتروبيا", "Language": "اللغة", "Slow": "بطيئة", "Medium": "متوسطة", diff --git a/src/locales/de/sidebar.json b/src/locales/de/sidebar.json index 1c31c5788..4c7775d46 100644 --- a/src/locales/de/sidebar.json +++ b/src/locales/de/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Datensatz", "Date Range": "Datenintervall", "Color By": "färben nach", - "Tree Options": "Baumeinstellungen", "Layout": "Anordnung", "rectangular": "rechteckig", "radial": "kreisförmig", @@ -14,15 +13,14 @@ "Branch Labels": "Astbeschriftungen", "Search Strains": "In Strängen suchen", "Second Tree": "Zweiter Baum", - "Map Options": "Karteneinstellungen", "Geographic resolution": "Geographische Aufteilung", "Animation Speed": "Geschwindigkeit der Animation", "Loop animation": "In einer Schleife animieren", "Animate cumulative history": "Gesamten Verlauf miteinbeziehen", "Panel Options": "Hauptansicht-Einstellungen", - "Show tree": "Baum anzeigen", - "Show map": "Karte anzeigen", - "Show entropy": "Entropie anzeigen", + "Tree": "Baum", + "Map": "Karte", + "Entropy": "Entropie", "Language": "Sprache", "Slow": "Langsam", "Medium": "Mittel", diff --git a/src/locales/en/sidebar.json b/src/locales/en/sidebar.json index 0e4ffc229..fe78fd56a 100644 --- a/src/locales/en/sidebar.json +++ b/src/locales/en/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Dataset", "Date Range": "Date Range", "Color By": "Color By", - "Tree Options": "Tree Options", "Layout": "Layout", "rectangular": "rectangular", "radial": "radial", @@ -15,15 +14,14 @@ "Branch Labels": "Branch Labels", "Search Strains": "Search Strains", "Second Tree": "Second Tree", - "Map Options": "Map Options", "Geographic resolution": "Geographic resolution", "Animation Speed": "Animation Speed", "Loop animation": "Loop animation", "Animate cumulative history": "Animate cumulative history", "Panel Options": "Panel Options", - "Show tree": "Show tree", - "Show map": "Show map", - "Show entropy": "Show entropy", + "Tree": "Tree", + "Map": "Map", + "Entropy": "Entropy", "Language": "Language", "Slow": "Slow", "Medium": "Medium", diff --git a/src/locales/es/sidebar.json b/src/locales/es/sidebar.json index d93a81e75..4f749afaa 100644 --- a/src/locales/es/sidebar.json +++ b/src/locales/es/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Conjunto de datos", "Date Range": "Rango de fechas", "Color By": "Asigna colores por", - "Tree Options": "Opciones del árbol", "Layout": "Diseño", "rectangular": "rectangular", "radial": "radial", @@ -14,15 +13,14 @@ "Branch Labels": "Etiquetas de rama", "Search Strains": "Buscar cepas", "Second Tree": "Segundo árbol", - "Map Options": "Opciones del mapa", "Geographic resolution": "Región geográfica", "Animation Speed": "Velocidad de la animación", "Loop animation": "Repitir la animación", "Animate cumulative history": "Animar historial cumulativo", "Panel Options": "Opciones del panel", - "Show tree": "Visualizar árbol", - "Show map": "Visualizar mapa", - "Show entropy": "Visualizar entropía", + "Tree": "Árbol", + "Map": "Mapa", + "Entropy": "Entropía", "Language": "Idioma", "Slow": "Lento", "Medium": "Medio", diff --git a/src/locales/fr/sidebar.json b/src/locales/fr/sidebar.json index 7ed38c1de..48b255b4a 100644 --- a/src/locales/fr/sidebar.json +++ b/src/locales/fr/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Jeu de données", "Date Range": "Intervalle de dates", "Color By": "Couleur par", - "Tree Options": "Options d'arborescence", "Layout": "Disposition", "rectangular": "rectangulaire", "radial": "radiale", @@ -15,15 +14,14 @@ "Branch Labels": "Libellés de branches", "Search Strains": "Chercher souches", "Second Tree": "Deuxième arbre", - "Map Options": "Options de carte", "Geographic resolution": "Résolution géographique", "Animation Speed": "Vitesse d'animation", "Loop animation": "Animation en boucle", "Animate cumulative history": "Animer l'historique cumulatif", "Panel Options": "Options du panneau", - "Show tree": "Montrer arbre", - "Show map": "Montrer carte", - "Show entropy": "Montrer entropie", + "Tree": "Arbre", + "Map": "Carte", + "Entropy": "Entropie", "Language": "Langue", "Slow": "Lent", "Medium": "Moyen", diff --git a/src/locales/it/sidebar.json b/src/locales/it/sidebar.json index 81e647a4a..fad3fbb5f 100644 --- a/src/locales/it/sidebar.json +++ b/src/locales/it/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Dataset", "Date Range": "Intervallo di date", "Color By": "Colore di", - "Tree Options": "Opzioni di albero", "Layout": "Disposizione", "rectangular": "rettangolare", "radial": "radiale", @@ -15,15 +14,14 @@ "Branch Labels": "Etichette di branche", "Search Strains": "Cercare ceppi", "Second Tree": "Secondo albero", - "Map Options": "Opzioni di mappa", "Geographic resolution": "Risoluzione geografica", "Animation Speed": "Velocità di animazioni", "Loop animation": "Animazioni in loop", "Animate cumulative history": "Animare la storia cumulativa", "Panel Options": "Opzioni di pannello", - "Show tree": "Mostrare albero", - "Show map": "Mostrare mappa", - "Show entropy": "Mostrare entropia", + "Tree": "Albero", + "Map": "Mappa", + "Entropy": "Entropia", "Language": "Lingua", "Slow": "Lento", "Medium": "Medio", diff --git a/src/locales/ja/sidebar.json b/src/locales/ja/sidebar.json index a6d830af1..9fe5e1293 100644 --- a/src/locales/ja/sidebar.json +++ b/src/locales/ja/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "データセット", "Date Range": "データ範囲", "Color By": "色分け", - "Tree Options": "ツリーのオプション", "Layout": "レイアウト", "rectangular": "矩形", "radial": "放射状", @@ -15,15 +14,14 @@ "Branch Labels": "枝のラベル", "Search Strains": "系統を検索", "Second Tree": "第二ツリー", - "Map Options": "地図のオプション", "Geographic resolution": "地域分けの単位", "Animation Speed": "アニメーション速度", "Loop animation": "アニメーションを繰り返し", "Animate cumulative history": "累積の履歴をアニメーション", "Panel Options": "パネルのオプション", - "Show tree": "ツリーを表示", - "Show map": "地図を表示", - "Show entropy": "エントロピーを表示", + "Tree": "ツリー", + "Map": "地図", + "Entropy": "エントロピー", "Language": "言語", "Slow": "遅い", "Medium": "普通", diff --git a/src/locales/lt/sidebar.json b/src/locales/lt/sidebar.json index f2fef0e68..0f3c9d3be 100644 --- a/src/locales/lt/sidebar.json +++ b/src/locales/lt/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Duomenų rinkinys", "Date Range": "Laiko ribos", "Color By": "Spalvinti pagal", - "Tree Options": "Medžio parinktys", "Layout": "Išdėstymas", "rectangular": "stačiakampis", "radial": "apskritas", @@ -15,15 +14,14 @@ "Branch Labels": "Šakų žymės", "Search Strains": "Ieškoti štamų", "Second Tree": "Antras medis", - "Map Options": "Žemėlapio parinktys", "Geographic resolution": "Geografijos mastas", "Animation Speed": "Animacijos greitis", "Loop animation": "Kartoti laiko atkarpą", "Animate cumulative history": "Rodyti kauptinę istoriją", "Panel Options": "Langų parinktys", - "Show tree": "Rodyti medį", - "Show map": "Rodyti žemėlapį", - "Show entropy": "Rodyti entropiją", + "Tree": "Medį", + "Map": "Žemėlapį", + "Entropy": "Entropiją", "Language": "Kalba", "Slow": "Lėtas", "Medium": "Vidutiniškas", diff --git a/src/locales/pl/sidebar.json b/src/locales/pl/sidebar.json index 8e1b74659..490b8a8d7 100644 --- a/src/locales/pl/sidebar.json +++ b/src/locales/pl/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Zbiór danych", "Date Range": "Zakres dat", "Color By": "Kolorowanie według", - "Tree Options": "Opcje drzewa", "Layout": "Układ", "rectangular": "prostokątny", "radial": "radialny", @@ -16,7 +15,6 @@ "Branch Labels": "Etykiety gałęzi", "Search Strains": "Wyszukaj warianty", "Second Tree": "Drugie drzewo", - "Map Options": "Opcje mapy", "Frequency Options": "Opcje częstości", "Normalize frequencies": "Normalizuj częstości", "Geographic resolution": "Rozdzielczość geograficzna", @@ -24,9 +22,9 @@ "Loop animation": "Animacja pętli", "Animate cumulative history": "Animuj historię zbiorczą", "Panel Options": "Opcje panelu", - "Show tree": "Pokaż drzewo", - "Show map": "Pokaż mapę", - "Show entropy": "Pokaż entropię", + "Tree": "Drzewo", + "Map": "Mapę", + "Entropy": "Entropię", "Show transmission lines": "Pokaż drogi transmisji", "Tip Labels": "Etykiety końcówek", "Language": "Język", diff --git a/src/locales/pt/sidebar.json b/src/locales/pt/sidebar.json index a81f11c62..85a7bd91a 100644 --- a/src/locales/pt/sidebar.json +++ b/src/locales/pt/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Conjunto de Dados", "Date Range": "Intervalo de Datas", "Color By": "Atribuir cores por", - "Tree Options": "Opções de Árvore", "Layout": "Desenho", "rectangular": "retangular", "radial": "radial", @@ -15,15 +14,14 @@ "Branch Labels": "Rótulos dos ramos", "Search Strains": "Pesquisar Estirpes", "Second Tree": "Segunda Árvore", - "Map Options": "Opções do Mapa", "Geographic resolution": "Localização geográfica", "Animation Speed": "Velocidade de Animação", "Loop animation": "Repetir a animação", "Animate cumulative history": "Animar o histórico acumulado", "Panel Options": "Painel de Opções", - "Show tree": "Mostrar árvore", - "Show map": "Mostrar mapa", - "Show entropy": "Mostrar entropia", + "Tree": "Árvore", + "Map": "Mapa", + "Entropy": "Entropia", "Language": "Idioma", "Slow": "Lento", "Medium": "Médio", diff --git a/src/locales/ru/sidebar.json b/src/locales/ru/sidebar.json index 694cf85ad..7d83d068f 100644 --- a/src/locales/ru/sidebar.json +++ b/src/locales/ru/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Данные", "Date Range": "Временной Диапазон", "Color By": "Цвет", - "Tree Options": "Настройки Дерева", "Layout": "Тип диаграммы", "rectangular": "прямоугольный", "radial": "радиальный", @@ -14,15 +13,14 @@ "Branch Labels": "Названия Ветвей", "Search Strains": "Поиск Штаммов", "Second Tree": "Второе Дерево", - "Map Options": "Настройки Карты", "Geographic resolution": "Географическое разрешение", "Animation Speed": "Скорость Анимации", "Loop animation": "Повтор анимации", "Animate cumulative history": "Анимировать кумулятивную историю", "Panel Options": "Настройки Панели", - "Show tree": "Показать дерево", - "Show map": "Показать карту", - "Show entropy": "Показать энтропию", + "Tree": "Дерево", + "Map": "Карту", + "Entropy": "Энтропию", "Language": "Язык", "Slow": "Медленный", "Medium": "Средний", diff --git a/src/locales/tr/sidebar.json b/src/locales/tr/sidebar.json index be800a200..b2e30f9f6 100644 --- a/src/locales/tr/sidebar.json +++ b/src/locales/tr/sidebar.json @@ -2,7 +2,6 @@ "Dataset": "Veri kümesi", "Date Range": "Tarih Aralığı", "Color By": "Şuna Göre Renklendir", - "Tree Options": "Ağaç Seçenekleri", "Layout": "Görünüm", "rectangular": "dikdörtgensi", "radial": "dairesel", @@ -15,15 +14,14 @@ "Branch Labels": "Dal Etiketleri", "Search Strains": "Suşları Ara", "Second Tree": "İkinci Ağaç", - "Map Options": "Harita Seçenekleri", "Geographic resolution": "Coğrafik çözünürlük", "Animation Speed": "Animasyon Hızı", "Loop animation": "Döngülü animasyon", "Animate cumulative history": "Kümülatif tarihçeyi canlandır", "Panel Options": "Panel Seçenekleri", - "Show tree": "Ağacı göster", - "Show map": "Haritayı göster", - "Show entropy": "Entropiyi göster", + "Tree": "Ağacı", + "Map": "Haritayı", + "Entropy": "Entropiyi", "Language": "Dil", "Slow": "Yavaş", "Medium": "Orta", From 1ad4376bb3be9787181110d47fe8c5f26a207896 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:13:05 -0800 Subject: [PATCH 09/14] Rename unselectedBackground to alternateBackground This color is now used for more than just the unselected background. --- docs/customise-client/api.rst | 34 ++++++++++++++++--------------- src/components/controls/styles.js | 6 ++---- src/components/controls/toggle.js | 2 +- src/components/main/styles.js | 7 ++++++- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/docs/customise-client/api.rst b/docs/customise-client/api.rst index c389dbf48..975db00d2 100644 --- a/docs/customise-client/api.rst +++ b/docs/customise-client/api.rst @@ -55,25 +55,27 @@ For instance, here is the customisation used by nextstrain.org: "font-family": "Lato, Helvetica Neue, Helvetica, sans-serif", "selectedColor": "#5097BA", "unselectedColor": "#333", - "unselectedBackground": "#888" + "alternateBackground": "#888" } } -+--------------------------+------------------------------+----------------------------------------------------+ -| Properties | CSS string of | Description | -+==========================+==============================+====================================================+ -| selectedColor | color | Text color of selected text / button text | -+--------------------------+------------------------------+----------------------------------------------------+ -| unselectedColor | color | Text color of unselected text / button text | -+--------------------------+------------------------------+----------------------------------------------------+ -| color | color | Text color of all other text | -+--------------------------+------------------------------+----------------------------------------------------+ -| unselectedBackground | color | Background color of unselected toggle | -+--------------------------+------------------------------+----------------------------------------------------+ -| font-family | font | Font used throughout the sidebar | -+--------------------------+------------------------------+----------------------------------------------------+ -| background | color | Background color of the entire sidebar | -+--------------------------+------------------------------+----------------------------------------------------+ ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| Properties | CSS string of | Description | ++===================================+===============+==============================================================================+ +| selectedColor | color | Text color of selected text / button text | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| unselectedColor | color | Text color of unselected text / button text | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| color | color | Text color of all other text | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| unselectedBackground (deprecated) | color | Old key for ``alternateBackground`` | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| alternateBackground | color | Background color of some elements (unselected toggle, panel section borders) | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| font-family | font | Font used throughout the sidebar | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ +| background | color | Background color of the entire sidebar | ++-----------------------------------+---------------+------------------------------------------------------------------------------+ Components ---------- diff --git a/src/components/controls/styles.js b/src/components/controls/styles.js index f36456e24..668adba3e 100644 --- a/src/components/controls/styles.js +++ b/src/components/controls/styles.js @@ -37,10 +37,8 @@ export const PanelSectionContainer = styled.div` padding-bottom: 8px; // Add borders to delineate panel sections from other sections. - // TODO: Rename unselectedBackground to alternateBackground. - // https://github.com/nextstrain/auspice/pull/1704#discussion_r1385917481 - border-top: 1px solid ${(props) => props.theme.unselectedBackground}; - border-bottom: 1px solid ${(props) => props.theme.unselectedBackground}; + border-top: 1px solid ${(props) => props.theme.alternateBackground}; + border-bottom: 1px solid ${(props) => props.theme.alternateBackground}; // Don't add a top border when there is already a bottom border from a sibling // above. diff --git a/src/components/controls/toggle.js b/src/components/controls/toggle.js index e0ba253af..85c68a199 100644 --- a/src/components/controls/toggle.js +++ b/src/components/controls/toggle.js @@ -31,7 +31,7 @@ const Slider = styled.div` left: 0; right: 0; bottom: 0; - background-color: ${(props) => props.theme.unselectedBackground}; + background-color: ${(props) => props.theme.alternateBackground}; -webkit-transition: .4s; transition: .4s; border-radius: 12px; diff --git a/src/components/main/styles.js b/src/components/main/styles.js index b0a7ab245..4ef644443 100644 --- a/src/components/main/styles.js +++ b/src/components/main/styles.js @@ -42,10 +42,15 @@ const sidebarThemeDefaults = { sidebarBoxShadow: "rgba(255, 255, 255, 1)", selectedColor: "#5DA8A3", unselectedColor: "#BBB", - unselectedBackground: "#888" + alternateBackground: "#888" }; let sidebarThemeExtensions = {}; if (hasExtension("sidebarTheme")) { sidebarThemeExtensions = getExtension("sidebarTheme"); + + // unselectedBackground → alternateBackground + if (Object.prototype.hasOwnProperty.call(sidebarThemeExtensions, "unselectedBackground")) { + sidebarThemeExtensions["alternateBackground"] = sidebarThemeExtensions["unselectedBackground"]; + } } export const sidebarTheme = {...sidebarThemeDefaults, ...sidebarThemeExtensions}; From 404e2d4fa5a99356a11df2e172b6c04e5a4b93f6 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:23:02 -0700 Subject: [PATCH 10/14] Rename "Panel Options" to "Display" I chose the title "Display" even though it is called "layout" in the state because "Layout" is already used to describe tree layout, and I didn't want translations to conflict. I also contemplated putting this control at the top. However, its conditional rendering worsens usability upon toggling panel visibility, as the scroll position is changed due to its placement above the toggles. --- src/components/controls/controls.tsx | 4 ++-- src/components/controls/miscInfoText.js | 2 +- src/locales/ar/sidebar.json | 1 - src/locales/de/sidebar.json | 1 - src/locales/en/sidebar.json | 2 +- src/locales/es/sidebar.json | 1 - src/locales/fr/sidebar.json | 1 - src/locales/it/sidebar.json | 1 - src/locales/ja/sidebar.json | 1 - src/locales/lt/sidebar.json | 1 - src/locales/pl/sidebar.json | 1 - src/locales/pt/sidebar.json | 1 - src/locales/ru/sidebar.json | 1 - src/locales/tr/sidebar.json | 1 - 14 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/components/controls/controls.tsx b/src/components/controls/controls.tsx index 09c96f207..3071869f1 100644 --- a/src/components/controls/controls.tsx +++ b/src/components/controls/controls.tsx @@ -22,7 +22,7 @@ import ToggleTangle from "./toggle-tangle"; import Language from "./language"; import { ControlsContainer } from "./styles"; import FilterData, {FilterInfo} from "./filter"; -import {TreeInfo, MapInfo, AnimationOptionsInfo, PanelOptionsInfo, +import {TreeInfo, MapInfo, AnimationOptionsInfo, PanelLayoutInfo, ExplodeTreeInfo, EntropyInfo, FrequencyInfo, MeasurementsInfo} from "./miscInfoText"; import { ControlHeader } from "./controlHeader"; import MeasurementsOptions from "./measurementsOptions"; @@ -118,7 +118,7 @@ function Controls() { {canTogglePanelLayout && <> - + } diff --git a/src/components/controls/miscInfoText.js b/src/components/controls/miscInfoText.js index 92a61e591..dbf542db4 100644 --- a/src/components/controls/miscInfoText.js +++ b/src/components/controls/miscInfoText.js @@ -28,7 +28,7 @@ export const AnimationOptionsInfo = ( ); -export const PanelOptionsInfo = ( +export const PanelLayoutInfo = ( <> Control whether to show the tree and the map side-by-side (grid) or expanded (full). diff --git a/src/locales/ar/sidebar.json b/src/locales/ar/sidebar.json index 259b74ef3..782f620c9 100644 --- a/src/locales/ar/sidebar.json +++ b/src/locales/ar/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "سرعة الحركة", "Loop animation": "حركة متكررة", "Animate cumulative history": "تحريك التاريخ التراكمي", - "Panel Options": "خيارات اللوحة", "Tree": "الشجرة", "Map": "الخريطة", "Entropy": "الانتروبيا", diff --git a/src/locales/de/sidebar.json b/src/locales/de/sidebar.json index 4c7775d46..4263998f7 100644 --- a/src/locales/de/sidebar.json +++ b/src/locales/de/sidebar.json @@ -17,7 +17,6 @@ "Animation Speed": "Geschwindigkeit der Animation", "Loop animation": "In einer Schleife animieren", "Animate cumulative history": "Gesamten Verlauf miteinbeziehen", - "Panel Options": "Hauptansicht-Einstellungen", "Tree": "Baum", "Map": "Karte", "Entropy": "Entropie", diff --git a/src/locales/en/sidebar.json b/src/locales/en/sidebar.json index fe78fd56a..e4fe807f3 100644 --- a/src/locales/en/sidebar.json +++ b/src/locales/en/sidebar.json @@ -18,7 +18,7 @@ "Animation Speed": "Animation Speed", "Loop animation": "Loop animation", "Animate cumulative history": "Animate cumulative history", - "Panel Options": "Panel Options", + "Display": "Display", "Tree": "Tree", "Map": "Map", "Entropy": "Entropy", diff --git a/src/locales/es/sidebar.json b/src/locales/es/sidebar.json index 4f749afaa..20374258f 100644 --- a/src/locales/es/sidebar.json +++ b/src/locales/es/sidebar.json @@ -17,7 +17,6 @@ "Animation Speed": "Velocidad de la animación", "Loop animation": "Repitir la animación", "Animate cumulative history": "Animar historial cumulativo", - "Panel Options": "Opciones del panel", "Tree": "Árbol", "Map": "Mapa", "Entropy": "Entropía", diff --git a/src/locales/fr/sidebar.json b/src/locales/fr/sidebar.json index 48b255b4a..fbcaada9f 100644 --- a/src/locales/fr/sidebar.json +++ b/src/locales/fr/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "Vitesse d'animation", "Loop animation": "Animation en boucle", "Animate cumulative history": "Animer l'historique cumulatif", - "Panel Options": "Options du panneau", "Tree": "Arbre", "Map": "Carte", "Entropy": "Entropie", diff --git a/src/locales/it/sidebar.json b/src/locales/it/sidebar.json index fad3fbb5f..a47f6927c 100644 --- a/src/locales/it/sidebar.json +++ b/src/locales/it/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "Velocità di animazioni", "Loop animation": "Animazioni in loop", "Animate cumulative history": "Animare la storia cumulativa", - "Panel Options": "Opzioni di pannello", "Tree": "Albero", "Map": "Mappa", "Entropy": "Entropia", diff --git a/src/locales/ja/sidebar.json b/src/locales/ja/sidebar.json index 9fe5e1293..e8971760d 100644 --- a/src/locales/ja/sidebar.json +++ b/src/locales/ja/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "アニメーション速度", "Loop animation": "アニメーションを繰り返し", "Animate cumulative history": "累積の履歴をアニメーション", - "Panel Options": "パネルのオプション", "Tree": "ツリー", "Map": "地図", "Entropy": "エントロピー", diff --git a/src/locales/lt/sidebar.json b/src/locales/lt/sidebar.json index 0f3c9d3be..a121e919f 100644 --- a/src/locales/lt/sidebar.json +++ b/src/locales/lt/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "Animacijos greitis", "Loop animation": "Kartoti laiko atkarpą", "Animate cumulative history": "Rodyti kauptinę istoriją", - "Panel Options": "Langų parinktys", "Tree": "Medį", "Map": "Žemėlapį", "Entropy": "Entropiją", diff --git a/src/locales/pl/sidebar.json b/src/locales/pl/sidebar.json index 490b8a8d7..340c2428d 100644 --- a/src/locales/pl/sidebar.json +++ b/src/locales/pl/sidebar.json @@ -21,7 +21,6 @@ "Animation Speed": "Szybkość animacji", "Loop animation": "Animacja pętli", "Animate cumulative history": "Animuj historię zbiorczą", - "Panel Options": "Opcje panelu", "Tree": "Drzewo", "Map": "Mapę", "Entropy": "Entropię", diff --git a/src/locales/pt/sidebar.json b/src/locales/pt/sidebar.json index 85a7bd91a..3c0348468 100644 --- a/src/locales/pt/sidebar.json +++ b/src/locales/pt/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "Velocidade de Animação", "Loop animation": "Repetir a animação", "Animate cumulative history": "Animar o histórico acumulado", - "Panel Options": "Painel de Opções", "Tree": "Árvore", "Map": "Mapa", "Entropy": "Entropia", diff --git a/src/locales/ru/sidebar.json b/src/locales/ru/sidebar.json index 7d83d068f..ed95dec2d 100644 --- a/src/locales/ru/sidebar.json +++ b/src/locales/ru/sidebar.json @@ -17,7 +17,6 @@ "Animation Speed": "Скорость Анимации", "Loop animation": "Повтор анимации", "Animate cumulative history": "Анимировать кумулятивную историю", - "Panel Options": "Настройки Панели", "Tree": "Дерево", "Map": "Карту", "Entropy": "Энтропию", diff --git a/src/locales/tr/sidebar.json b/src/locales/tr/sidebar.json index b2e30f9f6..f45c9ecd7 100644 --- a/src/locales/tr/sidebar.json +++ b/src/locales/tr/sidebar.json @@ -18,7 +18,6 @@ "Animation Speed": "Animasyon Hızı", "Loop animation": "Döngülü animasyon", "Animate cumulative history": "Kümülatif tarihçeyi canlandır", - "Panel Options": "Panel Seçenekleri", "Tree": "Ağacı", "Map": "Haritayı", "Entropy": "Entropiyi", From e117e19669aa3b6a6c19a2bb7f99457213c92ffe Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:13:33 -0800 Subject: [PATCH 11/14] Vertically align items in HeaderContainer --- src/components/controls/styles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/controls/styles.js b/src/components/controls/styles.js index 668adba3e..f4bc723b4 100644 --- a/src/components/controls/styles.js +++ b/src/components/controls/styles.js @@ -24,6 +24,7 @@ export const ControlsContainer = styled.div` export const HeaderContainer = styled.div` display: flex; justify-content: space-between; + align-items: center; line-height: 28px; min-height: 28px; /* needed for safari, else the div height is 0 */ margin-top: 15px; From 41b850870c71f30452d94a8161c79bc4fa229349 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:28:02 -0800 Subject: [PATCH 12/14] Fix toggle height (and thus vertical alignment) in panel section header --- src/components/controls/toggle.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/controls/toggle.js b/src/components/controls/toggle.js index 85c68a199..17441e204 100644 --- a/src/components/controls/toggle.js +++ b/src/components/controls/toggle.js @@ -2,6 +2,11 @@ import React from "react"; import styled from 'styled-components'; import { SidebarSubtitle } from "./styles"; +const ToggleContainer = styled.div` + // Same as ToggleBackground, necessary for panel toggles. + height: 21px; +` + const ToggleBackground = styled.label` position: relative; display: inline-block; @@ -72,7 +77,7 @@ const Toggle = ({display, on, callback, label, style={}}) => { if (!display) return null; return ( -
+ @@ -82,7 +87,7 @@ const Toggle = ({display, on, callback, label, style={}}) => { )} -
+ ); }; From beadef7112b42b6daf0dac1b51646ecee5dde1a1 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:59:30 -0700 Subject: [PATCH 13/14] Add ability to show/hide panel options --- src/components/controls/panelChevron.tsx | 25 +++++++++++++ src/components/controls/panelHeader.tsx | 47 +++++++++++++++++++----- src/components/controls/panelSection.tsx | 13 ++++++- src/components/controls/styles.js | 2 +- 4 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 src/components/controls/panelChevron.tsx diff --git a/src/components/controls/panelChevron.tsx b/src/components/controls/panelChevron.tsx new file mode 100644 index 000000000..520a99fce --- /dev/null +++ b/src/components/controls/panelChevron.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import styled from 'styled-components'; +import { FaChevronRight, FaChevronDown } from "react-icons/fa"; + +const Container = styled.span` + padding-right: 6px; + color: ${(props) => props.theme.color}; +` + +type Props = { + show: boolean +} + +/** + * An interactive chevron to show/hide a panel's options. + */ +export const PanelChevron = ({ show }: Props) => { + const icon = show ? : + + return ( + + {icon} + + ) +} diff --git a/src/components/controls/panelHeader.tsx b/src/components/controls/panelHeader.tsx index d156269b8..e5cecfa0d 100644 --- a/src/components/controls/panelHeader.tsx +++ b/src/components/controls/panelHeader.tsx @@ -4,6 +4,7 @@ import { togglePanelDisplay } from "../../actions/panelDisplay"; import { HeaderContainer } from "./styles"; import Toggle from "./toggle"; import { AnnotatedTitle, Title, Tooltip } from "./annotatedTitle"; +import { PanelChevron } from "./panelChevron"; /** Panel identifier used internally. */ export type PanelId = string; @@ -15,28 +16,54 @@ type Props = { /** Indicates panel visibility. */ panelIsVisible: boolean + + /** Indicates whether there are options for the panel. */ + hasOptions: boolean + + /** Indicates options visibility. */ + optionsAreVisible: boolean + + /** Update options visibility. */ + setOptionsAreVisible: React.Dispatch> } /** * A header used by all panel controls, containing an interactive title. */ -export const PanelHeader = ({ panel, title, tooltip, panelIsVisible }: Props) => { +export const PanelHeader = ({ panel, title, tooltip, panelIsVisible, hasOptions, optionsAreVisible, setOptionsAreVisible }: Props) => { const dispatch = useAppDispatch(); function togglePanelVisibility() { dispatch(togglePanelDisplay(panel)) } + function toggleOptionsVisibility() { + setOptionsAreVisible(!optionsAreVisible); + } + return ( - - - + + + {hasOptions && + } + + + event.stopPropagation()}> + + ); }; diff --git a/src/components/controls/panelSection.tsx b/src/components/controls/panelSection.tsx index 7dc6594b8..de22a67a9 100644 --- a/src/components/controls/panelSection.tsx +++ b/src/components/controls/panelSection.tsx @@ -23,6 +23,14 @@ export const PanelSection = ({ panel, title, tooltip, options=undefined }: Props const panelIsVisible = panelsToDisplay.includes(panel) + // Initially, panel visibility determines options visibility. + const [optionsAreVisible, setOptionsAreVisible] = React.useState(panelIsVisible); + + // Subsequent panel visibility updates also determines options visibility. + React.useEffect(() => { + setOptionsAreVisible(panelIsVisible) + }, [panelIsVisible]) + return ( - {panelIsVisible && options} + {optionsAreVisible && options} ); }; diff --git a/src/components/controls/styles.js b/src/components/controls/styles.js index f4bc723b4..30b57b5db 100644 --- a/src/components/controls/styles.js +++ b/src/components/controls/styles.js @@ -49,7 +49,7 @@ export const PanelSectionContainer = styled.div` `; export const TitleAndIconContainer = styled.span` - display: flex; + display: inline-flex; align-items: center; `; From e018f30d2bea1844bf85b28665788fb62264d601 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:27:57 -0800 Subject: [PATCH 14/14] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03f319574..a142c58d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +* Redesigned the panel sections in the sidebar. ([#1704](https://github.com/nextstrain/auspice/pull/1704)) + * Moved panel visibility toggles to the header. + * Added the ability to show/hide panel options. +* customisation: Renamed `sidebarTheme.unselectedBackground` to a more generic name, `sidebarTheme.alternateBackground`, while keeping backwards compatibility. ([#1704](https://github.com/nextstrain/auspice/pull/1704/commits/1ad4376bb3be9787181110d47fe8c5f26a207896)) + ## version 2.50.0 - 2023/10/30