Add new plugin topics (#12)

This commit is contained in:
Simon Lecoq
2020-12-08 12:37:09 +01:00
committed by GitHub
parent 7f77d33bb9
commit 9a3f05dab0
12 changed files with 221 additions and 10 deletions

View File

@@ -32,6 +32,7 @@
posts:"Recent posts",
isocalendar:"Isometric commit calendar",
gists:"Gists metrics",
topics:"Starred topics",
"base.header":"Header",
"base.activity":"Account activity",
"base.community":"Community stats",

View File

@@ -48,7 +48,7 @@
//Compute metrics
console.debug(`metrics/compute/${login} > compute`)
const computer = Templates[template].default || Templates[template]
await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, url, imgb64, axios, puppeteer, format, bytes, shuffle}})
await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, url, imgb64, axios, puppeteer, format, bytes, shuffle, htmlescape}})
const promised = await Promise.all(pending)
//Check plugins errors
@@ -113,6 +113,16 @@
return array
}
/** Escape html */
function htmlescape(string) {
return string
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;")
}
/** Placeholder generator */
function placeholder({data, conf, q}) {
//Proxifier
@@ -154,6 +164,7 @@
followup:{issues:{count:0}, pr:{count:0}},
habits:{indents:{style:`########`}},
languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:`######`, color:"#ebedf0", value:1/(x+1)}))},
topics:{list:[...new Array(12).fill(null).map(() => ({name:`######`, description:`Lorem ipsum dolor sit amet, consectetur adipiscing elit.`, icon:null})), {name:`And ## more...`, description:"", icon:null}]},
}[key]??{})]
)),
token:{scopes:[]},

View File

@@ -11,6 +11,7 @@
import pagespeed from "./pagespeed/index.mjs"
import posts from "./posts/index.mjs"
import selfskip from "./selfskip/index.mjs"
import topics from "./topics/index.mjs"
import traffic from "./traffic/index.mjs"
//Exports
@@ -25,5 +26,6 @@
pagespeed,
posts,
selfskip,
topics,
traffic,
}

View File

@@ -0,0 +1,67 @@
//Setup
export default async function ({login, imports, q}, {enabled = false} = {}) {
//Plugin execution
try {
//Check if plugin is enabled and requirements are met
if ((!enabled)||(!q.topics))
return null
//Parameters override
let {"topics.sort":sort = "stars", "topics.limit":limit = 15} = q
//Shuffle
const shuffle = (sort === "random")
//Sort method
sort = {starred:"created", activity:"updated", stars:"stars", random:"created"}[sort] ?? "starred"
//Limit
limit = Math.max(1, Math.min(20, Number(limit)))
//Start puppeteer and navigate to topics
let topics = []
console.debug(`metrics/compute/${login}/plugins > topics > starting browser`)
const browser = await imports.puppeteer.launch({headless:true, executablePath:process.env.PUPPETEER_BROWSER_PATH, args:["--no-sandbox", "--disable-extensions", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]})
console.debug(`metrics/compute/${login}/plugins > topics > loaded ${await browser.version()}`)
const page = await browser.newPage()
//Iterate through pages
for (let i = 1; i <= 100; i++) {
//Load page
console.debug(`metrics/compute/${login}/plugins > topics > loading page ${i}`)
await page.goto(`https://github.com/stars/${login}/topics?direction=desc&page=${i}&sort=${sort}`)
const frame = page.mainFrame()
//Extract topics
await Promise.race([frame.waitForSelector("ul.repo-list"), frame.waitForSelector(".blankslate")])
const starred = await frame.evaluate(() => [...document.querySelectorAll("ul.repo-list li")].map(li => ({
name:li.querySelector(".f3").innerText,
description:li.querySelector(".f5").innerText,
icon:li.querySelector("img")?.src ?? null,
})))
//Check if next page exists
if (!starred.length)
break
topics.push(...starred)
}
//Shuffle topics
if (shuffle)
topics = imports.shuffle(topics)
//Limit topics
if (limit > 0) {
console.debug(`metrics/compute/${login}/plugins > topics > keeping only ${limit} topics`)
const removed = topics.slice(limit)
topics = topics.slice(0, limit)
topics.push({name:`And ${removed.length} more...`, description:removed.map(({name}) => name).join(", "), icon:null})
}
//Convert icons to base64
for (const topic of topics) {
if (topic.icon) {
console.debug(`metrics/compute/${login}/plugins > topics > processing ${topic.name}`)
topic.icon = await imports.imgb64(topic.icon)
}
//Escape HTML description
topic.description = imports.htmlescape(topic.description)
}
//Results
return {list:topics}
}
//Handle errors
catch (error) {
console.debug(error)
throw {error:{message:`An error occured`}}
}
}

View File

@@ -12,6 +12,7 @@
+ (!!computed.plugins.posts)*64 + (computed.plugins.posts ? computed.plugins.posts.posts ? Math.max(0, computed.plugins.posts.posts.length)*40 : 0 : 0)
+ (!!computed.plugins.isocalendar)*192 + (computed.plugins.isocalendar ? computed.plugins.isocalendar.duration === 'full-year' ? 100 : 0 : 0)
+ (!!computed.plugins.gists)*68
+ (!!computed.plugins.topics)*160
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!computed.plugins.habits))+(!!computed.plugins.pagespeed)+(!!computed.plugins.languages)+(!!computed.plugins.music)+(!!computed.plugins.posts)+(!!computed.plugins.isocalendar)+(!!computed.plugins.gists))-1))*4
%>">
@@ -396,6 +397,33 @@
</section>
<% } %>
<% if (computed.plugins.topics) { %>
<section>
<h2 class="field">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M14.184 1.143a1.75 1.75 0 00-2.502-.57L.912 7.916a1.75 1.75 0 00-.53 2.32l.447.775a1.75 1.75 0 002.275.702l11.745-5.656a1.75 1.75 0 00.757-2.451l-1.422-2.464zm-1.657.669a.25.25 0 01.358.081l1.422 2.464a.25.25 0 01-.108.35l-2.016.97-1.505-2.605 1.85-1.26zM9.436 3.92l1.391 2.41-5.42 2.61-.942-1.63 4.97-3.39zM3.222 8.157l-1.466 1a.25.25 0 00-.075.33l.447.775a.25.25 0 00.325.1l1.598-.769-.83-1.436zm6.253 2.306a.75.75 0 00-.944-.252l-1.809.87a.75.75 0 00-.293.253L4.38 14.326a.75.75 0 101.238.848l1.881-2.75v2.826a.75.75 0 001.5 0v-2.826l1.881 2.75a.75.75 0 001.238-.848l-2.644-3.863z"></path></svg>
Starred topics
</h2>
<div class="row">
<% if (computed.plugins.topics.error) { %>
<section>
<div class="field error">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.topics.error.message %>
</div>
</section>
<% } else { %>
<section>
<div class="topics fill-width">
<% for (const {name, description} of computed.plugins.topics.list) { %>
<div class="label" title="<%= description %>"><%= name.toLocaleLowerCase() %></div>
<% } %>
</div>
</section>
<% } %>
</div>
</section>
<% } %>
<% if (computed.plugins.music) { %>
<section>
<h2 class="field">

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -113,6 +113,24 @@
opacity: .7;
}
/* Labels */
.label {
background-color: #F1F8FF;
color: #0366D6;
padding: 0 10px;
font-weight: 500;
line-height: 22px;
margin: 2px 5px;
white-space: nowrap;
border-radius: 32px;
font-size: 12px;
}
.label:hover {
background-color: #DDEEFF;
cursor: pointer;
}
/* Habits */
.habits {
margin: 0;
@@ -242,6 +260,12 @@
padding-top: 1px;
}
/* Topics */
.topics {
display: flex;
flex-wrap: wrap;
}
/* Fade animation */
.af {
opacity: 0;