1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Twin towns of the world</title>
<link rel="stylesheet" href="/static/style.css">
<!-- Applied before the first paint, and therefore inline and in <head>:
map.js is loaded at the end of <body>, so setting the theme there would
show a frame of the wrong one. A saved "light" would flash dark first,
which is exactly the flicker the preference exists to avoid.
No stored choice leaves color-scheme alone, i.e. following the OS. -->
<script>
(function () {
try {
var t = (JSON.parse(localStorage.getItem("twin-towns.view.v1")) || {}).theme;
if (t === "light" || t === "dark") document.documentElement.style.colorScheme = t;
} catch (e) { /* storage disabled or corrupt: the OS setting is a fine answer */ }
})();
</script>
</head>
<body>
<div class="layout">
<div id="mapwrap"><svg id="map"></svg></div>
<aside>
<div class="head">
<h1>Twin towns of the world</h1>
<!-- Revealed by map.js; see #theme in style.css for why it starts
hidden. The label and title are set from the current state. -->
<button type="button" id="theme" hidden></button>
</div>
<div class="sub">Sister cities, from Wikidata P190</div>
<div class="search">
<input type="search" id="q" placeholder="Search a town…"
autocomplete="off" spellcheck="false" aria-label="search for a town">
<ul id="results" hidden></ul>
</div>
<div class="timeline">
<label>Twinned <span id="yearlabel">…</span></label>
<div id="hist"></div>
<!-- Two overlaid range inputs make the dual-handle slider: there is no
native two-handle control, and this keeps both handles keyboard
reachable. min/max/value are set from the data by buildHistogram,
so no stale bound flashes before it loads. -->
<div class="dual">
<div id="yearfill"></div>
<input type="range" id="yearfrom" aria-label="earliest year">
<input type="range" id="yearto" aria-label="latest year">
</div>
<div class="axis"><span id="axismin"></span><span id="axismax"></span></div>
<div id="histmeta" class="meta"></div>
<label class="chk"><input type="checkbox" id="undated" checked> show undated</label>
</div>
<div id="info">
<p class="hint">Loading…</p>
</div>
<footer>
{{ .Plottable }} places mapped ({{ .Places }} total) ·
{{ .Pairs }} twinnings, {{ .Dated }} dated{{ if .Ended }},
{{ .Ended }} dissolved{{ end }}<br>
{{ if .FirstYear }}Dated {{ .FirstYear }}–{{ .LastYear }}<br>{{ end }}
{{ with .IngestedAt }}Data fetched {{ . }}<br>{{ end }}
Source: <a href="https://www.wikidata.org/wiki/Property:P190">Wikidata P190</a>,
CC0. <kbd>Esc</kbd> clears.
</footer>
</aside>
</div>
<script src="/static/map.js"></script>
</body>
</html>
|