Content
cardk-card
- store
- reads card.title, card.heading, card.text
- actions
- card_open, card_dismiss
- keys
- tab, enter
- needs
- k-btn, k-title
Markup: components/card.tui
<!-- k-card · Contract: reads card.title, card.heading, card.text · Actions: card_open, card_dismiss · Keys: tab, enter · Requires: k-btn, k-title -->
<tui theme="auto">
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<screen id="demo" focus="#card__open">
<col width="1fr" height="1fr" gap="1" pad="1">
<text class="k-title">card / panel</text>
<!-- COPY: a card is a `box` with class `k-card` and a `title`. The
border turns to the focus color while anything inside holds focus
(`.k-card:focus-within`). The class gives it `height: auto` to
wrap its content; write a number or fr on the box to fix it. -->
<box class="k-card" title="{card.title}">
<text class="k-card-title">{card.heading}</text>
<text class="k-card-muted">{card.text}</text>
<row class="k-card-actions">
<button id="card__open" class="k-btn primary" label="Open" on:click="card_open"/>
<button id="card__dismiss" class="k-btn ghost" label="Dismiss" on:click="card_dismiss"/>
</row>
</box>
<!-- COPY: side-by-side cards share the row; each takes `1fr`. -->
<row width="1fr" height="auto" gap="1">
<box class="k-card" title="Left">
<text class="k-card-text">First card</text>
</box>
<box class="k-card" title="Right">
<text class="k-card-text">Second card</text>
</box>
</row>
</col>
</screen>
</tui>alertk-alert
- store
- reads alert.message
- needs
- k-title
Markup: components/alert.tui
<!-- k-alert · Contract: reads alert.message · Actions: none · Keys: none · Requires: k-title -->
<tui theme="auto">
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<screen id="demo">
<col width="1fr" height="1fr" gap="0" pad="1">
<text class="k-title">alert / callout</text>
<!-- COPY: an alert is a `box` with class `k-alert` plus a modifier
(info, ok, warn, danger). The title is the box title; the body
wraps. `k-alert-icon` takes the same modifier so it matches. -->
<box class="k-alert info" title="Heads up">
<row class="k-alert-row">
<text class="k-alert-icon info">i</text>
<text class="k-alert-text">Deploys are paused until 09:00 UTC.</text>
</row>
</box>
<box class="k-alert ok" title="Saved">
<row class="k-alert-row">
<text class="k-alert-icon ok">✓</text>
<text class="k-alert-text">Your changes are live in every region.</text>
</row>
</box>
<box class="k-alert warn" title="Quota">
<row class="k-alert-row">
<text class="k-alert-icon warn">!</text>
<text class="k-alert-text">You have used 92% of this month's build minutes.</text>
</row>
</box>
<box class="k-alert danger" title="Build failed">
<row class="k-alert-row">
<text class="k-alert-icon danger">✗</text>
<text class="k-alert-text">{alert.message}</text>
</row>
</box>
</col>
</screen>
</tui>badgek-badge
- store
- reads build.number, build.status, build.ok
- needs
- k-title
Markup: components/badge.tui
<!-- k-badge · Contract: reads build.number, build.status, build.ok · Actions: none · Keys: none · Requires: k-title -->
<tui theme="auto">
<!-- Every kit document loads the sheets in this order: tokens, components, then your own. -->
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<screen id="demo">
<col width="1fr" height="1fr" gap="1" pad="1">
<text class="k-title">badge</text>
<!-- COPY: a badge is one text with two classes: `k-badge` and a
modifier. Modifiers: accent, ok, warn, danger, info (none =
neutral). The label is literal text or a {path}. -->
<row width="1fr" height="1" gap="1">
<text class="k-badge">draft</text>
<text class="k-badge accent">new</text>
<text class="k-badge ok">passing</text>
</row>
<row width="1fr" height="1" gap="1">
<text class="k-badge warn">flaky</text>
<text class="k-badge danger">failed</text>
<text class="k-badge info">{build.number}</text>
</row>
<!-- COPY: choose the modifier from data with class:NAME guards on the
same node (the guards are paths the host keeps true or false). -->
<row width="1fr" height="1" gap="1">
<text class="k-badge" class:ok="build.ok" class:danger="!build.ok">{build.status}</text>
</row>
</col>
</screen>
</tui>statk-stat
- store
- reads stats.req.{value, delta, good, hist[]} and stats.err.{value, delta, good, hist[]}
- needs
- k-title
Markup: components/stat.tui
<!-- k-stat · Contract: reads stats.req.{value, delta, good, hist[]} and stats.err.{value, delta, good, hist[]} · Actions: none · Keys: none · Requires: k-title -->
<tui theme="auto">
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<screen id="demo">
<col width="1fr" height="1fr" gap="1" pad="1">
<text class="k-title">stat / KPI card</text>
<!-- COPY: a stat is a `box` with class `k-stat`: the label as the box
title, the value in bold, and a row with the change
(`k-stat-delta`, plus `good` or `bad` for green or red; guard it
with class:good / class:bad: whether a rise is good depends on
the metric) and a `sparkline` (class `k-stat-spark`) bound to an
array of numbers. Put stats in a row; each takes `1fr` of the
width. -->
<row width="1fr" height="auto" gap="1">
<box class="k-stat" title="Requests">
<text class="k-stat-value">{stats.req.value}</text>
<row class="k-stat-row">
<text class="k-stat-delta" class:good="stats.req.good" class:bad="!stats.req.good">{stats.req.delta}</text>
<sparkline class="k-stat-spark" bind="stats.req.hist"/>
</row>
</box>
<box class="k-stat" title="Errors">
<text class="k-stat-value">{stats.err.value}</text>
<row class="k-stat-row">
<text class="k-stat-delta" class:good="stats.err.good" class:bad="!stats.err.good">{stats.err.delta}</text>
<sparkline class="k-stat-spark" bind="stats.err.hist"/>
</row>
</box>
</row>
</col>
</screen>
</tui>labeled progressk-meter
- store
- reads meters.upload.{label, text, pct}, meters.disk.{text, pct, warn, crit}, meters.tests.{text, pct} (pct is 0 to 100)
- needs
- k-title
Markup: components/meter.tui
<!-- k-meter · Contract: reads meters.upload.{label, text, pct}, meters.disk.{text, pct, warn, crit}, meters.tests.{text, pct} (pct is 0 to 100) · Actions: none · Keys: none · Requires: k-title -->
<tui theme="auto">
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<screen id="demo">
<col width="1fr" height="1fr" gap="1" pad="1">
<text class="k-title">labeled progress</text>
<!-- COPY: a meter is a `col` with class `k-meter`: a head row (label
on the left, the value text on the right) over a `progress` with
class `k-meter-bar`. `bind` is a number from 0 to 100. Add a
status color to the bar with the modifier `ok`, `warn`, or
`danger`, or pick it from data with class:NAME guards. The host
updates the number (and the text) as the work advances. -->
<col class="k-meter">
<row class="k-meter-head">
<text class="k-meter-label">{meters.upload.label}</text>
<spacer/>
<text class="k-meter-value">{meters.upload.text}</text>
</row>
<progress class="k-meter-bar" bind="meters.upload.pct"/>
</col>
<col class="k-meter">
<row class="k-meter-head">
<text class="k-meter-label">Disk</text>
<spacer/>
<text class="k-meter-value">{meters.disk.text}</text>
</row>
<progress class="k-meter-bar" class:warn="meters.disk.warn" class:danger="meters.disk.crit" bind="meters.disk.pct"/>
</col>
<col class="k-meter">
<row class="k-meter-head">
<text class="k-meter-label">Tests</text>
<spacer/>
<text class="k-meter-value">{meters.tests.text}</text>
</row>
<progress class="k-meter-bar ok" bind="meters.tests.pct"/>
</col>
</col>
</screen>
</tui>empty statek-empty
- store
- reads empty.title, empty.text
- actions
- empty_create
- keys
- enter on the button
- needs
- k-btn, k-title
Markup: components/empty.tui
<!-- k-empty · Contract: reads empty.title, empty.text · Actions: empty_create · Keys: enter on the button · Requires: k-btn, k-title -->
<tui theme="auto">
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<screen id="demo" focus="#empty__create">
<col width="1fr" height="1fr" pad="1">
<text class="k-title">empty state</text>
<!-- COPY: an empty state is a `col` with class `k-empty` (it fills the
space left and centers its children), an icon, a title, one line
of help, and the call to action (a button label is literal text).
Show it with `if="!items.any"` next to the list it replaces. -->
<col class="k-empty">
<text class="k-empty-icon">◌</text>
<text class="k-empty-title">{empty.title}</text>
<text class="k-empty-text">{empty.text}</text>
<button id="empty__create" class="k-btn primary" label="New deployment" on:click="empty_create"/>
</col>
</col>
</screen>
</tui>log panelk-log
- store
- reads log.count, log.lines[] {n, text, debug, info, warn, err}; the host appends lines
- actions
- log_append (the host's key)
- keys
- j and k scroll, g top, G follow
- needs
- k-hints
Markup: components/log.tui
<!-- k-log · Contract: reads log.count, log.lines[] {n, text, debug, info, warn, err}; the host appends lines · Actions: log_append (the host's key) · Keys: j and k scroll, g top, G follow · Requires: k-hints -->
<tui theme="auto">
<style src="../theme.tcss"/>
<style src="../kit.tcss"/>
<keymap when="#log">
<bind keys="j" action="move-next" keycap="j/k" label="scroll"/>
<bind keys="k" action="move-prev"/>
<bind keys="G" action="move-last" label="follow"/>
<bind keys="g" action="move-first" label="top"/>
</keymap>
<screen id="demo" focus="#log">
<col width="1fr" height="1fr" gap="0">
<!-- COPY: a log panel is a `scroll` with class `k-log` and
`stick="bottom"`: it follows the end of its content as lines are
appended, until you scroll up to read; `move-last` (or scrolling
to the end) makes it follow again. It needs an `id` and must be
focusable to take the keys. The lines are a `col` with
`each` and a `key`; `height: auto` (the class) lets the column
be as tall as its lines, which is what the scroll measures.
Color a line with class:NAME guards: every line carries all the
flags (a missing path is B002), `false` for the ones it is not.
The host appends lines to the array (see examples/kit-gallery). -->
<scroll id="log" class="k-log" stick="bottom" focusable="true" title="build log · {log.count} lines">
<col class="k-log-lines" each="log.lines as l" key="l.n">
<text class="k-log-line" class:muted="l.debug" class:info="l.info" class:warn="l.warn" class:danger="l.err">{l.text}</text>
</col>
</scroll>
<hints class="k-hints"/>
</col>
</screen>
</tui>