Replace em-dashes in user-facing copy across the server-rendered pages, static frontend views, and the strings the app injects at runtime, using colons, commas, parentheses or full stops as the context wants. Data placeholder glyphs (a lone "—" for a missing reading) are left alone, since a hyphen there reads as a minus sign in temperature columns. Also tighten the high-visibility surfaces (home hero and meta, about, privacy, city and records ledes, glossary blurbs) toward a plainer, more direct voice while keeping every factual claim intact. Claude-Session: https://claude.ai/code/session_01XXxmNFy9cZ6Gh8Y9thZn62
89 lines
3.3 KiB
Django/Jinja
89 lines
3.3 KiB
Django/Jinja
{% extends "base.html.j2" %}
|
||
{% block title %}{{ page_title }}{% endblock %}
|
||
{% block description %}{{ page_description }}{% endblock %}
|
||
{% block canonical_path %}{{ canonical_path }}{% endblock %}
|
||
{% block content %}
|
||
<nav class="breadcrumb" aria-label="Breadcrumb">
|
||
{% for label, href in breadcrumb %}{% if href %}<a href="{{ href }}">{{ label }}</a>{% else %}<span>{{ label }}</span>{% endif %}{% if not loop.last %} <span class="sep">›</span> {% endif %}{% endfor %}
|
||
</nav>
|
||
<article class="climate-page">
|
||
<h1>City climates</h1>
|
||
<p class="lede">Average temperatures by month, all-time records, and how today compares, for
|
||
{{ n_cities }} cities across {{ n_countries }} countries. Every day is graded against that
|
||
location's own ~45 years of climate history.</p>
|
||
|
||
<div class="hub-search">
|
||
<input type="search" id="hub-q" placeholder="Search a city or country…" autocomplete="off"
|
||
aria-label="Search cities" />
|
||
</div>
|
||
<ul class="hub-results" id="hub-results" hidden></ul>
|
||
|
||
<div id="hub-directory">
|
||
{% for country, cs in groups.items() %}
|
||
<details class="hub-country">
|
||
<summary>{{ country }} <span class="hub-count">{{ cs | length }}</span></summary>
|
||
<ul class="city-links">
|
||
{% for c in cs %}<li><a href="{{ base }}/climate/{{ c.slug }}">{{ c.name }}</a></li>{% endfor %}
|
||
</ul>
|
||
</details>
|
||
{% endfor %}
|
||
</div>
|
||
</article>
|
||
|
||
{% raw %}
|
||
<script>
|
||
(function () {
|
||
var q = document.getElementById("hub-q");
|
||
var results = document.getElementById("hub-results");
|
||
var directory = document.getElementById("hub-directory");
|
||
if (!q || !results || !directory) return;
|
||
|
||
// Build a flat, alphabetical index from the crawlable directory links.
|
||
var index = [];
|
||
directory.querySelectorAll("details.hub-country").forEach(function (d) {
|
||
var country = (d.querySelector("summary").firstChild.textContent || "").trim();
|
||
d.querySelectorAll(".city-links a").forEach(function (a) {
|
||
index.push({ name: a.textContent, country: country, href: a.getAttribute("href") });
|
||
});
|
||
});
|
||
index.sort(function (a, b) {
|
||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||
});
|
||
|
||
function esc(s) {
|
||
return s.replace(/[&<>"']/g, function (c) {
|
||
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
|
||
});
|
||
}
|
||
|
||
function render() {
|
||
var term = q.value.trim().toLowerCase();
|
||
if (!term) {
|
||
results.hidden = true;
|
||
results.innerHTML = "";
|
||
directory.hidden = false;
|
||
return;
|
||
}
|
||
directory.hidden = true;
|
||
results.hidden = false;
|
||
var matches = index.filter(function (e) {
|
||
return e.name.toLowerCase().indexOf(term) >= 0 ||
|
||
e.country.toLowerCase().indexOf(term) >= 0;
|
||
});
|
||
if (!matches.length) {
|
||
results.innerHTML = '<li class="hub-empty muted">No cities match “' + esc(q.value.trim()) + "”.</li>";
|
||
return;
|
||
}
|
||
results.innerHTML = matches.slice(0, 300).map(function (e) {
|
||
return '<li><a href="' + e.href + '">' + esc(e.name) + "</a>" +
|
||
'<span class="hub-r-country">' + esc(e.country) + "</span></li>";
|
||
}).join("") + (matches.length > 300
|
||
? '<li class="hub-empty muted">…and ' + (matches.length - 300) + " more. Keep typing to narrow.</li>"
|
||
: "");
|
||
}
|
||
|
||
q.addEventListener("input", render);
|
||
})();
|
||
</script>
|
||
{% endraw %}
|
||
{% endblock %}
|