| 1 | {{- /* |
| 2 | Repo trend visualization — a lightweight, locally-rendered bar chart for a |
| 3 | numeric series (e.g. star history or weekly momentum). Deterministic and |
| 4 | dependency-free. Accessible: bars are aria-hidden decoration; the real data is |
| 5 | exposed as a visually-hidden description and an optional caption. |
| 6 | |
| 7 | Params (dict): |
| 8 | values : slice of numbers (required) |
| 9 | labels : optional slice of strings, aligned to values |
| 10 | repo : optional repo slug for the heading/link |
| 11 | heading : optional heading text |
| 12 | level : optional heading level (default "h3") |
| 13 | caption : optional caption / source text |
| 14 | */ -}} |
| 15 | {{- $values := .values | default slice -}} |
| 16 | {{- $labels := .labels | default slice -}} |
| 17 | {{- $repo := .repo | default "" -}} |
| 18 | {{- /* An empty/omitted repo is treated as absent: fall back to the plain |
| 19 | heading rather than emitting a broken "<empty> — trend" string. */ -}} |
| 20 | {{- $heading := .heading | default (cond (ne $repo "") (printf "%s — trend" $repo) "Trend") -}} |
| 21 | {{- $level := .level | default "h3" | lower -}} |
| 22 | {{- if not (in (slice "h2" "h3" "h4" "h5" "h6") $level) }}{{ $level = "h3" }}{{ end -}} |
| 23 | {{- /* $level is strictly whitelisted above, so the tag name is safe to emit; |
| 24 | the heading text itself remains contextually auto-escaped. */ -}} |
| 25 | {{- $hOpen := printf `<%s class="repo-trend__heading">` $level | safeHTML -}} |
| 26 | {{- $hClose := printf "</%s>" $level | safeHTML -}} |
| 27 | {{- $caption := .caption -}} |
| 28 | {{- if gt (len $values) 0 -}} |
| 29 | {{- $max := 0.0 -}} |
| 30 | {{- range $values }}{{ if gt (float .) $max }}{{ $max = (float .) }}{{ end }}{{ end -}} |
| 31 | {{- if le $max 0.0 }}{{ $max = 1.0 }}{{ end -}} |
| 32 | {{- $n := len $values -}} |
| 33 | {{- $summary := slice -}} |
| 34 | {{- range $i, $v := $values -}} |
| 35 | {{- $lab := cond (gt (len $labels) $i) (index $labels $i) (printf "Point %d" (add $i 1)) -}} |
| 36 | {{- $summary = $summary | append (printf "%s: %s" $lab (lang.FormatNumber 0 $v)) -}} |
| 37 | {{- end -}} |
| 38 | <figure class="repo-trend" role="group" aria-label="{{ $heading }}"> |
| 39 | {{ $hOpen }} |
| 40 | {{- if $repo }}<a href="https://github.com/{{ $repo }}" aria-label="Open GitHub repository {{ $repo }}">{{ $heading }}</a>{{ else }}{{ $heading }}{{ end -}} |
| 41 | {{ $hClose }} |
| 42 | <svg class="repo-trend__chart" viewBox="0 0 {{ mul $n 100 }} 320" preserveAspectRatio="none" aria-hidden="true" focusable="false"> |
| 43 | {{- $slot := 100 -}} |
| 44 | {{- range $i, $v := $values -}} |
| 45 | {{- $h := math.Round (mul (div (float $v) $max) 300.0) -}} |
| 46 | {{- if lt $h 3.0 }}{{ $h = 3.0 }}{{ end -}} |
| 47 | {{- $x := add (mul $i $slot) 22 -}} |
| 48 | {{- $y := sub 320 $h -}} |
| 49 | <rect x="{{ $x }}" y="{{ $y }}" width="56" height="{{ $h }}" rx="4" /> |
| 50 | {{- end -}} |
| 51 | </svg> |
| 52 | <p class="visually-hidden">{{ $heading }}. {{ delimit $summary "; " }}.</p> |
| 53 | {{- /* Render the caption as a safe inline subset (#329): allow simple |
| 54 | emphasis/links from Markdown, but strip any <img> the markdown image |
| 55 | syntax would emit so no third-party/hotlinked imagery can slip in. */ -}} |
| 56 | {{- with $caption }}<figcaption class="repo-trend__caption">{{ . | markdownify | replaceRE `(?i)<img[^>]*>` "" | safeHTML }}</figcaption>{{ end }} |
| 57 | </figure> |
| 58 | {{- end -}} |