Files
metrics/src/html/app.js
lowlighter 60d02a6d90 Version 2.2 (new additions)
- Smarter placeholders
- Merged placeholders with real templates to avoid maintening duplicates
- Moved style/js away from index.html and refactor
- Svg size is now computed again from templates
- Base metrics is now contained in special plugin "base", which can be disabled  part by part if you just want to include a plugin instead
- Reformatted a bit terminal template
- Test now look templates directory
2020-10-24 17:31:37 +02:00

151 lines
6.6 KiB
JavaScript

;(async function() {
//Init
const url = new URLSearchParams(window.location.search)
const {data:templates} = await axios.get("/templates.list")
const {data:plugins} = await axios.get("/plugins.list")
const {data:base} = await axios.get("/plugins.base.parts.list")
//App
return new Vue({
//Initialization
el:"main",
async mounted() {
await this.load()
},
//Data initialization
data:{
user:url.get("user") || "",
palette:url.get("palette") || "light",
plugins:{
base,
list:plugins,
enabled:{base:Object.fromEntries(base.map(key => [key, true]))},
descriptions:{
pagespeed:"Website performances",
languages:"Most used languages",
followup:"Issues and pull requests",
traffic:"Pages views",
lines:"Lines of code changed",
habits:"Coding habits",
selfskip:"Skip metrics commits",
"base.header":"Header",
"base.activity":"Account activity",
"base.community":"Community stats",
"base.repositories":"Repositories metrics",
"base.metadata":"Metadata",
},
},
templates:{
list:templates,
selected:url.get("template") || templates[0],
loaded:{},
placeholder:"",
descriptions:{
classic:"Classic template",
terminal:"Terminal template",
},
},
generated:{
pending:false,
content:"",
error:false,
},
},
//Computed data
computed:{
//User's repository
repo() {
return `https://github.com/${this.user}/${this.user}`
},
//Endpoint to use for computed metrics
url() {
const plugins = Object.entries(this.plugins.enabled)
.flatMap(([key, value]) => key === "base" ? Object.entries(value).map(([key, value]) => [`base.${key}`, value]) : [[key, value]])
.filter(([key, value]) => /^base[.]\w+$/.test(key) ? !value : value)
.map(([key, value]) => `${key}=${+value}`)
const params = [...(this.templates.selected !== templates[0] ? [`template=${this.templates.selected}`] : []), ...plugins].join("&")
return `${window.location.protocol}//${window.location.host}/${this.user}${params.length ? `?${params}` : ""}`
},
},
//Methods
methods:{
//Load and render image
async load() {
//Load template
const template = this.templates.selected
if (!this.templates.loaded[template]) {
const {data:{image, style}} = await axios.get(`/placeholder.svg?template=${template}`)
this.templates.loaded[template] = {image, style}
}
const {image = "", style = {}} = this.templates.loaded[this.templates.selected] || {}
if (!image)
return this.templates.placeholder = "#"
//Proxifier
const proxify = (target) => typeof target === "object" ? new Proxy(target, {
get(target, property) {
//Primitive conversion
if (property === Symbol.toPrimitive)
return () => "▇"
//Iterables
if (property === Symbol.iterator)
return Reflect.get(target, property)
//Plugins should not be proxified by default as they can be toggled by user
if (/^plugins$/.test(property))
return Reflect.get(target, property)
//Consider no errors on plugins
if (/^error/.test(property))
return undefined
//Proxify recursively
return proxify(property in target ? Reflect.get(target, property) : {})
}
}) : target
//Placeholder data
const data = {
style,
s(_, letter) { return letter === "y" ? "ies" : "s" },
base:this.plugins.enabled.base,
meta:{version:"0.0.0", author:"lowlighter", placeholder:true},
user:proxify({name:`▇▇▇▇`, websiteUrl:`▇▇▇▇▇▇▇▇▇▇▇▇`}),
computed:proxify({
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
registration:"▇ years ago",
calendar:new Array(14).fill({color:"#ebedf0"}),
licenses:{favorite:`▇▇▇▇`},
plugins:Object.fromEntries(Object.entries(this.plugins.enabled).filter(([key, enabled]) => (key !== "base")&&(enabled)).map(([key]) => {
return [key, proxify({
pagespeed:{scores:["Performance", "Accessibility", "Best Practices", "SEO"].map(title => ({title, score:NaN}))},
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)}))},
}[key]||{})]
})),
token:{scopes:[]},
}),
}
//Render placeholder
this.templates.placeholder = this.serialize(ejs.render(image, data))
this.generated.content = ""
},
//Generate metrics and flush cache
async generate() {
//Avoid requests spamming
if (this.generated.pending)
return
this.generated.pending = true
//Compute metrics
try {
await axios.get(`/action.flush?&token=${(await axios.get(`/action.flush?user=${this.user}`)).data.token}`)
this.generated.content = this.serialize((await axios.get(this.url)).data)
} catch {
this.generated.error = true
}
finally {
this.generated.pending = false
}
},
//Serialize svg
serialize(svg) {
return `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`
},
},
})
})()