-
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathindex.html
More file actions
114 lines (104 loc) · 4.78 KB
/
Copy pathindex.html
File metadata and controls
114 lines (104 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MikroTik NPK Archive</title>
<style>
* { box-sizing: border-box; }
body { font-family: ui-sans-serif, system-ui, sans-serif; max-width: 960px; margin: 0 auto; padding: 1rem; background: #1a1a1a; color: #e0e0e0; }
.header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
h1 { font-size: 1.25rem; font-weight: 600; margin: 0; }
.coffee { font-size: 1.00rem; color: #888; }
.coffee a { color: #6ab; }
.browse { margin-bottom: 1.25rem; padding: 0.75rem; background: #252525; border-radius: 6px; }
.browse h2 { font-size: 0.95rem; font-weight: 600; margin: 0 0 0.5rem 0; color: #ccc; }
.browse-row { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: baseline; margin-bottom: 0.5rem; }
.browse-row:last-child { margin-bottom: 0; }
.browse-row .label { font-size: 0.85rem; color: #888; margin-right: 0.25rem; }
.browse-row a { font-size: 0.9rem; }
.browse-row a + a { margin-left: 0.25rem; }
table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
th, td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid #333; }
th { color: #888; font-weight: 500; }
a { color: #6ab; text-decoration: none; }
a:hover { text-decoration: underline; }
.load { color: #888; }
.err { color: #c66; }
</style>
</head>
<body>
<div class="header">
<h1>MikroTik NPK Archive</h1>
<span class="coffee"><a href="https://buymeacoffee.com/icewzl" target="_blank" rel="noopener">Buy me a coffee</a></span>
</div>
<div id="browse" class="browse" style="display: none;">
<h2>Browse firmware</h2>
<div class="browse-row"><span class="label">By branch:</span> <span id="browse-branches"></span></div>
<div class="browse-row"><span class="label">By arch:</span> <span id="browse-archs"></span></div>
</div>
<div id="out" class="load">Loading…</div>
<script>
let list = [];
let selectedBranch = "";
let selectedArch = "";
const outEl = document.getElementById("out");
function escapeHtml(s) {
const div = document.createElement("div");
div.textContent = s;
return div.innerHTML;
}
function escapeAttr(s) {
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
}
function render() {
let rows = list;
if (selectedBranch) rows = rows.filter(r => r.branch === selectedBranch);
if (selectedArch) rows = rows.filter(r => r.arch === selectedArch);
if (rows.length === 0) {
outEl.innerHTML = "<p class=\"load\">No firmware in this folder.</p>";
return;
}
let html = "<table><thead><tr><th>Branch</th><th>Arch</th><th>File</th><th></th></tr></thead><tbody>";
rows.forEach(r => {
html += "<tr><td>" + escapeHtml(r.branch) + "</td><td>" + escapeHtml(r.arch) + "</td><td>" + escapeHtml(r.name) + "</td><td><a href=\"" + escapeAttr(r.path) + "\" download>Download</a></td></tr>";
});
html += "</tbody></table>";
outEl.innerHTML = html;
}
function setBranch(b) {
selectedBranch = b || "";
render();
}
function setArch(a) {
selectedArch = a || "";
render();
}
function fillBrowse() {
const branches = [...new Set(list.map(r => r.branch))].sort();
const archs = [...new Set(list.map(r => r.arch))].sort();
const browseBranches = document.getElementById("browse-branches");
const browseArchs = document.getElementById("browse-archs");
browseBranches.innerHTML = "<a href=\"#\" data-value=\"\">All</a> " + branches.map(b => "<a href=\"#\" data-value=\"" + escapeAttr(b) + "\">" + escapeHtml(b) + "</a>").join(" ");
browseArchs.innerHTML = "<a href=\"#\" data-value=\"\">All</a> " + archs.map(a => "<a href=\"#\" data-value=\"" + escapeAttr(a) + "\">" + escapeHtml(a) + "</a>").join(" ");
browseBranches.querySelectorAll("a").forEach(a => {
a.addEventListener("click", e => { e.preventDefault(); setBranch(a.getAttribute("data-value")); });
});
browseArchs.querySelectorAll("a").forEach(a => {
a.addEventListener("click", e => { e.preventDefault(); setArch(a.getAttribute("data-value")); });
});
document.getElementById("browse").style.display = "block";
}
fetch("firmware.json")
.then(r => { if (!r.ok) throw new Error(r.status); return r.json(); })
.then(data => {
list = data;
fillBrowse();
render();
})
.catch(() => {
outEl.innerHTML = "<p class=\"err\">Could not load firmware list. Ensure firmware.json exists (run build_index.py).</p>";
});
</script>
</body>
</html>