JSFiddle - React, Tailwind, and code Playground
by angchen
HTML
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<link
href="https://fonts.googleapis.com/css?family=Roboto"
rel="stylesheet"
/>
<link href="https://fonts.googleapis.com/css2?family=Material+Icons+Outlined" rel="stylesheet">
</head>
<body>
<div class="commutes">
<div class="commutes-map">
<div id="map"></div>
</div>
<div class="commutes-info">
<div class="commutes-initial-state">
<svg width="53" height="53" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M41 20H18.6c-9.5 0-10.8 13.5 0 13.5h14.5C41 33.5 41 45 33 45H17.7" stroke="#D2E3FC" stroke-width="5"></path>
<path d="M41 22c.2 0 .4 0 .6-.2l.4-.5c.3-1 .7-1.7 1.1-2.5l2-3c.8-1 1.5-2 2-3 .6-1 .9-2.3.9-3.8 0-2-.7-3.6-2-5-1.4-1.3-3-2-5-2s-3.6.7-5 2c-1.3 1.4-2 3-2 5 0 1.4.3 2.6.8 3.6s1.2 2 2 3.2c.9 1 1.6 2 2 2.8.5.9 1 1.7 1.2 2.7l.4.5.6.2Zm0-10.5c-.7 0-1.3-.2-1.8-.7-.5-.5-.7-1.1-.7-1.8s.2-1.3.7-1.8c.5-.5 1.1-.7 1.8-.7s1.3.2 1.8.7c.5.5.7 1.1.7 1.8s-.2 1.3-.7 1.8c-.5.5-1.1.7-1.8.7Z" fill="#185ABC"></path>
<path d="m12 32-8 6v12h5v-7h6v7h5V38l-8-6Z" fill="#4285F4"></path>
</svg>
<div class="commutes-initial-state-description">
<h2 class="heading">Add a destination</h2>
<p>See travel time and directions for places nearby</p>
</div>
<button class="commutes-add-button">
<span class="material-icons-outlined">add</span>
<span class="label">Add destination</span>
</button>
</div>
<div class="commutes-destination-list">
<div class="commutes-destination">
</div>
<div class="commutes-list-controls">
<div class="left-control hide material-icons-outlined" data-direction="-1">
chevron_left
</div>
<div...
CSS
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.hide {
display: none;
}
.commutes {
height: 100%;
min-width: 360px !important;
max-width: 100% !important;
font-family: Arial, sans-serif;
resize: both;
display: flex;
justify-content: center;
flex-direction: column;
flex-wrap: wrap;
align-content: stretch;
}
.commutes-info {
box-sizing: border-box;
border-top: none;
overflow: hidden;
border-radius: 0 0 8px 8px;
position: relative;
max-width: 100%;
flex: 0 0 110px;
}
.commutes-initial-state {
display: none;
border: 1px solid #dadce0;
border-radius: 8px;
justify-content: space-between;
padding: 16px;
box-sizing: border-box;
height: 98px;
margin-top: 8px;
}
.commutes-initial-state svg {
flex: 0 0 53px;
margin-right: 16px;
align-self: center;
}
.commutes-initial-state-description {
align-self: center;
flex-grow: 1;
margin-right: 16px;
}
.commutes-initial-state-description h2 {
margin: 0;
color: #202124;
font: 22px/28px Arial, sans-serif;
}
.commutes-initial-state-description p {
margin: 0;
color: #5f6368;
font: 13px/20px Arial, sans-serif;
}
.commutes-destination-list {
display: flex;
border: 1px solid #dadce0;
border-radius: 8px;
box-sizing: border-box;
height: 98px;
margin-top: 8px;
}
.commutes-destination-list .commutes-list-controls {
display: flex;
position: absolute;
top: 50%;
margin-top: -20px;
padding: 8px;
border-radius: 40px;
background-color: #fff;
z-index: 100;
box-shadow: 0 2px 3px 0 rgb(60 64 67 / 30%), 0 6px 10px 4px rgb(60 64 67 / 15%);
cursor: pointer;
}
.commutes-destination-list .right-control {
right: 16px;
}
.commutes-destination-list:hover .commutes-list-controls {
display: block;
}
.commutes button {
align-self: center;
cursor: pointer;
border-radius: 4px;
}
.commutes-initial-state .commutes-add-button {
background-color: #4285f4;
color: #fff;
border-color: #fff;
...
JavaScript
let map;
/** Hides a DOM element and optionally focuses on focusEl. */
function hideElement(el, focusEl) {
el.style.display = 'none';
if (focusEl) focusEl.focus();
}
/** Shows a DOM element that has been hidden and optionally focuses on focusEl. */
function showElement(el, focusEl) {
el.style.display = 'block';
if (focusEl) focusEl.focus();
}
/** Determines if a DOM element contains content that cannot be scrolled into view. */
function hasHiddenContent(el) {
const noscroll = window.getComputedStyle(el).overflowY.includes('hidden');
return noscroll && el.scrollHeight > el.clientHeight;
}
function updateMapView(destination) {
if (!destination && !destination.geometry && !destination.geometry.location) return;
/* map = new google.maps.LatLng(destination.geometry.location.toJSON()) */
const location = destination.geometry.location.toJSON();
let myLatlng = new google.maps.LatLng(location);
map.setCenter(location);
new google.maps.Marker({
position: myLatlng,
map,
title: destination.name,
});
}
function initMap() {
initializeCommutesPanel();
map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: -34.397,
lng: 150.644
},
zoom: 8,
});
}
function initializeCommutesPanel() {
const widgetEl = document.querySelector('.commutes');
const addCommutesButtonEl = widgetEl.querySelector('.commutes-add-button');
const commutesModal = widgetEl.querySelector('.commutes-modal-container');
const cancelButton = commutesModal.querySelector('.cancel-button');
const input = document.getElementById("destination-address-input");
const autocomplete = new google.maps.places.Autocomplete(input);
const addButton = commutesModal.querySelector('.primary-button');
addCommutesButtonEl.addEventListener('click', () => {
showElement(commutesModal);
});
let destinationToAdd;
let destinations;
addButton.addEventListener('click', () => {
const destinationAddress =...