update cached information and add a little paragraph about the boroughs

This commit is contained in:
David 2022-03-19 11:45:05 -04:00
parent 2cd3020151
commit 5b2f60992c
3 changed files with 947 additions and 627 deletions

View File

@ -1,47 +1,133 @@
<html><head> <html>
<meta charset="utf-8"> <head>
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta charset="utf-8" />
<title>Independent Bookstores in New York City - Best Community Bookstores in NYC</title> <meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="google-site-verification" content="hEfog9h0E3JQW91ZUZM5ayPb6DND0WbUa2_W8yTIuVw"> <title>
<link rel="icon" type="image/png" href="/img/favicon.png"> Independent Bookstores in New York City - Best Community Bookstores in NYC
<link rel="apple-touch-icon" href="/img/social.jpg"> </title>
<meta
name="google-site-verification"
content="hEfog9h0E3JQW91ZUZM5ayPb6DND0WbUa2_W8yTIuVw"
/>
<link rel="icon" type="image/png" href="/img/favicon.png" />
<link rel="apple-touch-icon" href="/img/social.jpg" />
<script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/mustache.js"></script> <script type="text/javascript" src="js/mustache.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/2.1.0/jquery.scrollTo.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/2.1.0/jquery.scrollTo.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.js"></script> <script src="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.css" rel="stylesheet"> <link
<link href="https://fonts.googleapis.com/css?family=Acme|Lato" rel="stylesheet"> href="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.css"
<link media="screen" rel="stylesheet" type="text/css" href="css/site.css"> rel="stylesheet"
<meta property="title" name="title" content="Independent Bookstores in New York City - Best Community Bookstores in NYC"> />
<meta property="description" name="description" content="A guide to and map of every independent bookstore in New York City. We have a full list of community bookstores in NYC with locations and descriptions."> <link
<meta name="twitter:card" content="summary"> href="https://fonts.googleapis.com/css?family=Acme|Lato"
<meta name="twitter:site" content="www.nycbookstores.org"> rel="stylesheet"
<meta name="twitter:title" content="NYC Bookstores"> />
<meta name="twitter:description" content="A Guide To The Many Independent Bookstores Of New York City"> <link media="screen" rel="stylesheet" type="text/css" href="css/site.css" />
<meta name="twitter:image" content="https://www.nycbookstores.org/img/social.jpg"> <meta
<meta property="og:url" content="https://www.nycbookstores.org/"> property="title"
<meta property="og:title" content="NYC Bookstores"> name="title"
<meta property="og:description" content="A Guide To The Many Independent Bookstores Of New York City"> content="Independent Bookstores in New York City - Best Community Bookstores in NYC"
<meta property="og:image" content="https://www.nycbookstores.org/img/social.jpg"> />
<meta
property="description"
name="description"
content="A guide to and map of every independent bookstore in New York City. We have a complete list of community bookstores in NYC with locations and descriptions."
/>
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="www.nycbookstores.org" />
<meta name="twitter:title" content="NYC Bookstores" />
<meta
name="twitter:description"
content="A Guide To The Many Independent Bookstores Of New York City"
/>
<meta
name="twitter:image"
content="https://www.nycbookstores.org/img/social.jpg"
/>
<meta property="og:url" content="https://www.nycbookstores.org/" />
<meta property="og:title" content="NYC Bookstores" />
<meta
property="og:description"
content="A Guide To The Many Independent Bookstores Of New York City"
/>
<meta
property="og:image"
content="https://www.nycbookstores.org/img/social.jpg"
/>
</head> </head>
<body> <body>
<div id="wrapper"> <div id="wrapper">
<h1>NYC Bookstores</h1> <h1>NYC Bookstores</h1>
<div> <div>
<ul class="nav"> <ul class="nav">
<li><h2>The Many Independent Bookstores of New York City</h2></li> <li><h2>The Many Independent Bookstores of New York City</h2></li>
<li><a id="viewInfo">info</a></li> <li><a id="viewInfo">info</a></li>
<li><a href="https://git.yetaga.in/alazyreader/nyc-bookstores/" target="_blank">git</a></li> <li>
<li><a href="https://www.twitter.com/alazyreader" target="_blank">@alazyreader</a></li> <a
href="https://git.yetaga.in/alazyreader/nyc-bookstores/"
target="_blank"
>git</a
>
</li>
<li>
<a href="https://www.twitter.com/alazyreader" target="_blank"
>@alazyreader</a
>
</li>
</ul> </ul>
</div> </div>
<div class="container"> <div class="container">
<div id="map"></div> <div id="map"></div>
<div id="info"> <div id="info">
<p>New York City loves its independent bookstores. It <a href="https://www.nytimes.com/2006/10/15/nyregion/thecity/15book.html" target="_blank">eulogizes those that have faded</a> and celebrates when new ventures are launched. And while the historic <a href="https://untappedcities.com/2015/08/26/4th-avenue-the-history-of-nycs-book-row/" target="_blank">Book Row may have passed away in the 80s</a>, there are still many indie bookstores dotting the map. Here, I have attempted to collect all of the currently-open general-interest independent booksellers in NYC. Any store with regular-ish hours (excluding religious booksellers and appointment-only rare book sellers) is included.</p> <p>
<p>The listings here are kept up-to-date to the best of my ability; however, I make no promises about either the accuracy or reliability of the information. If you spot an error, or I&apos;ve missed a shop, please let me know by <a href="mailto:delta.mu.alpha@gmail.com" target="_blank">email</a> or <a href="https://www.twitter.com/alazyreader" target="_blank">twitter</a>. Based on the &quot;<a href="https://github.com/jlord/hack-spots" target="_blank">Hack Spots</a>&quot; website by <a href="https://www.twitter.com/jllord" target="_blank">@jllord</a>.</p> New York City loves its independent bookstores. It
<p>There are currently <span id="storeCount"></span> stores indexed on this page.</p> <a
href="https://www.nytimes.com/2006/10/15/nyregion/thecity/15book.html"
target="_blank"
>eulogizes those that have faded</a
>
and celebrates when new ventures are launched. And while the
historic
<a
href="https://untappedcities.com/2015/08/26/4th-avenue-the-history-of-nycs-book-row/"
target="_blank"
>Book Row may have passed away in the 80s</a
>, there are still many indie bookstores dotting the map, across all
five boroughs. Here, I have attempted to collect all of the
currently-open general-interest independent booksellers in NYC. Any
store with regular-ish hours (excluding religious booksellers and
appointment-only rare book sellers) is included.
</p>
<p>
While Manhattan and Brooklyn still lead the pack, Queens has a
respectable number of stores, and all five boroughs are represented,
with the Bronx and Staten Island both hosting independent stores.
Lower Manhattan has the highest density of booksellers, however.
</p>
<p>
The listings here are kept up-to-date to the best of my ability;
however, I make no promises about either the accuracy or reliability
of the information. If you spot an error, or I&apos;ve missed a
shop, please let me know by
<a href="mailto:delta.mu.alpha@gmail.com" target="_blank">email</a>
or
<a href="https://www.twitter.com/alazyreader" target="_blank"
>twitter</a
>. Orignally based on the &quot;<a
href="https://github.com/jlord/hack-spots"
target="_blank"
>Hack Spots</a
>&quot; website by
<a href="https://www.twitter.com/jllord" target="_blank">@jllord</a>
(although I don&apos;t believe any of the actual underlying code
still survives at this point).
</p>
<p>
There are currently <span id="storeCount">97</span> stores indexed
on this page.
</p>
</div> </div>
<div id="selected"></div> <div id="selected"></div>
</div> </div>
@ -51,7 +137,11 @@
<div class="container"> <div class="container">
<div id="Stores"> <div id="Stores">
<table> <table>
<tbody><tr><th class="tHeader">Name</th><th class="tHeader">Address</th></tr> <tbody>
<tr>
<th class="tHeader">Name</th>
<th class="tHeader">Address</th>
</tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">192 Books</td> <td class="name">192 Books</td>
<td>192 10th Ave, New York</td> <td>192 10th Ave, New York</td>
@ -84,14 +174,6 @@
<td class="name">Avoid The Day Bookstore &amp; Cafe</td> <td class="name">Avoid The Day Bookstore &amp; Cafe</td>
<td>99-04 A Rockaway Beach Blvd, Rockaway Park</td> <td>99-04 A Rockaway Beach Blvd, Rockaway Park</td>
</tr> </tr>
<tr id class="spotRow">
<td class="name">Bankstreet Bookstore</td>
<td>2780 Broadway, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Ben&apos;s Books</td>
<td>145 Ainslie St, Brooklyn</td>
</tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Berl&apos;s Brooklyn Poetry Shop</td> <td class="name">Berl&apos;s Brooklyn Poetry Shop</td>
<td>126A Front St, Brooklyn</td> <td>126A Front St, Brooklyn</td>
@ -108,6 +190,10 @@
<td class="name">Bonnie Slotnick Cookbooks</td> <td class="name">Bonnie Slotnick Cookbooks</td>
<td>28 East 2nd St, New York</td> <td>28 East 2nd St, New York</td>
</tr> </tr>
<tr id class="spotRow">
<td class="name">Book Club Bar</td>
<td>197 E 3rd St, New York</td>
</tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Book Culture</td> <td class="name">Book Culture</td>
<td>536 W 112th St, New York</td> <td>536 W 112th St, New York</td>
@ -142,7 +228,7 @@
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Books Of Wonder</td> <td class="name">Books Of Wonder</td>
<td>18 West 18th St, New York</td> <td>42 West 17th St, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Books Of Wonder (Upper West Side)</td> <td class="name">Books Of Wonder (Upper West Side)</td>
@ -180,6 +266,10 @@
<td class="name">Community Bookstore</td> <td class="name">Community Bookstore</td>
<td>143 7th Ave, Brooklyn</td> <td>143 7th Ave, Brooklyn</td>
</tr> </tr>
<tr id class="spotRow">
<td class="name">Cups and Books</td>
<td>2024 Bedford Ave, Brooklyn</td>
</tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Dashwood Books</td> <td class="name">Dashwood Books</td>
<td>33 Bond St, New York</td> <td>33 Bond St, New York</td>
@ -193,7 +283,9 @@
<td>99 St. Mark&apos;s Place, New York</td> <td>99 St. Mark&apos;s Place, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Every Thing Goes Book Cafe and Neighborhood Stage</td> <td class="name">
Every Thing Goes Book Cafe and Neighborhood Stage
</td>
<td>208 Bay St, Staten Island</td> <td>208 Bay St, Staten Island</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
@ -205,7 +297,9 @@
<td>686 Fulton St, Brooklyn</td> <td>686 Fulton St, Brooklyn</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Greenlight Bookstore (Prospect Lefferts Gardens)</td> <td class="name">
Greenlight Bookstore (Prospect Lefferts Gardens)
</td>
<td>632 Flatbush Ave, Brooklyn</td> <td>632 Flatbush Ave, Brooklyn</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
@ -297,8 +391,8 @@
<td>2 W 14th St, New York</td> <td>2 W 14th St, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Pioneer Books</td> <td class="name">Pillow-Cat Books</td>
<td>159 Pioneer St, Brooklyn</td> <td>328 East 9th St, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Posman Books Chelsea Market</td> <td class="name">Posman Books Chelsea Market</td>
@ -345,7 +439,9 @@
<td>939 Lexington Ave, New York</td> <td>939 Lexington Ave, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Shakespeare &amp; Company (Upper West Side)</td> <td class="name">
Shakespeare &amp; Company (Upper West Side)
</td>
<td>2020 Broadway, New York</td> <td>2020 Broadway, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
@ -364,6 +460,10 @@
<td class="name">Strand Bookstore</td> <td class="name">Strand Bookstore</td>
<td>828 Broadway, New York</td> <td>828 Broadway, New York</td>
</tr> </tr>
<tr id class="spotRow">
<td class="name">Sweet Pickle Books</td>
<td>47 Orchard St, New York</td>
</tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Terrace Books</td> <td class="name">Terrace Books</td>
<td>242 Prospect Park West, Brooklyn</td> <td>242 Prospect Park West, Brooklyn</td>
@ -394,7 +494,7 @@
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Three Lives &amp; Company</td> <td class="name">Three Lives &amp; Company</td>
<td>154 West 10th St, New York</td> <td>238 West 10th St, New York</td>
</tr> </tr>
<tr id class="spotRow"> <tr id class="spotRow">
<td class="name">Topos Bookstore Cafe</td> <td class="name">Topos Bookstore Cafe</td>
@ -432,14 +532,23 @@
<td class="name">Word Up Books</td> <td class="name">Word Up Books</td>
<td>2113 Amsterdam Ave, New York</td> <td>2113 Amsterdam Ave, New York</td>
</tr> </tr>
</tbody></table> <tr id class="spotRow">
<td class="name">Yu and Me Books</td>
<td>44 Mulberry St, New York</td>
</tr>
</tbody>
</table>
</div> </div>
</div> </div>
</div><!-- end wrapper --> </div>
<!-- end wrapper -->
<script id="Table" type="text/html"> <script id="Table" type="text/html">
<table> <table>
<tr><th class="tHeader">Name</th><th class="tHeader">Address</th></tr> <tr>
<th class="tHeader">Name</th>
<th class="tHeader">Address</th>
</tr>
{{#rows}} {{#rows}}
<tr id="{{rowNumber}}" class="spotRow"> <tr id="{{rowNumber}}" class="spotRow">
<td class="name">{{name}}</td> <td class="name">{{name}}</td>
@ -452,65 +561,75 @@
<script id="selectedStore" type="text/html"> <script id="selectedStore" type="text/html">
{{#store}} {{#store}}
<h2>{{name}}</h2> <h2>{{name}}</h2>
<p class="address">{{address}}<p> <p class="address">{{address}}</p>
<p class="address">{{city}},NY {{#postcode}} {{postcode}} {{/postcode}}</p> <p></p>
<p class="address">
{{city}},NY {{#postcode}} {{postcode}} {{/postcode}}
</p>
<p> <p>
<a href="https://maps.google.com/maps?q={{name}} {{address}},{{city}},NY" target="_blank">View in Google Maps</a> <a
href="https://maps.google.com/maps?q={{name}} {{address}},{{city}},NY"
target="_blank"
>View in Google Maps</a
>
</p> </p>
<ul> <ul>
<li> <li>
<span class="store-details">Events:</span> {{events}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="store-details">Events:</span>
{{events}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="store-details">Caf&eacute;:</span> {{cafe}} <span class="store-details">Caf&eacute;:</span> {{cafe}}
</li> </li>
{{#website}} {{#website}}
<li><a href='{{website}}' target="_blank">{{website}}</a></li> <li><a href="{{website}}" target="_blank">{{website}}</a></li>
{{/website}} {{/website}}
</ul> </ul>
{{#description}} {{#description}}
<p class="description">{{description}}</p> <p class="description">{{description}}</p>
{{/description}} {{/description}} {{/store}}
{{/store}}
</script> </script>
<script> <script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYWxhenlyZWFkZXIiLCJhIjoiY2lucDZhb2JxMHp6MHRxa2pvaTFoOWpuZyJ9.DILGYYxxt7A-A_lHHwp6tQ'; mapboxgl.accessToken =
"pk.eyJ1IjoiYWxhenlyZWFkZXIiLCJhIjoiY2lucDZhb2JxMHp6MHRxa2pvaTFoOWpuZyJ9.DILGYYxxt7A-A_lHHwp6tQ";
var map = new mapboxgl.Map({ var map = new mapboxgl.Map({
container: 'map', container: "map",
style: 'mapbox://styles/mapbox/basic-v9', style: "mapbox://styles/mapbox/basic-v9",
center: [-73.957292, 40.729071], // arbitrary center point center: [-73.957292, 40.729071], // arbitrary center point
zoom: 10, zoom: 10,
minZoom: 9, minZoom: 9,
maxZoom: 17, maxZoom: 17,
dragRotate: false dragRotate: false,
}); });
var popup = new mapboxgl.Popup({ var popup = new mapboxgl.Popup({
closeOnClick: false, closeOnClick: false,
closeButton: false closeButton: false,
}); });
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
$.getJSON('./stores.json', function(data) { $.getJSON("./stores.json", function (data) {
data.sort( data.sort(function (a, b) {
function(a, b) {
var aname = a.name.toLowerCase(); var aname = a.name.toLowerCase();
var bname = b.name.toLowerCase(); var bname = b.name.toLowerCase();
return aname === bname ? 0 : +(aname > bname) || -1; return aname === bname ? 0 : +(aname > bname) || -1;
} });
) $.each(data, function (key, value) {
$.each(data, function(key, value) {
value.rowNumber = key; value.rowNumber = key;
value.slug = slugify(value.name); value.slug = slugify(value.name);
}); });
$('#storeCount').html(data.length); $("#storeCount").html(data.length);
window.data = data; window.data = data;
loadMap(data); loadMap(data);
}); });
}); });
window.addEventListener("hashchange", function(e){ window.addEventListener(
updateViewBySlug(e.newURL.split('#')[1]); "hashchange",
}, false); function (e) {
updateViewBySlug(e.newURL.split("#")[1]);
},
false
);
function updateHash(slug) { function updateHash(slug) {
history.pushState(null, null, "#" + slug); history.pushState(null, null, "#" + slug);
@ -519,18 +638,18 @@
function slugify(str) { function slugify(str) {
return str return str
.toLowerCase() .toLowerCase()
.replace(/é/g,'e') .replace(/é/g, "e")
.replace(/&/g,' and ') .replace(/&/g, " and ")
.replace(/ /g,'-') .replace(/ /g, "-")
.replace(/[']+/g,'') .replace(/[']+/g, "")
.replace(/[^\w-]+/g,'-') .replace(/[^\w-]+/g, "-")
.replace(/-+/g,'-') .replace(/-+/g, "-")
.replace(/^-|-$/g,''); .replace(/^-|-$/g, "");
} }
function getStoreBySlug(slug) { function getStoreBySlug(slug) {
var ret = false; var ret = false;
$.each(window.data, function(key, value) { $.each(window.data, function (key, value) {
if (value.slug === slug) { if (value.slug === slug) {
ret = value; ret = value;
return false; return false;
@ -552,32 +671,33 @@
function boundingBox(point) { function boundingBox(point) {
// add some buffer to a point to give the user some leeway // add some buffer to a point to give the user some leeway
return [[point.x - 5, point.y - 5], [point.x + 5, point.y + 5]] return [
[point.x - 5, point.y - 5],
[point.x + 5, point.y + 5],
];
} }
function updateSelectedStore(store, pushState=false) { function updateSelectedStore(store, pushState = false) {
map.flyTo({center: [store.long, store.lat]}); map.flyTo({ center: [store.long, store.lat] });
popup.setLngLat([store.long, store.lat]) popup.setLngLat([store.long, store.lat]).setHTML(store.name).addTo(map);
.setHTML(store.name)
.addTo(map);
$('#info').hide(); $("#info").hide();
var template = $('#selectedStore').html(); var template = $("#selectedStore").html();
var rendered = Mustache.render(template, {store: store}); var rendered = Mustache.render(template, { store: store });
$('#selected').html(rendered); $("#selected").html(rendered);
$('#selected').show(); $("#selected").show();
if (pushState) { if (pushState) {
updateHash(store.slug); updateHash(store.slug);
} }
} }
function showInfo(pushState=true) { function showInfo(pushState = true) {
$('#selected').hide(); $("#selected").hide();
popup.remove(); popup.remove();
$('#info').show(); $("#info").show();
if (pushState) { if (pushState) {
updateHash('info'); updateHash("info");
} }
} }
@ -585,45 +705,49 @@
var geolocate = new mapboxgl.GeolocateControl(); var geolocate = new mapboxgl.GeolocateControl();
var points = []; var points = [];
$.each(data, function(key, value) { $.each(data, function (key, value) {
points.push({ points.push({
"type": "Feature", type: "Feature",
"geometry": { geometry: {
"type": "Point", type: "Point",
"coordinates": [value.long, value.lat] coordinates: [value.long, value.lat],
}, },
"properties": value properties: value,
}); });
}); });
map.on('load', function () { map.on("load", function () {
map.addLayer({ map.addLayer({
"id": "stores", id: "stores",
"type": "circle", type: "circle",
"source": { source: {
"type": "geojson", type: "geojson",
"data": { data: {
"type": "FeatureCollection", type: "FeatureCollection",
"features": points features: points,
}
}, },
"paint": { },
paint: {
"circle-radius": 5, "circle-radius": 5,
"circle-color": "#B9FCFC", "circle-color": "#B9FCFC",
"circle-stroke-width": 2, "circle-stroke-width": 2,
"circle-stroke-color": "#000000" "circle-stroke-color": "#000000",
} },
}) });
map.addControl(new mapboxgl.NavigationControl(), 'top-left'); map.addControl(new mapboxgl.NavigationControl(), "top-left");
map.addControl(geolocate, 'top-right'); map.addControl(geolocate, "top-right");
updateViewBySlug(window.location.hash.split("#")[1]); updateViewBySlug(window.location.hash.split("#")[1]);
}); });
map.on('click', function (e) { map.on("click", function (e) {
if (!map.getLayer('stores')) { return; } if (!map.getLayer("stores")) {
return;
}
popup.remove(); popup.remove();
// Use queryRenderedFeatures to get features at a click event's point // Use queryRenderedFeatures to get features at a click event's point
var features = map.queryRenderedFeatures(boundingBox(e.point), { layers: ['stores'] }); var features = map.queryRenderedFeatures(boundingBox(e.point), {
layers: ["stores"],
});
// fly to the location of the click event // fly to the location of the click event
if (features.length) { if (features.length) {
var store = features[0]; var store = features[0];
@ -633,40 +757,60 @@
}); });
// indicate that the symbols are clickable by changing the cursor style to 'pointer'. // indicate that the symbols are clickable by changing the cursor style to 'pointer'.
map.on('mousemove', function (e) { map.on("mousemove", function (e) {
if (!map.getLayer('stores')) { return; } if (!map.getLayer("stores")) {
var features = map.queryRenderedFeatures(boundingBox(e.point), { layers: ['stores'] }); return;
map.getCanvas().style.cursor = features.length ? 'pointer' : ''; }
var features = map.queryRenderedFeatures(boundingBox(e.point), {
layers: ["stores"],
});
map.getCanvas().style.cursor = features.length ? "pointer" : "";
}); });
geolocate.on('geolocate', function (e) { geolocate.on("geolocate", function (e) {
map.setZoom(14); map.setZoom(14);
popup.setLngLat([e.coords.longitude, e.coords.latitude]) popup
.setHTML('Current Location') .setLngLat([e.coords.longitude, e.coords.latitude])
.setHTML("Current Location")
.addTo(map); .addTo(map);
}); });
var template = $('#Table').html(); var template = $("#Table").html();
var rendered = Mustache.render(template, {rows: data}); var rendered = Mustache.render(template, { rows: data });
$('#Stores').html(rendered); $("#Stores").html(rendered);
$("#Stores tbody tr").not(':first').on("click", function() { $("#Stores tbody tr")
.not(":first")
.on("click", function () {
updateSelectedStore(data[$(this)[0].id], true); updateSelectedStore(data[$(this)[0].id], true);
$(window).scrollTo($("#selected"), 250, {offset: {top: -15}}); $(window).scrollTo($("#selected"), 250, { offset: { top: -15 } });
}); });
$('#viewInfo').on("click", showInfo); $("#viewInfo").on("click", showInfo);
}; }
</script> </script>
<script> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function (i, s, o, g, r, a, m) {
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), i["GoogleAnalyticsObject"] = r;
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) (i[r] =
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); i[r] ||
function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
"script",
"https://www.google-analytics.com/analytics.js",
"ga"
);
ga('create', 'UA-100418882-1', 'auto'); ga("create", "UA-100418882-1", "auto");
ga('send', 'pageview'); ga("send", "pageview");
</script> </script>
</body>
</html>
</body></html>

View File

@ -1,24 +1,25 @@
const cheerio = require('cheerio'); const cheerio = require("cheerio");
const mustache = require('./js/mustache.js'); const mustache = require("./js/mustache.js");
const fs = require('fs'); const fs = require("fs");
const stores = require('./stores.json'); const stores = require("./stores.json");
fs.readFile('./index.html', function (err, data) { fs.readFile("./index.html", function (err, data) {
if (err) { throw err; } if (err) {
throw err;
}
const $ = cheerio.load(data); const $ = cheerio.load(data);
stores.sort( stores.sort(function (a, b) {
function(a, b) {
var aname = a.name.toLowerCase(); var aname = a.name.toLowerCase();
var bname = b.name.toLowerCase(); var bname = b.name.toLowerCase();
return aname === bname ? 0 : +(aname > bname) || -1; return aname === bname ? 0 : +(aname > bname) || -1;
} });
);
$('#Stores').html(mustache.render($('#Table').html(), {rows: stores})); $("#Stores").html(mustache.render($("#Table").html(), { rows: stores }));
$("#storeCount").html(stores.length);
fs.writeFile('./index.html', $.html(), (err) => { fs.writeFile("./index.html", $.html(), (err) => {
if (err) throw err; if (err) throw err;
console.log('Default view updated.'); console.log("Default view updated.");
}); });
}); });

177
package-lock.json generated
View File

@ -1,8 +1,183 @@
{ {
"name": "nyc-bookstores", "name": "nyc-bookstores",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 1, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": {
"": {
"name": "nyc-bookstores",
"version": "1.0.0",
"license": "BSD-3-Clause",
"dependencies": {
"cheerio": "^1.0.0-rc.1"
}
},
"node_modules/@types/node": {
"version": "14.6.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz",
"integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ=="
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"node_modules/cheerio": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
"integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
"dependencies": {
"css-select": "~1.2.0",
"dom-serializer": "~0.1.1",
"entities": "~1.1.1",
"htmlparser2": "^3.9.1",
"lodash": "^4.15.0",
"parse5": "^3.0.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
"dependencies": {
"boolbase": "~1.0.0",
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
}
},
"node_modules/css-what": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
"engines": {
"node": "*"
}
},
"node_modules/dom-serializer": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
"integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
"dependencies": {
"domelementtype": "^1.3.0",
"entities": "^1.1.1"
}
},
"node_modules/domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"node_modules/domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"dependencies": {
"domelementtype": "1"
}
},
"node_modules/domutils": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
"dependencies": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"node_modules/entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"node_modules/htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"dependencies": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"node_modules/nth-check": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
"dependencies": {
"boolbase": "~1.0.0"
}
},
"node_modules/parse5": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
"integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
}
},
"dependencies": { "dependencies": {
"@types/node": { "@types/node": {
"version": "14.6.4", "version": "14.6.4",