mirror of
https://github.com/techgaun/active-forks.git
synced 2024-12-22 13:32:14 +01:00
UI and other changes (#1)
* Use bootstrap-v4 * Add favicon * Change showError to showMsg * Make it bookmarkable * Few changes * Show spinner while loading * Hide spinner by default
This commit is contained in:
parent
8e17912802
commit
4c080d63a6
3 changed files with 143 additions and 54 deletions
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 361 KiB |
61
index.html
61
index.html
|
@ -1,36 +1,59 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Find Active Github Forks</title>
|
<meta charset="UTF-8">
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
<title>Active GitHub Forks</title>
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding-top: 2rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.black {
|
||||||
|
color: #292b2c;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-offset-2 col-8">
|
<div class="col-sm-12 col-lg-12">
|
||||||
<div class="panel panel-default">
|
<div class="card">
|
||||||
<div class="panel-heading text-center">
|
<div class="card-header text-center">
|
||||||
<h3>Find Active Github Forks</h3>
|
<h3>
|
||||||
|
<a href="https://github.com/techgaun/active-forks" class="black">
|
||||||
|
<i class="fa fa-github-alt pull-left" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
Active GitHub Forks
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-body">
|
<div class="card-block">
|
||||||
<form id="form" class="form-horizontal" role="form">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<form id="form" role="form">
|
||||||
<input id="repo" class="form-control" type="text" placeholder="techgaun/github-dorks">
|
<div class="input-group">
|
||||||
<span class="input-group-btn">
|
<input id="q" name="q" class="form-control" type="text" placeholder="techgaun/github-dorks">
|
||||||
<button onClick="fetchData()" type="button" class="btn btn-primary">Find</button>
|
<span class="input-group-btn">
|
||||||
</span>
|
<button id="find" onClick="fetchData()" type="button" class="btn btn-primary">
|
||||||
</div>
|
<i id="spinner" class="fa fa-spinner fa-pulse fa-fw" hidden></i> Find
|
||||||
</form>
|
</button>
|
||||||
|
</span>
|
||||||
<div id='data-body' class="">
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="data-body"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="footer" class="card-footer text-muted"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-offset-2 col-md-8">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="js/main.js"></script>
|
<script type="text/javascript" src="js/main.js"></script>
|
||||||
|
|
136
js/main.js
136
js/main.js
|
@ -1,44 +1,85 @@
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
const repo = getQueryParams().q;
|
||||||
|
if (repo) {
|
||||||
|
document.getElementById('q').value = repo;
|
||||||
|
fetchData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById('form').addEventListener('submit', (e) => {
|
document.getElementById('form').addEventListener('submit', (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
fetchData()
|
fetchData();
|
||||||
})
|
});
|
||||||
|
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
const repo = document.getElementById('repo').value
|
const repo = document.getElementById('q').value;
|
||||||
const re = /[-_\w]+\/[-_.\w]+/
|
const re = /[-_\w]+\/[-_.\w]+/;
|
||||||
|
|
||||||
|
window.history.pushState('', '', `?q=${repo}`);
|
||||||
|
|
||||||
if (re.test(repo)) {
|
if (re.test(repo)) {
|
||||||
fetchAndShow(repo)
|
fetchAndShow(repo);
|
||||||
} else {
|
} else {
|
||||||
showError('Invalid github repo given. Format is <username>/<repo>')
|
showMsg('Invalid GitHub repository! Format is <username>/<repo>', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchAndShow(repo) {
|
function fetchAndShow(repo) {
|
||||||
|
document.getElementById('find').disabled = true;
|
||||||
|
document.getElementById('spinner').removeAttribute('hidden');
|
||||||
|
|
||||||
fetch(`https://api.github.com/repos/${repo}/forks?sort=stargazers`)
|
fetch(`https://api.github.com/repos/${repo}/forks?sort=stargazers`)
|
||||||
.then(function(response) {
|
.then((response) => response.json())
|
||||||
response.json()
|
.then((data) => {
|
||||||
.then(function(data) {
|
showData(data);
|
||||||
showData(data)
|
|
||||||
})
|
document.getElementById('find').disabled = false;
|
||||||
})
|
document.getElementById('spinner').setAttribute('hidden', 'hidden');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showError(msg) {
|
function showMsg(msg, type) {
|
||||||
document.getElementById('data-body').innerHTML = `<div class="alert alert-danger">${msg}</div>`
|
let alert_type = 'alert-info';
|
||||||
|
|
||||||
|
if (type === 'danger') {
|
||||||
|
alert_type = 'alert-danger';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('footer').innerHTML = '';
|
||||||
|
|
||||||
|
document.getElementById('data-body').innerHTML = `
|
||||||
|
<div class="alert ${alert_type} alert-dismissible fade show" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
${msg}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showData(data) {
|
function showData(data) {
|
||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
showError('Github Repo does not exist')
|
showMsg('GitHub repository does not exist', 'danger');
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
document.getElementById('data-body').innerHTML = `<div class="alert alert-info">No forks exist</div>`
|
showMsg('No forks exist!');
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const thead = '<thead><tr><th>Repository</th><th>Stargazers</th><th>Forks</th><th>Last Update</th></tr></thead>'
|
|
||||||
const html = []
|
const html = [];
|
||||||
|
const thead = `
|
||||||
|
<thead>
|
||||||
|
<tr class="table-active">
|
||||||
|
<th><i class="fa fa-github" aria-hidden="true"></i> Repository</th>
|
||||||
|
<th><i class="fa fa-star" aria-hidden="true"></i> Stargazers</th>
|
||||||
|
<th><i class="fa fa-code-fork" aria-hidden="true"></i> Forks</th>
|
||||||
|
<th><i class="fa fa-clock-o" aria-hidden="true"></i> Last Update</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
`;
|
||||||
|
|
||||||
for (const fork of data) {
|
for (const fork of data) {
|
||||||
const item = `
|
const item = `
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -47,41 +88,66 @@ function showData(data) {
|
||||||
<td>${fork.forks_count}</td>
|
<td>${fork.forks_count}</td>
|
||||||
<td>${timeSince(fork.updated_at)} ago</td>
|
<td>${timeSince(fork.updated_at)} ago</td>
|
||||||
</tr>
|
</tr>
|
||||||
`
|
`;
|
||||||
html.push(item)
|
html.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('data-body').innerHTML = `
|
document.getElementById('data-body').innerHTML = `
|
||||||
<table class="table table-striped">
|
<div class="table-responsive rounded">
|
||||||
${thead}
|
<table class="table table-striped table-bordered table-hover">
|
||||||
<tbody>${html.join('')}</tbody>
|
${thead}
|
||||||
</table>
|
<tbody>${html.join('')}</tbody>
|
||||||
`
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.getElementById('footer').innerHTML = `${data.length} ${data.length == 1 ? 'result' : 'results'}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQueryParams() {
|
||||||
|
let query = location.search;
|
||||||
|
if (!query) {
|
||||||
|
return { };
|
||||||
|
}
|
||||||
|
|
||||||
|
return (/^[?#]/.test(query) ? query.slice(1) : query)
|
||||||
|
.split('&')
|
||||||
|
.reduce((params, param) => {
|
||||||
|
let [ key, value ] = param.split('=');
|
||||||
|
params[key] = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : '';
|
||||||
|
return params;
|
||||||
|
}, { });
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeSince(date_str) {
|
function timeSince(date_str) {
|
||||||
const date = new Date(date_str)
|
const date = new Date(date_str);
|
||||||
const seconds = Math.floor((new Date() - date) / 1000);
|
const seconds = Math.floor((new Date() - date) / 1000);
|
||||||
|
|
||||||
let interval = Math.floor(seconds / 31536000);
|
let interval = Math.floor(seconds / 31536000);
|
||||||
|
|
||||||
if (interval > 1) {
|
if (interval > 1) {
|
||||||
return interval + " years";
|
return interval + ' years';
|
||||||
}
|
}
|
||||||
|
|
||||||
interval = Math.floor(seconds / 2592000);
|
interval = Math.floor(seconds / 2592000);
|
||||||
if (interval > 1) {
|
if (interval > 1) {
|
||||||
return interval + " months";
|
return interval + ' months';
|
||||||
}
|
}
|
||||||
|
|
||||||
interval = Math.floor(seconds / 86400);
|
interval = Math.floor(seconds / 86400);
|
||||||
if (interval > 1) {
|
if (interval > 1) {
|
||||||
return interval + " days";
|
return interval + ' days';
|
||||||
}
|
}
|
||||||
|
|
||||||
interval = Math.floor(seconds / 3600);
|
interval = Math.floor(seconds / 3600);
|
||||||
if (interval > 1) {
|
if (interval > 1) {
|
||||||
return interval + " hours";
|
return interval + ' hours';
|
||||||
}
|
}
|
||||||
|
|
||||||
interval = Math.floor(seconds / 60);
|
interval = Math.floor(seconds / 60);
|
||||||
if (interval > 1) {
|
if (interval > 1) {
|
||||||
return interval + " minutes";
|
return interval + ' minutes';
|
||||||
}
|
}
|
||||||
return Math.floor(seconds) + " seconds";
|
|
||||||
|
return Math.floor(seconds) + ' seconds';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue