This commit is contained in:
parent
650f381148
commit
11fa3d1558
38 changed files with 819 additions and 148 deletions
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
#app-loading {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
z-index: 100;
|
||||
background: salmon;
|
||||
inset: 0;
|
||||
align-content: center;
|
||||
font-family: Banquise;
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
background: salmon;
|
||||
|
||||
p {
|
||||
width: 10ch;
|
||||
|
|
@ -25,15 +25,19 @@
|
|||
0% {
|
||||
content: "";
|
||||
}
|
||||
|
||||
25% {
|
||||
content: ".";
|
||||
}
|
||||
|
||||
50% {
|
||||
content: "..";
|
||||
}
|
||||
|
||||
75% {
|
||||
content: "...";
|
||||
}
|
||||
|
||||
100% {
|
||||
content: "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 749 B After Width: | Height: | Size: 750 B |
96
public/sortable-table.css
Normal file
96
public/sortable-table.css
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
.sr-only {
|
||||
position: absolute;
|
||||
top: -30em;
|
||||
}
|
||||
|
||||
table.sortable td, table.sortable th {
|
||||
width: 8em;
|
||||
padding: 0.125em 0.25em;
|
||||
}
|
||||
|
||||
table.sortable th {
|
||||
position: relative;
|
||||
border-bottom: thin solid #888;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.sortable th.no-sort {
|
||||
padding-top: 0.35em;
|
||||
}
|
||||
|
||||
table.sortable th:nth-child(5) {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
table.sortable th button {
|
||||
cursor: pointer;
|
||||
inset: 0;
|
||||
display: inline;
|
||||
width: 100%;
|
||||
margin: 1px;
|
||||
padding: 4px;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
table.sortable th button span {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
table.sortable th[aria-sort="descending"] span::after {
|
||||
content: "▼";
|
||||
top: 0;
|
||||
font-size: 100%;
|
||||
color: currentcolor;
|
||||
}
|
||||
|
||||
table.sortable th[aria-sort="ascending"] span::after {
|
||||
content: "▲";
|
||||
top: 0;
|
||||
font-size: 100%;
|
||||
color: currentcolor;
|
||||
}
|
||||
|
||||
table.show-unsorted-icon th:not([aria-sort]) button span::after {
|
||||
content: "♢";
|
||||
position: relative;
|
||||
top: -3px;
|
||||
left: -4px;
|
||||
font-size: 100%;
|
||||
color: currentcolor;
|
||||
}
|
||||
|
||||
table.sortable td.num {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
table.sortable tbody tr:nth-child(odd) {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
/* Focus and hover styling */
|
||||
|
||||
table.sortable th button:focus, table.sortable th button:hover {
|
||||
padding: 2px;
|
||||
border: 2px solid currentcolor;
|
||||
background-color: #e5f4ff;
|
||||
}
|
||||
|
||||
table.sortable th button:focus span, table.sortable th button:hover span {
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
table.sortable th:not([aria-sort]) button:focus span::after, table.sortable
|
||||
th:not([aria-sort])
|
||||
button:hover
|
||||
span::after {
|
||||
content: "▼";
|
||||
top: 0;
|
||||
font-size: 100%;
|
||||
color: currentcolor;
|
||||
}
|
||||
167
public/sortable-table.js
Normal file
167
public/sortable-table.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* This content is licensed according to the W3C Software License at
|
||||
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
|
||||
*
|
||||
* File: sortable-table.js
|
||||
*
|
||||
* Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
class SortableTable {
|
||||
constructor(tableNode) {
|
||||
this.tableNode = tableNode;
|
||||
|
||||
this.columnHeaders = tableNode.querySelectorAll("thead th");
|
||||
|
||||
this.sortColumns = [];
|
||||
|
||||
for (var i = 0; i < this.columnHeaders.length; i++) {
|
||||
var ch = this.columnHeaders[i];
|
||||
var buttonNode = ch.querySelector("button");
|
||||
if (buttonNode) {
|
||||
this.sortColumns.push(i);
|
||||
buttonNode.setAttribute("data-column-index", i);
|
||||
buttonNode.addEventListener("click", this.handleClick.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
this.optionCheckbox = document.querySelector(
|
||||
"input[type=\"checkbox\"][value=\"show-unsorted-icon\"]",
|
||||
);
|
||||
|
||||
if (this.optionCheckbox) {
|
||||
this.optionCheckbox.addEventListener(
|
||||
"change",
|
||||
this.handleOptionChange.bind(this),
|
||||
);
|
||||
if (this.optionCheckbox.checked) {
|
||||
this.tableNode.classList.add("show-unsorted-icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(event) {
|
||||
var tgt = event.currentTarget;
|
||||
this.setColumnHeaderSort(tgt.getAttribute("data-column-index"));
|
||||
}
|
||||
|
||||
handleOptionChange(event) {
|
||||
var tgt = event.currentTarget;
|
||||
|
||||
if (tgt.checked) {
|
||||
this.tableNode.classList.add("show-unsorted-icon");
|
||||
} else {
|
||||
this.tableNode.classList.remove("show-unsorted-icon");
|
||||
}
|
||||
}
|
||||
|
||||
/* EVENT HANDLERS */
|
||||
|
||||
setColumnHeaderSort(columnIndex) {
|
||||
if (typeof columnIndex === "string") {
|
||||
columnIndex = parseInt(columnIndex);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.columnHeaders.length; i++) {
|
||||
var ch = this.columnHeaders[i];
|
||||
var buttonNode = ch.querySelector("button");
|
||||
if (i === columnIndex) {
|
||||
var value = ch.getAttribute("aria-sort");
|
||||
if (value === "descending") {
|
||||
ch.setAttribute("aria-sort", "ascending");
|
||||
this.sortColumn(
|
||||
columnIndex,
|
||||
"ascending",
|
||||
ch.classList.contains("num"),
|
||||
);
|
||||
} else {
|
||||
ch.setAttribute("aria-sort", "descending");
|
||||
this.sortColumn(
|
||||
columnIndex,
|
||||
"descending",
|
||||
ch.classList.contains("num"),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (ch.hasAttribute("aria-sort") && buttonNode) {
|
||||
ch.removeAttribute("aria-sort");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sortColumn(columnIndex, sortValue, isNumber) {
|
||||
function compareValues(a, b) {
|
||||
if (sortValue === "ascending") {
|
||||
if (a.value === b.value) {
|
||||
return 0;
|
||||
} else {
|
||||
if (isNumber) {
|
||||
return a.value - b.value;
|
||||
} else {
|
||||
return a.value < b.value ? -1 : 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (a.value === b.value) {
|
||||
return 0;
|
||||
} else {
|
||||
if (isNumber) {
|
||||
return b.value - a.value;
|
||||
} else {
|
||||
return a.value > b.value ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof isNumber !== "boolean") {
|
||||
isNumber = false;
|
||||
}
|
||||
|
||||
var tbodyNode = this.tableNode.querySelector("tbody");
|
||||
var rowNodes = [];
|
||||
var dataCells = [];
|
||||
|
||||
var rowNode = tbodyNode.firstElementChild;
|
||||
|
||||
var index = 0;
|
||||
while (rowNode) {
|
||||
rowNodes.push(rowNode);
|
||||
var rowCells = rowNode.querySelectorAll("th, td");
|
||||
var dataCell = rowCells[columnIndex];
|
||||
|
||||
var data = {};
|
||||
data.index = index;
|
||||
data.value = dataCell.textContent.toLowerCase().trim();
|
||||
if (isNumber) {
|
||||
data.value = parseFloat(data.value);
|
||||
}
|
||||
dataCells.push(data);
|
||||
rowNode = rowNode.nextElementSibling;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
dataCells.sort(compareValues);
|
||||
|
||||
// remove rows
|
||||
while (tbodyNode.firstChild) {
|
||||
tbodyNode.removeChild(tbodyNode.lastChild);
|
||||
}
|
||||
|
||||
// add sorted rows
|
||||
for (var i = 0; i < dataCells.length; i += 1) {
|
||||
tbodyNode.appendChild(rowNodes[dataCells[i].index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize sortable table buttons
|
||||
window.addEventListener("load", function() {
|
||||
var sortableTables = document.querySelectorAll("table.sortable");
|
||||
for (var i = 0; i < sortableTables.length; i++) {
|
||||
new SortableTable(sortableTables[i]);
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue