Version 1.9 (#6)
This commit is contained in:
34
README.md
34
README.md
@@ -87,6 +87,9 @@ jobs:
|
|||||||
# Name of SVG image output
|
# Name of SVG image output
|
||||||
filename: github-metrics.svg
|
filename: github-metrics.svg
|
||||||
|
|
||||||
|
# Template to use (see src/templates to get a list of supported templates)
|
||||||
|
template: classic
|
||||||
|
|
||||||
# Enable Google PageSpeed metrics for account attached website
|
# Enable Google PageSpeed metrics for account attached website
|
||||||
# See https://developers.google.com/speed/docs/insights/v5/get-started for more informations
|
# See https://developers.google.com/speed/docs/insights/v5/get-started for more informations
|
||||||
plugin_pagespeed: no
|
plugin_pagespeed: no
|
||||||
@@ -230,6 +233,14 @@ Open and edit `settings.json` to configure your instance using a text editor of
|
|||||||
//Intended for easier development and disabled by default
|
//Intended for easier development and disabled by default
|
||||||
"debug":false,
|
"debug":false,
|
||||||
|
|
||||||
|
//Template configuration
|
||||||
|
"templates":{
|
||||||
|
//Default template
|
||||||
|
"default":"classic",
|
||||||
|
//Enabled template. Leave empty to enable all defined templates
|
||||||
|
"enabled":[],
|
||||||
|
},
|
||||||
|
|
||||||
//Plugins configuration
|
//Plugins configuration
|
||||||
"plugins":{
|
"plugins":{
|
||||||
//Google PageSpeed plugin
|
//Google PageSpeed plugin
|
||||||
@@ -322,6 +333,7 @@ systemctl status github_metrics
|
|||||||
<summary>⚠️ HTTP errors code</summary>
|
<summary>⚠️ HTTP errors code</summary>
|
||||||
|
|
||||||
The following errors code can be encountered if on a server instance :
|
The following errors code can be encountered if on a server instance :
|
||||||
|
* `400 Bad request` : Query is invalid (e.g. unsupported template)
|
||||||
* `403 Forbidden` : User is not allowed in `restricted` users list
|
* `403 Forbidden` : User is not allowed in `restricted` users list
|
||||||
* `404 Not found` : GitHub API did not found the requested user
|
* `404 Not found` : GitHub API did not found the requested user
|
||||||
* `429 Too many requests` : Thrown when rate limiter is trigerred
|
* `429 Too many requests` : Thrown when rate limiter is trigerred
|
||||||
@@ -514,10 +526,13 @@ Add the following to your workflow :
|
|||||||
|
|
||||||
#### Metrics generator
|
#### Metrics generator
|
||||||
|
|
||||||
|
* `src/setup.mjs` contains the configuration setup
|
||||||
* `src/metrics.mjs` contains the metrics renderer
|
* `src/metrics.mjs` contains the metrics renderer
|
||||||
* `src/query.graphql` is the GraphQL query sent to GitHub GraphQL API
|
* `src/templates/*` contains templates files
|
||||||
* `src/style.css` contains the style used by the generated SVG image
|
* `src/templates/*/image.svg` contains the template used by the generated SVG image
|
||||||
* `src/template.svg` contains the template used by the generated SVG image
|
* `src/templates/*/query.graphql` is the GraphQL query sent to GitHub GraphQL API
|
||||||
|
* `src/templates/*/style.css` contains the style used by the generated SVG image
|
||||||
|
* `src/templates/*/template.mjs` contains the code which prepares data for rendering
|
||||||
* `src/plugins/*` contains the source code of metrics plugins
|
* `src/plugins/*` contains the source code of metrics plugins
|
||||||
|
|
||||||
#### Metrics server instance
|
#### Metrics server instance
|
||||||
@@ -527,6 +542,7 @@ Add the following to your workflow :
|
|||||||
|
|
||||||
#### GitHub action
|
#### GitHub action
|
||||||
|
|
||||||
|
* `action.yml` contains the GitHub action descriptor
|
||||||
* `action/index.mjs` contains the GitHub action code
|
* `action/index.mjs` contains the GitHub action code
|
||||||
* `action/dist/index.js` contains compiled the GitHub action code
|
* `action/dist/index.js` contains compiled the GitHub action code
|
||||||
* `utils/build.mjs` contains the GitHub action builder
|
* `utils/build.mjs` contains the GitHub action builder
|
||||||
@@ -541,18 +557,18 @@ Read the few sections below to get started with project structure.
|
|||||||
|
|
||||||
#### Adding new metrics through GraphQL API, REST API or Third-Party service
|
#### Adding new metrics through GraphQL API, REST API or Third-Party service
|
||||||
|
|
||||||
To use [GitHub GraphQL API](https://docs.github.com/en/graphql), update the GraphQL query from `src/query.graphql`.
|
To use [GitHub GraphQL API](https://docs.github.com/en/graphql), update the GraphQL query from `templates/*/query.graphql`.
|
||||||
Raw queried data should be exposed in `data.user` whereas computed data should be in `data.computed`, and code should be updated through `src/metrics.mjs`.
|
Raw queried data should be exposed in `data.user` whereas computed data should be in `data.computed`, and code should be updated through `templates/*/template.mjs`.
|
||||||
|
|
||||||
To use [GitHub Rest API](https://docs.github.com/en/rest) or a third-party service instead, create a new plugin in `src/plugins`.
|
To use [GitHub Rest API](https://docs.github.com/en/rest) or a third-party service instead, create a new plugin in `src/plugins`.
|
||||||
Plugins should be self-sufficient and re-exported from [src/plugins/index.mjs](https://github.com/lowlighter/metrics/blob/master/src/plugins/index.mjs), to be later included in the `//Plugins` section of `src/metrics.mjs`.
|
Plugins should be self-sufficient and re-exported from [src/plugins/index.mjs](https://github.com/lowlighter/metrics/blob/master/src/plugins/index.mjs), to be later included in the `//Plugins` section of `templates/*/template.mjs`.
|
||||||
Data generated should be exposed in `data.computed.plugins[plugin]` where `plugin` is your plugin's name.
|
Data generated should be exposed in `data.computed.plugins[plugin]` where `plugin` is your plugin's name.
|
||||||
|
|
||||||
#### Updating the SVG template
|
#### Updating the SVG template
|
||||||
|
|
||||||
The SVG template is located in `src/template.svg` and include the CSS from `src/style.css`.
|
The SVG template is located in `templates/*/image.svg` and include the CSS from `templates/*/style.css`.
|
||||||
|
|
||||||
It's actually a long JavaScript template string, so you can actually include variables (e.g. `` `${data.user.name}` ``) and execute inline code, like ternary conditions (e.g. `` `${computed.plugins.plugin ? `<div>${computed.plugins.plugin.data}</div>` : ""}` ``) which are useful for conditional statements.
|
It is rendered with [EJS](https://github.com/mde/ejs) so you can actually include variables (e.g. `<%= user.name %>`) and execute simple code, like control statements.
|
||||||
|
|
||||||
#### Metrics server and GitHub action
|
#### Metrics server and GitHub action
|
||||||
|
|
||||||
@@ -584,6 +600,8 @@ This way you'll be able to rapidly test SVG renders with your browser.
|
|||||||
* To apply rate limiting on server and avoid spams and hitting GitHub API's own rate limit
|
* To apply rate limiting on server and avoid spams and hitting GitHub API's own rate limit
|
||||||
* [octokit/graphql.js](https://github.com/octokit/graphql.js/) and [octokit/rest.js](https://github.com/octokit/rest.js)
|
* [octokit/graphql.js](https://github.com/octokit/graphql.js/) and [octokit/rest.js](https://github.com/octokit/rest.js)
|
||||||
* To perform request to GitHub GraphQL API and GitHub REST API
|
* To perform request to GitHub GraphQL API and GitHub REST API
|
||||||
|
* [mde/ejs](https://github.com/mde/ejs)
|
||||||
|
* To render SVG images
|
||||||
* [ptarjan/node-cache](https://github.com/ptarjan/node-cache)
|
* [ptarjan/node-cache](https://github.com/ptarjan/node-cache)
|
||||||
* To cache generated content
|
* To cache generated content
|
||||||
* [renanbastos93/image-to-base64](https://github.com/renanbastos93/image-to-base64)
|
* [renanbastos93/image-to-base64](https://github.com/renanbastos93/image-to-base64)
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ inputs:
|
|||||||
filename:
|
filename:
|
||||||
description: Name of SVG image output
|
description: Name of SVG image output
|
||||||
default: github-metrics.svg
|
default: github-metrics.svg
|
||||||
|
template:
|
||||||
|
description: Template to use
|
||||||
|
default: classic
|
||||||
optimize:
|
optimize:
|
||||||
description: Optimize SVG image
|
description: Optimize SVG image
|
||||||
default: yes
|
default: yes
|
||||||
|
|||||||
599
action/dist/index.js
vendored
599
action/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
//Imports
|
//Imports
|
||||||
import path from "path"
|
import * as _setup from "./../src/setup.mjs"
|
||||||
import * as _metrics from "./../src/metrics.mjs"
|
import * as _metrics from "./../src/metrics.mjs"
|
||||||
import * as _octokit from "@octokit/graphql"
|
import * as _octokit from "@octokit/graphql"
|
||||||
import * as _core from "@actions/core"
|
import * as _core from "@actions/core"
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
;((async function () {
|
;((async function () {
|
||||||
//Hack because ES modules are not correctly transpiled with ncc
|
//Hack because ES modules are not correctly transpiled with ncc
|
||||||
const [core, github, octokit, metrics] = [_core, _github, _octokit, _metrics].map(m => (m && m.default) ? m.default : m)
|
const [core, github, octokit, setup, metrics] = [_core, _github, _octokit, _setup, _metrics].map(m => (m && m.default) ? m.default : m)
|
||||||
//Yaml boolean converter
|
//Yaml boolean converter
|
||||||
const bool = (value, defaulted = false) => typeof value === "string" ? /^(?:[Tt]rue|[Oo]n|[Yy]es)$/.test(value) : defaulted
|
const bool = (value, defaulted = false) => typeof value === "string" ? /^(?:[Tt]rue|[Oo]n|[Yy]es)$/.test(value) : defaulted
|
||||||
//Runner
|
//Runner
|
||||||
@@ -27,9 +27,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Load configuration
|
||||||
|
const conf = await setup()
|
||||||
|
console.log(`Configuration | loaded`)
|
||||||
|
|
||||||
//Load svg template, style and query
|
//Load svg template, style and query
|
||||||
const template = `<#include template.svg>`, style = `<#include style.css>`, query = `<#include query.graphql>`
|
const template = core.getInput("template") || "classic"
|
||||||
console.log(`Templates | loaded`)
|
console.log(`Template to use | ${template}`)
|
||||||
|
|
||||||
//Token for data gathering
|
//Token for data gathering
|
||||||
const token = core.getInput("token")
|
const token = core.getInput("token")
|
||||||
@@ -43,8 +47,7 @@
|
|||||||
|
|
||||||
//SVG output
|
//SVG output
|
||||||
const filename = core.getInput("filename") || "github-metrics.svg"
|
const filename = core.getInput("filename") || "github-metrics.svg"
|
||||||
const output = path.join(filename)
|
console.log(`SVG output file | ${filename}`)
|
||||||
console.log(`SVG output file | ${output}`)
|
|
||||||
|
|
||||||
//SVG optimization
|
//SVG optimization
|
||||||
const optimize = bool(core.getInput("optimize"), true)
|
const optimize = bool(core.getInput("optimize"), true)
|
||||||
@@ -76,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Render metrics
|
//Render metrics
|
||||||
const rendered = await metrics({login:user, q}, {template, style, query, graphql, rest, plugins, optimize})
|
const rendered = await metrics({login:user, q}, {graphql, rest, plugins, conf})
|
||||||
console.log(`Render | complete`)
|
console.log(`Render | complete`)
|
||||||
|
|
||||||
//Commit to repository
|
//Commit to repository
|
||||||
|
|||||||
60
package-lock.json
generated
60
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "metrics",
|
"name": "metrics",
|
||||||
"version": "1.6.0",
|
"version": "1.9.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -136,9 +136,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.11.8",
|
"version": "14.11.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.10.tgz",
|
||||||
"integrity": "sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw=="
|
"integrity": "sha512-yV1nWZPlMFpoXyoknm4S56y2nlTAuFYaJuQtYRAOU7xA/FJ9RY0Xm7QOkaYMMmr8ESdHIuUb6oQgR/0+2NqlyA=="
|
||||||
},
|
},
|
||||||
"@types/q": {
|
"@types/q": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.4",
|
||||||
@@ -209,6 +209,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
},
|
},
|
||||||
|
"async": {
|
||||||
|
"version": "0.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
|
||||||
|
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
|
||||||
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.20.0",
|
"version": "0.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
|
||||||
@@ -220,8 +225,7 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"before-after-hook": {
|
"before-after-hook": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
@@ -267,7 +271,6 @@
|
|||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -348,8 +351,7 @@
|
|||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
@@ -524,15 +526,23 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||||
},
|
},
|
||||||
|
"ejs": {
|
||||||
|
"version": "3.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.5.tgz",
|
||||||
|
"integrity": "sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w==",
|
||||||
|
"requires": {
|
||||||
|
"jake": "^10.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"encodeurl": {
|
"encodeurl": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||||
},
|
},
|
||||||
"entities": {
|
"entities": {
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
|
||||||
"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
|
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
|
||||||
},
|
},
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.7",
|
"version": "1.17.7",
|
||||||
@@ -624,6 +634,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz",
|
||||||
"integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA=="
|
"integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA=="
|
||||||
},
|
},
|
||||||
|
"filelist": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ==",
|
||||||
|
"requires": {
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"finalhandler": {
|
"finalhandler": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||||
@@ -841,6 +859,17 @@
|
|||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"jake": {
|
||||||
|
"version": "10.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
|
||||||
|
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
|
||||||
|
"requires": {
|
||||||
|
"async": "0.9.x",
|
||||||
|
"chalk": "^2.4.2",
|
||||||
|
"filelist": "^1.0.1",
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.14.0",
|
"version": "3.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
|
||||||
@@ -908,7 +937,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@@ -951,9 +979,9 @@
|
|||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
"nan": {
|
"nan": {
|
||||||
"version": "2.14.1",
|
"version": "2.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
|
||||||
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
|
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"needle": {
|
"needle": {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "metrics",
|
"name": "metrics",
|
||||||
"version": "1.8.0",
|
"version": "1.9.0",
|
||||||
"description": "Generate an user's GitHub metrics as SVG image format to embed somewhere else",
|
"description": "Generate an user's GitHub metrics as SVG image format to embed somewhere else",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.mjs",
|
"start": "node index.mjs",
|
||||||
"build": "node utils/build.mjs",
|
"build": "node utils/build.mjs",
|
||||||
"test": "node tests/metrics.mjs",
|
"test": "node tests/metrics.mjs",
|
||||||
"upgrade": "npm install @actions/core@latest @actions/github@latest @octokit/graphql@latest @octokit/rest@latest axios@latest compression@latest express@latest express-rate-limit@latest image-to-base64@latest memory-cache@latest svgo@latest @vercel/ncc@latest libxmljs@latest"
|
"upgrade": "npm install @actions/core@latest @actions/github@latest @octokit/graphql@latest @octokit/rest@latest axios@latest compression@latest ejs@latest express@latest express-rate-limit@latest image-to-base64@latest memory-cache@latest svgo@latest @vercel/ncc@latest libxmljs@latest"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
"@octokit/rest": "^18.0.6",
|
"@octokit/rest": "^18.0.6",
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
|
"ejs": "^3.1.5",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-rate-limit": "^5.1.3",
|
"express-rate-limit": "^5.1.3",
|
||||||
"image-to-base64": "^2.1.1",
|
"image-to-base64": "^2.1.1",
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
"optimize":true, "//":"Optimize SVG image",
|
"optimize":true, "//":"Optimize SVG image",
|
||||||
"debug":false, "//":"Debug mode",
|
"debug":false, "//":"Debug mode",
|
||||||
|
|
||||||
|
"templates":{ "//":"Template configuration",
|
||||||
|
"default":"classic", "//":"Default template",
|
||||||
|
"enabled":[], "//":"Enabled templates, leave empty to enable all templates"
|
||||||
|
},
|
||||||
|
|
||||||
"plugins":{ "//":"Additional plugins (optional)",
|
"plugins":{ "//":"Additional plugins (optional)",
|
||||||
"pagespeed":{ "//":"Pagespeed plugin",
|
"pagespeed":{ "//":"Pagespeed plugin",
|
||||||
"enabled":false, "//":"Enable or disable PageSpeed metrics",
|
"enabled":false, "//":"Enable or disable PageSpeed metrics",
|
||||||
|
|||||||
41
src/app.mjs
41
src/app.mjs
@@ -1,29 +1,21 @@
|
|||||||
//Imports
|
//Imports
|
||||||
import express from "express"
|
import express from "express"
|
||||||
import fs from "fs"
|
|
||||||
import path from "path"
|
|
||||||
import octokit from "@octokit/graphql"
|
import octokit from "@octokit/graphql"
|
||||||
import OctokitRest from "@octokit/rest"
|
import OctokitRest from "@octokit/rest"
|
||||||
import cache from "memory-cache"
|
import cache from "memory-cache"
|
||||||
import ratelimit from "express-rate-limit"
|
import ratelimit from "express-rate-limit"
|
||||||
import metrics from "./metrics.mjs"
|
|
||||||
import compression from "compression"
|
import compression from "compression"
|
||||||
|
import setup from "./setup.mjs"
|
||||||
|
import metrics from "./metrics.mjs"
|
||||||
|
|
||||||
//Load svg template, style and query
|
/** App */
|
||||||
async function load() {
|
export default async function () {
|
||||||
return await Promise.all(["template.svg", "style.css", "query.graphql"].map(async file => `${await fs.promises.readFile(path.join("src", file))}`))
|
|
||||||
}
|
|
||||||
|
|
||||||
//Setup
|
//Load configuration settings
|
||||||
export default async function setup() {
|
const conf = await setup()
|
||||||
|
const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = conf.settings
|
||||||
|
|
||||||
//Load settings
|
//Load octokits
|
||||||
const settings = JSON.parse((await fs.promises.readFile(path.join("settings.json"))).toString())
|
|
||||||
const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = settings
|
|
||||||
if (debug)
|
|
||||||
console.debug(settings)
|
|
||||||
//Load svg template, style and query
|
|
||||||
let [template, style, query] = await load()
|
|
||||||
const graphql = octokit.graphql.defaults({headers:{authorization: `token ${token}`}})
|
const graphql = octokit.graphql.defaults({headers:{authorization: `token ${token}`}})
|
||||||
const rest = new OctokitRest.Octokit({auth:token})
|
const rest = new OctokitRest.Octokit({auth:token})
|
||||||
|
|
||||||
@@ -47,11 +39,10 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
//Base routes
|
//Base routes
|
||||||
const statics = path.resolve("src/html")
|
|
||||||
const limiter = ratelimit({max:60, windowMs:60*1000})
|
const limiter = ratelimit({max:60, windowMs:60*1000})
|
||||||
app.get("/", limiter, (req, res) => res.sendFile(`${statics}/index.html`))
|
app.get("/", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
|
||||||
app.get("/index.html", limiter, (req, res) => res.sendFile(`${statics}/index.html`))
|
app.get("/index.html", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
|
||||||
app.get("/placeholder.svg", limiter, (req, res) => res.sendFile(`${statics}/placeholder.svg`))
|
app.get("/placeholder.svg", limiter, (req, res) => res.sendFile(`${conf.statics}/placeholder.svg`))
|
||||||
app.get("/favicon.ico", limiter, (req, res) => res.sendStatus(204))
|
app.get("/favicon.ico", limiter, (req, res) => res.sendStatus(204))
|
||||||
|
|
||||||
//Metrics
|
//Metrics
|
||||||
@@ -63,7 +54,6 @@
|
|||||||
console.debug(`metrics/app/${login} > 403 (not in whitelisted users)`)
|
console.debug(`metrics/app/${login} > 403 (not in whitelisted users)`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read cached data if possible
|
//Read cached data if possible
|
||||||
if ((!debug)&&(cached)&&(cache.get(login))) {
|
if ((!debug)&&(cached)&&(cache.get(login))) {
|
||||||
res.header("Content-Type", "image/svg+xml")
|
res.header("Content-Type", "image/svg+xml")
|
||||||
@@ -79,9 +69,7 @@
|
|||||||
//Compute rendering
|
//Compute rendering
|
||||||
try {
|
try {
|
||||||
//Render
|
//Render
|
||||||
if (debug)
|
const rendered = await metrics({login, q:req.query}, {graphql, rest, plugins, conf})
|
||||||
[template, style, query] = await load()
|
|
||||||
const rendered = await metrics({login, q:req.query}, {template, style, query, graphql, rest, plugins, optimize:settings.optimize})
|
|
||||||
//Cache
|
//Cache
|
||||||
if ((!debug)&&(cached))
|
if ((!debug)&&(cached))
|
||||||
cache.put(login, rendered, cached)
|
cache.put(login, rendered, cached)
|
||||||
@@ -96,6 +84,11 @@
|
|||||||
console.debug(`metrics/app/${login} > 404 (user not found)`)
|
console.debug(`metrics/app/${login} > 404 (user not found)`)
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
|
//Invalid template
|
||||||
|
if ((error instanceof Error)&&(/^unsupported template$/.test(error.message))) {
|
||||||
|
console.debug(`metrics/app/${login} > 400 (bad request)`)
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
//General error
|
//General error
|
||||||
console.error(error)
|
console.error(error)
|
||||||
res.sendStatus(500)
|
res.sendStatus(500)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
Embed these metrics on your GitHub profile by adding the markdown below in your <i>README.md</i> at <a id="user-repo" href="#"><span class="user"></span>/<span class="user"></span></a>
|
Embed these metrics on your GitHub profile by adding the markdown below in your <i>README.md</i> at <a id="user-repo" href="#"><span class="user"></span>/<span class="user"></span></a>
|
||||||
<br>
|
<br>
|
||||||
<div class="code">
|
<div class="code">
|
||||||

|

|
||||||
</div>
|
</div>
|
||||||
For even more metrics (coding habits, PageSpeed performances, number of line of code you wrote, page views, etc.), setup this as a <a href="https://github.com/marketplace/actions/github-metrics-as-svg-image">GitHub action</a> on your repository !<br>
|
For even more metrics (coding habits, PageSpeed performances, number of line of code you wrote, page views, etc.), setup this as a <a href="https://github.com/marketplace/actions/github-metrics-as-svg-image">GitHub action</a> on your repository !<br>
|
||||||
Check out <a href="https://github.com/lowlighter/metrics">lowlighter/metrics</a> for more informations
|
Check out <a href="https://github.com/lowlighter/metrics">lowlighter/metrics</a> for more informations
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
document.querySelector("#metrics .generated").style.opacity = 0
|
document.querySelector("#metrics .generated").style.opacity = 0
|
||||||
document.querySelector("aside").style.opacity = 0
|
document.querySelector("aside").style.opacity = 0
|
||||||
//Update github user
|
//Update github user
|
||||||
document.querySelector(".code").innerHTML = ``
|
document.querySelector(".code .url").innerText = `${window.location.href}${user}`
|
||||||
document.querySelector("#user-repo").href = `https://github.com/${user}/${user}`
|
document.querySelector("#user-repo").href = `https://github.com/${user}/${user}`
|
||||||
document.querySelectorAll(".user").forEach(node => node.innerText = user)
|
document.querySelectorAll(".user").forEach(node => node.innerText = user)
|
||||||
//Update metrics
|
//Update metrics
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
current = user
|
current = user
|
||||||
document.querySelector("#metrics .generated").src = `https://metrics.lecoq.io/${user}`
|
document.querySelector("#metrics .generated").src = `${window.location.href}${user}`
|
||||||
document.querySelector("#metrics .generated").onload = function () {
|
document.querySelector("#metrics .generated").onload = function () {
|
||||||
document.querySelector("#metrics .placeholder").style.opacity = 0
|
document.querySelector("#metrics .placeholder").style.opacity = 0
|
||||||
document.querySelector("#metrics .generated").style.opacity = 1
|
document.querySelector("#metrics .generated").style.opacity = 1
|
||||||
|
|||||||
104
src/metrics.mjs
104
src/metrics.mjs
@@ -1,96 +1,50 @@
|
|||||||
//Imports
|
//Imports
|
||||||
import imgb64 from "image-to-base64"
|
import ejs from "ejs"
|
||||||
import SVGO from "svgo"
|
import SVGO from "svgo"
|
||||||
|
import imgb64 from "image-to-base64"
|
||||||
import Plugins from "./plugins/index.mjs"
|
import Plugins from "./plugins/index.mjs"
|
||||||
|
import Templates from "./templates/index.mjs"
|
||||||
|
|
||||||
//Setup
|
//Setup
|
||||||
export default async function metrics({login, q}, {template, style, query, graphql, rest, plugins, selfless = true, optimize = true}) {
|
export default async function metrics({login, q}, {graphql, rest, plugins, conf}) {
|
||||||
//Compute rendering
|
//Compute rendering
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
//Init
|
||||||
|
const template = q.template || conf.settings.templates.default
|
||||||
|
const pending = []
|
||||||
|
const s = (value, end = "") => value > 1 ? {y:"ies", "":"s"}[end] : end
|
||||||
|
if ((!(template in Templates))||(!(template in conf.templates))||((conf.settings.templates.enabled.length)&&(!conf.settings.templates.enabled.includes(template))))
|
||||||
|
throw new Error("unsupported template")
|
||||||
|
const {query, image, style} = conf.templates[template]
|
||||||
|
|
||||||
//Query data from GitHub API
|
//Query data from GitHub API
|
||||||
console.debug(`metrics/metrics/${login} > query`)
|
console.debug(`metrics/compute/${login} > query`)
|
||||||
const data = await graphql(query
|
const data = await graphql(query
|
||||||
.replace(/[$]login/, `"${login}"`)
|
.replace(/[$]login/, `"${login}"`)
|
||||||
.replace(/[$]calendar.to/, `"${(new Date()).toISOString()}"`)
|
.replace(/[$]calendar.to/, `"${(new Date()).toISOString()}"`)
|
||||||
.replace(/[$]calendar.from/, `"${(new Date(Date.now()-14*24*60*60*1000)).toISOString()}"`)
|
.replace(/[$]calendar.from/, `"${(new Date(Date.now()-14*24*60*60*1000)).toISOString()}"`)
|
||||||
)
|
)
|
||||||
|
console.debug(`metrics/compute/${login} > query > success`)
|
||||||
|
|
||||||
//Init
|
//Template
|
||||||
const languages = {colors:{}, total:0, stats:{}}
|
console.debug(`metrics/compute/${login} > compute`)
|
||||||
const licenses = {favorite:"", used:{}}
|
const computer = Templates[template].default || Templates[template]
|
||||||
const computed = data.computed = {commits:0, languages, licenses, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0}, plugins:{}}
|
await computer({login, q}, {data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, imgb64}})
|
||||||
const avatar = imgb64(data.user.avatarUrl)
|
|
||||||
const pending = []
|
|
||||||
|
|
||||||
//Plugins
|
|
||||||
if (data.user.websiteUrl)
|
|
||||||
Plugins.pagespeed({login, url:data.user.websiteUrl, computed, pending, q}, plugins.pagespeed)
|
|
||||||
Plugins.lines({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.lines)
|
|
||||||
Plugins.traffic({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.traffic)
|
|
||||||
Plugins.habits({login, rest, computed, pending, q}, plugins.habits)
|
|
||||||
Plugins.selfskip({login, rest, computed, pending, q}, plugins.selfskip)
|
|
||||||
|
|
||||||
//Iterate through user's repositories
|
|
||||||
for (const repository of data.user.repositories.nodes) {
|
|
||||||
//Simple properties with totalCount
|
|
||||||
for (const property of ["watchers", "stargazers", "issues_open", "issues_closed", "pr_open", "pr_merged"])
|
|
||||||
computed.repositories[property] += repository[property].totalCount
|
|
||||||
//Forks
|
|
||||||
computed.repositories.forks += repository.forkCount
|
|
||||||
//Languages
|
|
||||||
for (const {size, node:{color, name}} of Object.values(repository.languages.edges)) {
|
|
||||||
languages.stats[name] = (languages.stats[name] || 0) + size
|
|
||||||
languages.colors[name] = color || "#ededed"
|
|
||||||
languages.total += size
|
|
||||||
}
|
|
||||||
//License
|
|
||||||
if (repository.licenseInfo)
|
|
||||||
licenses.used[repository.licenseInfo.spdxId] = (licenses.used[repository.licenseInfo.spdxId] || 0) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
//Compute count for issues and pull requests
|
|
||||||
for (const property of ["issues", "pr"])
|
|
||||||
computed.repositories[`${property}_count`] = computed.repositories[`${property}_open`] + computed.repositories[`${property}_${property === "pr" ? "merged" : "closed"}`]
|
|
||||||
|
|
||||||
//Compute total commits and sponsorships
|
|
||||||
computed.commits = data.user.contributionsCollection.totalCommitContributions + data.user.contributionsCollection.restrictedContributionsCount
|
|
||||||
computed.sponsorships = data.user.sponsorshipsAsSponsor.totalCount + data.user.sponsorshipsAsMaintainer.totalCount
|
|
||||||
|
|
||||||
//Compute registration date
|
|
||||||
const diff = (Date.now()-(new Date(data.user.createdAt)).getTime())/(365*24*60*60*1000)
|
|
||||||
const years = Math.floor(diff)
|
|
||||||
const months = Math.ceil((diff-years)*12)
|
|
||||||
computed.registration = years ? `${years} year${years > 1 ? "s" : ""} ago` : `${months} month${months > 1 ? "s" : ""} ago`
|
|
||||||
|
|
||||||
//Compute languages stats
|
|
||||||
Object.keys(languages.stats).map(name => languages.stats[name] /= languages.total)
|
|
||||||
languages.favorites = Object.entries(languages.stats).sort(([an, a], [bn, b]) => b - a).slice(0, 8).map(([name, value]) => ({name, value, color:languages.colors[name], x:0}))
|
|
||||||
for (let i = 1; i < languages.favorites.length; i++)
|
|
||||||
languages.favorites[i].x = languages.favorites[i-1].x + languages.favorites[i-1].value
|
|
||||||
|
|
||||||
//Compute licenses stats
|
|
||||||
licenses.favorite = Object.entries(licenses.used).sort(([an, a], [bn, b]) => b - a).slice(0, 1).map(([name, value]) => name) || ""
|
|
||||||
|
|
||||||
//Compute calendar
|
|
||||||
computed.calendar = data.user.calendar.contributionCalendar.weeks.flatMap(({contributionDays}) => contributionDays).slice(0, 14).reverse()
|
|
||||||
|
|
||||||
//Avatar (base64)
|
|
||||||
computed.avatar = await avatar || "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
|
||||||
|
|
||||||
//Wait for pending promises
|
|
||||||
await Promise.all(pending)
|
await Promise.all(pending)
|
||||||
|
console.debug(`metrics/compute/${login} > compute > success`)
|
||||||
|
|
||||||
//Eval rendering
|
//Eval rendering
|
||||||
console.debug(`metrics/metrics/${login} > computed`)
|
console.debug(`metrics/compute/${login} > render`)
|
||||||
let rendered = eval(`\`${template}\``)
|
let rendered = await ejs.render(image, {...data, s, style}, {async:true})
|
||||||
console.debug(`metrics/metrics/${login} > templated`)
|
console.debug(`metrics/compute/${login} > render > success`)
|
||||||
|
|
||||||
//Optimize rendering
|
//Optimize rendering
|
||||||
if (optimize) {
|
if (conf.optimize) {
|
||||||
|
console.debug(`metrics/compute/${login} > optimize`)
|
||||||
const svgo = new SVGO({full:true, plugins:[{cleanupAttrs:true}, {inlineStyles:false}]})
|
const svgo = new SVGO({full:true, plugins:[{cleanupAttrs:true}, {inlineStyles:false}]})
|
||||||
const {data:optimized} = await svgo.optimize(rendered)
|
const {data:optimized} = await svgo.optimize(rendered)
|
||||||
console.debug(`metrics/metrics/${login} > optimized`)
|
console.debug(`metrics/compute/${login} > optimize > success`)
|
||||||
rendered = optimized
|
rendered = optimized
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,5 +52,11 @@
|
|||||||
return rendered
|
return rendered
|
||||||
}
|
}
|
||||||
//Internal error
|
//Internal error
|
||||||
catch (error) { throw (((Array.isArray(error.errors))&&(error.errors[0].type === "NOT_FOUND")) ? new Error("user not found") : error) }
|
catch (error) {
|
||||||
|
//User not found
|
||||||
|
if (((Array.isArray(error.errors))&&(error.errors[0].type === "NOT_FOUND")))
|
||||||
|
throw new Error("user not found")
|
||||||
|
//Generic error
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
return computed.plugins.habits = null
|
return computed.plugins.habits = null
|
||||||
if (!q.habits)
|
if (!q.habits)
|
||||||
return computed.plugins.habits = null
|
return computed.plugins.habits = null
|
||||||
console.debug(`metrics/plugins/habits/${login} > started`)
|
console.debug(`metrics/compute/${login}/plugins > habits`)
|
||||||
|
computed.svg.height += 70
|
||||||
|
|
||||||
//Plugin execution
|
//Plugin execution
|
||||||
pending.push(new Promise(async solve => {
|
pending.push(new Promise(async solve => {
|
||||||
@@ -44,12 +45,14 @@
|
|||||||
}
|
}
|
||||||
//Save results
|
//Save results
|
||||||
computed.plugins.habits = habits
|
computed.plugins.habits = habits
|
||||||
console.debug(`metrics/plugins/habits/${login} > ${JSON.stringify(computed.plugins.habits)}`)
|
console.debug(`metrics/compute/${login}/plugins > habits > success`)
|
||||||
|
console.debug(JSON.stringify(computed.plugins.habits))
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
//Generic error
|
//Generic error
|
||||||
computed.plugins.habits = {error:`An error occured`}
|
computed.plugins.habits = {error:`An error occured`}
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > habits > error`)
|
||||||
console.debug(error)
|
console.debug(error)
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
return computed.plugins.lines = null
|
return computed.plugins.lines = null
|
||||||
if (!q.lines)
|
if (!q.lines)
|
||||||
return computed.plugins.lines = null
|
return computed.plugins.lines = null
|
||||||
console.debug(`metrics/plugins/lines/${login} > started`)
|
console.debug(`metrics/compute/${login}/plugins > lines`)
|
||||||
|
computed.svg.height += 20
|
||||||
|
|
||||||
//Plugin execution
|
//Plugin execution
|
||||||
pending.push(new Promise(async solve => {
|
pending.push(new Promise(async solve => {
|
||||||
@@ -37,12 +38,14 @@
|
|||||||
lines.deleted = format(lines.deleted)
|
lines.deleted = format(lines.deleted)
|
||||||
//Save results
|
//Save results
|
||||||
computed.plugins.lines = {...lines}
|
computed.plugins.lines = {...lines}
|
||||||
console.debug(`metrics/plugins/lines/${login} > ${JSON.stringify(computed.plugins.lines)}`)
|
console.debug(`metrics/compute/${login}/plugins > lines > success`)
|
||||||
|
console.debug(JSON.stringify(computed.plugins.lines))
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
//Generic error
|
//Generic error
|
||||||
computed.plugins.pagespeed = {error:`An error occured`}
|
computed.plugins.lines = {error:`An error occured`}
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > lines > error`)
|
||||||
console.debug(error)
|
console.debug(error)
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
return computed.plugins.pagespeed = null
|
return computed.plugins.pagespeed = null
|
||||||
if (!q.pagespeed)
|
if (!q.pagespeed)
|
||||||
return computed.plugins.pagespeed = null
|
return computed.plugins.pagespeed = null
|
||||||
console.debug(`metrics/plugins/pagespeed/${login} > started`)
|
console.debug(`metrics/compute/${login}/plugins > pagespeed`)
|
||||||
|
computed.svg.height += 130
|
||||||
|
|
||||||
//Plugin execution
|
//Plugin execution
|
||||||
pending.push(new Promise(async solve => {
|
pending.push(new Promise(async solve => {
|
||||||
@@ -26,18 +27,20 @@
|
|||||||
}))
|
}))
|
||||||
//Save results
|
//Save results
|
||||||
computed.plugins.pagespeed = {url, scores:[scores.get("performance"), scores.get("accessibility"), scores.get("best-practices"), scores.get("seo")]}
|
computed.plugins.pagespeed = {url, scores:[scores.get("performance"), scores.get("accessibility"), scores.get("best-practices"), scores.get("seo")]}
|
||||||
console.debug(`metrics/plugins/pagespeed/${login} > ${JSON.stringify(computed.plugins.pagespeed)}`)
|
console.debug(`metrics/compute/${login}/plugins > pagespeed > success`)
|
||||||
|
console.debug(JSON.stringify(computed.plugins.pagespeed))
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
//Thrown when token is incorrect
|
//Thrown when token is incorrect
|
||||||
if ((error.response)&&(error.response.status)) {
|
if ((error.response)&&(error.response.status)) {
|
||||||
computed.plugins.pagespeed = {url, error:`PageSpeed token error (code ${error.response.status})`}
|
computed.plugins.pagespeed = {url, error:`PageSpeed token error (code ${error.response.status})`}
|
||||||
console.debug(`metrics/plugins/traffic/${login} > ${error.response.status}`)
|
console.debug(`metrics/plugins/pagespeed/${login} > ${error.response.status}`)
|
||||||
return solve()
|
return solve()
|
||||||
}
|
}
|
||||||
//Generic error
|
//Generic error
|
||||||
computed.plugins.pagespeed = {error:`An error occured`}
|
computed.plugins.pagespeed = {error:`An error occured`}
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > pagespeed > error`)
|
||||||
console.debug(error)
|
console.debug(error)
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
return computed.plugins.selfskip = null
|
return computed.plugins.selfskip = null
|
||||||
if (!q.selfskip)
|
if (!q.selfskip)
|
||||||
return computed.plugins.selfskip = null
|
return computed.plugins.selfskip = null
|
||||||
console.debug(`metrics/plugins/selfskip/${login} > started`)
|
console.debug(`metrics/compute/${login}/plugins > selfskip`)
|
||||||
|
|
||||||
//Plugin execution
|
//Plugin execution
|
||||||
pending.push(new Promise(async solve => {
|
pending.push(new Promise(async solve => {
|
||||||
@@ -20,12 +20,14 @@
|
|||||||
}
|
}
|
||||||
//Save results
|
//Save results
|
||||||
computed.plugins.selfskip = {commits}
|
computed.plugins.selfskip = {commits}
|
||||||
console.debug(`metrics/plugins/selfskip/${login} > ${JSON.stringify(computed.plugins.selfskip)}`)
|
console.debug(`metrics/compute/${login}/plugins > selfskip > success`)
|
||||||
|
console.debug(JSON.stringify(computed.plugins.selfskip))
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
//Generic error
|
//Generic error
|
||||||
computed.plugins.selfskip = {error:`An error occured`}
|
computed.plugins.selfskip = {error:`An error occured`}
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > selfskip > error`)
|
||||||
console.debug(error)
|
console.debug(error)
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
return computed.plugins.traffic = null
|
return computed.plugins.traffic = null
|
||||||
if (!q.traffic)
|
if (!q.traffic)
|
||||||
return computed.plugins.traffic = null
|
return computed.plugins.traffic = null
|
||||||
console.debug(`metrics/plugins/traffic/${login} > started`)
|
console.debug(`metrics/compute/${login}/plugins > traffic`)
|
||||||
|
computed.svg.height += 20
|
||||||
|
|
||||||
//Plugin execution
|
//Plugin execution
|
||||||
pending.push(new Promise(async solve => {
|
pending.push(new Promise(async solve => {
|
||||||
@@ -28,18 +29,20 @@
|
|||||||
views.uniques = format(views.uniques)
|
views.uniques = format(views.uniques)
|
||||||
//Save results
|
//Save results
|
||||||
computed.plugins.traffic = {views}
|
computed.plugins.traffic = {views}
|
||||||
console.debug(`metrics/plugins/traffic/${login} > ${JSON.stringify(computed.plugins.traffic)}`)
|
console.debug(`metrics/compute/${login}/plugins > traffic > success`)
|
||||||
|
console.debug(JSON.stringify(computed.plugins.traffic))
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
//Thrown when token has unsufficient permissions
|
//Thrown when token has unsufficient permissions
|
||||||
if (error.status === 403) {
|
if (error.status === 403) {
|
||||||
computed.plugins.traffic = {error:`Insufficient token rights`}
|
computed.plugins.traffic = {error:`Insufficient token rights`}
|
||||||
console.debug(`metrics/plugins/traffic/${login} > ${error.status}`)
|
console.debug(`metrics/compute/${login}/plugins > error > 403 (insufficient token rights)`)
|
||||||
return solve()
|
return solve()
|
||||||
}
|
}
|
||||||
//Generic error
|
//Generic error
|
||||||
computed.plugins.traffic = {error:`An error occured`}
|
computed.plugins.traffic = {error:`An error occured`}
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > error`)
|
||||||
console.debug(error)
|
console.debug(error)
|
||||||
solve()
|
solve()
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/setup.mjs
Normal file
67
src/setup.mjs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//Imports
|
||||||
|
import fs from "fs"
|
||||||
|
import path from "path"
|
||||||
|
|
||||||
|
/** Setup */
|
||||||
|
export default async function () {
|
||||||
|
|
||||||
|
//Init
|
||||||
|
console.debug(`metrics/setup > setup`)
|
||||||
|
const templates = "src/templates"
|
||||||
|
const conf = {
|
||||||
|
templates:{},
|
||||||
|
settings:{},
|
||||||
|
statics:path.resolve("src/html")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load settings
|
||||||
|
console.debug(`metrics/setup > load settings.json`)
|
||||||
|
if (fs.existsSync(path.resolve("settings.json"))) {
|
||||||
|
conf.settings = JSON.parse(`${await fs.promises.readFile(path.resolve("settings.json"))}`)
|
||||||
|
console.debug(`metrics/setup > load settings.json > success`)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
console.debug(`metrics/setup > load settings.json > (missing)`)
|
||||||
|
if (!conf.settings.templates)
|
||||||
|
conf.settings.templates = {default:"classic", enabled:[]}
|
||||||
|
if (conf.settings.debug)
|
||||||
|
console.debug(conf.settings)
|
||||||
|
|
||||||
|
//Load templates
|
||||||
|
if (fs.existsSync(path.resolve(templates))) {
|
||||||
|
for (const name of await fs.promises.readdir(templates)) {
|
||||||
|
//Cache templates
|
||||||
|
if (/^index.mjs$/.test(name))
|
||||||
|
continue
|
||||||
|
console.debug(`metrics/setup > load template [${name}]`)
|
||||||
|
const files = [
|
||||||
|
`${templates}/${name}/query.graphql`,
|
||||||
|
`${templates}/${name}/image.svg`,
|
||||||
|
`${templates}/${name}/style.css`,
|
||||||
|
]
|
||||||
|
const [query, image, style] = await Promise.all(files.map(async file => `${await fs.promises.readFile(path.resolve(file))}`))
|
||||||
|
conf.templates[name] = {query, image, style}
|
||||||
|
console.debug(`metrics/setup > load template [${name}] > success`)
|
||||||
|
//Debug
|
||||||
|
if (conf.settings.debug) {
|
||||||
|
Object.defineProperty(conf.templates, name, {
|
||||||
|
get() {
|
||||||
|
console.debug(`metrics/setup > reload template [${name}]`)
|
||||||
|
const [query, image, style] = files.map(file => `${fs.readFileSync(path.resolve(file))}`)
|
||||||
|
console.debug(`metrics/setup > reload template [${name}] > success`)
|
||||||
|
return {query, image, style}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.debug(`metrics/setup > load templates from build`)
|
||||||
|
conf.templates = JSON.parse(Buffer.from(`<#assets>`, "base64").toString("utf8"))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Conf
|
||||||
|
console.debug(`metrics/setup > setup > success`)
|
||||||
|
return conf
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="${485 + ((computed.plugins.lines||computed.plugins.traffic) ? 20 : 0) + (computed.plugins.pagespeed ? 130 : 0) + (computed.plugins.habits ? 70 : 0)}">
|
<svg xmlns="http://www.w3.org/2000/svg" width="<%= computed.svg.width %>" height="<%= computed.svg.height %>">
|
||||||
<style>
|
<style>
|
||||||
${style}
|
<%= style %>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<foreignObject x="0" y="0" width="100%" height="100%">
|
<foreignObject x="0" y="0" width="100%" height="100%">
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h1 class="field">
|
<h1 class="field">
|
||||||
<img class="avatar" src="data:image/png;base64,${data.computed.avatar}" width="20" height="20" />
|
<img class="avatar" src="data:image/png;base64,<%= computed.avatar %>" width="20" height="20" />
|
||||||
<span>${data.user.name || data.user.login}</span>
|
<span><%= user.name || user.login %></span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -17,27 +17,27 @@
|
|||||||
<section>
|
<section>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.75a.75.75 0 00-1.5 0v3.5a.75.75 0 00.471.696l2.5 1a.75.75 0 00.557-1.392L8.5 7.742V4.75z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.75a.75.75 0 00-1.5 0v3.5a.75.75 0 00.471.696l2.5 1a.75.75 0 00.557-1.392L8.5 7.742V4.75z"></path></svg>
|
||||||
Joined GitHub ${data.computed.registration}
|
Joined GitHub <%= computed.registration %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
||||||
Followed by ${data.user.followers.totalCount} user${data.user.followers.totalCount > 1 ? "s" : ""}
|
Followed by <%= user.followers.totalCount %> user<%= s(user.followers.totalCount) %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="field calendar">
|
<div class="field calendar">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${data.computed.calendar.length*15} 11" width="${data.computed.calendar.length*15}" height="16">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 <%= computed.calendar.length*15 %> 11" width="<%= computed.calendar.length*15 %>" height="16">
|
||||||
<g>
|
<g>
|
||||||
${data.computed.calendar.map(({color}, x) => `
|
<% for (const [x, {color}] of Object.entries(computed.calendar)) { %>
|
||||||
<rect class="day" x="${x*15}" y="0" width="11" height="11" fill="${color}" rx="2" ry="2" />
|
<rect class="day" x="<%= x*15 %>" y="0" width="11" height="11" fill="<%= color %>" rx="2" ry="2" />
|
||||||
`).join("")}
|
<% } %>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1 2.5A2.5 2.5 0 013.5 0h8.75a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0V1.5h-8a1 1 0 00-1 1v6.708A2.492 2.492 0 013.5 9h3.25a.75.75 0 010 1.5H3.5a1 1 0 100 2h5.75a.75.75 0 010 1.5H3.5A2.5 2.5 0 011 11.5v-9zm13.23 7.79a.75.75 0 001.06-1.06l-2.505-2.505a.75.75 0 00-1.06 0L9.22 9.229a.75.75 0 001.06 1.061l1.225-1.224v6.184a.75.75 0 001.5 0V9.066l1.224 1.224z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1 2.5A2.5 2.5 0 013.5 0h8.75a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0V1.5h-8a1 1 0 00-1 1v6.708A2.492 2.492 0 013.5 9h3.25a.75.75 0 010 1.5H3.5a1 1 0 100 2h5.75a.75.75 0 010 1.5H3.5A2.5 2.5 0 011 11.5v-9zm13.23 7.79a.75.75 0 001.06-1.06l-2.505-2.505a.75.75 0 00-1.06 0L9.22 9.229a.75.75 0 001.06 1.061l1.225-1.224v6.184a.75.75 0 001.5 0V9.066l1.224 1.224z"></path></svg>
|
||||||
Contributed to ${data.user.repositoriesContributedTo.totalCount} repositor${data.user.repositoriesContributedTo.totalCount > 1 ? "ies" : "y"}
|
Contributed to <%= user.repositoriesContributedTo.totalCount %> repositor<%= s(user.repositoriesContributedTo.totalCount, "y") %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -54,23 +54,23 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M10.5 7.75a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm1.43.75a4.002 4.002 0 01-7.86 0H.75a.75.75 0 110-1.5h3.32a4.001 4.001 0 017.86 0h3.32a.75.75 0 110 1.5h-3.32z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M10.5 7.75a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm1.43.75a4.002 4.002 0 01-7.86 0H.75a.75.75 0 110-1.5h3.32a4.001 4.001 0 017.86 0h3.32a.75.75 0 110 1.5h-3.32z"></path></svg>
|
||||||
${data.computed.commits - (computed.plugins.selfskip ? computed.plugins.selfskip.commits||0 : 0)} Commit${data.computed.commits - (computed.plugins.selfskip ? computed.plugins.selfskip.commits||0 : 0) > 1 ? "s" : ""}
|
<%= computed.commits - (computed.plugins.selfskip ? computed.plugins.selfskip.commits||0 : 0) %> Commit<% s(computed.commits - (computed.plugins.selfskip ? computed.plugins.selfskip.commits||0 : 0)) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.5 1.75a.25.25 0 01.25-.25h8.5a.25.25 0 01.25.25v7.736a.75.75 0 101.5 0V1.75A1.75 1.75 0 0011.25 0h-8.5A1.75 1.75 0 001 1.75v11.5c0 .966.784 1.75 1.75 1.75h3.17a.75.75 0 000-1.5H2.75a.25.25 0 01-.25-.25V1.75zM4.75 4a.75.75 0 000 1.5h4.5a.75.75 0 000-1.5h-4.5zM4 7.75A.75.75 0 014.75 7h2a.75.75 0 010 1.5h-2A.75.75 0 014 7.75zm11.774 3.537a.75.75 0 00-1.048-1.074L10.7 14.145 9.281 12.72a.75.75 0 00-1.062 1.058l1.943 1.95a.75.75 0 001.055.008l4.557-4.45z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.5 1.75a.25.25 0 01.25-.25h8.5a.25.25 0 01.25.25v7.736a.75.75 0 101.5 0V1.75A1.75 1.75 0 0011.25 0h-8.5A1.75 1.75 0 001 1.75v11.5c0 .966.784 1.75 1.75 1.75h3.17a.75.75 0 000-1.5H2.75a.25.25 0 01-.25-.25V1.75zM4.75 4a.75.75 0 000 1.5h4.5a.75.75 0 000-1.5h-4.5zM4 7.75A.75.75 0 014.75 7h2a.75.75 0 010 1.5h-2A.75.75 0 014 7.75zm11.774 3.537a.75.75 0 00-1.048-1.074L10.7 14.145 9.281 12.72a.75.75 0 00-1.062 1.058l1.943 1.95a.75.75 0 001.055.008l4.557-4.45z"></path></svg>
|
||||||
${data.user.contributionsCollection.totalPullRequestReviewContributions} Pull request${data.user.contributionsCollection.totalPullRequestReviewContributions > 1 ? "s" : ""} reviewed
|
<%= user.contributionsCollection.totalPullRequestReviewContributions %> Pull request<%= s(user.contributionsCollection.totalPullRequestReviewContributions) %> reviewed
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"></path></svg>
|
||||||
${data.user.contributionsCollection.totalPullRequestContributions} Pull request${data.user.contributionsCollection.totalPullRequestContributions > 1 ? "s" : ""} opened
|
<%= user.contributionsCollection.totalPullRequestContributions %> Pull request<%= s(user.contributionsCollection.totalPullRequestContributions) %> opened
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>
|
||||||
${data.user.contributionsCollection.totalIssueContributions} Issue${data.user.contributionsCollection.totalIssueContributions > 1 ? "s" : ""} opened
|
<%= user.contributionsCollection.totalIssueContributions %> Issue<%= s(user.contributionsCollection.totalIssueContributions) %> opened
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.75 2.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 01.75.75v2.19l2.72-2.72a.75.75 0 01.53-.22h4.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25H2.75zM1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0113.25 12H9.06l-2.573 2.573A1.457 1.457 0 014 13.543V12H2.75A1.75 1.75 0 011 10.25v-7.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.75 2.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 01.75.75v2.19l2.72-2.72a.75.75 0 01.53-.22h4.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25H2.75zM1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0113.25 12H9.06l-2.573 2.573A1.457 1.457 0 014 13.543V12H2.75A1.75 1.75 0 011 10.25v-7.5z"></path></svg>
|
||||||
${data.user.issueComments.totalCount} issue comment${data.user.issueComments.totalCount > 1 ? "s" : ""}
|
<%= user.issueComments.totalCount %> issue comment<%= s(user.issueComments.totalCount) %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -81,23 +81,23 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
||||||
Following ${data.user.following.totalCount} user${data.user.followers.totalCount > 1 ? "s" : ""}
|
Following <%= user.following.totalCount %> user<% s(user.followers.totalCount) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.565 20.565 0 008 13.393a20.561 20.561 0 003.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.75.75 0 01-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5zM8 14.25l-.345.666-.002-.001-.006-.003-.018-.01a7.643 7.643 0 01-.31-.17 22.075 22.075 0 01-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.08 22.08 0 01-3.744 2.584l-.018.01-.006.003h-.002L8 14.25zm0 0l.345.666a.752.752 0 01-.69 0L8 14.25z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.565 20.565 0 008 13.393a20.561 20.561 0 003.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.75.75 0 01-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5zM8 14.25l-.345.666-.002-.001-.006-.003-.018-.01a7.643 7.643 0 01-.31-.17 22.075 22.075 0 01-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.08 22.08 0 01-3.744 2.584l-.018.01-.006.003h-.002L8 14.25zm0 0l.345.666a.752.752 0 01-.69 0L8 14.25z"></path></svg>
|
||||||
Sponsoring ${data.computed.sponsorships} repositor${data.computed.sponsorships > 1 ? "ies" : "y"}
|
Sponsoring <%= computed.sponsorships %> repositor<%= s(computed.sponsorships, "y") %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path></svg>
|
||||||
Starred ${data.user.starredRepositories.totalCount} repositor${data.user.starredRepositories.totalCount > 1 ? "ies" : "y"}
|
Starred <%= user.starredRepositories.totalCount %> repositor<%= s(user.starredRepositories.totalCount, "y") %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path></svg>
|
||||||
Watching ${data.user.watching.totalCount} repositor${data.user.watching.totalCount > 1 ? "ies" : "y"}
|
Watching <%= user.watching.totalCount %> repositor <%= s(user.watching.totalCount, "y") %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 14.25c0 .138.112.25.25.25H4v-1.25a.75.75 0 01.75-.75h2.5a.75.75 0 01.75.75v1.25h2.25a.25.25 0 00.25-.25V1.75a.25.25 0 00-.25-.25h-8.5a.25.25 0 00-.25.25v12.5zM1.75 16A1.75 1.75 0 010 14.25V1.75C0 .784.784 0 1.75 0h8.5C11.216 0 12 .784 12 1.75v12.5c0 .085-.006.168-.018.25h2.268a.25.25 0 00.25-.25V8.285a.25.25 0 00-.111-.208l-1.055-.703a.75.75 0 11.832-1.248l1.055.703c.487.325.779.871.779 1.456v5.965A1.75 1.75 0 0114.25 16h-3.5a.75.75 0 01-.197-.026c-.099.017-.2.026-.303.026h-3a.75.75 0 01-.75-.75V14h-1v1.25a.75.75 0 01-.75.75h-3zM3 3.75A.75.75 0 013.75 3h.5a.75.75 0 010 1.5h-.5A.75.75 0 013 3.75zM3.75 6a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM3 9.75A.75.75 0 013.75 9h.5a.75.75 0 010 1.5h-.5A.75.75 0 013 9.75zM7.75 9a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM7 6.75A.75.75 0 017.75 6h.5a.75.75 0 010 1.5h-.5A.75.75 0 017 6.75zM7.75 3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 14.25c0 .138.112.25.25.25H4v-1.25a.75.75 0 01.75-.75h2.5a.75.75 0 01.75.75v1.25h2.25a.25.25 0 00.25-.25V1.75a.25.25 0 00-.25-.25h-8.5a.25.25 0 00-.25.25v12.5zM1.75 16A1.75 1.75 0 010 14.25V1.75C0 .784.784 0 1.75 0h8.5C11.216 0 12 .784 12 1.75v12.5c0 .085-.006.168-.018.25h2.268a.25.25 0 00.25-.25V8.285a.25.25 0 00-.111-.208l-1.055-.703a.75.75 0 11.832-1.248l1.055.703c.487.325.779.871.779 1.456v5.965A1.75 1.75 0 0114.25 16h-3.5a.75.75 0 01-.197-.026c-.099.017-.2.026-.303.026h-3a.75.75 0 01-.75-.75V14h-1v1.25a.75.75 0 01-.75.75h-3zM3 3.75A.75.75 0 013.75 3h.5a.75.75 0 010 1.5h-.5A.75.75 0 013 3.75zM3.75 6a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM3 9.75A.75.75 0 013.75 9h.5a.75.75 0 010 1.5h-.5A.75.75 0 013 9.75zM7.75 9a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM7 6.75A.75.75 0 017.75 6h.5a.75.75 0 010 1.5h-.5A.75.75 0 017 6.75zM7.75 3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5z"></path></svg>
|
||||||
Member of ${data.user.organizations.totalCount} organization${data.user.organizations.totalCount > 1 ? "s" : ""}
|
Member of <%= user.organizations.totalCount %> organization <%= s(user.organizations.totalCount) %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -106,59 +106,61 @@
|
|||||||
<section>
|
<section>
|
||||||
<h2 class="field">
|
<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="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"></path></svg>
|
||||||
${data.user.repositories.totalCount} Repositor${data.user.repositories.totalCount > 1 ? "ies" : "y"}
|
<%= user.repositories.totalCount %> Repositor<%= s(user.repositories.totalCount, "y") %>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<section>
|
<section>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8.75.75a.75.75 0 00-1.5 0V2h-.984c-.305 0-.604.08-.869.23l-1.288.737A.25.25 0 013.984 3H1.75a.75.75 0 000 1.5h.428L.066 9.192a.75.75 0 00.154.838l.53-.53-.53.53v.001l.002.002.002.002.006.006.016.015.045.04a3.514 3.514 0 00.686.45A4.492 4.492 0 003 11c.88 0 1.556-.22 2.023-.454a3.515 3.515 0 00.686-.45l.045-.04.016-.015.006-.006.002-.002.001-.002L5.25 9.5l.53.53a.75.75 0 00.154-.838L3.822 4.5h.162c.305 0 .604-.08.869-.23l1.289-.737a.25.25 0 01.124-.033h.984V13h-2.5a.75.75 0 000 1.5h6.5a.75.75 0 000-1.5h-2.5V3.5h.984a.25.25 0 01.124.033l1.29.736c.264.152.563.231.868.231h.162l-2.112 4.692a.75.75 0 00.154.838l.53-.53-.53.53v.001l.002.002.002.002.006.006.016.015.045.04a3.517 3.517 0 00.686.45A4.492 4.492 0 0013 11c.88 0 1.556-.22 2.023-.454a3.512 3.512 0 00.686-.45l.045-.04.01-.01.006-.005.006-.006.002-.002.001-.002-.529-.531.53.53a.75.75 0 00.154-.838L13.823 4.5h.427a.75.75 0 000-1.5h-2.234a.25.25 0 01-.124-.033l-1.29-.736A1.75 1.75 0 009.735 2H8.75V.75zM1.695 9.227c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327l-1.305 2.9zm10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327l-1.305 2.9z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8.75.75a.75.75 0 00-1.5 0V2h-.984c-.305 0-.604.08-.869.23l-1.288.737A.25.25 0 013.984 3H1.75a.75.75 0 000 1.5h.428L.066 9.192a.75.75 0 00.154.838l.53-.53-.53.53v.001l.002.002.002.002.006.006.016.015.045.04a3.514 3.514 0 00.686.45A4.492 4.492 0 003 11c.88 0 1.556-.22 2.023-.454a3.515 3.515 0 00.686-.45l.045-.04.016-.015.006-.006.002-.002.001-.002L5.25 9.5l.53.53a.75.75 0 00.154-.838L3.822 4.5h.162c.305 0 .604-.08.869-.23l1.289-.737a.25.25 0 01.124-.033h.984V13h-2.5a.75.75 0 000 1.5h6.5a.75.75 0 000-1.5h-2.5V3.5h.984a.25.25 0 01.124.033l1.29.736c.264.152.563.231.868.231h.162l-2.112 4.692a.75.75 0 00.154.838l.53-.53-.53.53v.001l.002.002.002.002.006.006.016.015.045.04a3.517 3.517 0 00.686.45A4.492 4.492 0 0013 11c.88 0 1.556-.22 2.023-.454a3.512 3.512 0 00.686-.45l.045-.04.01-.01.006-.005.006-.006.002-.002.001-.002-.529-.531.53.53a.75.75 0 00.154-.838L13.823 4.5h.427a.75.75 0 000-1.5h-2.234a.25.25 0 01-.124-.033l-1.29-.736A1.75 1.75 0 009.735 2H8.75V.75zM1.695 9.227c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327l-1.305 2.9zm10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327l-1.305 2.9z"></path></svg>
|
||||||
${data.computed.licenses.favorite.length ? `Prefer ${data.computed.licenses.favorite} license` : "No license preference" }
|
<% if (computed.licenses.favorite.length) { %>
|
||||||
|
Prefer <%= computed.licenses.favorite %> license
|
||||||
|
<% } else { %>
|
||||||
|
No license preference
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8.878.392a1.75 1.75 0 00-1.756 0l-5.25 3.045A1.75 1.75 0 001 4.951v6.098c0 .624.332 1.2.872 1.514l5.25 3.045a1.75 1.75 0 001.756 0l5.25-3.045c.54-.313.872-.89.872-1.514V4.951c0-.624-.332-1.2-.872-1.514L8.878.392zM7.875 1.69a.25.25 0 01.25 0l4.63 2.685L8 7.133 3.245 4.375l4.63-2.685zM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432L2.5 5.677zm6.25 8.271l4.625-2.683a.25.25 0 00.125-.216V5.677L8.75 8.432v5.516z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8.878.392a1.75 1.75 0 00-1.756 0l-5.25 3.045A1.75 1.75 0 001 4.951v6.098c0 .624.332 1.2.872 1.514l5.25 3.045a1.75 1.75 0 001.756 0l5.25-3.045c.54-.313.872-.89.872-1.514V4.951c0-.624-.332-1.2-.872-1.514L8.878.392zM7.875 1.69a.25.25 0 01.25 0l4.63 2.685L8 7.133 3.245 4.375l4.63-2.685zM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432L2.5 5.677zm6.25 8.271l4.625-2.683a.25.25 0 00.125-.216V5.677L8.75 8.432v5.516z"></path></svg>
|
||||||
${data.user.packages.totalCount} Package${data.user.packages.totalCount > 1 ? "s" : ""}
|
<%= user.packages.totalCount %> Package <%= s(user.packages.totalCount) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" ><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25V1.75a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm9.22 3.72a.75.75 0 000 1.06L10.69 8 9.22 9.47a.75.75 0 101.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0zM6.78 6.53a.75.75 0 00-1.06-1.06l-2 2a.75.75 0 000 1.06l2 2a.75.75 0 101.06-1.06L5.31 8l1.47-1.47z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" ><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25V1.75a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm9.22 3.72a.75.75 0 000 1.06L10.69 8 9.22 9.47a.75.75 0 101.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0zM6.78 6.53a.75.75 0 00-1.06-1.06l-2 2a.75.75 0 000 1.06l2 2a.75.75 0 101.06-1.06L5.31 8l1.47-1.47z"></path></svg>
|
||||||
${data.user.gists.totalCount} Gist${data.user.gists.totalCount > 1 ? "s" : ""}
|
<%= user.gists.totalCount %> Gist <%= s(user.gists.totalCount) %>
|
||||||
</div>
|
</div>
|
||||||
${computed.plugins.lines ? computed.plugins.lines.error ? `
|
<% if (computed.plugins.lines) { %>
|
||||||
<div class="field error">
|
<div class="field <%= computed.plugins.lines.error ? 'error' : '' %>">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.72 3.22a.75.75 0 011.06 1.06L2.06 8l3.72 3.72a.75.75 0 11-1.06 1.06L.47 8.53a.75.75 0 010-1.06l4.25-4.25zm6.56 0a.75.75 0 10-1.06 1.06L13.94 8l-3.72 3.72a.75.75 0 101.06 1.06l4.25-4.25a.75.75 0 000-1.06l-4.25-4.25z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.72 3.22a.75.75 0 011.06 1.06L2.06 8l3.72 3.72a.75.75 0 11-1.06 1.06L.47 8.53a.75.75 0 010-1.06l4.25-4.25zm6.56 0a.75.75 0 10-1.06 1.06L13.94 8l-3.72 3.72a.75.75 0 101.06 1.06l4.25-4.25a.75.75 0 000-1.06l-4.25-4.25z"></path></svg>
|
||||||
${computed.plugins.lines.error}
|
<% if (computed.plugins.lines.error) { %>
|
||||||
</div>
|
<%= computed.plugins.lines.error %>
|
||||||
` : `
|
<% } else { %>
|
||||||
<div class="field">
|
<%= computed.plugins.lines.added %> added, <%= computed.plugins.lines.deleted %> removed
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.72 3.22a.75.75 0 011.06 1.06L2.06 8l3.72 3.72a.75.75 0 11-1.06 1.06L.47 8.53a.75.75 0 010-1.06l4.25-4.25zm6.56 0a.75.75 0 10-1.06 1.06L13.94 8l-3.72 3.72a.75.75 0 101.06 1.06l4.25-4.25a.75.75 0 000-1.06l-4.25-4.25z"></path></svg>
|
<% } %>
|
||||||
${computed.plugins.lines.added} added, ${computed.plugins.lines.deleted} removed
|
</div>
|
||||||
</div>` : ""
|
<% } %>
|
||||||
}
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path></svg>
|
||||||
${data.computed.repositories.stargazers} Stargazer${data.computed.repositories.stargazers > 1 ? "s" : ""}
|
<%= computed.repositories.stargazers %> Stargazer<%= s(computed.repositories.stargazers) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z"></path></svg>
|
||||||
${data.computed.repositories.forks} Fork${data.computed.repositories.forks > 1 ? "s" : ""}
|
<%= computed.repositories.forks %> Fork<%= s(computed.repositories.forks) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path></svg>
|
||||||
${data.computed.repositories.watchers} Watcher${data.computed.repositories.watchers > 1 ? "s" : ""}
|
<%= computed.repositories.watchers %> Watcher<%= s(computed.repositories.watchers) %>
|
||||||
</div>
|
</div>
|
||||||
${computed.plugins.traffic ? computed.plugins.traffic.error ? `
|
<% if (computed.plugins.traffic) { %>
|
||||||
<div class="field error">
|
<div class="field <%= computed.plugins.traffic.error ? 'error' : '' %>">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 1.75A.75.75 0 01.75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0111.006 1h4.245a.75.75 0 01.75.75v10.5a.75.75 0 01-.75.75h-4.507a2.25 2.25 0 00-1.591.659l-.622.621a.75.75 0 01-1.06 0l-.622-.621A2.25 2.25 0 005.258 13H.75a.75.75 0 01-.75-.75V1.75zm8.755 3a2.25 2.25 0 012.25-2.25H14.5v9h-3.757c-.71 0-1.4.201-1.992.572l.004-7.322zm-1.504 7.324l.004-5.073-.002-2.253A2.25 2.25 0 005.003 2.5H1.5v9h3.757a3.75 3.75 0 011.994.574z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 1.75A.75.75 0 01.75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0111.006 1h4.245a.75.75 0 01.75.75v10.5a.75.75 0 01-.75.75h-4.507a2.25 2.25 0 00-1.591.659l-.622.621a.75.75 0 01-1.06 0l-.622-.621A2.25 2.25 0 005.258 13H.75a.75.75 0 01-.75-.75V1.75zm8.755 3a2.25 2.25 0 012.25-2.25H14.5v9h-3.757c-.71 0-1.4.201-1.992.572l.004-7.322zm-1.504 7.324l.004-5.073-.002-2.253A2.25 2.25 0 005.003 2.5H1.5v9h3.757a3.75 3.75 0 011.994.574z"></path></svg>
|
||||||
${computed.plugins.traffic.error}
|
<% if (computed.plugins.traffic.error) { %>
|
||||||
</div>
|
<%= computed.plugins.traffic.error %>
|
||||||
` : `
|
<% } else { %>
|
||||||
<div class="field">
|
<%= computed.plugins.traffic.views.count %> view<%= s(computed.plugins.traffic.views.count) %> in last two weeks
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 1.75A.75.75 0 01.75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0111.006 1h4.245a.75.75 0 01.75.75v10.5a.75.75 0 01-.75.75h-4.507a2.25 2.25 0 00-1.591.659l-.622.621a.75.75 0 01-1.06 0l-.622-.621A2.25 2.25 0 005.258 13H.75a.75.75 0 01-.75-.75V1.75zm8.755 3a2.25 2.25 0 012.25-2.25H14.5v9h-3.757c-.71 0-1.4.201-1.992.572l.004-7.322zm-1.504 7.324l.004-5.073-.002-2.253A2.25 2.25 0 005.003 2.5H1.5v9h3.757a3.75 3.75 0 011.994.574z"></path></svg>
|
<% } %>
|
||||||
${computed.plugins.traffic.views.count} views in last two weeks
|
</div>
|
||||||
</div>` : ""
|
<% } %>
|
||||||
}
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -171,18 +173,18 @@
|
|||||||
<mask id="issues-bar">
|
<mask id="issues-bar">
|
||||||
<rect x="0" y="0" width="220" height="8" fill="white" rx="5"/>
|
<rect x="0" y="0" width="220" height="8" fill="white" rx="5"/>
|
||||||
</mask>
|
</mask>
|
||||||
<rect mask="url(#issues-bar)" x="0" y="0" width="${data.computed.repositories.issues_count ? 0 : 220}" height="8" fill="#d1d5da"/>
|
<rect mask="url(#issues-bar)" x="0" y="0" width="<%= computed.repositories.issues_count ? 0 : 220 %>" height="8" fill="#d1d5da"/>
|
||||||
<rect mask="url(#issues-bar)" x="0" y="0" width="${(data.computed.repositories.issues_closed/data.computed.repositories.issues_count)*220 || 0}" height="8" fill="#d73a49"/>
|
<rect mask="url(#issues-bar)" x="0" y="0" width="<%= (computed.repositories.issues_closed/computed.repositories.issues_count)*220 || 0 %>" height="8" fill="#d73a49"/>
|
||||||
<rect mask="url(#issues-bar)" x="${(data.computed.repositories.issues_closed/data.computed.repositories.issues_count)*220 || 0}" y="0" width="${(1-data.computed.repositories.issues_closed/data.computed.repositories.issues_count)*220 || 0}" height="8" fill="#28a745"/>
|
<rect mask="url(#issues-bar)" x="<%= (computed.repositories.issues_closed/computed.repositories.issues_count)*220 || 0 %>" y="0" width="<%= (1-computed.repositories.issues_closed/computed.repositories.issues_count)*220 || 0 %>" height="8" fill="#28a745"/>
|
||||||
</svg>
|
</svg>
|
||||||
<div class="field horizontal fill-width">
|
<div class="field horizontal fill-width">
|
||||||
<div class="field center">
|
<div class="field center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#d73a49" fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 0110.65-5.003.75.75 0 00.959-1.153 8 8 0 102.592 8.33.75.75 0 10-1.444-.407A6.5 6.5 0 011.5 8zM8 12a1 1 0 100-2 1 1 0 000 2zm0-8a.75.75 0 01.75.75v3.5a.75.75 0 11-1.5 0v-3.5A.75.75 0 018 4zm4.78 4.28l3-3a.75.75 0 00-1.06-1.06l-2.47 2.47-.97-.97a.749.749 0 10-1.06 1.06l1.5 1.5a.75.75 0 001.06 0z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#d73a49" fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 0110.65-5.003.75.75 0 00.959-1.153 8 8 0 102.592 8.33.75.75 0 10-1.444-.407A6.5 6.5 0 011.5 8zM8 12a1 1 0 100-2 1 1 0 000 2zm0-8a.75.75 0 01.75.75v3.5a.75.75 0 11-1.5 0v-3.5A.75.75 0 018 4zm4.78 4.28l3-3a.75.75 0 00-1.06-1.06l-2.47 2.47-.97-.97a.749.749 0 10-1.06 1.06l1.5 1.5a.75.75 0 001.06 0z"></path></svg>
|
||||||
<span class="no-wrap">${data.computed.repositories.issues_closed} Closed</span>
|
<span class="no-wrap"><%= computed.repositories.issues_closed %> Closed</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field center">
|
<div class="field center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#28a745" fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#28a745" fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>
|
||||||
<span class="no-wrap">${data.computed.repositories.issues_open} Open</span>
|
<span class="no-wrap"><%= computed.repositories.issues_open %> Open</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -193,18 +195,18 @@
|
|||||||
<mask id="pr-bar">
|
<mask id="pr-bar">
|
||||||
<rect x="0" y="0" width="220" height="8" fill="white" rx="5"/>
|
<rect x="0" y="0" width="220" height="8" fill="white" rx="5"/>
|
||||||
</mask>
|
</mask>
|
||||||
<rect mask="url(#pr-bar)" x="0" y="0" width="${data.computed.repositories.pr_count ? 0 : 220}" height="8" fill="#d1d5da"/>
|
<rect mask="url(#pr-bar)" x="0" y="0" width="<%= computed.repositories.pr_count ? 0 : 220 %>" height="8" fill="#d1d5da"/>
|
||||||
<rect mask="url(#pr-bar)" x="0" y="0" width="${(data.computed.repositories.pr_merged/data.computed.repositories.pr_count)*220 || 0}" height="8" fill="#6f42c1"/>
|
<rect mask="url(#pr-bar)" x="0" y="0" width="<%= (computed.repositories.pr_merged/computed.repositories.pr_count)*220 || 0 %>" height="8" fill="#6f42c1"/>
|
||||||
<rect mask="url(#pr-bar)" x="${(data.computed.repositories.pr_merged/data.computed.repositories.pr_count)*220 || 0}" y="0" width="${(1-data.computed.repositories.pr_merged/data.computed.repositories.pr_count)*220 || 0}" height="8" fill="#28a745"/>
|
<rect mask="url(#pr-bar)" x="<%= (computed.repositories.pr_merged/computed.repositories.pr_count)*220 || 0 %>" y="0" width="<%= (1-computed.repositories.pr_merged/computed.repositories.pr_count)*220 || 0 %>" height="8" fill="#28a745"/>
|
||||||
</svg>
|
</svg>
|
||||||
<div class="field horizontal fill-width">
|
<div class="field horizontal fill-width">
|
||||||
<div class="field center">
|
<div class="field center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#6f42c1" fill-rule="evenodd" d="M5 3.254V3.25v.005a.75.75 0 110-.005v.004zm.45 1.9a2.25 2.25 0 10-1.95.218v5.256a2.25 2.25 0 101.5 0V7.123A5.735 5.735 0 009.25 9h1.378a2.251 2.251 0 100-1.5H9.25a4.25 4.25 0 01-3.8-2.346zM12.75 9a.75.75 0 100-1.5.75.75 0 000 1.5zm-8.5 4.5a.75.75 0 100-1.5.75.75 0 000 1.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#6f42c1" fill-rule="evenodd" d="M5 3.254V3.25v.005a.75.75 0 110-.005v.004zm.45 1.9a2.25 2.25 0 10-1.95.218v5.256a2.25 2.25 0 101.5 0V7.123A5.735 5.735 0 009.25 9h1.378a2.251 2.251 0 100-1.5H9.25a4.25 4.25 0 01-3.8-2.346zM12.75 9a.75.75 0 100-1.5.75.75 0 000 1.5zm-8.5 4.5a.75.75 0 100-1.5.75.75 0 000 1.5z"></path></svg>
|
||||||
<span class="no-wrap">${data.computed.repositories.pr_merged} Merged</span>
|
<span class="no-wrap"><%= computed.repositories.pr_merged %> Merged</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field center">
|
<div class="field center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#28a745" fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="#28a745" fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"></path></svg>
|
||||||
<span class="no-wrap">${data.computed.repositories.pr_open} Open</span>
|
<span class="no-wrap"><%= computed.repositories.pr_open %> Open</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -217,22 +219,22 @@
|
|||||||
<mask id="languages-bar">
|
<mask id="languages-bar">
|
||||||
<rect x="0" y="0" width="460" height="8" fill="white" rx="5"/>
|
<rect x="0" y="0" width="460" height="8" fill="white" rx="5"/>
|
||||||
</mask>
|
</mask>
|
||||||
<rect mask="url(#languages-bar)" x="0" y="0" width="${data.computed.languages.favorites.length ? 0 : 460}" height="8" fill="#d1d5da"/>
|
<rect mask="url(#languages-bar)" x="0" y="0" width="<%= computed.languages.favorites.length ? 0 : 460 %>" height="8" fill="#d1d5da"/>
|
||||||
${data.computed.languages.favorites.map(({name, value, color, x}) => `
|
<% for (const {name, value, color, x} of computed.languages.favorites) { %>
|
||||||
<rect mask="url(#languages-bar)" x="${x*460}" y="0" width="${value*460}" height="8" fill="${color}"/>
|
<rect mask="url(#languages-bar)" x="<%= x*460 %>" y="0" width="<%= value*460 %>" height="8" fill="<%= color %>"/>
|
||||||
`).join("")}
|
<% } %>
|
||||||
</svg>
|
</svg>
|
||||||
<div class="field center horizontal-wrap fill-width">
|
<div class="field center horizontal-wrap fill-width">
|
||||||
${data.computed.languages.favorites.map(({name, color}) => `
|
<% for (const {name, value, color} of computed.languages.favorites) { %>
|
||||||
<div class="field center no-wrap language">
|
<div class="field center no-wrap language">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="${color}" fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="<%= color %>" fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8z"></path></svg>
|
||||||
${name}
|
<%= name %>
|
||||||
</div>
|
</div>
|
||||||
`).join("")}
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
${computed.plugins.pagespeed ? `
|
<% if (computed.plugins.pagespeed) { %>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<section>
|
<section>
|
||||||
<h2 class="field">
|
<h2 class="field">
|
||||||
@@ -241,65 +243,70 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg>
|
||||||
${computed.plugins.pagespeed.url}
|
<%= user.websiteUrl %>
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>` : ""
|
|
||||||
}
|
|
||||||
${computed.plugins.pagespeed ? computed.plugins.pagespeed.error ? `
|
|
||||||
<div class="row">
|
|
||||||
<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="M4.47.22A.75.75 0 015 0h6a.75.75 0 01.53.22l4.25 4.25c.141.14.22.331.22.53v6a.75.75 0 01-.22.53l-4.25 4.25A.75.75 0 0111 16H5a.75.75 0 01-.53-.22L.22 11.53A.75.75 0 010 11V5a.75.75 0 01.22-.53L4.47.22zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5H5.31zM8 4a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 018 4zm0 8a1 1 0 100-2 1 1 0 000 2z"></path></svg>
|
|
||||||
${computed.plugins.pagespeed.error}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
` : `
|
<% if (computed.plugins.pagespeed.error) { %>
|
||||||
<section>
|
<div class="row">
|
||||||
<div class="row fill-width">
|
<section>
|
||||||
<section class="categories">
|
<div class="field error">
|
||||||
${computed.plugins.pagespeed.scores.map(({score, title}) => `
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.47.22A.75.75 0 015 0h6a.75.75 0 01.53.22l4.25 4.25c.141.14.22.331.22.53v6a.75.75 0 01-.22.53l-4.25 4.25A.75.75 0 0111 16H5a.75.75 0 01-.53-.22L.22 11.53A.75.75 0 010 11V5a.75.75 0 01.22-.53L4.47.22zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5H5.31zM8 4a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 018 4zm0 8a1 1 0 100-2 1 1 0 000 2z"></path></svg>
|
||||||
<div class="categorie column">
|
<%= computed.plugins.pagespeed.error %>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="50" height="50" class="gauge ${score >= 0.9 ? 'high' : score >= 0.5 ? 'average' : 'low'}">
|
</div>
|
||||||
<circle class="gauge-base" r="53" cx="60" cy="60"></circle>
|
|
||||||
<circle class="gauge-arc" transform="rotate(-90 60 60)" r="53" cx="60" cy="60" stroke-dasharray="${score * 329} 329"></circle>
|
|
||||||
<text x="60" y="60" dominant-baseline="central" >${Math.round(score*100)}</text>
|
|
||||||
</svg>
|
|
||||||
<span class="title">${title}</span>
|
|
||||||
</div>
|
|
||||||
`).join("")}
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</section>` : ""
|
<% } else { %>
|
||||||
}
|
<section>
|
||||||
|
<div class="row fill-width">
|
||||||
|
<section class="categories">
|
||||||
|
<% for (const {score, title} of computed.plugins.pagespeed.scores) { %>
|
||||||
|
<div class="categorie column">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="50" height="50" class="gauge <%= score >= 0.9 ? 'high' : score >= 0.5 ? 'average' : 'low' %>">
|
||||||
|
<circle class="gauge-base" r="53" cx="60" cy="60"></circle>
|
||||||
|
<circle class="gauge-arc" transform="rotate(-90 60 60)" r="53" cx="60" cy="60" stroke-dasharray="<%= score * 329 %> 329"></circle>
|
||||||
|
<text x="60" y="60" dominant-baseline="central" ><%= Math.round(score*100) %></text>
|
||||||
|
</svg>
|
||||||
|
<span class="title"><%= title %></span>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
${computed.plugins.habits ? `
|
<% if (computed.plugins.habits) { %>
|
||||||
<section>
|
<section>
|
||||||
<h2 class="field">
|
<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="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 01-1.484.211c-.04-.282-.163-.547-.37-.847a8.695 8.695 0 00-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.75.75 0 01-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75zM6 15.25a.75.75 0 01.75-.75h2.5a.75.75 0 010 1.5h-2.5a.75.75 0 01-.75-.75zM5.75 12a.75.75 0 000 1.5h4.5a.75.75 0 000-1.5h-4.5z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 01-1.484.211c-.04-.282-.163-.547-.37-.847a8.695 8.695 0 00-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.75.75 0 01-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75zM6 15.25a.75.75 0 01.75-.75h2.5a.75.75 0 010 1.5h-2.5a.75.75 0 01-.75-.75zM5.75 12a.75.75 0 000 1.5h4.5a.75.75 0 000-1.5h-4.5z"></path></svg>
|
||||||
Coding habits
|
Coding habits
|
||||||
</h2>
|
</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
${computed.plugins.habits.error ? `
|
<% if (computed.plugins.habits.error) { %>
|
||||||
<section>
|
<section>
|
||||||
<div class="field error">
|
<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="M4.47.22A.75.75 0 015 0h6a.75.75 0 01.53.22l4.25 4.25c.141.14.22.331.22.53v6a.75.75 0 01-.22.53l-4.25 4.25A.75.75 0 0111 16H5a.75.75 0 01-.53-.22L.22 11.53A.75.75 0 010 11V5a.75.75 0 01.22-.53L4.47.22zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5H5.31zM8 4a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 018 4zm0 8a1 1 0 100-2 1 1 0 000 2z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.47.22A.75.75 0 015 0h6a.75.75 0 01.53.22l4.25 4.25c.141.14.22.331.22.53v6a.75.75 0 01-.22.53l-4.25 4.25A.75.75 0 0111 16H5a.75.75 0 01-.53-.22L.22 11.53A.75.75 0 010 11V5a.75.75 0 01.22-.53L4.47.22zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5H5.31zM8 4a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 018 4zm0 8a1 1 0 100-2 1 1 0 000 2z"></path></svg>
|
||||||
${computed.plugins.habits.error}
|
<%= computed.plugins.habits.error %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
` : `
|
<% } else { %>
|
||||||
<ul class="habits">
|
<ul class="habits">
|
||||||
${computed.plugins.habits.indents.style ? `<li>Use ${computed.plugins.habits.indents.style} for indents</li>` : ""}
|
<% if (computed.plugins.habits.indents.style) { %>
|
||||||
${!Number.isNaN(computed.plugins.habits.commits.hour) ? `<li>Mostly push code around ${computed.plugins.habits.commits.hour}:00</li>` : ""}
|
<li>Use <%= computed.plugins.habits.indents.style %> for indents</li>
|
||||||
|
<% } %>
|
||||||
|
<% if (!Number.isNaN(computed.plugins.habits.commits.hour)) { %>
|
||||||
|
<li>Mostly push code around <%= computed.plugins.habits.commits.hour %>:00</li>
|
||||||
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
`}
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</section>` : ""
|
</section>
|
||||||
}
|
<% } %>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
Last updated ${new Date()}
|
<span>These metrics <%= !computed.token.scopes.includes("repo") ? "does not include" : "includes" %> private contributions</span>
|
||||||
|
<span>Last updated <%= new Date() %></span>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@@ -107,6 +107,11 @@
|
|||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field.language small {
|
||||||
|
margin-left: 4px;
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
|
||||||
/* Habits */
|
/* Habits */
|
||||||
.habits {
|
.habits {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -117,10 +122,13 @@
|
|||||||
/* Footer */
|
/* Footer */
|
||||||
footer {
|
footer {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
text-align: right;
|
font-size: 10px;
|
||||||
font-size: 8px;
|
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
text-align: right;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Speed test categories */
|
/* Speed test categories */
|
||||||
68
src/templates/classic/template.mjs
Normal file
68
src/templates/classic/template.mjs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/** Template processort */
|
||||||
|
export default async function ({login, q}, {data, rest, graphql, plugins}, {s, pending, imports}) {
|
||||||
|
|
||||||
|
//Init
|
||||||
|
const languages = {colors:{}, total:0, stats:{}}
|
||||||
|
const licenses = {favorite:"", used:{}}
|
||||||
|
const computed = data.computed = {commits:0, languages, licenses, svg:{height:505, width:480}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0}, plugins:{}}
|
||||||
|
const avatar = imports.imgb64(data.user.avatarUrl)
|
||||||
|
|
||||||
|
//Plugins
|
||||||
|
if (data.user.websiteUrl)
|
||||||
|
imports.plugins.pagespeed({login, url:data.user.websiteUrl, computed, pending, q}, plugins.pagespeed)
|
||||||
|
imports.plugins.lines({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.lines)
|
||||||
|
imports.plugins.traffic({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.traffic)
|
||||||
|
imports.plugins.habits({login, rest, computed, pending, q}, plugins.habits)
|
||||||
|
imports.plugins.selfskip({login, rest, computed, pending, q}, plugins.selfskip)
|
||||||
|
|
||||||
|
//Iterate through user's repositories
|
||||||
|
for (const repository of data.user.repositories.nodes) {
|
||||||
|
//Simple properties with totalCount
|
||||||
|
for (const property of ["watchers", "stargazers", "issues_open", "issues_closed", "pr_open", "pr_merged"])
|
||||||
|
computed.repositories[property] += repository[property].totalCount
|
||||||
|
//Forks
|
||||||
|
computed.repositories.forks += repository.forkCount
|
||||||
|
//Languages
|
||||||
|
for (const {size, node:{color, name}} of Object.values(repository.languages.edges)) {
|
||||||
|
languages.stats[name] = (languages.stats[name] || 0) + size
|
||||||
|
languages.colors[name] = color || "#ededed"
|
||||||
|
languages.total += size
|
||||||
|
}
|
||||||
|
//License
|
||||||
|
if (repository.licenseInfo)
|
||||||
|
licenses.used[repository.licenseInfo.spdxId] = (licenses.used[repository.licenseInfo.spdxId] || 0) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//Compute count for issues and pull requests
|
||||||
|
for (const property of ["issues", "pr"])
|
||||||
|
computed.repositories[`${property}_count`] = computed.repositories[`${property}_open`] + computed.repositories[`${property}_${property === "pr" ? "merged" : "closed"}`]
|
||||||
|
|
||||||
|
//Compute total commits and sponsorships
|
||||||
|
computed.commits = data.user.contributionsCollection.totalCommitContributions + data.user.contributionsCollection.restrictedContributionsCount
|
||||||
|
computed.sponsorships = data.user.sponsorshipsAsSponsor.totalCount + data.user.sponsorshipsAsMaintainer.totalCount
|
||||||
|
|
||||||
|
//Compute registration date
|
||||||
|
const diff = (Date.now()-(new Date(data.user.createdAt)).getTime())/(365*24*60*60*1000)
|
||||||
|
const years = Math.floor(diff)
|
||||||
|
const months = Math.ceil((diff-years)*12)
|
||||||
|
computed.registration = years ? `${years} year${s(years)} ago` : `${months} month${s(months)} ago`
|
||||||
|
|
||||||
|
//Compute languages stats
|
||||||
|
Object.keys(languages.stats).map(name => languages.stats[name] /= languages.total)
|
||||||
|
languages.favorites = Object.entries(languages.stats).sort(([an, a], [bn, b]) => b - a).slice(0, 8).map(([name, value]) => ({name, value, color:languages.colors[name], x:0}))
|
||||||
|
for (let i = 1; i < languages.favorites.length; i++)
|
||||||
|
languages.favorites[i].x = languages.favorites[i-1].x + languages.favorites[i-1].value
|
||||||
|
|
||||||
|
//Compute licenses stats
|
||||||
|
licenses.favorite = Object.entries(licenses.used).sort(([an, a], [bn, b]) => b - a).slice(0, 1).map(([name, value]) => name) || ""
|
||||||
|
|
||||||
|
//Compute calendar
|
||||||
|
computed.calendar = data.user.calendar.contributionCalendar.weeks.flatMap(({contributionDays}) => contributionDays).slice(0, 14).reverse()
|
||||||
|
|
||||||
|
//Avatar (base64)
|
||||||
|
computed.avatar = await avatar || "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
||||||
|
|
||||||
|
//Token scopes
|
||||||
|
computed.token.scopes = (await rest.request("HEAD /")).headers["x-oauth-scopes"].split(", ")
|
||||||
|
|
||||||
|
}
|
||||||
7
src/templates/index.mjs
Normal file
7
src/templates/index.mjs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//Imports
|
||||||
|
import classic from "./classic/template.mjs"
|
||||||
|
|
||||||
|
//Exports
|
||||||
|
export default {
|
||||||
|
classic
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import metrics from "../src/metrics.mjs"
|
import metrics from "../src/metrics.mjs"
|
||||||
|
import setup from "../src/setup.mjs"
|
||||||
import build from "../utils/build.mjs"
|
import build from "../utils/build.mjs"
|
||||||
import octokit from "@octokit/graphql"
|
import octokit from "@octokit/graphql"
|
||||||
import OctokitRest from "@octokit/rest"
|
import OctokitRest from "@octokit/rest"
|
||||||
@@ -19,11 +20,9 @@
|
|||||||
const graphql = octokit.graphql.defaults({headers:{authorization: `token ${token}`}})
|
const graphql = octokit.graphql.defaults({headers:{authorization: `token ${token}`}})
|
||||||
const rest = new OctokitRest.Octokit({auth:token})
|
const rest = new OctokitRest.Octokit({auth:token})
|
||||||
|
|
||||||
//Load svg template, style and query
|
|
||||||
const [template, style, query] = await Promise.all(["template.svg", "style.css", "query.graphql"].map(async file => `${await fs.promises.readFile(path.join("src", file))}`))
|
|
||||||
|
|
||||||
//Compute render
|
//Compute render
|
||||||
const rendered = await metrics({login:"lowlighter", q:{}}, {template, style, query, graphql, rest, plugins:{}})
|
const conf = await setup()
|
||||||
|
const rendered = await metrics({login:"lowlighter", q:{}}, {graphql, rest, plugins:{}, conf})
|
||||||
|
|
||||||
//Ensure it's a well-formed SVG image
|
//Ensure it's a well-formed SVG image
|
||||||
const parsed = libxmljs.parseXml(rendered)
|
const parsed = libxmljs.parseXml(rendered)
|
||||||
|
|||||||
@@ -17,12 +17,22 @@
|
|||||||
sourceMapRegister:false,
|
sourceMapRegister:false,
|
||||||
})
|
})
|
||||||
|
|
||||||
//Perform static includes
|
//Perform assets includes
|
||||||
for (const match of [...code.match(/(?<=`)<#include (.+?)>(?=`)/g)]) {
|
const assets = {}
|
||||||
const file = match.match(/<#include (.+?)>/)[1]
|
const templates = path.join(__dirname, "..", "src/templates")
|
||||||
code = code.replace(`<#include ${file}>`, `${await fs.promises.readFile(path.join(__dirname, "..", "src", file))}`.replace(/([$`\\])/g, "\\$1"))
|
for (const name of await fs.promises.readdir(templates)) {
|
||||||
console.log(`Included ${file}`)
|
if (/^index.mjs$/.test(name))
|
||||||
|
continue
|
||||||
|
console.log(`Including template ${name}`)
|
||||||
|
const files = [
|
||||||
|
`${templates}/${name}/query.graphql`,
|
||||||
|
`${templates}/${name}/image.svg`,
|
||||||
|
`${templates}/${name}/style.css`,
|
||||||
|
]
|
||||||
|
const [query, image, style] = await Promise.all(files.map(async file => `${await fs.promises.readFile(path.resolve(file))}`))
|
||||||
|
assets[name] = {query, image, style}
|
||||||
}
|
}
|
||||||
|
code = code.replace(`<#assets>`, Buffer.from(JSON.stringify(assets)).toString("base64"))
|
||||||
|
|
||||||
//Perform version include
|
//Perform version include
|
||||||
const version = JSON.parse(await fs.promises.readFile(path.join(__dirname, "..", "package.json"))).version
|
const version = JSON.parse(await fs.promises.readFile(path.join(__dirname, "..", "package.json"))).version
|
||||||
|
|||||||
Reference in New Issue
Block a user