Skip to content

Commit

Permalink
Improve link sharing by using an icon (#175)
Browse files Browse the repository at this point in the history
Solves
#138

Also squashes a small bug in the lots-toggle-{on,off} button.
  • Loading branch information
JamesLowenthal authored Feb 11, 2024
1 parent 1bb5aa9 commit f5dd0c1
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 68 deletions.
2 changes: 0 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,6 @@ <h3>Acknowledgments</h3>
/></a>
</div>

<div class="copied-link-message">The link is copied</div>

<div id="map"></div>
<script type="module">
import setUpSite from "./src/js/setUpSite";
Expand Down
20 changes: 0 additions & 20 deletions src/css/_copied-link.scss

This file was deleted.

1 change: 0 additions & 1 deletion src/css/style.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@use "about";
@use "controls";
@use "copied-link";
@use "donate";
@use "header";
@use "scorecard";
Expand Down
9 changes: 8 additions & 1 deletion src/js/fontAwesome.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ import {
faCircleXmark,
faLink,
faUpRightFromSquare,
faCheck,
} from "@fortawesome/free-solid-svg-icons";
import "@fortawesome/fontawesome-svg-core/styles.css";

const setUpIcons = () => {
library.add(faCircleInfo, faCircleXmark, faLink, faUpRightFromSquare);
library.add(
faCircleInfo,
faCircleXmark,
faLink,
faUpRightFromSquare,
faCheck
);
dom.watch();
};

Expand Down
55 changes: 11 additions & 44 deletions src/js/setUpSite.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* global document, navigator, window */
/* global document, window */
import { Control, Map, Popup, TileLayer, geoJSON } from "leaflet";
import "leaflet/dist/leaflet.css";

import { determineShareUrl, extractCityIdFromUrl } from "./cityId";
import { extractCityIdFromUrl } from "./cityId";
import setUpIcons from "./fontAwesome";
import scoreCardsData from "../../data/score-cards.json";
import setUpAbout from "./about";
import setUpShareUrlClickListener from "./share";

const parkingLots = import("../../data/parking-lots/*"); // eslint-disable-line

Expand Down Expand Up @@ -83,45 +84,6 @@ const createMap = () => {
return map;
};

/**
* Copy `value` to the user's clipboard and show the copied link message.
*
* @param string value
*/
const copyToClipboard = async (value) => {
try {
await navigator.clipboard.writeText(value);
} catch (err) {
// eslint-disable-next-line no-console
console.error("Failed to write to clipboard: ", err);
}

const copiedLinkMessageElement = document.querySelector(
".copied-link-message"
);
copiedLinkMessageElement.style.display = "block";
setTimeout(() => {
copiedLinkMessageElement.style.display = "none";
}, 1000);
};

/**
* Add an event listener for the share button to copy the link to the clipboard.
*
* @param string cityId: e.g. `st.-louis-mo`
*/
const setUpShareUrlClickListener = (cityId) => {
// We put the event listener on `map` because it is never erased, unlike the copy button
// being recreated every time the score card changes. This is called "event delegation".
document.querySelector("#map").addEventListener("click", async (event) => {
const targetElement = event.target.closest("div.url-copy-button > a");
if (targetElement) {
const shareUrl = determineShareUrl(window.location.href, cityId);
await copyToClipboard(shareUrl);
}
});
};

/**
* Generate the HTML for the score card.
*
Expand All @@ -141,7 +103,12 @@ const generateScorecard = (scoreCardEntry) => {
} = scoreCardEntry;
let result = `
<div class="title">${Name}</div>
<div class="url-copy-button"><a href="#"><i class="fa-solid fa-link fa-xl"></i></a></div>
<div class="url-copy-button">
<a href="#" class="share-icon">
<i class="share-link-icon fa-solid fa-link fa-xl" title="Copy link"></i>
<i class="share-check-icon fa-solid fa-check fa-xl" title="Link Copied!" style="display: none"></i>
</a>
</div>
<hr>
<div><span class="details-title">Parking: </span><span class="details-value">${Percentage} of central city</span></div>
<div><span class="details-title">Parking score: </span><span class="details-value">${ParkingScore}</span></div>
Expand Down Expand Up @@ -299,10 +266,10 @@ const setUpParkingLotsLayer = async (map) => {
// If `#lots-toggle` is in the URL, we show buttons to toggle parking lots.
if (window.location.href.indexOf("#lots-toggle") !== -1) {
document.querySelector("#lots-toggle").style.display = "block";
document.querySelector("#lots-toggle-on").addEventListener("click", () => {
document.querySelector("#lots-toggle-off").addEventListener("click", () => {
parkingLayer.removeFrom(map);
});
document.querySelector("#lots-toggle-off").addEventListener("click", () => {
document.querySelector("#lots-toggle-on").addEventListener("click", () => {
parkingLayer.addTo(map);
});
}
Expand Down
51 changes: 51 additions & 0 deletions src/js/share.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* global document, navigator, window */
import { determineShareUrl } from "./cityId";
/**
* Copy `value` to the user's clipboard
*
* @param string value
*/
const copyToClipboard = async (value) => {
try {
await navigator.clipboard.writeText(value);
} catch (err) {
// eslint-disable-next-line no-console
console.error("Failed to write to clipboard: ", err);
}
};

/**
* Toggle share link icon briefly to show user an indicator
*
* @param {HTMLAnchorElement} shareIcon
*/
const switchIcons = (shareIcon) => {
const linkIcon = shareIcon.querySelector("svg.share-link-icon");
const checkIcon = shareIcon.querySelector("svg.share-check-icon");
linkIcon.style.display = "none";
checkIcon.style.display = "inline-block";
setTimeout(() => {
linkIcon.style.display = "inline-block";
checkIcon.style.display = "none";
}, 1000);
};

/**
* Add an event listener for the share button to copy the link to the clipboard.
*
* @param string cityId: e.g. `st.-louis-mo`
*/
const setUpShareUrlClickListener = (cityId) => {
// We put the event listener on `map` because it is never erased, unlike the copy button
// being recreated every time the score card changes. This is called "event delegation".
document.querySelector("#map").addEventListener("click", async (event) => {
const targetElement = event.target.closest("div.url-copy-button > a");
if (targetElement) {
const shareUrl = determineShareUrl(window.location.href, cityId);
await copyToClipboard(shareUrl);
switchIcons(targetElement);
}
});
};

export default setUpShareUrlClickListener;

0 comments on commit f5dd0c1

Please sign in to comment.