Toggle diff (529 lines)
diff --git a/assets/js/sort-table.js b/assets/js/sort-table.js
deleted file mode 100644
index 26fbc49..0000000
--- a/assets/js/sort-table.js
+++ /dev/null
@@ -1,312 +0,0 @@
-// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
-/**
- * sort-table.js
- * A pure JavaScript (no dependencies) solution to make HTML
- * Tables sortable
- *
- * Copyright (c) 2013 Tyler Uebele
- * Released under the MIT license. See included LICENSE.txt
- * or http://opensource.org/licenses/MIT
- *
- * latest version available at https://github.com/tyleruebele/sort-table
- *
- * With changes Copyright (c) 2022 Ricardo Wurmus
- */
-
-/**
- * Sort the rows in a HTML Table
- *
- * @param Table The Table DOM object
- * @param col The zero-based column number by which to sort
- * @param dir Optional. The sort direction; pass 1 for asc; -1 for desc
- * @returns void
- */
-function sortTable(Table, col, dir) {
- var sortClass, i;
-
- // get previous sort column
- sortTable.sortCol = -1;
- sortClass = Table.className.match(/js-sort-\d+/);
- if (null != sortClass) {
- sortTable.sortCol = sortClass[0].replace(/js-sort-/, '');
- Table.className = Table.className.replace(new RegExp(' ?' + sortClass[0] + '\\b'), '');
- }
- // If sort column was not passed, use previous
- if ('undefined' === typeof col) {
- col = sortTable.sortCol;
- }
-
- if ('undefined' !== typeof dir) {
- // Accept -1 or 'desc' for descending. All else is ascending
- sortTable.sortDir = dir == -1 || dir == 'desc' ? -1 : 1;
- } else {
- // sort direction was not passed, use opposite of previous
- sortClass = Table.className.match(/js-sort-(a|de)sc/);
- if (null != sortClass && sortTable.sortCol == col) {
- sortTable.sortDir = 'js-sort-asc' == sortClass[0] ? -1 : 1;
- } else {
- sortTable.sortDir = 1;
- }
- }
- Table.className = Table.className.replace(/ ?js-sort-(a|de)sc/g, '');
-
- // update sort column
- Table.className += ' js-sort-' + col;
- sortTable.sortCol = col;
-
- // update sort direction
- Table.className += ' js-sort-' + (sortTable.sortDir == -1 ? 'desc' : 'asc');
-
- // get sort type
- if (col < Table.tHead.rows[Table.tHead.rows.length - 1].cells.length) {
- sortClass = Table.tHead.rows[Table.tHead.rows.length - 1].cells[col].className.match(/js-sort-[-\w]+/);
- }
- // Improved support for colspan'd headers
- for (i = 0; i < Table.tHead.rows[Table.tHead.rows.length - 1].cells.length; i++) {
- if (col == Table.tHead.rows[Table.tHead.rows.length - 1].cells[i].getAttribute('data-js-sort-colNum')) {
- sortClass = Table.tHead.rows[Table.tHead.rows.length - 1].cells[i].className.match(/js-sort-[-\w]+/);
- }
- }
- if (null != sortClass) {
- sortTable.sortFunc = sortClass[0].replace(/js-sort-/, '');
- } else {
- sortTable.sortFunc = 'string';
- }
- // Set the headers for the active column to have the decorative class
- Table.querySelectorAll('.js-sort-active').forEach(function(Node) {
- Node.className = Node.className.replace(/ ?js-sort-active\b/, '');
- });
- Table.querySelectorAll('[data-js-sort-colNum="' + col + '"]:not(:empty)').forEach(function(Node) {
- Node.className += ' js-sort-active';
- });
-
- // sort!
- var rows = [],
- TBody = Table.tBodies[0];
-
- for (i = 0; i < TBody.rows.length; i++) {
- rows[i] = TBody.rows[i];
- }
- if ('none' != sortTable.sortFunc) {
- rows.sort(sortTable.compareRow);
- }
-
- while (TBody.firstChild) {
- TBody.removeChild(TBody.firstChild);
- }
- for (i = 0; i < rows.length; i++) {
- TBody.appendChild(rows[i]);
- }
-}
-
-/**
- * Compare two table rows based on current settings
- *
- * @param RowA A TR DOM object
- * @param RowB A TR DOM object
- * @returns {number} 1 if RowA is greater, -1 if RowB, 0 if equal
- */
-sortTable.compareRow = function(RowA, RowB) {
- var valA, valB;
- if ('function' != typeof sortTable[sortTable.sortFunc]) {
- sortTable.sortFunc = 'string';
- }
- valA = sortTable[sortTable.sortFunc](RowA.cells[sortTable.sortCol]);
- valB = sortTable[sortTable.sortFunc](RowB.cells[sortTable.sortCol]);
-
- return valA == valB ? 0 : sortTable.sortDir * (valA > valB ? 1 : -1);
-};
-
-/**
- * Strip all HTML, no exceptions
- * @param html
- * @returns {string}
- */
-sortTable.stripTags = function(html) {
- return html.replace(/<\/?[a-z][a-z0-9]*\b[^>]*>/gi, '');
-};
-
-/**
- * Helper function that converts a table cell (TD) to a comparable value
- * Converts innerHTML to a timestamp, 0 for invalid dates
- *
- * @param Cell A TD DOM object
- * @returns {Number}
- */
-sortTable.date = function(Cell) {
- // If okDate library is available, Use it for advanced Date processing
- if (okDate) {
- var Date = okDate(sortTable.stripTags(Cell.innerHTML));
- return Date ? Date.getTime() : 0;
- } else {
- return (new Date(sortTable.stripTags(Cell.innerHTML))).getTime() || 0;
- }
-};
-
-/**
- * Helper function that converts a table cell (TD) to a comparable value
- * Converts innerHTML to a JS Number object
- *
- * @param Cell A TD DOM object
- * @returns {Number}
- */
-sortTable.number = function(Cell) {
- return Number(sortTable.stripTags(Cell.innerHTML).replace(/[^-\d.]/g, ''));
-};
-
-/**
- * Helper function that converts a table cell (TD) to a comparable value
- * Converts innerHTML to a lower case string for insensitive compare
- *
- * @param Cell A TD DOM object
- * @returns {String}
- */
-sortTable.string = function(Cell) {
- return sortTable.stripTags(Cell.innerHTML).toLowerCase();
-};
-
-/**
- * Helper function that converts a table cell (TD) to a comparable value
- *
- * @param Cell A TD DOM object
- * @returns {String}
- */
-sortTable.raw = function(Cell) {
- return Cell.innerHTML;
-};
-
-/**
- * Helper function that acts on a sortable data attribute of a table
- * cell (TD).
- *
- * @param Cell A TD DOM object
- * @returns {Number}
- */
-sortTable.position = function(Cell) {
- return Number(Cell.getAttribute('data-js-sort-position'));
-};
-
-
-/**
- * Helper function that converts a table cell (TD) to a comparable value
- * Captures the last space-delimited token from innerHTML
- *
- * @param Cell A TD DOM object
- * @returns {String}
- */
-sortTable.last = function(Cell) {
- return sortTable.stripTags(Cell.innerHTML).split(' ').pop().toLowerCase();
-};
-
-/**
- * Helper function that converts a table cell (TD) to a comparable value
- * Captures the value of the first childNode
- *
- * @param Cell A TD DOM object
- * @returns {String}
- */
-sortTable.input = function(Cell) {
- for (var i = 0; i < Cell.children.length; i++) {
- if ('object' == typeof Cell.children[i]
- && 'undefined' != typeof Cell.children[i].value
- ) {
- return Cell.children[i].value.toLowerCase();
- }
- }
-
- return sortTable.string(Cell);
-};
-
-/**
- * Helper function that prevents sorting by always returning null
- *
- * @param Cell A TD DOM object
- * @returns null
- */
-sortTable.none = function(Cell) {
- return null;
-};
-
-/**
- * Return the click handler appropriate to the specified Table and column
- *
- * @param Table Table to sort
- * @param col Column to sort by
- * @returns {Function} Click Handler
- */
-sortTable.getClickHandler = function(Table, col) {
- return function() {
- sortTable(Table, col);
- };
-};
-
-/**
- * Attach sortTable() calls to table header cells' onclick events
- * If the table(s) do not have a THead node, one will be created around the
- * first row
- */
-sortTable.init = function() {
- var THead, Tables, Handler;
- if (document.querySelectorAll) {
- Tables = document.querySelectorAll('table.js-sort-table');
- } else {
- Tables = document.getElementsByTagName('table');
- }
-
- for (var i = 0; i < Tables.length; i++) {
- // Because IE<8 doesn't support querySelectorAll, skip unclassed tables
- if (!document.querySelectorAll && null === Tables[i].className.match(/\bjs-sort-table\b/)) {
- continue;
- }
-
- // Prevent repeat processing
- if (Tables[i].attributes['data-js-sort-table']) {
- continue;
- }
-
- // Ensure table has a tHead element
- if (!Tables[i].tHead) {
- THead = document.createElement('thead');
- THead.appendChild(Tables[i].rows[0]);
- Tables[i].insertBefore(THead, Tables[i].children[0]);
- } else {
- THead = Tables[i].tHead;
- }
-
- // Attach click events to table header
- for (var rowNum = 0; rowNum < THead.rows.length; rowNum++) {
- for (var cellNum = 0, colNum = 0; cellNum < THead.rows[rowNum].cells.length; cellNum++) {
- console.log(cellNum, rowNum, THead);
- // Define which column the header should invoke sorting for
- THead.rows[rowNum].cells[cellNum].setAttribute('data-js-sort-colNum', colNum);
- Handler = sortTable.getClickHandler(Tables[i], colNum);
- window.addEventListener
- ? THead.rows[rowNum].cells[cellNum].addEventListener('click', Handler)
- : window.attachEvent && THead.rows[rowNum].cells[cellNum].attachEvent('onclick', Handler);
- colNum += THead.rows[rowNum].cells[cellNum].colSpan;
- }
- }
-
- // Mark table as processed
- Tables[i].setAttribute('data-js-sort-table', 'true')
- }
-
- // Add default styles as the first style in head so they can be easily overwritten by user styles
- var element = document.createElement('style');
- document.head.insertBefore(element, document.head.childNodes[0]);
- var sheet = element.sheet;
- sheet.insertRule('table.js-sort-asc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25b2";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0);
- sheet.insertRule('table.js-sort-desc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25bc";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0);
-};
-
-// Run sortTable.init() when the page loads
-window.addEventListener
- ? window.addEventListener('load', sortTable.init, false)
- : window.attachEvent && window.attachEvent('onload', sortTable.init)
- ;
-
-// Shim for IE11's lack of NodeList.prototype.forEach
-if (typeof NodeList.prototype.forEach !== "function") {
- NodeList.prototype.forEach = Array.prototype.forEach;
-}
-// @license-end
diff --git a/assets/mumi.scss b/assets/mumi.scss
index 2581b2c..f8ca586 100644
--- a/assets/mumi.scss
+++ b/assets/mumi.scss
@@ -9,6 +9,31 @@ $commit_header: #005cc5;
@import "pico/scss/pico";
@import "_theme-switcher.scss";
+// Additional colors from assets/pico/docs/js/src/material-design-colors.js
+// Blue
+$blue-50: #e3f2fd !default;
+$blue-100: #bbdefb !default;
+$blue-200: #90caf9 !default;
+$blue-300: #64b5f6 !default;
+$blue-400: #42a5f5 !default;
+$blue-500: #2196f3 !default;
+$blue-600: #1e88e5 !default;
+$blue-700: #1976d2 !default;
+$blue-800: #1565c0 !default;
+$blue-900: #0d47a1 !default;
+
+// Purple
+$purple-50: #f3e5f5 !default;
+$purple-100: #e1bee7 !default;
+$purple-200: #ce93d8 !default;
+$purple-300: #ba68c8 !default;
+$purple-400: #ab47bc !default;
+$purple-500: #9c27b0 !default;
+$purple-600: #8e24aa !default;
+$purple-700: #7b1fa2 !default;
+$purple-800: #6a1b9a !default;
+$purple-900: #4a148c !default;
+
:root {
--spacing: .5em;
--font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
@@ -266,6 +291,58 @@ nav span.navbar-text {
height: 1.3em;
}
+.issue-list {
+ padding: 0;
+}
+.issue-list-item {
+ list-style-type: none;
+}
+.issue-list-item-metadata {
+ color: dimgray;
+ font-size: smaller;
+}
+.issue-list .tags {
+ list-style-type: none;
+ padding: 0;
+ display: inline;
+}
+.issue-list .tag, .issue-list .severity {
+ display: inline;
+}
+.issue-list .tag a, .issue-list .severity a {
+ padding: 0 0.2em;
+ color: white;
+ background-color: $blue-900;
+ margin: auto 0.25em;
+ font-size: smaller;
+}
+.issue-list .severity-critical a,
+.issue-list .severity-grave a,
+.issue-list .severity-serious a,
+.issue-list .severity-important a,
+.issue-list .tag-security a,
+.issue-list .tag-help a {
+ background-color: $red-900;
+}
+.issue-list .severity-minor a,
+.issue-list .severity-wishlist a,
+.issue-list .tag-easy a {
+ background-color: $green-800;
+}
+.issue-list .tag-wontfix a,
+.issue-list .tag-moreinfo a,
+.issue-list .tag-unreproducible a,
+.issue-list .tag-fixed a,
+.issue-list .tag-notabug a {
+ background-color: $amber-900;
+}
+.issue-list .tag-patch a,
+.issue-list .tag-fixed a,
+.issue-list .tag-pending a,
+.issue-list .tag-confirmed a {
+ background-color: $purple-800;
+}
+
body > footer {
border-color: var(--nav-border-color);
border-style: dashed none none none;
diff --git a/mumi/web/view/html.scm b/mumi/web/view/html.scm
index ae311fe..d6d219f 100644
--- a/mumi/web/view/html.scm
+++ b/mumi/web/view/html.scm
@@ -80,9 +80,7 @@
"Now with even more " (span (@ (class "lambda")) "λ") "! ")
(p "This is free software. Download the "
(a (@ (href "https://git.savannah.gnu.org/cgit/guix/mumi.git"))
- "source code here") "."))
- (script
- (@ (src "/js/sort-table.js")))))))
+ "source code here") "."))))))
(define* (search-form #:key (standalone? #f) (text ""))
`(form (@ (id "search")
@@ -272,43 +270,16 @@ simple query language. Here is a list of supported query terms:")
(article
(h4 "Recent activity "
(small (a (@ (href "recent")) "(More)")))
- (table
- (@ (class "js-sort-table"))
- (thead
- (tr (@ (class "heading"))
- (th (@ (class "js-sort-number")) "ID")
- (th "Subject")
- (th (@ (class "js-sort-position")) "Date submitted")
- (th "Status")))
- (tbody
- ,@(list-of-bugs (recent-bugs 10)))))
+ ,(list-of-bugs (recent-bugs 10)))
(article
(h4 "Forgotten issues "
(small (a (@ (href "forgotten")) "(More)")))
- (table
- (@ (class "js-sort-table"))
- (thead
- (tr (@ (class "heading"))
- (th (@ (class "js-sort-number")) "ID")
- (th "Subject")
- (th (@ (class "js-sort-position")) "Date submitted")
- (th "Status")))
- (tbody
- ,@(list-of-bugs (forgotten-issues 10)))))
+ ,(list-of-bugs (forgotten-issues 10)))
(article
(h4 "Priority bugs")
- (table
- (@ (class "js-sort-table"))
- (thead
- (tr (@ (class "heading"))
- (th (@ (class "js-sort-number")) "ID")
- (th "Subject")
- (th (@ (class "js-sort-position")) "Date submitted")
- (th "Status")))
- (tbody
- ,@(priority-bugs))))))))
+ ,(priority-bugs))))))
(define (help)
(layout
@@ -725,44 +696,45 @@ currently disabled."))
,comment-box))))))
(define (list-of-bugs bugs)
- "Return table rows for all BUGS."
- (map (lambda (bug)
- (let ((id (number->string (bug-num bug))))
- `(tr (@ (class ,(bug-severity bug)))
- (td ,(or id "-"))
- (td
- ,@(if (member (bug-severity bug) '("serious" "important"))
- `((svg (@ (xmlns"http://www.w3.org/2000/svg")
- (xmlns:xlink "http://www.w3.org/1999/xlink")
- (viewBox "0 0 14 16")
- (version "1.1")
- (height "1rem")
- (width "1rem")
- (aria-hidden "true"))
- (title ,(bug-severity bug))
- (path (@ (fill-rule "evenodd")
- (d "\
-M7 2.3c3.14 0 5.7 2.56 5.7 5.7\
-s-2.56 5.7-5.7 5.7A5.71 5.71 0 011.3 8\
-c0-3.14 2.56-5.7 5.7-5.7z\
-M7 1C3.14 1 0 4.14 0 8\
-s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7z\
-m1 3H6v5h2V4zm0 6H6v2h2v-2z")))))
- '())
- ,@(map (lambda (tag)
- `(a (@ (href ,(string-append "search?query=tag:" tag)))
- (span
- (@ (class ,(string-append "badge badge-info " tag)))
- ,tag)))
- (bug-tags bug))
- ,(if id
- `(a (@ (href ,(string-append "/" id)))
- ,(bug-subject* bug))
- (bug-subject* bug)))
- (td (@ (data-js-sort-position ,(date->string (bug-date bug) "~s")))
- ,(date->string (bug-date bug)))
- (td ,(status-tag bug)))))
- bugs))
+ "Return list of all BUGS."
+ `(ul (@ (class "issue-list"))
+ ,@(map (lambda (bug)
+ `(li (@ (class "issue-list-item"))
+ (a (@ (href ,(string-append "/" (number->string (bug-num bug)))))
+ ,(bug-subject* bug))
+ (ul (@ (class "tags"))
+ ,@(let ((severity (bug-severity bug)))
+ (if (and severity
+ (not (string=? severity "normal")))
+ `((li (@ (class ,(string-join (list "severity"
+