museums/templates/pages/{id}.html
<!DOCTYPE html>
<html>
{% set rows = sql("select * from museums where id = :id", {"id": id}) %}
{% if not rows %}
{{ raise_404("Museum not found") }}
{% endif %}
{% set photos = sql("""
with urls as (select
json_extract(j.value, '$.url') as url
from
museums,
json_each(photos) j
where
museums.id = :id)
select url, width, height from photos where url in (select url from urls)
""", {"id": id}) %}
<head>
<meta charset="utf-8">
{% set museum = rows[0] %}
{% set retina = 1 %}
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ museum.name }}</title>
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@nichemuseums">
<meta name="twitter:creator" content="@simonw">
<meta name="twitter:title" content="{{ museum.name }}">
<meta name="twitter:description" content="{{ museum.description }}">
<meta name="twitter:image" content="{{ museum.photo_url }}?w=1600&h=800&fit=crop&auto=compress">
<meta name="twitter:image:alt" content="{{ museum.photo_alt }}">
<meta property="og:url" content="https://www.niche-museums.com/{{ museum.id }}">
<meta property="og:type" content="article">
<meta property="og:title" content="{{ museum.name }}">
<meta property="og:description" content="{{ museum.description }}">
<meta property="og:image" content="{{ museum.photo_url }}?w=1600&h=800&fit=crop&auto=compress">
<meta property="og:image:alt" content="{{ museum.photo_alt }}">
<meta property="og:image:width" content="800">
<meta property="og:image:height" content="400">
{% include "_analytics.html" %}
<link rel="stylesheet" href="/static/museums.css">
<link rel="stylesheet" href="/static/photoswipe.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="anonymous">
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" crossorigin="anonymous"></script>
<script src="/static/lazysizes.min.js" async></script>
<script type="module">
import PhotoSwipeLightbox from '/static/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#photos',
children: '.gallery-photo',
pswpModule: '/static/photoswipe.esm.js'
});
lightbox.init();
</script>
</head>
<body>
<nav class="navbar is-black" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<strong>Niche Museums</strong>
</a>
<a class="navbar-item" href="/about">
<span class="button is-small is-outlined is-white">About</span>
</a>
</div>
</nav>
<section class="section" id="cards">
{% include "_museum_card.html" %}
</section>
{% if museum.press %}
<section class="section articles" id="press">
<div class="box content">
{% for article in json.loads(museum.press) %}
<h3 class="title is-5"><a href="{{ article.url }}">{{ article.title }}</a></h2>
<p>{{ article.author }}, {{ article.publication }}, {{ nicer_date(article.date) }}</p>
{% endfor %}
</div>
</section>
{% endif %}
{% if museum.photos %}
<section class="section photos" id="photos">
<div class="masonry">
{% for photo in photos %}
<a data-pswp-height="{{ photo.height }}" data-pswp-width="{{ photo.width }}" href="{{ photo.url }}?w=1200&auto=compress" class="gallery-photo"><img class="lazyload" src="{{ photo.url }}?w=400&blur=200&px=16&auto=format" data-src="{{ photo.url }}?w=400&auto=compress"{% if photo.alt %} alt="{{ photo.alt }}"{% endif %}></a>
{% endfor %}
</div>
</section>
{% endif %}
<section class="section map-section">
<div id="themap"></div>
</section>
<section class="section nearby-section">
{% for museum in sql("""
select *, haversine(latitude, longitude, :latitude, :longitude, 'mi') as distance_mi
from museums
where id != :id
and permanently_closed is null order by distance_mi limit 3
""", {
"latitude": museum.latitude,
"longitude": museum.longitude,
"id": museum.id
}) %}
<div class="card box">
<div class="content">
{% if museum.photo_url %}
<a href="/{{ museum.id }}"><img width="200" height="100" class="is-pulled-right" src="{{ museum.photo_url }}?w=400&h=200&fit=crop&auto=compress" alt="{{ museum.photo_alt }}"></a>
{% endif %}
<h2><a href="/{{ museum.id }}">{{ museum.name }}</a></h2>
<p class="distance-away">{{ museum.distance_mi|round(2) }} miles away</p>
</div>
</div>
{% endfor %}
</section>
<script>
const latitude = {{ museum.latitude }};
const longitude = {{ museum.longitude }};
document.addEventListener('DOMContentLoaded', () => {
let el = document.querySelector('#themap');
el.className = 'box';
el.style.width = '100%';
el.style.height = '500px';
let latlng = L.latLng(latitude, longitude);
let map = L.map(el, {
center: latlng,
zoom: {{ museum.map_zoom or "16" }}
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
}).addTo(map);
L.marker(latlng).addTo(map);
});
</script>
</body>
</html>