breadcrumbs
This commit is contained in:
parent
1abbe63776
commit
f3d3e77f0f
5 changed files with 293 additions and 5 deletions
|
|
@ -1,9 +1,12 @@
|
|||
/* Based on the default lighttpd styles, this butters up the UI */
|
||||
|
||||
|
||||
|
||||
body {
|
||||
font-family: "Poppins", sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
body>h2 {
|
||||
|
|
@ -21,6 +24,25 @@ div.foot {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.breadcrumbs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px;
|
||||
height: 34px;
|
||||
.path-next {
|
||||
margin: 0 5px;
|
||||
height: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.crumb {
|
||||
align-items: center;
|
||||
color: black;
|
||||
display: flex;
|
||||
font-family: "Poppins", sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
|
|
@ -33,6 +55,10 @@ hr {
|
|||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
hr.full-width {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -41,7 +67,6 @@ hr {
|
|||
margin: 10px;
|
||||
box-sizing: border-box;
|
||||
font-family: "Poppins", sans-serif;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
|
|
|
|||
4
assets/images/home.svg
Normal file
4
assets/images/home.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="22" height="20" viewBox="0 0 22 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.6923 18.5H17.7692C18.4492 18.5 19 17.9886 19 17.3571V8.48489C19 8.14203 18.8346 7.81775 18.5485 7.6006L12.3446 2.88714C12.0146 2.63714 11.6015 2.5 11.1762 2.5H10.8246C10.3985 2.5 9.98539 2.63714 9.6554 2.88714L3.45154 7.6006C3.16538 7.81775 3 8.14203 3 8.48489V17.3571C3 17.9886 3.55076 18.5 4.23076 18.5H7.30766C7.64766 18.5 7.92304 18.2443 7.92304 17.9286V12.7857C7.92304 12.1543 8.4738 11.6428 9.1538 11.6428H12.8461C13.5261 11.6428 14.0768 12.1543 14.0768 12.7857V17.9286C14.0768 18.2443 14.3523 18.5 14.6923 18.5Z" fill="black"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 659 B |
4
assets/images/next.svg
Normal file
4
assets/images/next.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="7" height="10" viewBox="0 0 7 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.316 2.17H1.926L5.314 5.376L1.926 8.596H0.316L3.704 5.376L0.316" fill="black"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 200 B |
|
|
@ -96,8 +96,39 @@ window.onload = function () {
|
|||
const { files, folders } = extractDirectoryListing();
|
||||
console.log('Files:', files);
|
||||
console.log('Folders:', folders);
|
||||
const listDiv = document.querySelector('div.list');
|
||||
|
||||
// insert a new div before div.list
|
||||
// Header with breadcrumbs
|
||||
const usbRoot = "/usb-butter/";
|
||||
const h2Path = document.querySelector('h2').textContent;
|
||||
console.log("H2 Path:", h2Path);
|
||||
const path = h2Path.replace('Index of ', '').replace(usbRoot, '');
|
||||
console.log("Path:", path);
|
||||
|
||||
const breadcrumbs = document.createElement("div");
|
||||
breadcrumbs.classList.add('breadcrumbs');
|
||||
let breadcrumbHTML = `
|
||||
<a href="/"><img class="home-icon" src="/assets/images/home.svg" alt="home"></a>
|
||||
<a href="${usbRoot}" class="crumb"><img class="path-next" src="/assets/images/next.svg">Explore</a>
|
||||
`;
|
||||
pathSteps = path.split('/');
|
||||
let pathToHere = usbRoot;
|
||||
pathSteps.forEach((step, index) => {
|
||||
pathToHere += step + '/';
|
||||
if (step !== "") {
|
||||
breadcrumbHTML += `
|
||||
<a href="${pathToHere}" class="crumb"><img class="path-next" src="/assets/images/next.svg">${step}</a>`;
|
||||
}
|
||||
});
|
||||
breadcrumbs.innerHTML = breadcrumbHTML;
|
||||
listDiv.parentNode.insertBefore(breadcrumbs, listDiv);
|
||||
|
||||
// hr
|
||||
const fullWithHR = document.createElement('hr');
|
||||
fullWithHR.classList.add('full-width');
|
||||
listDiv.parentNode.insertBefore(fullWithHR, listDiv);
|
||||
|
||||
// Create a folder listing
|
||||
const folderListing = document.createElement("div");
|
||||
folderListing.classList.add('folder-list');
|
||||
folderListing.innerHTML = '<h2>Folders</h2>';
|
||||
|
|
@ -111,7 +142,6 @@ window.onload = function () {
|
|||
});
|
||||
|
||||
// do the insertion
|
||||
const listDiv = document.querySelector('div.list');
|
||||
listDiv.parentNode.insertBefore(folderListing, listDiv);
|
||||
|
||||
if (folders.length > 0 && files.length > 0) {
|
||||
|
|
|
|||
225
simulated-usb-butter/johns_folder/index.html
Normal file
225
simulated-usb-butter/johns_folder/index.html
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
---
|
||||
layout: empty
|
||||
---
|
||||
|
||||
<!-- This simulates a drive being plugged in. CI moves this into place as /usb-butter. You can too. -->
|
||||
<!-- Mostly, this is a copy paste of the real dirlisting. We modify the JS and CSS links to load ones from this repo. -->
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Index of /usb-butter/johns_folder/</title>
|
||||
<meta name="viewport" content="initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="{{ site.baseurl }}/assets/css/butter-dir-listing.css">
|
||||
<script src="{{ site.baseurl }}/assets/js/butter-dir-listing.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Index of /usb-butter/johns_folder/</h2>
|
||||
<div class="list">
|
||||
<table summary="Directory Listing" cellpadding="0" cellspacing="0">
|
||||
<thead><tr><th class="n">Name</th><th class="m">Last Modified</th><th class="s">Size</th><th class="t">Type</th></tr></thead>
|
||||
<tbody>
|
||||
<tr class="d"><td class="n"><a href="../">..</a>/</td><td class="m"> </td><td class="s">- </td><td class="t">Directory</td></tr>
|
||||
<tr class="d"><td class="n"><a href="johns_subfolder1/">johns_subfolder1</a>/</td><td class="m">2024-Apr-30 17:11:52</td><td class="s">- </td><td class="t">Directory</td></tr>
|
||||
<tr class="d"><td class="n"><a href="johns_subfolder2/">johns_subfolder2</a>/</td><td class="m">2024-Apr-30 17:11:54</td><td class="s">- </td><td class="t">Directory</td></tr>
|
||||
<tr><td class="n"><a href="lub.zip">lub.zip</a></td><td class="m">2024-May-01 15:38:22</td><td class="s">30.3M</td><td class="t">application/zip</td></tr>
|
||||
<tr><td class="n"><a href="test.txt">test.txt</a></td><td class="m">2024-Mar-07 14:55:59</td><td class="s">0.0K</td><td class="t">text/plain;charset=utf-8</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="foot">lighttpd/1.4.69</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// <!--
|
||||
|
||||
var click_column;
|
||||
var name_column = 0;
|
||||
var date_column = 1;
|
||||
var size_column = 2;
|
||||
var type_column = 3;
|
||||
var prev_span = null;
|
||||
|
||||
if (typeof(String.prototype.localeCompare) === 'undefined') {
|
||||
String.prototype.localeCompare = function(str, locale, options) {
|
||||
return ((this == str) ? 0 : ((this > str) ? 1 : -1));
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof(String.prototype.toLocaleUpperCase) === 'undefined') {
|
||||
String.prototype.toLocaleUpperCase = function() {
|
||||
return this.toUpperCase();
|
||||
};
|
||||
}
|
||||
|
||||
function get_inner_text(el) {
|
||||
if((typeof el == 'string')||(typeof el == 'undefined'))
|
||||
return el;
|
||||
if(el.innerText)
|
||||
return el.innerText;
|
||||
else {
|
||||
var str = "";
|
||||
var cs = el.childNodes;
|
||||
var l = cs.length;
|
||||
for (var i=0;i<l;i++) {
|
||||
if (cs[i].nodeType==1) str += get_inner_text(cs[i]);
|
||||
else if (cs[i].nodeType==3) str += cs[i].nodeValue;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function isdigit(c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
function unit_multiplier(unit) {
|
||||
return (unit=='K') ? 1000
|
||||
: (unit=='M') ? 1000000
|
||||
: (unit=='G') ? 1000000000
|
||||
: (unit=='T') ? 1000000000000
|
||||
: (unit=='P') ? 1000000000000000
|
||||
: (unit=='E') ? 1000000000000000000 : 1;
|
||||
}
|
||||
|
||||
var li_date_regex=/(\d{4})-(\w{3})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/;
|
||||
|
||||
var li_mon = ['Jan','Feb','Mar','Apr','May','Jun',
|
||||
'Jul','Aug','Sep','Oct','Nov','Dec'];
|
||||
|
||||
function li_mon_num(mon) {
|
||||
var i; for (i = 0; i < 12 && mon != li_mon[i]; ++i); return i;
|
||||
}
|
||||
|
||||
function li_date_cmp(s1, s2) {
|
||||
var dp1 = li_date_regex.exec(s1)
|
||||
var dp2 = li_date_regex.exec(s2)
|
||||
for (var i = 1; i < 7; ++i) {
|
||||
var cmp = (2 != i)
|
||||
? parseInt(dp1[i]) - parseInt(dp2[i])
|
||||
: li_mon_num(dp1[2]) - li_mon_num(dp2[2]);
|
||||
if (0 != cmp) return cmp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function sortfn_then_by_name(a,b,sort_column) {
|
||||
if (sort_column == name_column || sort_column == type_column) {
|
||||
var ad = (a.cells[type_column].innerHTML === 'Directory');
|
||||
var bd = (b.cells[type_column].innerHTML === 'Directory');
|
||||
if (ad != bd) return (ad ? -1 : 1);
|
||||
}
|
||||
var at = get_inner_text(a.cells[sort_column]);
|
||||
var bt = get_inner_text(b.cells[sort_column]);
|
||||
var cmp;
|
||||
if (sort_column == name_column) {
|
||||
if (at == '../') return -1;
|
||||
if (bt == '../') return 1;
|
||||
}
|
||||
if (a.cells[sort_column].className == 'int') {
|
||||
cmp = parseInt(at)-parseInt(bt);
|
||||
} else if (sort_column == date_column) {
|
||||
var ad = isdigit(at.substr(0,1));
|
||||
var bd = isdigit(bt.substr(0,1));
|
||||
if (ad != bd) return (!ad ? -1 : 1);
|
||||
cmp = li_date_cmp(at,bt);
|
||||
} else if (sort_column == size_column) {
|
||||
var ai = parseInt(at, 10) * unit_multiplier(at.substr(-1,1));
|
||||
var bi = parseInt(bt, 10) * unit_multiplier(bt.substr(-1,1));
|
||||
if (at.substr(0,1) == '-') ai = -1;
|
||||
if (bt.substr(0,1) == '-') bi = -1;
|
||||
cmp = ai - bi;
|
||||
} else {
|
||||
cmp = at.toLocaleUpperCase().localeCompare(bt.toLocaleUpperCase());
|
||||
if (0 != cmp) return cmp;
|
||||
cmp = at.localeCompare(bt);
|
||||
}
|
||||
if (0 != cmp || sort_column == name_column) return cmp;
|
||||
return sortfn_then_by_name(a,b,name_column);
|
||||
}
|
||||
|
||||
function sortfn(a,b) {
|
||||
return sortfn_then_by_name(a,b,click_column);
|
||||
}
|
||||
|
||||
function resort(lnk) {
|
||||
var span = lnk.childNodes[1];
|
||||
var table = lnk.parentNode.parentNode.parentNode.parentNode;
|
||||
var rows = new Array();
|
||||
for (var j=1;j<table.rows.length;j++)
|
||||
rows[j-1] = table.rows[j];
|
||||
click_column = lnk.parentNode.cellIndex;
|
||||
rows.sort(sortfn);
|
||||
|
||||
if (prev_span != null) prev_span.innerHTML = '';
|
||||
if (span.getAttribute('sortdir')=='down') {
|
||||
span.innerHTML = '↑';
|
||||
span.setAttribute('sortdir','up');
|
||||
rows.reverse();
|
||||
} else {
|
||||
span.innerHTML = '↓';
|
||||
span.setAttribute('sortdir','down');
|
||||
}
|
||||
for (var i=0;i<rows.length;i++)
|
||||
table.tBodies[0].appendChild(rows[i]);
|
||||
prev_span = span;
|
||||
}
|
||||
|
||||
function init_sort(init_sort_column, ascending) {
|
||||
var tables = document.getElementsByTagName("table");
|
||||
for (var i = 0; i < tables.length; i++) {
|
||||
var table = tables[i];
|
||||
//var c = table.getAttribute("class")
|
||||
//if (-1 != c.split(" ").indexOf("sort")) {
|
||||
var row = table.rows[0].cells;
|
||||
for (var j = 0; j < row.length; j++) {
|
||||
var n = row[j];
|
||||
if (n.childNodes.length == 1 && n.childNodes[0].nodeType == 3) {
|
||||
var link = document.createElement("a");
|
||||
var title = n.childNodes[0].nodeValue.replace(/:$/, "");
|
||||
link.appendChild(document.createTextNode(title));
|
||||
link.setAttribute("href", "#");
|
||||
link.setAttribute("class", "sortheader");
|
||||
link.setAttribute("onclick", "resort(this);return false;");
|
||||
var arrow = document.createElement("span");
|
||||
arrow.setAttribute("class", "sortarrow");
|
||||
arrow.appendChild(document.createTextNode(":"));
|
||||
link.appendChild(arrow)
|
||||
n.replaceChild(link, n.firstChild);
|
||||
}
|
||||
}
|
||||
var lnk = row[init_sort_column].firstChild;
|
||||
if (ascending) {
|
||||
var span = lnk.childNodes[1];
|
||||
span.setAttribute('sortdir','down');
|
||||
}
|
||||
resort(lnk);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
function init_sort_from_query() {
|
||||
var urlParams = new URLSearchParams(location.search);
|
||||
var c = 0;
|
||||
var o = 0;
|
||||
switch (urlParams.get('C')) {
|
||||
case "N": c=0; break;
|
||||
case "M": c=1; break;
|
||||
case "S": c=2; break;
|
||||
case "T":
|
||||
case "D": c=3; break;
|
||||
}
|
||||
switch (urlParams.get('O')) {
|
||||
case "A": o=1; break;
|
||||
case "D": o=0; break;
|
||||
}
|
||||
init_sort(c,o);
|
||||
}
|
||||
init_sort_from_query();
|
||||
|
||||
// -->
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue