<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Deployments</title>
<style>
:root {
--bg: #e8eaed;
--surface: #ffffff;
--border: #d7dade;
--border-strong: #c3c7cc;
--text: #1f2328;
--text-dim: #626c76;
--accent: #2456c4;
--accent-soft: #eaf0fc;
--hover: #f4f6f8;
--ok: #1a7f37;
--fail: #c0392b;
--warn: #9a6700;
--run: #2456c4;
font-size: 16px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
background: var(--bg);
font-family: "Segoe UI", -apple-system, "Helvetica Neue", Arial, sans-serif;
color: var(--text);
-webkit-font-smoothing: antialiased;
}
body {
display: flex;
justify-content: center;
padding: 56px 40px;
}
.panel {
background: var(--surface);
border: 1px solid var(--border-strong);
border-radius: 8px;
box-shadow: 0 1px 2px rgba(20,25,32,0.06), 0 4px 14px rgba(20,25,32,0.05);
overflow: hidden;
width: 940px;
max-width: 100%;
}
.panel-head {
display: flex;
align-items: baseline;
justify-content: space-between;
padding: 14px 18px 12px;
border-bottom: 1px solid var(--border);
}
.panel-head h1 {
font-size: 14px;
font-weight: 600;
letter-spacing: 0.01em;
}
.panel-head .meta {
font-size: 11.5px;
color: var(--text-dim);
}
table {
width: 100%;
border-collapse: collapse;
font-size: 12.5px;
table-layout: fixed;
}
col.c-status { width: 118px; }
col.c-service { width: auto; }
col.c-region { width: 122px; }
col.c-deploy { width: 138px; }
col.c-dur { width: 84px; }
col.c-time { width: 172px; }
thead th {
text-align: left;
font-size: 10.5px;
font-weight: 600;
letter-spacing: 0.07em;
text-transform: uppercase;
color: var(--text-dim);
background: #fafbfc;
border-bottom: 1px solid var(--border-strong);
padding: 0;
user-select: none;
}
thead th .th-inner {
display: flex;
align-items: center;
gap: 5px;
padding: 9px 12px;
cursor: pointer;
white-space: nowrap;
}
thead th .th-inner:hover { color: var(--text); }
thead th.num .th-inner { justify-content: flex-end; }
/* active sort column */
thead th.sorted {
color: var(--text);
background: #f1f3f6;
box-shadow: inset 0 -2px 0 var(--accent);
}
thead th.sorted .th-inner { color: var(--text); }
.sort-arrow {
font-size: 9px;
line-height: 1;
color: var(--accent);
}
.sort-arrow.idle {
color: #b6bcc4;
visibility: hidden;
}
thead th .th-inner:hover .sort-arrow.idle { visibility: visible; }
tbody td {
padding: 8px 12px;
border-bottom: 1px solid var(--border);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--hover); }
/* statically demonstrated hover state */
tr.is-hover { background: var(--hover); }
/* selected row */
tr.is-selected {
background: var(--accent-soft);
}
tr.is-selected td:first-child {
box-shadow: inset 3px 0 0 var(--accent);
}
tr.is-selected:hover { background: #e0e9fa; }
.mono {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 11.5px;
}
.svc {
font-weight: 600;
color: var(--text);
}
.svc .ver {
font-weight: 400;
color: var(--text-dim);
font-family: Consolas, Menlo, monospace;
font-size: 11px;
margin-left: 6px;
}
.num { text-align: right; }
.dim { color: var(--text-dim); }
/* status badges: icon glyph + label, never colour alone */
.status {
display: inline-flex;
align-items: center;
gap: 6px;
font-weight: 600;
font-size: 11.5px;
}
.status .glyph {
display: inline-flex;
width: 14px;
height: 14px;
align-items: center;
justify-content: center;
border-radius: 50%;
font-size: 9px;
font-weight: 700;
line-height: 1;
flex: none;
}
.st-ok { color: var(--ok); }
.st-ok .glyph { background: #dcf0e2; color: var(--ok); }
.st-fail { color: var(--fail); }
.st-fail .glyph { background: #fbe3e0; color: var(--fail); }
.st-run { color: var(--run); }
.st-run .glyph { background: #e2eafb; color: var(--run); }
.st-roll { color: var(--warn); }
.st-roll .glyph { background: #f8ecd2; color: var(--warn); }
.user {
display: inline-flex;
align-items: center;
gap: 7px;
min-width: 0;
}
.avatar {
width: 18px;
height: 18px;
border-radius: 50%;
background: #dfe3e8;
color: #4a5563;
font-size: 8.5px;
font-weight: 700;
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
letter-spacing: 0.02em;
}
.panel-foot {
display: flex;
justify-content: space-between;
align-items: center;
padding: 9px 18px;
border-top: 1px solid var(--border);
font-size: 11.5px;
color: var(--text-dim);
background: #fafbfc;
}
</style>
</head>
<body>
<div class="panel">
<div class="panel-head">
<h1>Server Deployments</h1>
<span class="meta">8 records · last refreshed 09:42 UTC</span>
</div>
<table aria-label="Server deployment records">
<colgroup>
<col class="c-status"><col class="c-service"><col class="c-region">
<col class="c-deploy"><col class="c-dur"><col class="c-time">
</colgroup>
<thead>
<tr>
<th scope="col"><span class="th-inner">Status <span class="sort-arrow idle">▲</span></span></th>
<th scope="col"><span class="th-inner">Service <span class="sort-arrow idle">▲</span></span></th>
<th scope="col"><span class="th-inner">Region <span class="sort-arrow idle">▲</span></span></th>
<th scope="col"><span class="th-inner">Deployed by <span class="sort-arrow idle">▲</span></span></th>
<th scope="col" class="num"><span class="th-inner">Duration <span class="sort-arrow idle">▲</span></span></th>
<th scope="col" class="sorted" aria-sort="descending">
<span class="th-inner">Timestamp <span class="sort-arrow">▼</span></span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="status st-run"><span class="glyph">▶</span>Running</span></td>
<td class="svc">billing-api <span class="ver">v3.9.1</span></td>
<td class="mono">eu-west-1</td>
<td><span class="user"><span class="avatar">RK</span>r.kaur</span></td>
<td class="num mono dim">1m 12s</td>
<td class="mono dim">2024-05-14 09:41:07</td>
</tr>
<tr class="is-selected" aria-selected="true">
<td><span class="status st-ok"><span class="glyph">✓</span>Success</span></td>
<td class="svc">auth-gateway <span class="ver">v2.4.0</span></td>
<td class="mono">us-east-1</td>
<td><span class="user"><span class="avatar">MO</span>m.okafor</span></td>
<td class="num mono dim">2m 48s</td>
<td class="mono dim">2024-05-14 09:18:33</td>
</tr>
<tr class="is-hover">
<td><span class="status st-fail"><span class="glyph">✕</span>Failed</span></td>
<td class="svc">search-indexer <span class="ver">v1.17.4</span></td>
<td class="mono">ap-south-1</td>
<td><span class="user"><span class="avatar">JT</span>j.tanaka</span></td>
<td class="num mono dim">0m 54s</td>
<td class="mono dim">2024-05-14 08:52:19</td>
</tr>
<tr>
<td><span class="status st-ok"><span class="glyph">✓</span>Success</span></td>
<td class="svc">notifications <span class="ver">v5.2.7</span></td>
<td class="mono">eu-central-1</td>
<td><span class="user"><span class="avatar">AL</span>a.lindgren</span></td>
<td class="num mono dim">3m 05s</td>
<td class="mono dim">2024-05-14 07:36:48</td>
</tr>
<tr>
<td><span class="status st-roll"><span class="glyph">↺</span>Rolled back</span></td>
<td class="svc">payments-worker <span class="ver">v4.0.0</span></td>
<td class="mono">us-west-2</td>
<td><span class="user"><span class="avatar">MO</span>m.okafor</span></td>
<td class="num mono dim">6m 31s</td>
<td class="mono dim">2024-05-14 06:04:12</td>
</tr>
<tr>
<td><span class="status st-ok"><span class="glyph">✓</span>Success</span></td>
<td class="svc">media-transcoder <span class="ver">v0.9.12</span></td>
<td class="mono">sa-east-1</td>
<td><span class="user"><span class="avatar">CD</span>c.duarte</span></td>
<td class="num mono dim">4m 22s</td>
<td class="mono dim">2024-05-13 22:47:55</td>
</tr>
<tr>
<td><span class="status st-fail"><span class="glyph">✕</span>Failed</span></td>
<td class="svc">edge-router <span class="ver">v7.1.3</span></td>
<td class="mono">us-east-2</td>
<td><span class="user"><span class="avatar">RK</span>r.kaur</span></td>
<td class="num mono dim">1m 47s</td>
<td class="mono dim">2024-05-13 20:15:02</td>
</tr>
<tr>
<td><span class="status st-ok"><span class="glyph">✓</span>Success</span></td>
<td class="svc">analytics-etl <span class="ver">v2.11.0</span></td>
<td class="mono">ap-northeast-1</td>
<td><span class="user"><span class="avatar">JT</span>j.tanaka</span></td>
<td class="num mono dim">8m 16s</td>
<td class="mono dim">2024-05-13 18:29:40</td>
</tr>
</tbody>
</table>
<div class="panel-foot">
<span>1 row selected</span>
<span>Sorted by timestamp · newest first</span>
</div>
</div>
<script>
// Minimal interactive affordance: clicking a header toggles the sorted state indicator.
document.querySelectorAll('thead th').forEach(function (th) {
th.querySelector('.th-inner').addEventListener('click', function () {
var current = document.querySelector('thead th.sorted');
if (current === th) {
var arrow = th.querySelector('.sort-arrow');
arrow.innerHTML = arrow.innerHTML.trim() === '\u25B2' ? '▼' : '▲';
th.setAttribute('aria-sort', arrow.innerHTML.trim() === '\u25B2' ? 'ascending' : 'descending');
return;
}
if (current) {
current.classList.remove('sorted');
current.removeAttribute('aria-sort');
current.querySelector('.sort-arrow').className = 'sort-arrow idle';
current.querySelector('.sort-arrow').innerHTML = '▲';
}
th.classList.add('sorted');
th.setAttribute('aria-sort', 'ascending');
var a = th.querySelector('.sort-arrow');
a.className = 'sort-arrow';
a.innerHTML = '▲';
});
});
// Row selection on click.
document.querySelectorAll('tbody tr').forEach(function (tr) {
tr.addEventListener('click', function () {
var sel = document.querySelector('tbody tr.is-selected');
if (sel) { sel.classList.remove('is-selected'); sel.removeAttribute('aria-selected'); }
tr.classList.add('is-selected');
tr.setAttribute('aria-selected', 'true');
});
});
</script>
</body>
</html>