From 11137912debfb686c0a7936302f8976f618986f5 Mon Sep 17 00:00:00 2001
From: kerthcet
Date: Sun, 8 Nov 2026 09:45:55 +0000
Subject: [PATCH] make the city name clickable
Signed-off-by: kerthcet
---
assets/scss/common/_custom.scss | 46 ++++++++++++++++++++++-
hugo_stats.json | 4 ++
layouts/_default/home.html | 16 ++++++++
layouts/partials/head/resource-hints.html | 6 +++
4 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/assets/scss/common/_custom.scss b/assets/scss/common/_custom.scss
index 3490307..4e34e41 100644
--- a/assets/scss/common/_custom.scss
+++ b/assets/scss/common/_custom.scss
@@ -668,7 +668,8 @@ $map-pulse-alpha: 0.18;
stroke: var(--bs-body-bg, #fff);
stroke-width: 3px;
paint-order: stroke;
- // Purely a caption for the dot, which is already the hit target.
+ // The pointer goes to `.worldmap-hit-label`, the transparent copy of this name in
+ // the html layer above, which is what makes the name open the card.
pointer-events: none;
}
@@ -910,6 +911,49 @@ $map-pulse-offsets:
z-index: 4;
}
+// The city's name as a second hover target for its card — see the template. The same
+// text at the same size as `.worldmap-label`, painted transparent over it, so its box
+// is the name's box. Everything is in map units turned into `cqw` (the layer is the
+// query container and is the map's width, so one viewBox unit is 0.1cqw), and shrunk
+// by `--mark-scale` exactly as the svg group is, so the two stay on top of each other
+// at every width the names are drawn at.
+//
+// Anchored at the hit's centre, which is the dot's: `--label-dx` and `--label-dy` from
+// the generated stylesheet are the svg label's own offset, and `dy` lands on its
+// baseline. With `line-height: 1` the baseline is about 0.8em below the top of the
+// line, so the box is lifted by that plus the padding — the padding is slack that
+// makes a 12px name a little easier to land on than its glyphs alone.
+.worldmap-hit-label {
+ display: none;
+ position: absolute;
+ left: calc(50% + var(--label-dx, 0) * 0.1cqw * var(--mark-scale, 1));
+ top: calc(50% + var(--label-dy, 0) * 0.1cqw * var(--mark-scale, 1));
+ padding: 0.2em;
+ font-size: calc(1.35cqw * var(--mark-scale, 1));
+ font-weight: 400;
+ line-height: 1;
+ white-space: nowrap;
+ color: transparent;
+ user-select: none;
+ transform: translate(-0.2em, -1em);
+}
+
+.worldmap-hit-label-end {
+ transform: translate(calc(-100% + 0.2em), -1em);
+}
+
+.worldmap-hit-label-middle {
+ transform: translate(-50%, -1em);
+}
+
+// Only where the svg draws the names — a target over a name that is not there would be
+// a patch of empty map that opens a card.
+@include media-breakpoint-up(xl) {
+ .worldmap-hit-label {
+ display: block;
+ }
+}
+
// The ring is the focus indicator's job here too, but on its own it is a 22% wash
// that would not pass for one, so focus also gets an outline. On the card's side
// rather than the dot's, because the dot is 5px across at its smallest.
diff --git a/hugo_stats.json b/hugo_stats.json
index 78eb253..12c9040 100644
--- a/hugo_stats.json
+++ b/hugo_stats.json
@@ -192,6 +192,10 @@
"worldmap-country",
"worldmap-dot",
"worldmap-hit",
+ "worldmap-hit-label",
+ "worldmap-hit-label-end",
+ "worldmap-hit-label-middle",
+ "worldmap-hit-label-start",
"worldmap-hit-left",
"worldmap-hits",
"worldmap-key-title",
diff --git a/layouts/_default/home.html b/layouts/_default/home.html
index 68057fb..b58408d 100644
--- a/layouts/_default/home.html
+++ b/layouts/_default/home.html
@@ -292,6 +292,22 @@ {{ .Title }}
{{ end }}
+ {{/* A second way into the card: the city's name. The dots are a few
+ pixels across and hard to hit, while the name beside each one is
+ the thing a reader is actually looking at. This is the same text
+ as the svg label, set transparent at the same size and laid over
+ it (offsets from the generated stylesheet, anchor from the class),
+ so its box is the name's own box without anything measuring it.
+
+ Inside the hit rather than beside it, which is the whole trick:
+ hovering it is hovering `.worldmap-hit`, and a tap or click on it
+ focuses the hit, so the card opens through the same `:hover` and
+ `:focus-within` rules as the dot and no script is needed.
+ `aria-hidden` because the card head already names the place. */}}
+ {{ $short := .short -}}
+ {{ with .offset -}}
+ {{ $short }}
+ {{- end }}
{{ end -}}
diff --git a/layouts/partials/head/resource-hints.html b/layouts/partials/head/resource-hints.html
index 9f4b8e6..3271d07 100644
--- a/layouts/partials/head/resource-hints.html
+++ b/layouts/partials/head/resource-hints.html
@@ -56,6 +56,12 @@
column of faces. */}}
{{ $room := cond (gt $pos.x (mul 0.5 $map.width)) (sub $left (div $size 2.0)) (sub (sub 100.0 $left) (div $size 2.0)) -}}
{{ $rules = $rules | append (printf ".worldmap-hit:nth-child(%d){left:%.3f%%;top:%.3f%%;width:calc(%.3f%% * var(--mark-scale, 1));--map-room:%.3f}" (add $i 1) $left $top $size $room) -}}
+{{/* Where the city's name sits relative to its dot, in viewBox units — the same
+ hand-placed offset the svg label is drawn at, so the name's hover target in
+ `.worldmap-hit-label` lands on the name. */}}
+{{ with $place.offset -}}
+{{ $rules = $rules | append (printf ".worldmap-hit:nth-child(%d){--label-dx:%.1f;--label-dy:%.1f}" (add $i 1) (float .dx) (float .dy)) -}}
+{{ end -}}
{{/* The point the svg's group for this mark is scaled about — its dot's centre, in
viewBox units. See `.worldmap-place` in the stylesheet; `nth-of-type` because the
groups are the only `` in the svg, one per mark in this same order. */}}