JSFiddle - React, Tailwind, and code Playground

by bgoonz

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Locator</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script src="https://www.gstatic.com/external_hosted/handlebars/v4.7.6/handlebars.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
    <script>
      const CONFIGURATION = {"capabilities":{"input":true,"autocomplete":true,"directions":true,"distanceMatrix":true,"details":true},"locations":[{"title":"327 Howard Ave","address1":"327 Howard Ave","address2":"Fair Lawn, NJ 07410, USA","coords":{"lat":40.94351876391365,"lng":-74.11912371739514},"placeId":"ChIJnxmzX2P7wokRTJrcCg7Qrbg"}],"mapOptions":{},"mapsApiKey":"AIzaSyBVYIr57O3fkBCZRco4n-Zhtp3eR9sQovk"};

      function initMap() {
        new LocatorPlus(CONFIGURATION);
      }
    </script>
    <script id="locator-result-items-tmpl" type="text/x-handlebars-template">
      {{#each locations}}
        <li class="location-result" data-location-index="{{index}}">
          <button class="select-location">
            <h2 class="name">{{title}}</h2>
          </button>
          <div class="address">{{address1}}<br>{{address2}}</div>
          <button class="details-button">
            View details
          </button>
          {{#if travelDistanceText}}
            <div class="distance">{{travelDistanceText}}</div>
          {{/if}}
          {{#if ../showDirectionsButton}}
            <button class="show-directions" title="Show directions to this location">
              <svg width="34" height="34" viewBox="0 0 34 34"
                   fill="none" xmlns="http://www.w3.org/2000/svg" alt="Show directions">
                <path d="M17.5867 9.24375L17.9403 8.8902V8.8902L17.5867 9.24375ZM16.4117 9.24375L16.7653 9.59731L16.7675 9.59502L16.4117 9.24375ZM8.91172 16.7437L8.55817 16.3902L8.91172 16.7437ZM8.91172 17.9229L8.55817 18.2765L8.55826...

CSS

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#map-container {
  width: 100%;
  height: 100%;
  position: relative;
  font-family: "Roboto", sans-serif;
  box-sizing: border-box;
}

#map-container button {
  background: none;
  color: inherit;
  border: none;
  padding: 0;
  font: inherit;
  font-size: inherit;
  cursor: pointer;
}

#map {
  position: absolute;
  left: 22em;
  top: 0;
  right: 0;
  bottom: 0;
}

#locations-panel {
  position: absolute;
  left: 0;
  width: 22em;
  top: 0;
  bottom: 0;
  overflow-y: auto;
  background: white;
  padding: 0.5em;
  box-sizing: border-box;
}

@media only screen and (max-width: 876px) {
  #map {
    left: 0;
    bottom: 50%;
  }

  #locations-panel {
    top: 50%;
    right: 0;
    width: unset;
  }
}

#locations-panel-list > header {
  padding: 1.4em 1.4em 0 1.4em;
}

#locations-panel-list h1.search-title {
  font-size: 1em;
  font-weight: 500;
  margin: 0;
}

#locations-panel-list h1.search-title > img {
  vertical-align: bottom;
  margin-top: -1em;
}

#locations-panel-list .search-input {
  width: 100%;
  margin-top: 0.8em;
  position: relative;
}

#locations-panel-list .search-input input {
  width: 100%;
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 0.3em;
  height: 2.2em;
  box-sizing: border-box;
  padding: 0 2.5em 0 1em;
  font-size: 1em;
}

#locations-panel-list .search-input-overlay {
  position: absolute;
}

#locations-panel-list .search-input-overlay.search {
  right: 2px;
  top: 2px;
  bottom: 2px;
  width: 2.4em;
}

#locations-panel-list .search-input-overlay.search button {
  width: 100%;
  height: 100%;
  border-radius: 0.2em;
  color: black;
  background: transparent;
}

#locations-panel-list .search-input-overlay.search .icon {
  margin-top: 0.05em;
  vertical-align: top;
}

#locations-panel-list .section-name {
  font-weight: 500;
  font-size: 0.9em;
  margin: 1.8em 0 1em 1.5em;
}

#locations-panel-list .location-result {
  position: relative;
  padding: 0.8em 3.5em 0.8em...

JavaScript

'use strict';

/** Hide a DOM element. */
function hideElement(el) {
  el.style.display = 'none';
}

/** Show a DOM element that has been hidden. */
function showElement(el) {
  el.style.display = 'block';
}

/**
 * Defines an instance of the Locator+ solution, to be instantiated
 * when the Maps library is loaded.
 */
function LocatorPlus(configuration) {
  const locator = this;

  locator.locations = configuration.locations || [];
  locator.capabilities = configuration.capabilities || {};

  const mapEl = document.getElementById('map');
  locator.panelListEl = document.getElementById('locations-panel-list');
  const sectionNameEl =
      document.getElementById('location-results-section-name');
  const resultsContainerEl = document.getElementById('location-results-list');

  const itemsTemplate = Handlebars.compile(
      document.getElementById('locator-result-items-tmpl').innerHTML);

  locator.searchLocation = null;
  locator.searchLocationMarker = null;
  locator.selectedLocationIdx = null;
  locator.userCountry = null;

  // Initialize the map -------------------------------------------------------
  const mapOptions = configuration.mapOptions;
  locator.map = new google.maps.Map(mapEl, {
    fullscreenControl: mapOptions.fullscreenControl,
    zoomControl: mapOptions.zoomControl,
    streetViewControl: mapOptions.streetViewControl,
    mapTypeControl: mapOptions.mapTypeControl,
    mapTypeControlOptions: {
      position: google.maps.ControlPosition.TOP_RIGHT,
    },
  });

  // Store selection.
  const selectResultItem = function(locationIdx, panToMarker) {
    locator.selectedLocationIdx = locationIdx;
    for (let locationElem of resultsContainerEl.children) {
      locationElem.classList.remove('selected');
      if (getResultIndex(locationElem) === locator.selectedLocationIdx) {
        locationElem.classList.add('selected');
      }
    }
    if (panToMarker && (locationIdx != null)) {
      locator.map.panTo(locator.locations[locationIdx].coords);
...