Shared substrate for the Pure Admin KPI showcase family.
Tracks @keenmate/pure-admin-core v2.7.1+ where the seven KPI showcase
designs (Terminal grid, Sparkline list, Comparison gauges, Hero+supporting,
Bento, Numeric strip, Editorial minimal) were promoted from inline demo
styles into permanent pa-kpi-* core components. This module provides the
parts every showcase reuses:
kpi_tile/1— the canonical tile (head · label · value · prev row · sparkline slot · optional hover detail) used by Terminal grid and as a standalone primitive.kpi_detail/1— hover detail popover with auto-built rows from typed props or a raw:inner_blockoverride. The host tile / row carries thephx-hook="PureAdminKpiTile"attribute; this component just emits the popover element that the hook finds and moves to<body>.kpi_sparkline/1— convenience SVG sparkline matching upstream defaults. Optional — the chart slot accepts any renderer.
Showcase-specific wrappers (terminal-grid chrome, hero+supporting layout,
bento grid, gauge list, etc.) build on top of these primitives in dedicated
modules — see PureAdmin.Components.Kpi.* siblings.
Design principles
- Pluggable chart rendering. The
:chartslot accepts any markup — inline SVG, a hook-mounted container for Chart.js / D3 / ApexCharts / Contex / etc. The framework does not pick a chart library. - Labels are fully customisable. Every textual element is an attribute or slot. No English strings are hardcoded; consumers control all i18n at the call site.
Auto-built detail popover
Set detail_title_text on kpi_tile/1 (plus any combination of
target_text / delta_absolute_text / previous_value_text / etc.) and
the popover body is built for you. The row order is Current → Previous →
Δ absolute → Δ percent → Target — rows without data are skipped. For raw
control, pass a :detail slot instead.
Floating UI requirement
The popover hook (PureAdminKpiTile) expects Floating UI loaded globally
as window.FloatingUIDOM — same convention as Tooltip / Popconfirm.
Summary
Functions
Renders the KPI hover detail popover.
Convenience SVG sparkline matching upstream's default look.
Renders a single KPI tile.
Functions
Renders the KPI hover detail popover.
Two ways to author content:
- Auto-built rows: pass
title_textand arowslist (typically produced byPureAdmin.Components.KpiDetail.build_auto_rows/1). Each row is%{label_text: ..., value_text: ..., sentiment: ...}. - Raw override: include any markup as
inner_block. The component just provides the<div class="pa-kpi-detail" role="tooltip">wrapper; write your own__title+<dl>inside.
The popover element is opt-in: it renders nothing when there's no title,
no rows, and no inner_block. Place it as a direct child of the host tile
/ row that carries phx-hook="PureAdminKpiTile" — the hook moves the
popover to <body> on mount and follows the cursor inside the host.
Examples
<.kpi_detail
title_text="Completion Rate · 30D"
rows={[
%{label_text: "Current", value_text: "88.6%"},
%{label_text: "Previous", value_text: "84.2%"},
%{label_text: "Δ absolute", value_text: "+4.4pp", sentiment: :pos},
%{label_text: "Target", value_text: "90.0%"}
]}
/>
<.kpi_detail>
<div class="pa-kpi-detail__title">Custom</div>
<p>Whatever markup you want.</p>
</.kpi_detail>Attributes
title_text(:string) - Defaults tonil.rows(:list) - Defaults to[].class(:string) - Defaults tonil.- Global attributes are accepted.
Slots
inner_block- Raw popover content — overrides title + rows.
Convenience SVG sparkline matching upstream's default look.
This is one option for the :chart slot — consumers who already have
a chart library should put that in the slot instead. The sparkline renders
a <polyline> inside an SVG with preserveAspectRatio="none" so the
line stretches to fill the container width. The framework's
--pa-chart-trendline-height and --pa-chart-trendline-stroke tokens
control height and stroke width.
When dot_at is given, the SVG emits a <circle> at that point — at
mount time PureAdminKpiSparkDot swaps it for a CSS-pixel-sized
<span class="pa-kpi-spark-dot"> so the dot stays circular regardless of
chart aspect ratio. Set id to engage the hook.
Examples
<.kpi_sparkline points="0,18 12,16 24,17 36,12 48,15" />
<.kpi_sparkline
id="spark-completion"
points="0,18 12,16 24,17 36,12 48,15 60,9 72,11 84,7 96,5"
dot_at={{96, 5}}
/>Attributes
id(:string) - Defaults tonil.points(:string) (required) - SVG polyline points (e.g. "0,18 12,16 24,17").view_box(:string) - Defaults to"0 0 100 24".dot_at(:any) -{cx, cy}tuple for the trailing dot. Defaults tonil.class(:string) - Defaults tonil.- Global attributes are accepted.
Renders a single KPI tile.
Used by the Terminal grid showcase and as a standalone primitive when
is_standalone is set. The tile is the hover host for the detail popover
when either detail_title_text is set OR a :detail slot is provided —
in those cases the component sets phx-hook="PureAdminKpiTile" (an
id is required for the hook).
Examples
<.kpi_tile
id="completion-rate-30d"
id_text="KPI.01 · 30d"
status_text="WARN"
status_variant="warn"
label_text="Completion Rate"
value_text="88.6"
unit_text="%"
variant="up"
previous_value_text="84.2%"
delta_text="▲ 5.2%"
delta_variant="positive"
detail_title_text="Completion Rate · 30D"
delta_absolute_text="+4.4pp"
target_text="90.0%"
>
<:chart>
<.kpi_sparkline points="0,18 12,16 24,17 36,12 48,15 60,9 72,11 84,7 96,5" dot_at={{96, 5}} />
</:chart>
</.kpi_tile>Standalone (outside a pa-kpi-terminal__grid):
<.kpi_tile id_text="KPI.07" label_text="Custom" value_text="42" is_standalone>
<:chart><!-- consumer-provided D3 / Apex / etc. --></:chart>
</.kpi_tile>Sentiment axes
variantcolours the entire tile's spark-direction cascade (up_strong/up/flat/down/down_strong). Named by sentiment of the change, not by line shape — error-rate dropping is"up", server-temp climbing is"down".value_variantcolours the focal number itself (rare — usually the delta carries the colour).delta_variantcolours the bottom-row delta text.
Attributes
id(:string) - Required when the popover hook is engaged (detail_title_text set OR :detail slot present). Defaults tonil.variant(:string) - Spark-direction sentiment cascade — colours the sparkline viacurrentColor. Defaults tonil. Must be one ofnil,"up_strong","up","flat","down", or"down_strong".is_standalone(:boolean) - Addspa-kpi-tile--standalone(full border + card bg + bottom margin) for tiles outsidepa-kpi-terminal__grid. Defaults tofalse.id_text(:string) - Identifier shown in tile head (e.g. "KPI.01 · 30d"). Defaults tonil.status_text(:string) - Status pill text (e.g. "WARN", "GOOD", "NEUTRAL"). Defaults tonil.status_variant(:string) - Status pill variant — built-ins: "warn" / "good" / "neutral". Defaults tonil.label_text(:string) - Uppercase mono tile label. Defaults tonil.value_text(:string) - Focal numeric value. Defaults tonil.unit_text(:string) - Unit suffix ("%", "°C", "K"). Defaults tonil.prefix_text(:string) - Currency / scale prefix ("$", "¥"). Defaults tonil.value_variant(:string) - Sentiment colour applied to the focal number. Defaults tonil. Must be one ofnil,"very_positive","positive","neutral","negative", or"very_negative".previous_value_text(:string) - Bare previous value (e.g. "84.2%"); rendered asprev <value>in the bottom row. Defaults tonil.delta_text(:string) - Bottom-row Δ% (e.g. "▲ 5.2%") — caller provides the arrow. Defaults tonil.delta_variant(:string) - Sentiment colour for the bottom-row delta. Defaults tonil. Must be one ofnil,"very_positive","positive","neutral","negative", or"very_negative".detail_title_text(:string) - Setting this (or providing:detail) enables the popover. Defaults tonil.delta_absolute_text(:string) - Absolute delta shown only in the popover. Defaults tonil.delta_absolute_sentiment(:atom) - Sentiment override for the Δ absolute popover row. Defaults tonil. Must be one ofnil,:pos,:neg, or:warn.target_text(:string) - Target value shown only in the popover. Defaults tonil.detail_rows(:list) - Override the auto-built popover rows with a typed list — seePureAdmin.Components.KpiDetail. Defaults tonil.class(:string) - Defaults tonil.- Global attributes are accepted.
Slots
head- Override the head row (id + status) with custom markup.label- Override the label cell with custom markup.value- Override the focal value cell with custom markup.previous_value- Override the prev/delta row with custom markup.chart- Chart cell — pass any SVG / hook-mounted chart container.detail- Raw popover content — overrides the auto-built popover.