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 -}} + + {{- 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. */}}