feat(web): click Executions' Started time to toggle relative/absolute

Both renderings are pre-rendered server-side into a <button>'s
data-relative/data-absolute attributes; app.js swaps textContent (and the
hover title, to the opposite value) on click, delegated on document.body
so it survives the card's own 5s htmx poll without needing to re-wire
after every swap. Click again to swap back.
This commit is contained in:
2026-07-25 20:56:33 +02:00
parent 8a34e663c7
commit 868dd1a036
5 changed files with 74 additions and 2 deletions
+16
View File
@@ -501,6 +501,22 @@ input[type="text"], input[type="number"], select {
/* Muted inline text (e.g. a relative-time suffix next to a file name). */
.text-dim { color: var(--text-dim); }
/* Executions "Started" cell: reset to read as plain inline text (no button
* chrome), with a dotted underline as the click-to-toggle affordance --
* not colour alone, same rule the rest of the app follows. app.js swaps
* between its data-relative/data-absolute values on click. */
.time-toggle {
background: none;
border: none;
padding: 0;
margin: 0;
font: inherit;
cursor: pointer;
text-decoration: underline dotted;
text-underline-offset: 2px;
}
.time-toggle:hover { color: var(--text); }
/* ── notices / confirm / result panels ───────────────────────────────── */
.notice {
+16
View File
@@ -204,6 +204,22 @@
}
});
// Executions "Started" cell: click swaps between the relative and
// absolute time already rendered into the button's own data attributes --
// no request. Delegated on body (not the button itself) so it keeps
// working after the Executions card's own 5s htmx poll replaces the row.
document.body.addEventListener("click", function (evt) {
var btn = evt.target.closest(".time-toggle");
if (!btn) {
return;
}
var next = btn.dataset.showing === "relative" ? "absolute" : "relative";
var shown = next === "relative" ? "absolute" : "relative";
btn.textContent = btn.dataset[next];
btn.title = btn.dataset[shown];
btn.dataset.showing = next;
});
document.addEventListener("DOMContentLoaded", function () {
observeStack();
processSlot(document.getElementById("action-slot"));
@@ -89,7 +89,9 @@
<td>{{ run.duration_sec | duration }}</td>
<td>
{% if run.started %}
<span class="text-dim" title="{{ run.started | localtime }}">{{ run.started | relative_time }}</span>
<button type="button" class="time-toggle text-dim" data-showing="relative"
data-relative="{{ run.started | relative_time }}" data-absolute="{{ run.started | localtime }}"
title="{{ run.started | localtime }}">{{ run.started | relative_time }}</button>
{% else %}
<span class="text-dim">—</span>
{% endif %}
@@ -137,7 +139,9 @@
<td><span class="text-dim">—</span></td>
<td>
{% if parsed.started %}
<span class="text-dim" title="{{ parsed.started | localtime }}">{{ parsed.started | relative_time }}</span>
<button type="button" class="time-toggle text-dim" data-showing="relative"
data-relative="{{ parsed.started | relative_time }}" data-absolute="{{ parsed.started | localtime }}"
title="{{ parsed.started | localtime }}">{{ parsed.started | relative_time }}</button>
{% else %}
<span class="text-dim">—</span>
{% endif %}