JSFiddle - React, Tailwind, and code Playground
by skirtle
HTML
<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
<div id="app">
<h3>Vue 3</h3>
<repo-table :repos="vue3"></repo-table>
<h3>Vue 2</h3>
<repo-table :repos="vue2"></repo-table>
</div>
<script type="text/x-template" id="repo-table">
<table class="table">
<thead>
<tr>
<th>Code</th>
<th>Last commit</th>
<th>90 days</th>
<th>Org / User</th>
<th>Live</th>
<th>GitHub</th>
</tr>
</thead>
<tbody>
<tr v-for="repo in sorted" :class="{ inactive: (dates[repo.lang] || '').startsWith('201') }">
<td>{{ repo.lang }}</td>
<td>{{ dates[repo.lang] }}</td>
<td>
{{ counts[repo.lang] }}
<template v-if="counts[repo.lang] === 100">
+
</template>
commits
</td>
<td><a :href="`https://github.com/${repo.owner}/`" target="_blank">{{ repo.owner }}</a></td>
<td>
<template v-if="repo.live">
✓
</template>
</td>
<td>
<a :href="`https://github.com/${repo.owner}/${repo.repo}/`" target="_blank">View repo</a>
</td>
</tr>
</tbody>
</table>
</script>
SCSS
* {
font-family: Arial, sans-serif;
}
.table {
border-collapse: collapse;
td, th {
border: 1px solid #777;
padding: 5px;
}
.inactive {
color: #777;
}
tr:hover td {
background: #eee;
}
}
JavaScript
function getRawCache() {
let cache = {}
try {
cache = JSON.parse(localStorage.getItem('docs-stats'))
} catch (ex) {
}
if (!cache || typeof cache !== 'object') {
cache = {}
}
return cache
}
function getCache(...args) {
const cache = getRawCache()
const key = args.join('-')
const entry = cache[key]
if (entry && entry.date + 2 * 60 * 60 * 1000 > Date.now()) {
return entry.value
}
return null
}
function setCache(...args) {
const value = args.pop()
const cache = getRawCache()
const key = args.join('-')
cache[key] = {
date: Date.now(),
value
}
localStorage.setItem('docs-stats', JSON.stringify(cache))
}
function withCache(cacheName, fn) {
return async function (...args) {
const cached = getCache(...args, cacheName)
if (cached != null) {
return cached
}
const value = await fn(...args)
setCache(...args, cacheName, value)
return value
}
}
const getLastDate = withCache('date', async (owner, repo, branch) => {
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/branches/${branch}`)
const data = await response.json()
const date = data.commit.commit.committer.date.split('T')[0]
return date
})
const getCommitDate = () => {
return new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toJSON().replace(/\.\d*/, '')
}
const commitCount = withCache('commitCount', async (owner, repo) => {
const dateString = getCommitDate()
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/commits?since=${dateString}&per_page=100`)
const data = await response.json()
return data.length
})
const RepoTable = {
template: '#repo-table',
props: ['repos'],
data () {
return {
dates: {},
counts: {}
}
},
computed: {
sorted () {
const dates = this.dates
return [...this.repos].sort((a, b) => {
const dateA = dates[a.lang] || '2000'
...