Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions layouts/partials/headers.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

<!-- Custom stylesheet - for your changes -->
<link href="{{ "css/custom.css" | relURL}}" rel="stylesheet">
<script src="{{ "js/table-enhancements.js" | relURL}}" defer></script>

<!-- Responsivity for older IE -->
{{ `
Expand Down
169 changes: 169 additions & 0 deletions static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,175 @@ h3.text-uppercase {
padding: 12px 10px;
}

/* Dense data tables */
.data-table {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius-md);
box-shadow: 0 8px 28px rgba(23, 38, 51, 0.08);
margin: 24px 0 36px;
overflow: hidden;
}

.data-table__toolbar {
align-items: center;
background: #f8fafb;
border-bottom: 1px solid var(--line);
display: flex;
gap: 18px;
justify-content: space-between;
padding: 12px 16px;
}

.data-table__search {
flex: 0 1 340px;
margin: 0;
position: relative;
}

.data-table__search i {
color: #71838d;
left: 13px;
pointer-events: none;
position: absolute;
top: 50%;
transform: translateY(-50%);
}

.data-table__input {
background: #fff;
border: 1px solid #cbd8de;
border-radius: var(--radius-sm);
color: var(--ink);
font-size: 14px;
height: 40px;
padding: 8px 13px 8px 38px;
width: 100%;
}

.data-table__input:focus {
border-color: var(--primary-accent);
box-shadow: 0 0 0 3px var(--form-shadow);
outline: 0;
}

.data-table__count {
color: var(--ink-muted);
flex: none;
font-size: 13px;
font-weight: 650;
}

.data-table__scroll {
max-width: 100%;
overflow: auto;
overscroll-behavior: contain;
scrollbar-color: #aebfc6 #edf2f4;
scrollbar-width: thin;
}

.data-table--large .data-table__scroll {
max-height: min(68vh, 720px);
}

#content .data-table__table {
border-collapse: separate;
border-spacing: 0;
margin: 0;
min-width: 760px;
width: 100%;
}

#content .data-table__table th,
#content .data-table__table td {
background-clip: padding-box;
border: 0;
border-bottom: 1px solid var(--line);
padding: 13px 16px;
vertical-align: middle;
}

#content .data-table__table thead th {
background: #eaf5f7;
border-bottom: 2px solid var(--primary-accent);
color: #173b47;
font-size: 14px;
font-weight: 750;
position: sticky;
top: 0;
white-space: normal;
z-index: 2;
}

#content .data-table__table tbody tr:nth-child(even) td {
background-color: #f8fafb;
}

#content .data-table__table tbody tr:hover td {
background-color: #eaf7f9;
}

#content .data-table__table th:first-child,
#content .data-table__table td:first-child {
box-shadow: 1px 0 0 var(--line);
left: 0;
min-width: 210px;
position: sticky;
text-align: left;
z-index: 1;
}

#content .data-table__table thead th:first-child {
background: #deeff2;
z-index: 3;
}

#content .data-table__table tbody td:not(:first-child) {
min-width: 118px;
text-align: center;
}

#content .data-table__table tbody tr:last-child td {
border-bottom: 0;
}

#content .data-table__table tr[hidden] {
display: none;
}

.data-table__scroll:focus-visible {
box-shadow: inset 0 0 0 3px var(--form-shadow);
outline: 0;
}

@media (max-width: 767px) {
.data-table {
border-radius: var(--radius-sm);
margin-left: -8px;
margin-right: -8px;
}

.data-table__toolbar {
align-items: stretch;
flex-direction: column;
gap: 8px;
}

.data-table__search {
flex-basis: auto;
}

#content .data-table__table th,
#content .data-table__table td {
padding: 11px 13px;
}

#content .data-table__table th:first-child,
#content .data-table__table td:first-child {
min-width: 180px;
}
}

#content blockquote {
background: var(--surface-soft);
border-left: 4px solid var(--primary-accent);
Expand Down
87 changes: 87 additions & 0 deletions static/js/table-enhancements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
(function () {
"use strict";

function getTableLabel(table, index) {
var heading = table.previousElementSibling;

while (heading && !/^H[2-6]$/.test(heading.tagName)) {
heading = heading.previousElementSibling;
}

return heading ? heading.textContent.trim() : "Data table " + (index + 1);
}

function enhanceTable(table, index) {
if (table.closest(".data-table") || table.matches(".table-plain")) {
return;
}

var rows = Array.prototype.slice.call(table.tBodies).reduce(function (allRows, body) {
return allRows.concat(Array.prototype.slice.call(body.rows));
}, []);
var label = getTableLabel(table, index);
var wrapper = document.createElement("div");
var scroller = document.createElement("div");

wrapper.className = "data-table" + (rows.length >= 15 ? " data-table--large" : "");
scroller.className = "data-table__scroll";
scroller.tabIndex = 0;
scroller.setAttribute("role", "region");
scroller.setAttribute("aria-label", label + ", scrollable table");

table.parentNode.insertBefore(wrapper, table);
wrapper.appendChild(scroller);
scroller.appendChild(table);
table.classList.add("data-table__table");

if (rows.length < 15) {
return;
}

var toolbar = document.createElement("div");
var searchGroup = document.createElement("label");
var searchIcon = document.createElement("i");
var search = document.createElement("input");
var count = document.createElement("span");
var updateCount = function (visible) {
count.textContent = visible + " of " + rows.length + " entries";
};

toolbar.className = "data-table__toolbar";
searchGroup.className = "data-table__search";
searchIcon.className = "fas fa-search";
searchIcon.setAttribute("aria-hidden", "true");
search.type = "search";
search.className = "data-table__input";
search.placeholder = "Filter table…";
search.setAttribute("aria-label", "Filter " + label);
count.className = "data-table__count";
count.setAttribute("aria-live", "polite");

search.addEventListener("input", function () {
var query = search.value.trim().toLocaleLowerCase();
var visible = 0;

rows.forEach(function (row) {
var matches = !query || row.textContent.toLocaleLowerCase().indexOf(query) !== -1;
row.hidden = !matches;
if (matches) {
visible += 1;
}
});

updateCount(visible);
});

searchGroup.appendChild(searchIcon);
searchGroup.appendChild(search);
toolbar.appendChild(searchGroup);
toolbar.appendChild(count);
wrapper.insertBefore(toolbar, scroller);
updateCount(rows.length);
}

document.addEventListener("DOMContentLoaded", function () {
Array.prototype.forEach.call(document.querySelectorAll("#content table"), enhanceTable);
});
}());
Loading