-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
100 lines (94 loc) · 3.3 KB
/
index.html
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
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Index of /</title>
<meta name="referrer" content="no-referrer">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/devicon/2.16.0/devicon.min.css" integrity="sha512-BlFCHJWngPEHme4TwlEob6dPLfoNaQBTTISPwr4344nxR353w2vgGZ7GiSadbbeR20cJeeM0u1I2lAZuIZ1aOQ==" crossorigin="anonymous">
<style>
:root { color-scheme: light dark; white-space: nowrap; }
[class^=devicon-], [class*=" devicon-"] { text-decoration: none; }
td { padding: 0 4px; }
</style>
<script type="importmap">
{
"imports": {
"vue": "https://cdnjs.cloudflare.com/ajax/libs/vue/3.5.13/vue.esm-browser.prod.min.js"
},
"integrity": {
"https://cdnjs.cloudflare.com/ajax/libs/vue/3.5.13/vue.esm-browser.prod.min.js": "sha512-uAd8ed9WXz2BRMGwkFbb1ysGRedDfzE9cRqI1FscRYxnps82YWOwY7mw+a5xiDRawy6dJ+YxcJq6s4bQvU4WNw=="
}
}
</script>
<script type="module" async>
function* parseLinks(str) {
let ret, propertyName;
for (const [g0, g1, g2, g3, g4] of str.matchAll(/<([^>]*)|; *([^ =]*)|= *"((?:[^"\\]|\\.)*)"|= *([^,;]*)/gu))
switch (g0[0]) {
case '<':
if (ret) yield ret;
ret = {value: g1};
break;
case ';':
propertyName = g2;
break;
case '=':
ret[propertyName] = g4 ?? g3.replace(/\\(.)/gu, "$1");
break;
}
if (ret) yield ret;
}
function links(str) {
if (str instanceof Response) str = str.headers;
if (str instanceof Headers) str = str.get("Link");
if (!str) return {};
return Object.groupBy(parseLinks(str), x => x.rel);
}
async function* ghRequest(url) {
for (;;) {
const resp = await fetch(url);
if (!resp.ok) throw new Error(`request to repos endpoint returned ${resp.status}`);
yield* await resp.json();
const { next } = links(resp);
if (!next) break;
url = next[0].value;
}
}
async function toArrayPromise(iter) {
const ret = [];
for await (const v of iter) ret.push(v);
return ret;
}
import { createApp } from "vue";
(async() => {
const data = {
location: location,
repos: await toArrayPromise(ghRequest(`https://api.github.com/users/${location.hostname.split(/\./u)[0]}/repos`)),
bFmt: new Intl.NumberFormat(undefined, {style: "unit", unit: "byte", unitDisplay: "narrow", notation: "compact"}).format,
kbFmt: new Intl.NumberFormat(undefined, {style: "unit", unit: "kilobyte"}).format,
devicon: {
"Shell": "bash",
"HTML": "html5",
"CSS": "css3",
"C#": "csharp",
"F#": "fsharp",
"Vim script": "vim",
"Jupyter Notebook": "jupyter",
},
};
createApp({data() { return data; }}).mount("body");
})();
</script>
<h1>Index of /</h1>
<hr>
<table>
<template v-for="repo in repos" :key="repo.id">
<tr v-if="!repo.fork && !repo.archived && !repo.disabled && repo.homepage != location">
<td><a :href="repo.html_url" class="devicon-github-plain"></a>
<td :title="repo.language"><i :class="`devicon-${devicon[repo.language] ?? repo.language?.toLowerCase()}-plain`"></i>
<td><a :href="repo.has_pages ? `https://${repo.owner.login}.github.io/${repo.name}/` : null">{{repo.name}}/</a>
<td :title="repo.created_at">{{repo.created_at.replace(/T.*/u, "")}}
<td :title="repo.updated_at">{{repo.updated_at.replace(/T.*/u, "")}}
<td :title="kbFmt(repo.size)" style="text-align: right">{{bFmt(repo.size * 1000)}}
<td>{{repo.description}}
</template>
</table>
<hr>