Skip to content

Instantly share code, notes, and snippets.

@lewdev
Last active February 14, 2023 09:03
Show Gist options
  • Select an option

  • Save lewdev/d747814c814efeb0968495954d4f9104 to your computer and use it in GitHub Desktop.

Select an option

Save lewdev/d747814c814efeb0968495954d4f9104 to your computer and use it in GitHub Desktop.
πŸ“¦ Gist Browser. Search and copy gist code
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<style>
a { text-decoration: none }
ul { margin-bottom: 0 }
</style>
<div class="container mt-2">
<div class="justify-content-between d-flex">
<input id="searchField" type="text" class="form-control w-100 mb-2" placeholder="Search..." oninput="render()"/>
<div class="p-2">
<button class="btn btn-light btn-sm rounded-circle" onclick="searchField.value='';render()" title="Clear">&times;</button>
</div>
</div>
<p id=o></p>
</div>
<dialog id="gist" class="rounded w-75 bg-light" style="top:3rem">
<button onclick="this.parentNode.close()" class="btn btn-light btn-sm rounded-circle" style="float:right">&times;</button>
<h2 id="gistTitle" class="d-block"></h2>
<div id="gistInfo"></div>
</dialog>
<dialog id="d" class="rounded w-75 bg-light" style="top:3rem">
<button onclick="this.parentNode.close()" class="btn btn-light btn-sm rounded-circle" style="float:right">&times;</button>
<h2 class="d-block">πŸ“„ <code id="filename"></code></h2>
<textarea id="dataStr" spellcheck="false" rows="10" class="w-100 form-control"></textarea>
<button class="btn btn-primary mt-2" onclick="navigator.clipboard.writeText(dataStr.value)">πŸ“‹ Copy</button>
</dialog>
<script>
const GithubApi = (() => {
// const crypt = (salt, text) => {
// const textToChars = (text) => text.split("").map((c) => c.charCodeAt(0));
// const byteHex = (n) => ("0" + Number(n).toString(16)).substr(-2);
// const applySaltToChar = (code) => textToChars(salt).reduce((a, b) => a ^ b, code);
// return text
// .split("")
// .map(textToChars)
// .map(applySaltToChar)
// .map(byteHex)
// .join("");
// };
//
const decrypt = (salt, encoded) => {
const textToChars = (text) => text.split("").map((c) => c.charCodeAt(0));
const applySaltToChar = (code) => textToChars(salt).reduce((a, b) => a ^ b, code);
return encoded
.match(/.{1,2}/g)
.map((hex) => parseInt(hex, 16))
.map(applySaltToChar)
.map((charCode) => String.fromCharCode(charCode))
.join("");
};
let username = null;
const tokenStr = "434c547b48764210731c566b60567e7e426b5d5c4a655c68465267686a71136c74671749161d7670";
const salt = "f2q23";
const TOKEN = decrypt(salt, tokenStr);
const API_URL = "https://api.github.com";
const get = path => fetch(`${API_URL}${path}`,{headers: {Authorization: `token ${TOKEN}`}})
.then(r => r.json())
.then(r => {if (r.message) alert(r.message); return r;})
.catch(error => err.innerHTML = error)
;
const handleCb = (data, cb) => { if (cb) cb(data); return data; };
return {
getUsername: () => username,
getUser: cb => get("/user").then(data => {
username = data.login;
return handleCb(data, cb);
}),
getGists: cb => get(`/users/${username}/gists?per_page=1000`)
.then(data => (
data.map(d => {
const { url, files, description } = d;
return {
url, description, files: Object.keys(files).map(key => {
const { filename, raw_url } = files[key];
return { filename, raw_url, public: d.public };
})
};
})
))
.then(data => handleCb(data, cb))
,
getRepos: cb => get(`/user/repos?per_page=100&type=public`)
.then(data => (
data.map(d => {
const { id, name, description, html_url, created_at, updated_at, stargazers_count, watchers, forks } = d;
return { id, name, description, html_url, private: d.private, created_at, updated_at, stargazers_count, watchers, forks };
})
))
.then(data => handleCb(data, cb))
,
// const getRepo = (repo, cb) => get(`/repos/${username}/${repo}`).then(data => handleCb(data, cb)),
};
})();
let gistList;
GithubApi.getUser(() => GithubApi.getGists(d => {gistList = d; render()}));
const renderFiles = files => `<ul>${files.map(f => `<li>πŸ“„ <button class="btn btn-light p-0" onclick="getRaw('${f.raw_url}')">${f.filename}</button></li>`).join``}</ul>`;
const getRaw = url => {
filename.innerHTML = dataStr.innerHTML = "";
fetch(url).then(d => d.text()).then(r => {
filename.innerHTML = url.split`/`.pop();
dataStr.innerHTML = r;
d.show();
})
};
const getGist = url => fetch(url).then(d => d.json()).then(({id, url, description, files}) => {
const username = GithubApi.getUsername();
const gistUrl = `https://gists.github.com/${username}/${id}`;
gistTitle.innerHTML = description;
gistInfo.innerHTML = `<div class="row">
<div class="col-6"><a href="${gistUrl}">πŸ”— View Gist</a></div>
<div class="col-6 text-right"><a href="${url}">πŸ’Ώ View Gist JSON</a></div>
<div class="col-12">${renderFiles(Object.keys(files).map(k => files[k]))}</div>
</div>`;
gist.show();
});
const render = () => o.innerHTML = `<table class="table table-striped table-hover table-bordered"><tbody>${gistList.filter(({description, files}) => {
const search = searchField.value;
if (!search) return true;
return description.includes(search) || files.some(f => f.filename.includes(search));
}).map(({url, description, files}) => `<tr><td>
<button class="btn btn-light p-0" onclick="getGist('${url}')">πŸ“ ${description}</button>
<div>${renderFiles(files)}</div>
</td></tr>`).join``}</tbody></table>`;
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment