All files / src/templates/sections key-figures.ts

100% Statements 11/11
100% Branches 10/10
100% Functions 2/2
100% Lines 10/10

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                                                              9x   8x   8x   9x 9x 9x 9x     9x     9x                   8x              
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
// SPDX-License-Identifier: Apache-2.0
 
/**
 * @module Templates/Sections/KeyFigures
 * @description Key-figures bar builder for quick-scan numeric highlights.
 * Split out of `section-builders.ts` (Refactor 8/8).
 */
 
import { escapeHTML } from '../../utils/file-utils.js';
import type { LanguageCode } from '../../types/index.js';
import { getLocalizedString, KEY_FIGURES_HEADINGS } from '../../constants/languages.js';
 
/**
 * A numeric highlight figure for a key-figures bar.
 */
export interface KeyFigure {
  /** Descriptive label for the figure */
  label: string;
  /** Formatted value string (e.g. "42", "78%") */
  value: string;
  /** Optional unit suffix (e.g. "votes", "days", "%") */
  unit?: string | undefined;
  /** Optional longer description for screen readers / tooltips */
  description?: string | undefined;
}
 
/**
 * Build an HTML key figures bar for quick-scan numeric highlights.
 *
 * Renders a horizontal strip of numeric summary cards. Each card shows a
 * value (with optional unit), a label, and an optional screen-reader-only
 * description. Empty figures array returns an empty string.
 *
 * @param figures - Array of {@link KeyFigure} items to render.
 * @param lang - Language code used for the section heading.
 * @returns HTML string for the key figures `<section>`, or empty string when figures is empty.
 */
export function buildKeyFiguresBar(figures: ReadonlyArray<KeyFigure>, lang: LanguageCode): string {
  if (figures.length === 0) return '';
 
  const heading = escapeHTML(getLocalizedString(KEY_FIGURES_HEADINGS, lang));
 
  const cards = figures
    .map((fig) => {
      const safeLabel = escapeHTML(fig.label);
      const safeValue = escapeHTML(fig.value);
      const safeUnit = fig.unit ? escapeHTML(fig.unit) : '';
      const unitSpan = safeUnit
        ? ` <span class="kf-unit" aria-hidden="true">${safeUnit}</span>`
        : '';
      const descriptionPart = fig.description
        ? `<span class="sr-only">${escapeHTML(fig.description)}</span>`
        : '';
      return (
        `<div class="key-figure-card" role="listitem" aria-label="${safeLabel}: ${safeValue}${safeUnit ? ' ' + safeUnit : ''}">` +
        `<span class="kf-value">${safeValue}${unitSpan}</span>` +
        `<span class="kf-label">${safeLabel}</span>` +
        descriptionPart +
        `</div>`
      );
    })
    .join('\n      ');
 
  return `<section class="key-figures-bar" aria-label="${heading}">
  <h2 class="sr-only">${heading}</h2>
  <div class="key-figures-grid" role="list">
      ${cards}
  </div>
</section>`;
}