Commit 12bbfe77 authored by jrc632's avatar jrc632
Browse files

Expandable Panel with Results Details

parent e57b9b56
Loading
Loading
Loading
Loading
+48 −11
Original line number Diff line number Diff line
@@ -10,12 +10,26 @@ import AppBar from '@mui/material/AppBar';
import Container from '@mui/material/Container';
import GeoTiffViewer from "../../js/geoTiffViewer";
import FootprintResults from "../presentational/FootprintResults.jsx";
import { getFeatures } from "../../js/ApiJsonCollection";

const css = {
  shown: {
    display: "block",
  expanded: {
    height: "100vh",
    display: "flex",
    flexDirection: "row",
    alignItems: "flex-start",
    background: "#f8f9fa"
  },
  stacked: {
    height: "100vh",
    display: "flex",
    flexDirection: "column",
    alignItems: "flex-start",
    background: "#f8f9fa"
  },
  shown: {
    display: "block"
  },
  hidden: {
    display: "none"
  }
@@ -30,13 +44,29 @@ const css = {
 */
export default function App() {
  const [targetPlanet, setTargetPlanet] = React.useState("Mars");
  const [showSortBar, setShowSortBar] = React.useState(true);
  const [sortBarStyle, setSortBarStyle] = React.useState(css.hidden);

  const [showSidePanel, setShowSidePanel] = React.useState(false);
  const [sidePanelVisStyle, setSidePanelVisStyle] = React.useState(css.shown);

  const [expandResults, setExpandResults] = React.useState(true);
  const [resultsExpandStyle, setResultsExpandStyle] = React.useState(css.stacked);

  const geoTiffViewer = new GeoTiffViewer("geoTiff-Container");

  const ShowHideSort = () => {
    setShowSortBar(!showSortBar);
    setSortBarStyle(showSortBar ? css.shown : css.hidden);
  const [footprintData, setFootprintData] = React.useState([]);

  const showHideSort = () => {
    console.log(showSidePanel + " -> ")
    console.log("Show/Hide");
    setShowSidePanel(!showSidePanel);
    setSidePanelVisStyle(showSidePanel ? css.shown : css.hidden);
    console.log(" -> " + showSidePanel);
  }

  const handlePanelLayout = (event) => {
    console.log("Expand/Collapse");
    setExpandResults(expandResults => !expandResults);
    setResultsExpandStyle(expandResults ? css.expanded : css.stacked);
  }

  /**
@@ -47,6 +77,11 @@ export default function App() {
    setTargetPlanet(value);
  };

  const handleFootprintClick = () => {
    setFootprintData(getFeatures);
    console.log(footprintData);
  };

  return (
    <div id="app-container">
      <div id="main-column">
@@ -60,14 +95,16 @@ export default function App() {
        </div>
      </div>
      <div id="right-bar">
        <div id="sort-filter-collapsed" onClick={ShowHideSort} >
        <div id="sort-filter-collapsed" onClick={showHideSort} >
          <ArrowLeftIcon/>
          Sort and Filter
          <ArrowLeftIcon/>
        </div>
          <div style={sortBarStyle}>
            <SearchAndFilterInput target={targetPlanet}/>
            <FootprintResults/>
          <div style={sidePanelVisStyle}>
            <div style={resultsExpandStyle}>
              <SearchAndFilterInput target={targetPlanet} footprintNavClick={handleFootprintClick} />
              <FootprintResults changeLayout={handlePanelLayout}/>
            </div>
          </div>
      </div>

+18 −26
Original line number Diff line number Diff line
import React, { Component } from "react";
import React, { useEffect } from "react";
import AstroMap from "../../js/AstroMap";
import AstroControlManager from "../../js/AstroControlManager";

@@ -8,36 +8,30 @@ import AstroControlManager from "../../js/AstroControlManager";
 * for the map.
 *
 *
 * @class MapContainer
 * @extends {Component}
 * @component MapContainer
 * @param {target, map, mapChange}
 */
export default class MapContainer extends Component {
  /**
   *
   * @param {*} props target - target body name
   */
  constructor(props) {
    super(props);
    this.state = {oldTarget: ""};
  }
export default function MapContainer(props) {
  
  const [oldTarget, setOldTarget] = React.useState("");

  /**
   * Invoked when the component is successfully mounted to the DOM, then
   * handles all of the map intialization and creation.
   */
  componentDidMount() {
    let map = new AstroMap("map-container", this.props.target, {});
  useEffect( () => {
    let map = new AstroMap("map-container", props.target, {});
    let controlManager = new AstroControlManager(map);
    controlManager.addTo(map);
    this.setState({oldTarget: this.props.target})
  }
    setOldTarget(props.target)
  }, []);

  /**
   * Invoked after the component's state has changed when the
   * target selector passes down a new target name from props.
   */
  componentDidUpdate() {
    if (this.props.target != this.state.oldTarget ) {
  useEffect( () => {
    if (props.target != oldTarget ) {
      // remove old map container and append new container to its parent
      let oldContainer = document.getElementById("map-container");
      let parent = oldContainer.parentNode;
@@ -54,16 +48,14 @@ export default class MapContainer extends Component {
      document.getElementById("projectionSouthPole").classList.remove("disabled");

      // create new map with updated target
      let map = new AstroMap("map-container", this.props.target, {});
      let map = new AstroMap("map-container", props.target, {});
      let controlManager = new AstroControlManager(map);
      controlManager.addTo(map);
      this.setState({oldTarget: this.props.target})
    }
      setOldTarget(props.target)
    }
  });

  render() {
  return (
    <div id="map-container" />
  );
}
}
+78 −53
Original line number Diff line number Diff line
import React, {useEffect} from "react";
// CSS
import { alpha } from "@mui/material/styles";
// Lists
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import Checkbox from '@mui/material/Checkbox';

// result action links
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';

// icons
import PreviewIcon from '@mui/icons-material/Preview';
import LaunchIcon from '@mui/icons-material/Launch';
import OpenInFullIcon from '@mui/icons-material/OpenInFull';
import CloseFullscreenIcon from '@mui/icons-material/CloseFullscreen';

// object with results
import { getFeatures } from "../../js/ApiJsonCollection";
import { autocompleteClasses } from "@mui/material";


/**
@@ -16,44 +24,14 @@ let css = {
    backgroundColor: "#f8f9fa",
    overflow: "hidden",
    display: "flex",
    alignItems: "flex-start"
  },
  container: {
    padding: "1rem",
    height: "100vh",
    width: 225,
    display: "flex",
    alignItems: "flex-start",
    flexDirection: "column",
    margin: "auto",
    padding: 0
  },
  textbox: {
    backgroundColor: "#e9ecef",
    "&:focus": {
      borderColor: "#1971c2"
    }
  },
  button: {
    width: "auto",
    color: "#fff",
    backgroundColor: "#1971c2",
    "&:hover": {
      backgroundColor: alpha("#1971c2", 0.7)
    }
  },
  buttonRemove: {
    width: "auto",
    color: "#fff",
    backgroundColor: "#64748B",
    "&:hover": {
      backgroundColor: alpha("#64748B", 0.7)
    }
  },
  title: {
    padding: "0.2rem",
    color: "#343a40",
    fontSize: 18,
    fontWeight: 600
    width: 275, 
    maxHeight: "100vh",
    wordWrap: "break-word",
    flexShrink: 1,
    padding: 0,
    borderLeft: "2px solid lightgray"
  }
};

@@ -78,17 +56,64 @@ export default function FootprintResults(props) {

  return (
    <div style={css.root}>
        <div style={css.container}>
          <div className="panelSection panelHeader">

      <div className="resultHeader">
        <span id="panelSectionTitle">
        Footprint Results
        </span>
        <span className="resultHeaderCheck">
          <Checkbox defaultChecked onChange={props.changeLayout}
            icon={<CloseFullscreenIcon/>} checkedIcon={<OpenInFullIcon/>}
            sx={{
              color: "#64748B",
              '&.Mui-checked': {
                color: "#64748B",
              },
            }}
          />
        </span>
      </div>
          <List>
      <div className="resultsList">
        {features.map((feature) => (
              <div className="panelSection" key={feature.id}>
                <ListItem>{feature.id}</ListItem>
          <div className="resultContainer" key={feature.id}>
            <div className="resultImgDiv">
              <img className="resultImg" src={feature.assets.thumbnail.href}/>
            </div>
            <div className="resultData">
              <div className="resultSub">
                <strong>Collection:</strong>&nbsp;{feature.collection}
              </div>
              <div className="resultSub">
                <strong>ID:</strong>&nbsp;{feature.id}
              </div>
              <div className="resultSub">
                <strong>Date:</strong>&nbsp;{feature.properties.datetime}
              </div>
            </div>
            <div className="resultLinks">
              <Stack direction="row" spacing={1}>
                <Chip
                  label="Metadata"
                  icon={<PreviewIcon/>}
                  size="small"
                  component="a"
                  href="#"
                  variant="outlined"
                  clickable
                />
                <Chip
                  label="STAC Browser"
                  icon={<LaunchIcon/>}
                  size="small"
                  component="a"
                  href="#"
                  variant="outlined"
                  clickable
                />
              </Stack>
            </div>
          </div>
        ))}
          </List>
      </div>
    </div>
  );
+12 −6
Original line number Diff line number Diff line
@@ -35,12 +35,13 @@ let css = {
    backgroundColor: "#f8f9fa",
    overflow: "hidden",
    display: "flex",
    alignItems: "flex-start"
    alignItems: "flex-start",
    flexShrink: 0,
  },
  container: {
    padding: "1rem",
    height: "100vh",
    width: 225,
    maxHeight: "100vh",
    width: 275,
    display: "flex",
    flexDirection: "column",
    margin: "auto",
@@ -100,9 +101,9 @@ export default function SearchAndFilterInput(props) {
  const [dateCheckVal, setDateCheckVal] = React.useState(false);
  const [dateFromVal, setDateFromVal] = React.useState(null);
  const [dateToVal, setDateToVal] = React.useState(null);
  const [maxPages, setMaxPages] = React.useState(0);
  const [maxNumberFootprints, setMaxNumberFootprints] = React.useState(0);
  const [limitVal, setLimitVal] = React.useState(0);
  const [maxPages, setMaxPages] = React.useState(10);
  const [maxNumberFootprints, setMaxNumberFootprints] = React.useState(10);
  const [limitVal, setLimitVal] = React.useState(10);

  // Clear all values
  const handleClear = (event) => {
@@ -168,6 +169,7 @@ export default function SearchAndFilterInput(props) {
    setLimitVal(value);
    setTimeout(() => {
      setMaxPages(getMaxNumberPages);
      props.footprintNavClick();
    }, 1000);
  }

@@ -177,12 +179,16 @@ export default function SearchAndFilterInput(props) {
      setMaxNumberFootprints(getNumberMatched);
      setLimitVal(10);
      setMaxPages(getMaxNumberPages);
      props.footprintNavClick();
    }, 1000);
  }, [props.target]);

  // Pagination
  const handlePageChange = (event, value) => {
    setCurrentPage(value);
    setTimeout(() => {
      props.footprintNavClick();
    }, 1000)
  };


+65 −4
Original line number Diff line number Diff line
@@ -228,21 +228,20 @@ Controls the CSS for projection buttons when there is no available projection
}

.panelSection {
  border-bottom-style: solid;
  border-bottom-width: 1px;
  border-bottom-color: rgba(0, 0, 0, 0.12);
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
  padding: 10px;
}

.panelHeader {
  font-family: sans-serif;
  font-weight: bold;
  padding: 10px;
  display: block;
}

.panelSectionHeader {
  display: inline;
  font-family: sans-serif;
  width: auto;
}

.panelItem {
@@ -268,6 +267,68 @@ Controls the CSS for projection buttons when there is no available projection
  margin-right: -10px;
}

.resultHeader {
  display: inline-flex;
  flex-direction: row;
  justify-content: space-between;
  align-content: baseline;
  font-family: sans-serif;
  font-weight: bold;
  padding: 10px;
  width: 275px;
}

.resultHeaderCheck {
  justify-content: flex-end;
  margin-top: -10px;
  margin-bottom: -10px;
  margin-right: 10px;
}

.resultsList {
  border-top: 1px solid rgba(0, 0, 0, 0.12);
  width: 275px;
  flex-shrink: 1;
  height: auto;
  overflow-y: scroll;
}

.resultContainer {
  display: grid;
  grid-template: "ra rb"
                 "rc rc"
                 / 20% 80%;
  border-bottom: 3px double rgba(0, 0, 0, 0.4);
  padding: 10px;
}

.resultSub {
  font-family: Roboto, Arial, Helvetica, sans-serif;
  font-size: small;
  padding-bottom: 2px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
  margin-bottom: 3px;

  word-wrap: break-word;
}

.resultImgDiv {
  grid-area: ra;
}

.resultData {
  grid-area: rb;
}

.resultLinks {
  grid-area: rc;
}

.resultImg {
  max-width: 32px;
  max-height: 96px;
}

summary {
  cursor: pointer;
  width: auto;