diff --git a/index.html b/index.html index 3908f05f7..1be3025f4 100644 --- a/index.html +++ b/index.html @@ -14,6 +14,10 @@ })(window, document, "script", "dataLayer", "GTM-KB579ZN7"); + + Timelapse Feature Explorer diff --git a/src/Viewer.tsx b/src/Viewer.tsx index a18f0601c..742014100 100644 --- a/src/Viewer.tsx +++ b/src/Viewer.tsx @@ -34,7 +34,7 @@ import { useConstructor, useDebounce, useRecentCollections } from "./colorizer/u import * as urlUtils from "./colorizer/utils/url_utils"; import { SCATTERPLOT_TIME_FEATURE } from "./components/Tabs/scatter_plot_data_utils"; import { DEFAULT_PLAYBACK_FPS } from "./constants"; -import { FlexRowAlignCenter } from "./styles/utils"; +import { FlexRow, FlexRowAlignCenter } from "./styles/utils"; import { LocationState } from "./types"; import Collection from "./colorizer/Collection"; @@ -51,6 +51,7 @@ import ColorRampDropdown from "./components/Dropdowns/ColorRampDropdown"; import HelpDropdown from "./components/Dropdowns/HelpDropdown"; import SelectionDropdown from "./components/Dropdowns/SelectionDropdown"; import Export from "./components/Export"; +import GlossaryPanel from "./components/GlossaryPanel"; import Header from "./components/Header"; import HoverTooltip from "./components/HoverTooltip"; import IconButton from "./components/IconButton"; @@ -834,19 +835,37 @@ function Viewer(): ReactElement { items={collection?.getDatasetKeys() || []} onChange={handleDatasetChange} /> - { - if (value !== featureKey && dataset) { - replaceFeature(dataset, value); - resetColorRampRangeToDefaults(dataset, value); - reportFeatureSelected(dataset, value); - } - }} - /> + + + // + // {featureKey && dataset?.getFeatureNameWithUnits(featureKey)} + // + // + // {dataset?.getFeatureData(featureKey)?.description} + // + // + // ) : ( + // dataset?.getFeatureNameWithUnits(featureKey) + // ) + selected={featureKey} + items={getFeatureDropdownData()} + onChange={(value) => { + if (value !== featureKey && dataset) { + replaceFeature(dataset, value); + resetColorRampRangeToDefaults(dataset, value); + reportFeatureSelected(dataset, value); + } + }} + /> + + ({ modalContain /** Applies theme as CSS variables that affect the rest of the document. */ const CssContainer = styled.div` - @import url("https://fonts.googleapis.com/css2?family=Lato&display=swap"); - @font-face { font-family: LatoExtended; font-style: normal; diff --git a/src/components/GlossaryPanel.tsx b/src/components/GlossaryPanel.tsx new file mode 100644 index 000000000..e55d1d24b --- /dev/null +++ b/src/components/GlossaryPanel.tsx @@ -0,0 +1,113 @@ +import { ReadOutlined } from "@ant-design/icons"; +import { Divider, Drawer, Radio, RadioChangeEvent, Tooltip } from "antd"; +import React, { ReactElement, useContext, useMemo, useState } from "react"; +import styled from "styled-components"; + +import { Dataset } from "../colorizer"; +import { FlexColumn, FlexRowAlignCenter } from "../styles/utils"; + +import { AppThemeContext } from "./AppStyle"; +import IconButton from "./IconButton"; + +type GlossaryPanelProps = { + dataset: Dataset | null; +}; + +const StyledDrawer = styled(Drawer)` + .ant-drawer-body { + padding-top: 16px; + } + + .ant-drawer-header-title { + // Move the close button to the right corner of the header + display: flex; + flex-direction: row-reverse; + } + + p { + margin: 0; + } +`; + +export default function GlossaryPanel(props: GlossaryPanelProps): ReactElement { + const [showPanel, setShowPanel] = useState(false); + const [alphabetizeFeatures, setAlphabetizeFeatures] = useState(false); + + const theme = useContext(AppThemeContext); + + const drawerContent = useMemo(() => { + const dataset = props.dataset; + if (dataset === null) { + return null; + } + const allFeatureData = dataset.featureKeys.map((featureKey) => dataset.getFeatureData(featureKey)!); + if (alphabetizeFeatures) { + allFeatureData.sort((a, b) => a.name.localeCompare(b.name)); + } + + return ( + + {allFeatureData.map((featureData) => { + const hasDescription = featureData.description && featureData.description !== ""; + const key = featureData.key; + return ( +

+ + {dataset.getFeatureNameWithUnits(key)} + +
+ {featureData.description} +

+ ); + })} +
+ ); + }, [props.dataset, alphabetizeFeatures]); + + return ( + <> + + { + setShowPanel(true); + }} + disabled={!props.dataset} + > + + + + { + setShowPanel(false); + }} + title={Feature glossary} + open={showPanel} + size="large" + style={{ color: theme.color.text.primary }} + > + + +

+ Sort by +

+ setAlphabetizeFeatures(e.target.value)} + > + Feature order + Alphabetical + +
+ + {drawerContent} +
+
+ + ); +} diff --git a/src/routes/LandingPage.tsx b/src/routes/LandingPage.tsx index d464a7d8e..52678a12d 100644 --- a/src/routes/LandingPage.tsx +++ b/src/routes/LandingPage.tsx @@ -1,5 +1,3 @@ -import { faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button, Divider, Tooltip } from "antd"; import React, { lazy, ReactElement, Suspense } from "react"; import { Link, useNavigate } from "react-router-dom"; @@ -7,7 +5,7 @@ import styled from "styled-components"; import { Dataset } from "../colorizer"; import { paramsToUrlQueryString } from "../colorizer/utils/url_utils"; -import { FlexColumn, FlexColumnAlignCenter, FlexRowAlignCenter, VisuallyHidden } from "../styles/utils"; +import { ExternalLink, FlexColumn, FlexColumnAlignCenter, FlexRowAlignCenter, VisuallyHidden } from "../styles/utils"; import { DatasetEntry, LocationState, ProjectEntry } from "../types"; import { PageRoutes } from "./index"; @@ -92,7 +90,7 @@ const FeatureHighlightsItem = styled(FlexColumn)` grid-row: span 2; & > h3 { - font-weight: 600; + font-weight: bold; } `; @@ -127,7 +125,7 @@ const ProjectCard = styled.li` gap: 0px; & h3 { - font-weight: 600; + font-weight: bold; } & p, @@ -188,7 +186,7 @@ const InReviewFlag = styled(FlexRowAlignCenter)` & > p { color: var(--color-flag-text); font-size: 10px; - font-weight: 700; + font-weight: bold; white-space: nowrap; } `; @@ -253,12 +251,7 @@ export default function LandingPage(): ReactElement { const publicationElement = project.publicationLink ? (

Related publication:{" "} - - {project.publicationName} - {/* Icon offset slightly to align with text */} - - (opens in new tab) - + {project.publicationName}

) : null; diff --git a/src/styles/utils.tsx b/src/styles/utils.tsx index 6249e280e..114dd65ab 100644 --- a/src/styles/utils.tsx +++ b/src/styles/utils.tsx @@ -82,6 +82,7 @@ export function ExternalLink(props: { href: string; children: React.ReactNode }) {props.children} + (opens in new tab) ); }