Plugin pagespeed detailed and workflow refactor (#15)

* Display debug logs on error

* Add workflow generator

* Minor plugins adjustements

* Add plugin_pagespeed_detailed option

* Rename computed.plugins to plugins

* Rebuild

* Fix mishandling of boolean value in url for web instance

* Add pagespeed.detailled option for web instances

* Update formatting of pagespeed detailed report

* Add version display and prefers-color-scheme for web instance
This commit is contained in:
Simon Lecoq
2020-12-10 12:59:56 +01:00
committed by GitHub
parent 6ef500d694
commit 484a124441
21 changed files with 745 additions and 342 deletions

View File

@@ -1,23 +0,0 @@
name: Analysis
on:
push:
branches: [master]
pull_request:
branches: [master]
schedule:
- cron: 0 0 * * *
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
uses: github/codeql-action/init@v1
with:
languages: javascript
config-file: ./.github/config/codeql.yml
- name: Analyze
uses: github/codeql-action/analyze@v1

View File

@@ -23,430 +23,504 @@ jobs:
- name: Test - name: Test
run: npm test run: npm test
test-master: analyze:
runs-on: ubuntu-latest
needs: ["test@master","test@latest"]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
uses: github/codeql-action/init@v1
with:
languages: javascript
config-file: ./.github/config/codeql.yml
- name: Analyze
uses: github/codeql-action/analyze@v1
# Tests cases below are auto generated through `npm run build`
# Edit utils/workflow.yml instead if you need to update workflow
test@master:
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
template: ["classic","terminal"]
steps: steps:
- name: Template > Classic - name: ${{ matrix.template }} > Base
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
repositories: 1
plugins_errors_fatal: yes
dryrun: yes dryrun: yes
- name: Template > Terminal
uses: lowlighter/metrics@master
with:
template: terminal
token: ${{ secrets.METRICS_TOKEN }}
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: header, activity, community, repositories, metadata
plugins_errors_fatal: yes plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > PageSpeed - name: ${{ matrix.template }} > Plugin > PageSpeed
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: "" base: ""
repositories: 1 plugins_errors_fatal: yes
plugin_pagespeed: yes plugin_pagespeed: yes
plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }} plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Music (playlist - apple) - name: ${{ matrix.template }} > Plugin > PageSpeed (detailed)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_pagespeed: yes
plugin_pagespeed_detailed: yes
plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }}
- name: ${{ matrix.template }} > Plugin > Music (playlist - apple)
uses: lowlighter/metrics@master
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes plugin_music: yes
plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_APPLE }} plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_APPLE }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Music (playlist - spotify) - name: ${{ matrix.template }} > Plugin > Music (playlist - spotify)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes plugin_music: yes
plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_SPOTIFY }} plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_SPOTIFY }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Music (recent - spotify) - name: ${{ matrix.template }} > Plugin > Music (recent - spotify)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes plugin_music: yes
plugin_music_provider: spotify plugin_music_provider: spotify
plugin_music_token: ${{ secrets.SPOTIFY_TOKENS }} plugin_music_token: ${{ secrets.SPOTIFY_TOKENS }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Posts (dev.to) - name: ${{ matrix.template }} > Plugin > Posts (dev.to)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_posts: yes plugin_posts: yes
plugin_posts_source: dev.to plugin_posts_source: dev.to
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Isocalendar - name: ${{ matrix.template }} > Plugin > Isocalendar
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_isocalendar: yes plugin_isocalendar: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Isocalendar (full year) - name: ${{ matrix.template }} > Plugin > Isocalendar (full year)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_isocalendar: yes plugin_isocalendar: yes
plugin_isocalendar_duration: full-year plugin_isocalendar_duration: full-year
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Habits - name: ${{ matrix.template }} > Plugin > Habits
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_habits: yes plugin_habits: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Languages - name: ${{ matrix.template }} > Plugin > Languages
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_languages: yes plugin_languages: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Follow-up - name: ${{ matrix.template }} > Plugin > Follow-up
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_followup: yes plugin_followup: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Lines - name: ${{ matrix.template }} > Plugin > Lines
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "repositories" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_lines: yes plugin_lines: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Traffic - name: ${{ matrix.template }} > Plugin > Traffic
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "repositories" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_traffic: yes plugin_traffic: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Gists - name: ${{ matrix.template }} > Plugin > Gists
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_gists: yes plugin_gists: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (stars) - name: ${{ matrix.template }} > Plugin > Topics (stars)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: stars plugin_topics_sort: stars
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (activity) - name: ${{ matrix.template }} > Plugin > Topics (activity)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: activity plugin_topics_sort: activity
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (starred) - name: ${{ matrix.template }} > Plugin > Topics (starred)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: starred plugin_topics_sort: starred
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (random) - name: ${{ matrix.template }} > Plugin > Topics (random)
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: random plugin_topics_sort: random
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Projects - name: ${{ matrix.template }} > Plugin > Projects
uses: lowlighter/metrics@master uses: lowlighter/metrics@master
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_projects: yes plugin_projects: yes
plugin_projects_limit: 2 plugin_projects_limit: 2
plugins_errors_fatal: yes
dryrun: yes
test-latest:
test@latest:
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
template: ["classic","terminal"]
steps: steps:
- name: Template > Classic - name: ${{ matrix.template }} > Base
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
repositories: 1
plugins_errors_fatal: yes
dryrun: yes dryrun: yes
- name: Template > Terminal
uses: lowlighter/metrics@latest
with:
template: terminal
token: ${{ secrets.METRICS_TOKEN }}
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: header, activity, community, repositories, metadata
plugins_errors_fatal: yes plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > PageSpeed - name: ${{ matrix.template }} > Plugin > PageSpeed
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: "" base: ""
repositories: 1 plugins_errors_fatal: yes
plugin_pagespeed: yes plugin_pagespeed: yes
plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }} plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Music (playlist - apple) - name: ${{ matrix.template }} > Plugin > PageSpeed (detailed)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_pagespeed: yes
plugin_pagespeed_detailed: yes
plugin_pagespeed_token: ${{ secrets.PAGESPEED_TOKEN }}
- name: ${{ matrix.template }} > Plugin > Music (playlist - apple)
uses: lowlighter/metrics@latest
with:
token: ${{ secrets.METRICS_TOKEN }}
dryrun: yes
repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes plugin_music: yes
plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_APPLE }} plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_APPLE }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Music (playlist - spotify) - name: ${{ matrix.template }} > Plugin > Music (playlist - spotify)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes plugin_music: yes
plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_SPOTIFY }} plugin_music_playlist: ${{ secrets.MUSIC_PLAYLIST_SPOTIFY }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Music (recent - spotify) - name: ${{ matrix.template }} > Plugin > Music (recent - spotify)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_music: yes plugin_music: yes
plugin_music_provider: spotify plugin_music_provider: spotify
plugin_music_token: ${{ secrets.SPOTIFY_TOKENS }} plugin_music_token: ${{ secrets.SPOTIFY_TOKENS }}
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Posts (dev.to) - name: ${{ matrix.template }} > Plugin > Posts (dev.to)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_posts: yes plugin_posts: yes
plugin_posts_source: dev.to plugin_posts_source: dev.to
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Isocalendar - name: ${{ matrix.template }} > Plugin > Isocalendar
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_isocalendar: yes plugin_isocalendar: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Isocalendar (full year) - name: ${{ matrix.template }} > Plugin > Isocalendar (full year)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_isocalendar: yes plugin_isocalendar: yes
plugin_isocalendar_duration: full-year plugin_isocalendar_duration: full-year
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Habits - name: ${{ matrix.template }} > Plugin > Habits
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_habits: yes plugin_habits: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Languages - name: ${{ matrix.template }} > Plugin > Languages
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_languages: yes plugin_languages: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Follow-up - name: ${{ matrix.template }} > Plugin > Follow-up
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_followup: yes plugin_followup: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Lines - name: ${{ matrix.template }} > Plugin > Lines
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "repositories" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_lines: yes plugin_lines: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Traffic - name: ${{ matrix.template }} > Plugin > Traffic
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "repositories" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_traffic: yes plugin_traffic: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Gists - name: ${{ matrix.template }} > Plugin > Gists
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_gists: yes plugin_gists: yes
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (stars) - name: ${{ matrix.template }} > Plugin > Topics (stars)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: stars plugin_topics_sort: stars
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (activity) - name: ${{ matrix.template }} > Plugin > Topics (activity)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: activity plugin_topics_sort: activity
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (starred) - name: ${{ matrix.template }} > Plugin > Topics (starred)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: starred plugin_topics_sort: starred
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Topics (random) - name: ${{ matrix.template }} > Plugin > Topics (random)
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_topics: yes plugin_topics: yes
plugin_topics_sort: random plugin_topics_sort: random
plugins_errors_fatal: yes
dryrun: yes
- name: Plugin > Projects - name: ${{ matrix.template }} > Plugin > Projects
uses: lowlighter/metrics@latest uses: lowlighter/metrics@latest
with: with:
token: ${{ secrets.METRICS_TOKEN }} token: ${{ secrets.METRICS_TOKEN }}
base: "" dryrun: yes
repositories: 1 repositories: 1
template: ${{ matrix.template }}
base: ""
plugins_errors_fatal: yes
plugin_projects: yes plugin_projects: yes
plugin_projects_limit: 2 plugin_projects_limit: 2
plugins_errors_fatal: yes
dryrun: yes

View File

@@ -75,6 +75,14 @@ inputs:
description: Enable Google PageSpeed metrics for account attached website description: Enable Google PageSpeed metrics for account attached website
default: no default: no
# Display additional PageSpeed audit metrics
# The following are displayed :
# First Contentful Paint, Speed Index, Largest Contentful Paint, Time to Interactive, Total Blocking Time, Cumulative Layout Shift
# See https://web.dev/performance-scoring/ and https://googlechrome.github.io/lighthouse/scorecalc/ for more informations
plugin_pagespeed_detailed:
description: Display additional PageSpeed audit metrics
default: no
# When PageSpeed plugin is enabled, it is advised to generate a token to avoid the rate-limiter # When PageSpeed plugin is enabled, it is advised to generate a token to avoid the rate-limiter
# 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_token: plugin_pagespeed_token:

File diff suppressed because one or more lines are too long

View File

@@ -10,6 +10,8 @@
const [core, github, octokit, setup, metrics] = [_core, _github, _octokit, _setup, _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
//Debug message buffer
const debugged = []
//Runner //Runner
try { try {
//Initialization //Initialization
@@ -60,7 +62,7 @@
//Debug mode //Debug mode
const debug = bool(core.getInput("debug")) const debug = bool(core.getInput("debug"))
if (!debug) if (!debug)
console.debug = () => null console.debug = message => debugged.push(message)
console.log(`Debug mode | ${debug}`) console.log(`Debug mode | ${debug}`)
//Base elements //Base elements
@@ -93,6 +95,9 @@
if (plugins.pagespeed.enabled) { if (plugins.pagespeed.enabled) {
plugins.pagespeed.token = core.getInput("plugin_pagespeed_token") plugins.pagespeed.token = core.getInput("plugin_pagespeed_token")
console.log(`Pagespeed token | ${plugins.pagespeed.token ? "provided" : "missing"}`) console.log(`Pagespeed token | ${plugins.pagespeed.token ? "provided" : "missing"}`)
for (const option of ["detailed"])
q[`pagespeed.${option}`] = core.getInput(`plugin_pagespeed_${option}`) || null
console.log(`Pagespeed detailed | ${q["pagespeed.detailed"]}`)
} }
//Music //Music
if (plugins.music.enabled) { if (plugins.music.enabled) {
@@ -195,6 +200,8 @@
//Errors //Errors
} catch (error) { } catch (error) {
console.error(error) console.error(error)
if (!bool(core.getInput("debug")))
console.debug("An error occured, logging debug message :", ...debugged)
core.setFailed(error.message) core.setFailed(error.message)
process.exit(1) process.exit(1)
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "metrics", "name": "metrics",
"version": "2.5.0", "version": "2.6.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": {

View File

@@ -49,6 +49,7 @@
app.get("/index.html", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`)) app.get("/index.html", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
app.get("/app.js", limiter, (req, res) => res.sendFile(`${conf.statics}/app.js`)) app.get("/app.js", limiter, (req, res) => res.sendFile(`${conf.statics}/app.js`))
app.get("/style.css", limiter, (req, res) => res.sendFile(`${conf.statics}/style.css`)) app.get("/style.css", limiter, (req, res) => res.sendFile(`${conf.statics}/style.css`))
app.get("/.version", limiter, (req, res) => res.status(200).send(conf.package.version))
app.get("/favicon.ico", limiter, (req, res) => res.sendStatus(204)) app.get("/favicon.ico", limiter, (req, res) => res.sendStatus(204))
app.get("/plugins.list", limiter, (req, res) => res.status(200).json(enabled)) app.get("/plugins.list", limiter, (req, res) => res.status(200).json(enabled))
app.get("/templates.list", limiter, (req, res) => res.status(200).json(templates)) app.get("/templates.list", limiter, (req, res) => res.status(200).json(templates))
@@ -159,7 +160,7 @@
query[key] = Number(value) query[key] = Number(value)
//Parse boolean //Parse boolean
if (/^(?:true|false)$/.test(value)) if (/^(?:true|false)$/.test(value))
query[key] = !!value query[key] = value === "true"
//Parse null //Parse null
if (/^null$/.test(value)) if (/^null$/.test(value))
query[key] = null query[key] = null

View File

@@ -4,6 +4,7 @@
const {data:templates} = await axios.get("/templates.list") const {data:templates} = await axios.get("/templates.list")
const {data:plugins} = await axios.get("/plugins.list") const {data:plugins} = await axios.get("/plugins.list")
const {data:base} = await axios.get("/plugins.base.parts.list") const {data:base} = await axios.get("/plugins.base.parts.list")
const {data:version} = await axios.get("/.version")
//App //App
return new Vue({ return new Vue({
//Initialization //Initialization
@@ -14,8 +15,9 @@
components:{Prism:PrismComponent}, components:{Prism:PrismComponent},
//Data initialization //Data initialization
data:{ data:{
version,
user:url.get("user") || "", user:url.get("user") || "",
palette:url.get("palette") || "light", palette:url.get("palette") || (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light") || "light",
plugins:{ plugins:{
base, base,
list:plugins, list:plugins,
@@ -41,6 +43,7 @@
"base.metadata":"Metadata", "base.metadata":"Metadata",
}, },
options:{ options:{
"pagespeed.detailed":false,
"habits.from":100, "habits.from":100,
"music.playlist":"", "music.playlist":"",
"music.mode":"playlist", "music.mode":"playlist",
@@ -91,12 +94,12 @@
}, },
//Embedded generated code //Embedded generated code
embed() { embed() {
return `[![GitHub metrics](${this.url})](https://github.com/lowlighter/metrics)` return `![GitHub metrics](${this.url})`
}, },
//GitHub action auto-generated code //GitHub action auto-generated code
action() { action() {
return [ return [
`# Visit https://github.com/lowlighter/metrics for full reference`, `# Visit https://github.com/lowlighter/metrics/blob/master/action.yml for full reference`,
`name: GitHub metrics as SVG image`, `name: GitHub metrics as SVG image`,
`on:`, `on:`,
` schedule: [{cron: "0 * * * *"}]`, ` schedule: [{cron: "0 * * * *"}]`,

View File

@@ -13,7 +13,7 @@
<!-- Vue app --> <!-- Vue app -->
<main :class="[palette]"> <main :class="[palette]">
<!-- Title --> <!-- Title -->
<h1><a href="https://github.com/lowlighter/metrics">Generate your metrics !</a></h1> <h1><a href="https://github.com/lowlighter/metrics">Metrics v{{ version }}</a></h1>
<!-- Content --> <!-- Content -->
<template> <template>
<section class="generator"> <section class="generator">
@@ -48,9 +48,14 @@
{{ plugins.descriptions[plugin] || plugin }} {{ plugins.descriptions[plugin] || plugin }}
</label> </label>
</div> </div>
<template v-if="(plugins.enabled.habits)||(plugins.enabled.music)||(plugins.enabled.posts)"> <i>*Additional plugins may be available when used as GitHub Action</i>
<template v-if="(plugins.enabled.pagespeed)||(plugins.enabled.habits)||(plugins.enabled.music)||(plugins.enabled.posts)">
<h3>2.3 Configure additional plugins</h3> <h3>2.3 Configure additional plugins</h3>
<div class="options"> <div class="options">
<label v-if="plugins.enabled.pagespeed">
Detailed PageSpeed report
<input type="checkbox" v-model="plugins.options['pagespeed.detailed']" @change="load">
</label>
<label v-if="(plugins.enabled.music)&&(plugins.options['music.mode'] === 'playlist')"> <label v-if="(plugins.enabled.music)&&(plugins.options['music.mode'] === 'playlist')">
Playlist embed link Playlist embed link
<input type="text" v-model="plugins.options['music.playlist']" placeholder="https://embed.music.apple.com/en/playlist/"> <input type="text" v-model="plugins.options['music.playlist']" placeholder="https://embed.music.apple.com/en/playlist/">

View File

@@ -98,6 +98,9 @@
.generator .steps { .generator .steps {
flex-grow: 1; flex-grow: 1;
width: 100%; width: 100%;
display: flex;
flex-direction: column;
align-items: center;
} }
.generator .preview { .generator .preview {
display: none; display: none;

View File

@@ -157,18 +157,19 @@
registration:"## years ago", registration:"## years ago",
calendar:new Array(14).fill({color:"#ebedf0"}), calendar:new Array(14).fill({color:"#ebedf0"}),
licenses:{favorite:`########`}, licenses:{favorite:`########`},
plugins:Object.fromEntries(enabled.map(key =>
[key, proxify({
posts:{source:"########", posts:new Array("posts.limit" in q ? Math.max(Number(q["posts.limit"])||0, 0) : 2).fill({title:"###### ###### ####### ######", date:"####"})},
music:{provider:"########", tracks:new Array("music.limit" in q ? Math.max(Number(q["music.limit"])||0, 0) : 4).fill({name:"##########", artist:"######", artwork:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg=="})},
pagespeed:{scores:["Performance", "Accessibility", "Best Practices", "SEO"].map(title => ({title, score:NaN}))},
followup:{issues:{count:0}, pr:{count:0}},
habits:{indents:{style:`########`}},
languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:`######`, color:"#ebedf0", value:1/(x+1)}))},
topics:{list:[...new Array(12).fill(null).map(() => ({name:`######`, description:`Lorem ipsum dolor sit amet, consectetur adipiscing elit.`, icon:null})), {name:`And ## more...`, description:"", icon:null}]},
}[key]??{})]
)),
token:{scopes:[]}, token:{scopes:[]},
}), }),
plugins:Object.fromEntries(enabled.map(key =>
[key, proxify({
posts:{source:"########", list:new Array("posts.limit" in q ? Math.max(Number(q["posts.limit"])||0, 0) : 2).fill({title:"###### ###### ####### ######", date:"####"})},
music:{provider:"########", tracks:new Array("music.limit" in q ? Math.max(Number(q["music.limit"])||0, 0) : 4).fill({name:"##########", artist:"######", artwork:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg=="})},
pagespeed:{detailed:!!q["pagespeed.detailed"], scores:["Performance", "Accessibility", "Best Practices", "SEO"].map(title => ({title, score:NaN}))},
followup:{issues:{count:0}, pr:{count:0}},
habits:{indents:{style:`########`}},
languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:"######", color:"#ebedf0", value:1/(x+1)}))},
topics:{list:[...new Array(12).fill(null).map(() => ({name:"######", description:"", icon:null})), {name:`And ## more...`, description:"", icon:null}]},
projects:{list:[...new Array(4).fill(null).map(() => ({name:"########", updated:"########", progress:{enabled:true, todo:"##", doing:"##", done:"##", total:"##"}}))]},
}[key]??{})]
)),
}) })
} }

View File

@@ -1,27 +1,43 @@
//Setup //Setup
export default async function ({imports, data, q}, {enabled = false, token = null} = {}) { export default async function ({login, imports, data, q}, {enabled = false, token = null} = {}) {
//Plugin execution //Plugin execution
try { try {
//Check if plugin is enabled and requirements are met //Check if plugin is enabled and requirements are met
if ((!enabled)||(!q.pagespeed)||(!data.user.websiteUrl)) if ((!enabled)||(!q.pagespeed)||(!data.user.websiteUrl))
return null return null
//Parameters override
let {"pagespeed.detailed":detailed = false} = q
//Duration in days
detailed = !!detailed
//Format url if needed //Format url if needed
let url = data.user.websiteUrl let url = data.user.websiteUrl
if (!/^https?:[/][/]/.test(url)) if (!/^https?:[/][/]/.test(url))
url = `https://${url}` url = `https://${url}`
const result = {url, detailed, scores:[], metrics:{}}
//Load scores from API //Load scores from API
const scores = new Map() const scores = new Map()
await Promise.all(["performance", "accessibility", "best-practices", "seo"].map(async category => { await Promise.all(["performance", "accessibility", "best-practices", "seo"].map(async category => {
const {score, title} = (await imports.axios.get(`https://www.googleapis.com/pagespeedonline/v5/runPagespeed?category=${category}&url=${url}&key=${token}`)).data.lighthouseResult.categories[category] const {score, title} = (await imports.axios.get(`https://www.googleapis.com/pagespeedonline/v5/runPagespeed?category=${category}&url=${url}&key=${token}`)).data.lighthouseResult.categories[category]
scores.set(category, {score, title}) scores.set(category, {score, title})
console.debug(`metrics/compute/${login}/plugins > pagespeed > ${category} audit performed`)
})) }))
result.scores = [scores.get("performance"), scores.get("accessibility"), scores.get("best-practices"), scores.get("seo")]
//Detailed metrics
if (detailed)
Object.assign(result.metrics, ...(await imports.axios.get(`https://www.googleapis.com/pagespeedonline/v5/runPagespeed?&url=${url}&key=${token}`)).data.lighthouseResult.audits.metrics.details.items)
//Integrity check
if (result.scores.filter(score => score).length < 4)
throw {error:{message:"Incomplete PageSpeed results"}, url}
//Results //Results
return {url, scores:[scores.get("performance"), scores.get("accessibility"), scores.get("best-practices"), scores.get("seo")]} return result
} }
//Handle errors //Handle errors
catch (error) { catch (error) {
if (error.response?.status) if (error.response?.status)
throw {error:{message:`PageSpeed token error (code ${error.response.status})`}, url} throw {error:{message:`PageSpeed token error (code ${error.response.status})`}, url}
if (error.error?.message)
throw error
console.debug(error)
throw {error:{message:`An error occured`}} throw {error:{message:`An error occured`}}
} }
} }

View File

@@ -30,7 +30,7 @@
posts = posts.slice(0, limit) posts = posts.slice(0, limit)
} }
//Results //Results
return {source, posts} return {source, list:posts}
} }
//Unhandled error //Unhandled error
throw {error:{message:`An error occured (could not retrieve posts)`}} throw {error:{message:`An error occured (could not retrieve posts)`}}

View File

@@ -35,7 +35,7 @@
for (const project of projects.nodes) { for (const project of projects.nodes) {
//Format date //Format date
const time = (Date.now()-new Date(project.updatedAt).getTime())/(24*60*60*1000) const time = (Date.now()-new Date(project.updatedAt).getTime())/(24*60*60*1000)
let updated = project.updatedAt let updated
if (time < 1) if (time < 1)
updated = "less than 1 day ago" updated = "less than 1 day ago"
else if (time < 30) else if (time < 30)

View File

@@ -3,18 +3,18 @@
+ (!!base.metadata)*38 + (!!base.metadata)*38
+ ((!!base.activity)||(!!base.community))*128 + ((!!base.activity)||(!!base.community))*128
+ (!!base.repositories)*108 + (!!base.repositories)*108
+ ((!!base.repositories)*((!!computed.plugins.traffic)||(!!computed.plugins.lines)))*16 + ((!!base.repositories)*((!!plugins.traffic)||(!!plugins.lines)))*16
+ (!!computed.plugins.followup)*68 + (!!plugins.followup)*68
+ (!!computed.plugins.pagespeed)*126 + (!!plugins.pagespeed)*126 + (plugins.pagespeed?.detailed ?? 0)*6*20
+ (!!computed.plugins.habits)*68 + (!!plugins.habits)*68
+ (!!computed.plugins.languages)*96 + (!!plugins.languages)*96
+ (!!computed.plugins.music)*64 + (computed.plugins.music ? computed.plugins.music.tracks ? 14+Math.max(0, computed.plugins.music.tracks.length-1)*36 : 0 : 0) + (!!plugins.music)*64 + (plugins.music?.tracks?.length ? 14+Math.max(0, plugins.music.tracks.length-1)*36 : 0)
+ (!!computed.plugins.posts)*64 + (computed.plugins.posts ? computed.plugins.posts.posts ? Math.max(0, computed.plugins.posts.posts.length)*40 : 0 : 0) + (!!plugins.posts)*64 + (plugins.posts?.list?.length ?? 0)*40
+ (!!computed.plugins.isocalendar)*192 + (computed.plugins.isocalendar ? computed.plugins.isocalendar.duration === 'full-year' ? 100 : 0 : 0) + (!!plugins.isocalendar)*192 + (plugins.isocalendar?.duration === 'full-year')*100
+ (!!computed.plugins.gists)*68 + (!!plugins.gists)*68
+ (!!computed.plugins.topics)*160 + (!!plugins.topics)*160
+ (!!computed.plugins.projects)*22 + (computed.plugins.projects ? computed.plugins.projects.list.length : 0)*60 + (!!plugins.projects)*22 + (plugins.projects?.list?.length ?? 0)*60
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!computed.plugins.habits))+(!!computed.plugins.pagespeed)+(!!computed.plugins.languages)+(!!computed.plugins.music)+(!!computed.plugins.posts)+(!!computed.plugins.isocalendar)+(!!computed.plugins.gists))-1))*4 + Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!plugins.habits))+(!!plugins.pagespeed)+(!!plugins.languages)+(!!plugins.music)+(!!plugins.posts)+(!!plugins.isocalendar)+(!!plugins.gists)+(!!plugins.topics)+(!!plugins.projects))-1))*4
%>"> %>">
<defs><style><%= fonts %></style></defs> <defs><style><%= fonts %></style></defs>
@@ -148,13 +148,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" d="M2.5 3.5c0-.133.058-.318.282-.55.227-.237.592-.484 1.1-.708C4.899 1.795 6.354 1.5 8 1.5c1.647 0 3.102.295 4.117.742.51.224.874.47 1.101.707.224.233.282.418.282.551 0 .133-.058.318-.282.55-.227.237-.592.484-1.1.708C11.101 5.205 9.646 5.5 8 5.5c-1.647 0-3.102-.295-4.117-.742-.51-.224-.874-.47-1.101-.707-.224-.233-.282-.418-.282-.551zM1 3.5c0-.626.292-1.165.7-1.59.406-.422.956-.767 1.579-1.041C4.525.32 6.195 0 8 0c1.805 0 3.475.32 4.722.869.622.274 1.172.62 1.578 1.04.408.426.7.965.7 1.591v9c0 .626-.292 1.165-.7 1.59-.406.422-.956.767-1.579 1.041C11.476 15.68 9.806 16 8 16c-1.805 0-3.475-.32-4.721-.869-.623-.274-1.173-.62-1.579-1.04-.408-.426-.7-.965-.7-1.591v-9zM2.5 8V5.724c.241.15.503.286.779.407C4.525 6.68 6.195 7 8 7c1.805 0 3.475-.32 4.722-.869.275-.121.537-.257.778-.407V8c0 .133-.058.318-.282.55-.227.237-.592.484-1.1.708C11.101 9.705 9.646 10 8 10c-1.647 0-3.102-.295-4.117-.742-.51-.224-.874-.47-1.101-.707C2.558 8.318 2.5 8.133 2.5 8zm0 2.225V12.5c0 .133.058.318.282.55.227.237.592.484 1.1.708 1.016.447 2.471.742 4.118.742 1.647 0 3.102-.295 4.117-.742.51-.224.874-.47 1.101-.707.224-.233.282-.418.282-.551v-2.275c-.241.15-.503.285-.778.406-1.247.549-2.917.869-4.722.869-1.805 0-3.475-.32-4.721-.869a6.236 6.236 0 01-.779-.406z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" d="M2.5 3.5c0-.133.058-.318.282-.55.227-.237.592-.484 1.1-.708C4.899 1.795 6.354 1.5 8 1.5c1.647 0 3.102.295 4.117.742.51.224.874.47 1.101.707.224.233.282.418.282.551 0 .133-.058.318-.282.55-.227.237-.592.484-1.1.708C11.101 5.205 9.646 5.5 8 5.5c-1.647 0-3.102-.295-4.117-.742-.51-.224-.874-.47-1.101-.707-.224-.233-.282-.418-.282-.551zM1 3.5c0-.626.292-1.165.7-1.59.406-.422.956-.767 1.579-1.041C4.525.32 6.195 0 8 0c1.805 0 3.475.32 4.722.869.622.274 1.172.62 1.578 1.04.408.426.7.965.7 1.591v9c0 .626-.292 1.165-.7 1.59-.406.422-.956.767-1.579 1.041C11.476 15.68 9.806 16 8 16c-1.805 0-3.475-.32-4.721-.869-.623-.274-1.173-.62-1.579-1.04-.408-.426-.7-.965-.7-1.591v-9zM2.5 8V5.724c.241.15.503.286.779.407C4.525 6.68 6.195 7 8 7c1.805 0 3.475-.32 4.722-.869.275-.121.537-.257.778-.407V8c0 .133-.058.318-.282.55-.227.237-.592.484-1.1.708C11.101 9.705 9.646 10 8 10c-1.647 0-3.102-.295-4.117-.742-.51-.224-.874-.47-1.101-.707C2.558 8.318 2.5 8.133 2.5 8zm0 2.225V12.5c0 .133.058.318.282.55.227.237.592.484 1.1.708 1.016.447 2.471.742 4.118.742 1.647 0 3.102-.295 4.117-.742.51-.224.874-.47 1.101-.707.224-.233.282-.418.282-.551v-2.275c-.241.15-.503.285-.778.406-1.247.549-2.917.869-4.722.869-1.805 0-3.475-.32-4.721-.869a6.236 6.236 0 01-.779-.406z"></path></svg>
<%= computed.diskUsage %> used <%= computed.diskUsage %> used
</div> </div>
<% if (computed.plugins.lines) { %> <% if (plugins.lines) { %>
<div class="field <%= computed.plugins.lines.error ? 'error' : '' %>"> <div class="field <%= 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="M2.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V4.664a.25.25 0 00-.073-.177l-2.914-2.914a.25.25 0 00-.177-.073H2.75zM1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V1.75zm7 1.5a.75.75 0 01.75.75v1.5h1.5a.75.75 0 010 1.5h-1.5v1.5a.75.75 0 01-1.5 0V7h-1.5a.75.75 0 010-1.5h1.5V4A.75.75 0 018 3.25zm-3 8a.75.75 0 01.75-.75h4.5a.75.75 0 010 1.5h-4.5a.75.75 0 01-.75-.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="M2.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V4.664a.25.25 0 00-.073-.177l-2.914-2.914a.25.25 0 00-.177-.073H2.75zM1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V1.75zm7 1.5a.75.75 0 01.75.75v1.5h1.5a.75.75 0 010 1.5h-1.5v1.5a.75.75 0 01-1.5 0V7h-1.5a.75.75 0 010-1.5h1.5V4A.75.75 0 018 3.25zm-3 8a.75.75 0 01.75-.75h4.5a.75.75 0 010 1.5h-4.5a.75.75 0 01-.75-.75z"></path></svg>
<% if (computed.plugins.lines.error) { %> <% if (plugins.lines.error) { %>
<%= computed.plugins.lines.error.message %> <%= plugins.lines.error.message %>
<% } else { %> <% } else { %>
<%= computed.plugins.lines.added %> added, <%= computed.plugins.lines.deleted %> removed <%= plugins.lines.added %> added, <%= plugins.lines.deleted %> removed
<% } %> <% } %>
</div> </div>
<% } %> <% } %>
@@ -176,13 +176,13 @@
<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>
<%= computed.repositories.watchers %> Watcher<%= s(computed.repositories.watchers) %> <%= computed.repositories.watchers %> Watcher<%= s(computed.repositories.watchers) %>
</div> </div>
<% if (computed.plugins.traffic) { %> <% if (plugins.traffic) { %>
<div class="field <%= computed.plugins.traffic.error ? 'error' : '' %>"> <div class="field <%= 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>
<% if (computed.plugins.traffic.error) { %> <% if (plugins.traffic.error) { %>
<%= computed.plugins.traffic.error.message %> <%= plugins.traffic.error.message %>
<% } else { %> <% } else { %>
<%= computed.plugins.traffic.views.count %> view<%= s(computed.plugins.traffic.views.count) %> in last two weeks <%= plugins.traffic.views.count %> view<%= s(plugins.traffic.views.count) %> in last two weeks
<% } %> <% } %>
</div> </div>
<% } %> <% } %>
@@ -191,16 +191,16 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.followup) { %> <% if (plugins.followup) { %>
<div class="row"> <div class="row">
<section class="column"> <section class="column">
<h3>Issues</h3> <h3>Issues</h3>
<% if (computed.plugins.followup.error) { %> <% if (plugins.followup.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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.followup.error.message %> <%= plugins.followup.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
@@ -208,18 +208,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="<%= computed.plugins.followup.issues.count ? 0 : 220 %>" height="8" fill="#d1d5da"/> <rect mask="url(#issues-bar)" x="0" y="0" width="<%= plugins.followup.issues.count ? 0 : 220 %>" height="8" fill="#d1d5da"/>
<rect mask="url(#issues-bar)" x="0" y="0" width="<%= (computed.plugins.followup.issues.closed/computed.plugins.followup.issues.count)*220 || 0 %>" height="8" fill="#d73a49"/> <rect mask="url(#issues-bar)" x="0" y="0" width="<%= (plugins.followup.issues.closed/plugins.followup.issues.count)*220 || 0 %>" height="8" fill="#d73a49"/>
<rect mask="url(#issues-bar)" x="<%= (computed.plugins.followup.issues.closed/computed.plugins.followup.issues.count)*220 || 0 %>" y="0" width="<%= (1-computed.plugins.followup.issues.closed/computed.plugins.followup.issues.count)*220 || 0 %>" height="8" fill="#28a745"/> <rect mask="url(#issues-bar)" x="<%= (plugins.followup.issues.closed/plugins.followup.issues.count)*220 || 0 %>" y="0" width="<%= (1-plugins.followup.issues.closed/plugins.followup.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"><%= computed.plugins.followup.issues.closed %> Closed</span> <span class="no-wrap"><%= plugins.followup.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"><%= computed.plugins.followup.issues.open %> Open</span> <span class="no-wrap"><%= plugins.followup.issues.open %> Open</span>
</div> </div>
</div> </div>
<% } %> <% } %>
@@ -227,11 +227,11 @@
<section class="column"> <section class="column">
<h3>Pull requests</h3> <h3>Pull requests</h3>
<% if (computed.plugins.followup.error) { %> <% if (plugins.followup.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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.followup.error.message %> <%= plugins.followup.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
@@ -239,18 +239,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="<%= computed.plugins.followup.pr.count ? 0 : 220 %>" height="8" fill="#d1d5da"/> <rect mask="url(#pr-bar)" x="0" y="0" width="<%= plugins.followup.pr.count ? 0 : 220 %>" height="8" fill="#d1d5da"/>
<rect mask="url(#pr-bar)" x="0" y="0" width="<%= (computed.plugins.followup.pr.merged/computed.plugins.followup.pr.count)*220 || 0 %>" height="8" fill="#6f42c1"/> <rect mask="url(#pr-bar)" x="0" y="0" width="<%= (plugins.followup.pr.merged/plugins.followup.pr.count)*220 || 0 %>" height="8" fill="#6f42c1"/>
<rect mask="url(#pr-bar)" x="<%= (computed.plugins.followup.pr.merged/computed.plugins.followup.pr.count)*220 || 0 %>" y="0" width="<%= (1-computed.plugins.followup.pr.merged/computed.plugins.followup.pr.count)*220 || 0 %>" height="8" fill="#28a745"/> <rect mask="url(#pr-bar)" x="<%= (plugins.followup.pr.merged/plugins.followup.pr.count)*220 || 0 %>" y="0" width="<%= (1-plugins.followup.pr.merged/plugins.followup.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"><%= computed.plugins.followup.pr.merged %> Merged</span> <span class="no-wrap"><%= plugins.followup.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"><%= computed.plugins.followup.pr.open %> Open</span> <span class="no-wrap"><%= plugins.followup.pr.open %> Open</span>
</div> </div>
</div> </div>
<% } %> <% } %>
@@ -259,14 +259,14 @@
</div> </div>
<% } %> <% } %>
<% if (computed.plugins.languages) { %> <% if (plugins.languages) { %>
<section class="column"> <section class="column">
<h3>Most used languages</h3> <h3>Most used languages</h3>
<% if (computed.plugins.languages.error) { %> <% if (plugins.languages.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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.languages.error.message %> <%= plugins.languages.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
@@ -274,13 +274,13 @@
<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="<%= computed.plugins.languages.favorites.length ? 0 : 460 %>" height="8" fill="#d1d5da"/> <rect mask="url(#languages-bar)" x="0" y="0" width="<%= plugins.languages.favorites.length ? 0 : 460 %>" height="8" fill="#d1d5da"/>
<% for (const {name, value, color, x} of computed.plugins.languages.favorites) { %> <% for (const {name, value, color, x} of plugins.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 %>"/>
<% } %> <% } %>
</svg> </svg>
<div class="field center horizontal-wrap fill-width"> <div class="field center horizontal-wrap fill-width">
<% for (const {name, value, color} of computed.plugins.languages.favorites) { %> <% for (const {name, value, color} of plugins.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 %>
@@ -291,23 +291,23 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.projects) { %> <% if (plugins.projects) { %>
<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="M1.75 0A1.75 1.75 0 000 1.75v12.5C0 15.216.784 16 1.75 16h12.5A1.75 1.75 0 0016 14.25V1.75A1.75 1.75 0 0014.25 0H1.75zM1.5 1.75a.25.25 0 01.25-.25h12.5a.25.25 0 01.25.25v12.5a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25V1.75zM11.75 3a.75.75 0 00-.75.75v7.5a.75.75 0 001.5 0v-7.5a.75.75 0 00-.75-.75zm-8.25.75a.75.75 0 011.5 0v5.5a.75.75 0 01-1.5 0v-5.5zM8 3a.75.75 0 00-.75.75v3.5a.75.75 0 001.5 0v-3.5A.75.75 0 008 3z"></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 0A1.75 1.75 0 000 1.75v12.5C0 15.216.784 16 1.75 16h12.5A1.75 1.75 0 0016 14.25V1.75A1.75 1.75 0 0014.25 0H1.75zM1.5 1.75a.25.25 0 01.25-.25h12.5a.25.25 0 01.25.25v12.5a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25V1.75zM11.75 3a.75.75 0 00-.75.75v7.5a.75.75 0 001.5 0v-7.5a.75.75 0 00-.75-.75zm-8.25.75a.75.75 0 011.5 0v5.5a.75.75 0 01-1.5 0v-5.5zM8 3a.75.75 0 00-.75.75v3.5a.75.75 0 001.5 0v-3.5A.75.75 0 008 3z"></path></svg>
<%= computed.plugins.projects.totalCount %> Project<%= s(computed.plugins.projects.totalCount) %> <%= plugins.projects.totalCount %> Project<%= s(plugins.projects.totalCount) %>
</h2> </h2>
<div class="row"> <div class="row">
<% if (computed.plugins.projects.error) { %> <% if (plugins.projects.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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.projects.error.message %> <%= plugins.projects.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
<section> <section>
<% for (const {name, updated, progress} of computed.plugins.projects.list) { %> <% for (const {name, updated, progress} of plugins.projects.list) { %>
<div class="row fill-width"> <div class="row fill-width">
<section> <section>
<div class="field"> <div class="field">
@@ -351,31 +351,31 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.gists) { %> <% if (plugins.gists) { %>
<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="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>
<%= computed.plugins.gists.totalCount %> Gist<%= s(computed.plugins.gists.totalCount) %> <%= plugins.gists.totalCount %> Gist<%= s(plugins.gists.totalCount) %>
</h2> </h2>
<div class="row"> <div class="row">
<% if (computed.plugins.gists.error) { %> <% if (plugins.gists.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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.gists.error.message %> <%= plugins.gists.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
<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>
<%= computed.plugins.gists.stargazers %> Stargazer<%= s(computed.plugins.gists.stargazers) %> <%= plugins.gists.stargazers %> Stargazer<%= s(plugins.gists.stargazers) %>
</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="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>
<%= computed.plugins.gists.forks %> Fork<%= s(computed.plugins.gists.forks) %> <%= plugins.gists.forks %> Fork<%= s(plugins.gists.forks) %>
</div> </div>
</section> </section>
<% } %> <% } %>
@@ -383,7 +383,7 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.pagespeed) { %> <% if (plugins.pagespeed) { %>
<div class="row"> <div class="row">
<section> <section>
<h2 class="field"> <h2 class="field">
@@ -396,12 +396,12 @@
</div> </div>
</section> </section>
</div> </div>
<% if (computed.plugins.pagespeed.error) { %> <% if (plugins.pagespeed.error) { %>
<div class="row"> <div class="row">
<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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.pagespeed.error.message %> <%= plugins.pagespeed.error.message %>
</div> </div>
</section> </section>
</div> </div>
@@ -409,7 +409,7 @@
<section> <section>
<div class="row fill-width"> <div class="row fill-width">
<section class="categories"> <section class="categories">
<% for (const {score, title} of computed.plugins.pagespeed.scores) { %> <% for (const {score, title} of plugins.pagespeed.scores) { %>
<div class="categorie column"> <div class="categorie column">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="50" height="50" class="gauge <%= !Number.isNaN(score) ? (score >= 0.9 ? 'high' : score >= 0.5 ? 'average' : 'low') : '' %>"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="50" height="50" class="gauge <%= !Number.isNaN(score) ? (score >= 0.9 ? 'high' : score >= 0.5 ? 'average' : 'low') : '' %>">
<circle class="gauge-base" r="53" cx="60" cy="60"></circle> <circle class="gauge-base" r="53" cx="60" cy="60"></circle>
@@ -426,30 +426,89 @@
</section> </section>
</div> </div>
</section> </section>
<% if (plugins.pagespeed.detailed) { %>
<div class="audits row">
<section>
<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.75.75A.75.75 0 016.5 0h3a.75.75 0 010 1.5h-.75v1l-.001.041a6.718 6.718 0 013.464 1.435l.007-.006.75-.75a.75.75 0 111.06 1.06l-.75.75-.006.007a6.75 6.75 0 11-10.548 0L2.72 5.03l-.75-.75a.75.75 0 011.06-1.06l.75.75.007.006A6.718 6.718 0 017.25 2.541a.756.756 0 010-.041v-1H6.5a.75.75 0 01-.75-.75zM8 14.5A5.25 5.25 0 108 4a5.25 5.25 0 000 10.5zm.389-6.7l1.33-1.33a.75.75 0 111.061 1.06L9.45 8.861A1.502 1.502 0 018 10.75a1.5 1.5 0 11.389-2.95z"></path></svg>
Time to interactive
</div>
<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 106.016 4.035.75.75 0 011.388-.57 8 8 0 11-4.37-4.37.75.75 0 01-.569 1.389A6.479 6.479 0 008 1.5zm6.28.22a.75.75 0 010 1.06l-4.063 4.064a2.5 2.5 0 11-1.06-1.06L13.22 1.72a.75.75 0 011.06 0zM7 8a1 1 0 112 0 1 1 0 01-2 0z"></path></svg>
Speed Index
</div>
<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.643 3.143L.427 1.927A.25.25 0 000 2.104V5.75c0 .138.112.25.25.25h3.646a.25.25 0 00.177-.427L2.715 4.215a6.5 6.5 0 11-1.18 4.458.75.75 0 10-1.493.154 8.001 8.001 0 101.6-5.684zM7.75 4a.75.75 0 01.75.75v2.992l2.028.812a.75.75 0 01-.557 1.392l-2.5-1A.75.75 0 017 8.25v-3.5A.75.75 0 017.75 4z"></path></svg>
Total Blocking Time
</div>
<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="M11.134 1.535C9.722 2.562 8.16 4.057 6.889 5.312 5.8 6.387 5.041 7.401 4.575 8.294a3.745 3.745 0 00-3.227 1.054c-.43.431-.69 1.066-.86 1.657a11.982 11.982 0 00-.358 1.914A21.263 21.263 0 000 15.203v.054l.75-.007-.007.75h.054a14.404 14.404 0 00.654-.012 21.243 21.243 0 001.63-.118c.62-.07 1.3-.18 1.914-.357.592-.17 1.226-.43 1.657-.861a3.745 3.745 0 001.055-3.217c.908-.461 1.942-1.216 3.04-2.3 1.279-1.262 2.764-2.825 3.775-4.249.501-.706.923-1.428 1.125-2.096.2-.659.235-1.469-.368-2.07-.606-.607-1.42-.55-2.069-.34-.66.213-1.376.646-2.076 1.155zm-3.95 8.48a3.76 3.76 0 00-1.19-1.192 9.758 9.758 0 011.161-1.607l1.658 1.658a9.853 9.853 0 01-1.63 1.142zM.742 16l.007-.75-.75.008A.75.75 0 00.743 16zM12.016 2.749c-1.224.89-2.605 2.189-3.822 3.384l1.718 1.718c1.21-1.205 2.51-2.597 3.387-3.833.47-.662.78-1.227.912-1.662.134-.444.032-.551.009-.575h-.001V1.78c-.014-.014-.112-.113-.548.027-.432.14-.995.462-1.655.942zM1.62 13.089a19.56 19.56 0 00-.104 1.395 19.55 19.55 0 001.396-.104 10.528 10.528 0 001.668-.309c.526-.151.856-.325 1.011-.48a2.25 2.25 0 00-3.182-3.182c-.155.155-.329.485-.48 1.01a10.515 10.515 0 00-.309 1.67z"></path></svg>
First Contentful Paint
</div>
<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 2.5a.25.25 0 00-.25.25v10.5c0 .138.112.25.25.25h.94a.76.76 0 01.03-.03l6.077-6.078a1.75 1.75 0 012.412-.06L14.5 10.31V2.75a.25.25 0 00-.25-.25H1.75zm12.5 11H4.81l5.048-5.047a.25.25 0 01.344-.009l4.298 3.889v.917a.25.25 0 01-.25.25zm1.75-.25V2.75A1.75 1.75 0 0014.25 1H1.75A1.75 1.75 0 000 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0016 13.25zM5.5 6a.5.5 0 11-1 0 .5.5 0 011 0zM7 6a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
Largest Contentful Paint
</div>
<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.75 14A1.75 1.75 0 016 12.25v-8.5C6 2.784 6.784 2 7.75 2h6.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0114.25 14h-6.5zm-.25-1.75c0 .138.112.25.25.25h6.5a.25.25 0 00.25-.25v-8.5a.25.25 0 00-.25-.25h-6.5a.25.25 0 00-.25.25v8.5zM4.9 3.508a.75.75 0 01-.274 1.025.25.25 0 00-.126.217v6.5a.25.25 0 00.126.217.75.75 0 01-.752 1.298A1.75 1.75 0 013 11.25v-6.5c0-.649.353-1.214.874-1.516a.75.75 0 011.025.274zM1.625 5.533a.75.75 0 10-.752-1.299A1.75 1.75 0 000 5.75v4.5c0 .649.353 1.214.874 1.515a.75.75 0 10.752-1.298.25.25 0 01-.126-.217v-4.5a.25.25 0 01.126-.217z"></path></svg>
Cumulative Layout Shift
</div>
</section>
<section>
<% for (const {score, suffix = "", threshold} of [
{score:plugins.pagespeed.metrics.interactive/1000, suffix:"s", threshold:[3.785, 7.3]},
{score:plugins.pagespeed.metrics.speedIndex/1000, suffix:"s", threshold:[3.387, 5.8]},
{score:plugins.pagespeed.metrics.totalBlockingTime/1000, suffix:"s", threshold:[.287, .6]},
{score:plugins.pagespeed.metrics.firstContentfulPaint/1000, suffix:"s", threshold:[2.336, 4]},
{score:plugins.pagespeed.metrics.largestContentfulPaint/1000, suffix:"s", threshold:[2.5, 4]},
{score:+plugins.pagespeed.metrics.cumulativeLayoutShift, threshold:[.1, .25]}
]) { %>
<div class="field">
<div class="audit text">
<% if (!Number.isNaN(score)) { %>
<%= score.toFixed(2).replace(/[.]0+$/, "") %> <%= suffix %>
<% } else { %>
N/A
<% } %>
</div>
<% if (Number.isNaN(score)) { %>
<svg xmlns="http://www.w3.org/2000/svg" class="audit" 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 0zm3.28 5.78a.75.75 0 00-1.06-1.06l-5.5 5.5a.75.75 0 101.06 1.06l5.5-5.5z"></path></svg>
<% } else if (score <= threshold[0]) { %>
<svg xmlns="http://www.w3.org/2000/svg" class="audit high" 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 0zM0 8a8 8 0 1116 0A8 8 0 010 8zm11.78-1.72a.75.75 0 00-1.06-1.06L6.75 9.19 5.28 7.72a.75.75 0 00-1.06 1.06l2 2a.75.75 0 001.06 0l4.5-4.5z"></path></svg>
<% } else if (score <= threshold[1]) { %>
<svg xmlns="http://www.w3.org/2000/svg" class="audit average" 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>
<% } else { %>
<svg xmlns="http://www.w3.org/2000/svg" class="audit low" 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>
<% } %>
</section>
</div>
<% } %>
<% } %> <% } %>
<% } %> <% } %>
<% if (computed.plugins.habits) { %> <% if (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">
<% if (computed.plugins.habits.error) { %> <% if (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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.habits.error.message %> <%= plugins.habits.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
<ul class="habits"> <ul class="habits">
<% if (computed.plugins.habits.indents.style) { %> <% if (plugins.habits.indents.style) { %>
<li>Use <%= computed.plugins.habits.indents.style %> for indents</li> <li>Use <%= plugins.habits.indents.style %> for indents</li>
<% } %> <% } %>
<% if (!Number.isNaN(computed.plugins.habits.commits.hour)) { %> <% if (!Number.isNaN(plugins.habits.commits.hour)) { %>
<li>Mostly push code around <%= computed.plugins.habits.commits.hour %>:00</li> <li>Mostly push code around <%= plugins.habits.commits.hour %>:00</li>
<% } %> <% } %>
</ul> </ul>
<% } %> <% } %>
@@ -457,24 +516,24 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.topics) { %> <% if (plugins.topics) { %>
<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="M14.184 1.143a1.75 1.75 0 00-2.502-.57L.912 7.916a1.75 1.75 0 00-.53 2.32l.447.775a1.75 1.75 0 002.275.702l11.745-5.656a1.75 1.75 0 00.757-2.451l-1.422-2.464zm-1.657.669a.25.25 0 01.358.081l1.422 2.464a.25.25 0 01-.108.35l-2.016.97-1.505-2.605 1.85-1.26zM9.436 3.92l1.391 2.41-5.42 2.61-.942-1.63 4.97-3.39zM3.222 8.157l-1.466 1a.25.25 0 00-.075.33l.447.775a.25.25 0 00.325.1l1.598-.769-.83-1.436zm6.253 2.306a.75.75 0 00-.944-.252l-1.809.87a.75.75 0 00-.293.253L4.38 14.326a.75.75 0 101.238.848l1.881-2.75v2.826a.75.75 0 001.5 0v-2.826l1.881 2.75a.75.75 0 001.238-.848l-2.644-3.863z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M14.184 1.143a1.75 1.75 0 00-2.502-.57L.912 7.916a1.75 1.75 0 00-.53 2.32l.447.775a1.75 1.75 0 002.275.702l11.745-5.656a1.75 1.75 0 00.757-2.451l-1.422-2.464zm-1.657.669a.25.25 0 01.358.081l1.422 2.464a.25.25 0 01-.108.35l-2.016.97-1.505-2.605 1.85-1.26zM9.436 3.92l1.391 2.41-5.42 2.61-.942-1.63 4.97-3.39zM3.222 8.157l-1.466 1a.25.25 0 00-.075.33l.447.775a.25.25 0 00.325.1l1.598-.769-.83-1.436zm6.253 2.306a.75.75 0 00-.944-.252l-1.809.87a.75.75 0 00-.293.253L4.38 14.326a.75.75 0 101.238.848l1.881-2.75v2.826a.75.75 0 001.5 0v-2.826l1.881 2.75a.75.75 0 001.238-.848l-2.644-3.863z"></path></svg>
Starred topics Starred topics
</h2> </h2>
<div class="row"> <div class="row">
<% if (computed.plugins.topics.error) { %> <% if (plugins.topics.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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.topics.error.message %> <%= plugins.topics.error.message %>
</div> </div>
</section> </section>
<% } else { %> <% } else { %>
<section> <section>
<div class="topics fill-width"> <div class="topics fill-width">
<% for (const {name, description} of computed.plugins.topics.list) { %> <% for (const {name, description} of plugins.topics.list) { %>
<div class="label" title="<%= description %>"><%= name.toLocaleLowerCase() %></div> <div class="label" title="<%= description %>"><%= name.toLocaleLowerCase() %></div>
<% } %> <% } %>
</div> </div>
@@ -484,29 +543,29 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.music) { %> <% if (plugins.music) { %>
<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="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 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></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 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></path></svg>
<%= computed.plugins.music.mode %> <%= plugins.music.mode %>
</h2> </h2>
<div class="row fill-width"> <div class="row fill-width">
<section> <section>
<% if (computed.plugins.music.provider) { %> <% if (plugins.music.provider) { %>
<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.002 2.725a.75.75 0 01.797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 11-1.497.098 10.502 10.502 0 00-9.776-9.776.75.75 0 01-.7-.798zM2 13a1 1 0 112 0 1 1 0 01-2 0zm.84-5.95a.75.75 0 00-.179 1.489c2.509.3 4.5 2.291 4.8 4.8a.75.75 0 101.49-.178A7.003 7.003 0 002.838 7.05z"></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.002 2.725a.75.75 0 01.797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 11-1.497.098 10.502 10.502 0 00-9.776-9.776.75.75 0 01-.7-.798zM2 13a1 1 0 112 0 1 1 0 01-2 0zm.84-5.95a.75.75 0 00-.179 1.489c2.509.3 4.5 2.291 4.8 4.8a.75.75 0 101.49-.178A7.003 7.003 0 002.838 7.05z"></path></svg>
From <%= computed.plugins.music.provider %> From <%= plugins.music.provider %>
</div> </div>
<% } %> <% } %>
<% if (computed.plugins.music.error) { %> <% if (plugins.music.error) { %>
<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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.music.error.message %> <%= plugins.music.error.message %>
</div> </div>
<% } else { %> <% } else { %>
<% if (computed.plugins.music.tracks.length) { %> <% if (plugins.music.tracks.length) { %>
<div class="tracklist"> <div class="tracklist">
<% for (const {name = "", artist = "", artwork = ""} of computed.plugins.music.tracks) { %> <% for (const {name = "", artist = "", artwork = ""} of plugins.music.tracks) { %>
<div class="track"> <div class="track">
<img src="data:image/png;base64,<%= artwork %>" width="32" height="32" alt=""/> <img src="data:image/png;base64,<%= artwork %>" width="32" height="32" alt=""/>
<div class="infos"> <div class="infos">
@@ -528,7 +587,7 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.posts) { %> <% if (plugins.posts) { %>
<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="M4.456.734a1.75 1.75 0 012.826.504l.613 1.327a3.081 3.081 0 002.084 1.707l2.454.584c1.332.317 1.8 1.972.832 2.94L11.06 10l3.72 3.72a.75.75 0 11-1.061 1.06L10 11.06l-2.204 2.205c-.968.968-2.623.5-2.94-.832l-.584-2.454a3.081 3.081 0 00-1.707-2.084l-1.327-.613a1.75 1.75 0 01-.504-2.826L4.456.734zM5.92 1.866a.25.25 0 00-.404-.072L1.794 5.516a.25.25 0 00.072.404l1.328.613A4.582 4.582 0 015.73 9.63l.584 2.454a.25.25 0 00.42.12l5.47-5.47a.25.25 0 00-.12-.42L9.63 5.73a4.581 4.581 0 01-3.098-2.537L5.92 1.866z"></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.456.734a1.75 1.75 0 012.826.504l.613 1.327a3.081 3.081 0 002.084 1.707l2.454.584c1.332.317 1.8 1.972.832 2.94L11.06 10l3.72 3.72a.75.75 0 11-1.061 1.06L10 11.06l-2.204 2.205c-.968.968-2.623.5-2.94-.832l-.584-2.454a3.081 3.081 0 00-1.707-2.084l-1.327-.613a1.75 1.75 0 01-.504-2.826L4.456.734zM5.92 1.866a.25.25 0 00-.404-.072L1.794 5.516a.25.25 0 00.072.404l1.328.613A4.582 4.582 0 015.73 9.63l.584 2.454a.25.25 0 00.42.12l5.47-5.47a.25.25 0 00-.12-.42L9.63 5.73a4.581 4.581 0 01-3.098-2.537L5.92 1.866z"></path></svg>
@@ -536,18 +595,18 @@
</h2> </h2>
<div class="row fill-width"> <div class="row fill-width">
<section> <section>
<% if (computed.plugins.posts.error) { %> <% if (plugins.posts.error) { %>
<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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.posts.error.message %> <%= plugins.posts.error.message %>
</div> </div>
<% } else { %> <% } else { %>
<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.002 2.725a.75.75 0 01.797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 11-1.497.098 10.502 10.502 0 00-9.776-9.776.75.75 0 01-.7-.798zM2 13a1 1 0 112 0 1 1 0 01-2 0zm.84-5.95a.75.75 0 00-.179 1.489c2.509.3 4.5 2.291 4.8 4.8a.75.75 0 101.49-.178A7.003 7.003 0 002.838 7.05z"></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.002 2.725a.75.75 0 01.797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 11-1.497.098 10.502 10.502 0 00-9.776-9.776.75.75 0 01-.7-.798zM2 13a1 1 0 112 0 1 1 0 01-2 0zm.84-5.95a.75.75 0 00-.179 1.489c2.509.3 4.5 2.291 4.8 4.8a.75.75 0 101.49-.178A7.003 7.003 0 002.838 7.05z"></path></svg>
From <%= computed.plugins.posts.source %> From <%= plugins.posts.source %>
</div> </div>
<% if (computed.plugins.posts.posts.length) { %> <% if (plugins.posts.list.length) { %>
<% for (const {title, date} of computed.plugins.posts.posts) { %> <% for (const {title, date} of plugins.posts.list) { %>
<div class="field post"> <div class="field post">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.75 0a.75.75 0 01.75.75V2h5V.75a.75.75 0 011.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 014.75 0zm0 3.5h8.5a.25.25 0 01.25.25V6h-11V3.75a.25.25 0 01.25-.25h2zm-2.25 4v6.75c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V7.5h-11z"></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.75 0a.75.75 0 01.75.75V2h5V.75a.75.75 0 011.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 014.75 0zm0 3.5h8.5a.25.25 0 01.25.25V6h-11V3.75a.25.25 0 01.25-.25h2zm-2.25 4v6.75c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V7.5h-11z"></path></svg>
<div class="infos"> <div class="infos">
@@ -568,7 +627,7 @@
</section> </section>
<% } %> <% } %>
<% if (computed.plugins.isocalendar) { %> <% if (plugins.isocalendar) { %>
<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="M4.75 0a.75.75 0 01.75.75V2h5V.75a.75.75 0 011.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 014.75 0zm0 3.5h8.5a.25.25 0 01.25.25V6h-11V3.75a.25.25 0 01.25-.25h2zm-2.25 4v6.75c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V7.5h-11z"></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.75 0a.75.75 0 01.75.75V2h5V.75a.75.75 0 011.5 0V2h1.25c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0113.25 16H2.75A1.75 1.75 0 011 14.25V3.75C1 2.784 1.784 2 2.75 2H4V.75A.75.75 0 014.75 0zm0 3.5h8.5a.25.25 0 01.25.25V6h-11V3.75a.25.25 0 01.25-.25h2zm-2.25 4v6.75c0 .138.112.25.25.25h10.5a.25.25 0 00.25-.25V7.5h-11z"></path></svg>
@@ -576,28 +635,28 @@
</h2> </h2>
<div class="row"> <div class="row">
<section> <section>
<% if (computed.plugins.isocalendar.error) { %> <% if (plugins.isocalendar.error) { %>
<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="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
<%= computed.plugins.isocalendar.error.message %> <%= plugins.isocalendar.error.message %>
</div> </div>
<% } %> <% } %>
</section> </section>
<% if (!computed.plugins.isocalendar.error) { %> <% if (!plugins.isocalendar.error) { %>
<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="M7.998 14.5c2.832 0 5-1.98 5-4.5 0-1.463-.68-2.19-1.879-3.383l-.036-.037c-1.013-1.008-2.3-2.29-2.834-4.434-.322.256-.63.579-.864.953-.432.696-.621 1.58-.046 2.73.473.947.67 2.284-.278 3.232-.61.61-1.545.84-2.403.633a2.788 2.788 0 01-1.436-.874A3.21 3.21 0 003 10c0 2.53 2.164 4.5 4.998 4.5zM9.533.753C9.496.34 9.16.009 8.77.146 7.035.75 4.34 3.187 5.997 6.5c.344.689.285 1.218.003 1.5-.419.419-1.54.487-2.04-.832-.173-.454-.659-.762-1.035-.454C2.036 7.44 1.5 8.702 1.5 10c0 3.512 2.998 6 6.498 6s6.5-2.5 6.5-6c0-2.137-1.128-3.26-2.312-4.438-1.19-1.184-2.436-2.425-2.653-4.81z"></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.998 14.5c2.832 0 5-1.98 5-4.5 0-1.463-.68-2.19-1.879-3.383l-.036-.037c-1.013-1.008-2.3-2.29-2.834-4.434-.322.256-.63.579-.864.953-.432.696-.621 1.58-.046 2.73.473.947.67 2.284-.278 3.232-.61.61-1.545.84-2.403.633a2.788 2.788 0 01-1.436-.874A3.21 3.21 0 003 10c0 2.53 2.164 4.5 4.998 4.5zM9.533.753C9.496.34 9.16.009 8.77.146 7.035.75 4.34 3.187 5.997 6.5c.344.689.285 1.218.003 1.5-.419.419-1.54.487-2.04-.832-.173-.454-.659-.762-1.035-.454C2.036 7.44 1.5 8.702 1.5 10c0 3.512 2.998 6 6.498 6s6.5-2.5 6.5-6c0-2.137-1.128-3.26-2.312-4.438-1.19-1.184-2.436-2.425-2.653-4.81z"></path></svg>
Current streak <%= computed.plugins.isocalendar.streak.current %> day<%= s(computed.plugins.isocalendar.streak.current) %> Current streak <%= plugins.isocalendar.streak.current %> day<%= s(plugins.isocalendar.streak.current) %>
</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 1.75a.75.75 0 00-1.5 0v12.5c0 .414.336.75.75.75h14.5a.75.75 0 000-1.5H1.5V1.75zm14.28 2.53a.75.75 0 00-1.06-1.06L10 7.94 7.53 5.47a.75.75 0 00-1.06 0L3.22 8.72a.75.75 0 001.06 1.06L7 7.06l2.47 2.47a.75.75 0 001.06 0l5.25-5.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="M1.5 1.75a.75.75 0 00-1.5 0v12.5c0 .414.336.75.75.75h14.5a.75.75 0 000-1.5H1.5V1.75zm14.28 2.53a.75.75 0 00-1.06-1.06L10 7.94 7.53 5.47a.75.75 0 00-1.06 0L3.22 8.72a.75.75 0 001.06 1.06L7 7.06l2.47 2.47a.75.75 0 001.06 0l5.25-5.25z"></path></svg>
~<%= computed.plugins.isocalendar.average %> commits per day ~<%= plugins.isocalendar.average %> commits per day
</div> </div>
</section> </section>
<% } %> <% } %>
</div> </div>
<% if (computed.plugins.isocalendar.svg) { %> <% if (plugins.isocalendar.svg) { %>
<%- computed.plugins.isocalendar.svg %> <%- plugins.isocalendar.svg %>
<% } %> <% } %>
</section> </section>
<% } %> <% } %>

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

@@ -207,6 +207,24 @@
stroke-dasharray: 0 329; stroke-dasharray: 0 329;
} }
} }
.audits {
margin-top: 8px;
}
.audit.text {
min-width: 36px;
}
.audit svg {
margin: 0;
}
.audit.high {
fill: #18b663;
}
.audit.average {
fill: #fb8c00;
}
.audit.low {
fill: #e53935;
}
/* Music plugin */ /* Music plugin */
.tracklist { .tracklist {

View File

@@ -2,20 +2,21 @@
export default async function ({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports}) { export default async function ({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports}) {
//Init //Init
const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0, releases:0}, plugins:{}} const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0, releases:0}}
const avatar = imports.imgb64(data.user.avatarUrl) const avatar = imports.imgb64(data.user.avatarUrl)
data.plugins = {}
//Plugins //Plugins
for (const name of Object.keys(imports.plugins)) { for (const name of Object.keys(imports.plugins)) {
pending.push((async () => { pending.push((async () => {
try { try {
computed.plugins[name] = await imports.plugins[name]({login, q, imports, data, computed, rest, graphql}, plugins[name]) data.plugins[name] = await imports.plugins[name]({login, q, imports, data, computed, rest, graphql}, plugins[name])
} }
catch (error) { catch (error) {
computed.plugins[name] = error data.plugins[name] = error
} }
finally { finally {
return {name, result:computed.plugins[name]} return {name, result:data.plugins[name]}
} }
})()) })())
} }

View File

@@ -4,16 +4,16 @@
+ (!!base.activity)*108 + (!!base.activity)*108
+ (!!base.community)*94 + (!!base.community)*94
+ (!!base.repositories)*142 + (!!base.repositories)*142
+ ((!!base.repositories)*(!!computed.plugins.traffic))*18 + ((!!base.repositories)*(!!plugins.traffic))*18
+ ((!!base.repositories)*(!!computed.plugins.followup))*102 + ((!!base.repositories)*(!!plugins.followup))*102
+ ((!!base.repositories)*(!!computed.plugins.lines))*34 + ((!!base.repositories)*(!!plugins.lines))*34
+ (!!computed.plugins.pagespeed)*110 + (!!plugins.pagespeed)*110
+ (!!computed.plugins.languages)*124 + (!!plugins.languages)*124
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+(!!computed.plugins.pagespeed)+(!!computed.plugins.languages))-1))*20 + Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+(!!plugins.pagespeed)+(!!plugins.languages))-1))*20
%>"> %>">
<% <%
meta.$ = `<span class="ps1-path">${`${user.login}`.toLocaleLowerCase()}@metrics</span>:<span class="ps1-location">~</span>${computed.token.scopes.includes("repo") ? "#" : "$"}` meta.$ = `<span class="ps1-path">${`${user.login}`.toLocaleLowerCase()}@metrics</span>:<span class="ps1-location">~</span>${computed.token.scopes.includes("repo") ? "#" : "$"}`
meta.animations = !meta.placeholder ? {stdin:.16, stdout:.28, length:(2+Object.keys(base).length+Object.keys(computed.plugins).length)} : {stdin:0, stdout:0, length:0} meta.animations = !meta.placeholder ? {stdin:.16, stdout:.28, length:(2+Object.keys(base).length+Object.keys(plugins).length)} : {stdin:0, stdout:0, length:0}
%> %>
<defs><style><%= fonts %></style></defs> <defs><style><%= fonts %></style></defs>
@@ -98,55 +98,55 @@ Last generated: <%= new Date().toGMTString() %>
<div class="stdin"><%- meta.$ %> ls -lh github/repositories</div><%# -%> <div class="stdin"><%- meta.$ %> ls -lh github/repositories</div><%# -%>
<div class="stdout"><%# -%> <div class="stdout"><%# -%>
Total <%= user.repositories.totalCount %> repositor<%= s(user.repositories.totalCount, "y") %> - <%= computed.diskUsage %> Total <%= user.repositories.totalCount %> repositor<%= s(user.repositories.totalCount, "y") %> - <%= computed.diskUsage %>
<% if (computed.plugins.traffic) { if (computed.plugins.traffic.error) { -%> <% if (plugins.traffic) { if (plugins.traffic.error) { -%>
---- <b> </b> views <span class="error">(<%= computed.plugins.traffic.error.message %>)</span> ---- <b> </b> views <span class="error">(<%= plugins.traffic.error.message %>)</span>
<% } else { -%> <% } else { -%>
-r-- <b><%= `${computed.plugins.traffic.views.count}`.padStart(5) %></b> views -r-- <b><%= `${plugins.traffic.views.count}`.padStart(5) %></b> views
<% }} -%> <% }} -%>
-r-- <b><%= `${computed.repositories.stargazers}`.padStart(5) %></b> stargazer<%= s(computed.repositories.stargazers) %> -r-- <b><%= `${computed.repositories.stargazers}`.padStart(5) %></b> stargazer<%= s(computed.repositories.stargazers) %>
-r-- <b><%= `${computed.repositories.forks}`.padStart(5) %></b> fork<%= s(computed.repositories.forks) %> -r-- <b><%= `${computed.repositories.forks}`.padStart(5) %></b> fork<%= s(computed.repositories.forks) %>
-r-- <b><%= `${computed.repositories.watchers}`.padStart(5) %></b> watcher<%= s(computed.repositories.watchers) %> -r-- <b><%= `${computed.repositories.watchers}`.padStart(5) %></b> watcher<%= s(computed.repositories.watchers) %>
dr-x <b><%= `${user.packages.totalCount}`.padStart(5) %></b> package<%= s(user.packages.totalCount) %> dr-x <b><%= `${user.packages.totalCount}`.padStart(5) %></b> package<%= s(user.packages.totalCount) %>
dr-x <b><%= `${user.gists.totalCount}`.padStart(5) %></b> gist<%= s(user.gists.totalCount) %> dr-x <b><%= `${user.gists.totalCount}`.padStart(5) %></b> gist<%= s(user.gists.totalCount) %>
<% if (computed.plugins.followup) { if (computed.plugins.followup.error) { -%> <% if (plugins.followup) { if (plugins.followup.error) { -%>
d--- <b> </b> ISSUES <span class="error">(<%= computed.plugins.followup.error.message %>)</span> d--- <b> </b> ISSUES <span class="error">(<%= plugins.followup.error.message %>)</span>
d--- <b> </b> PULL_REQUESTS <span class="error">(<%= computed.plugins.followup.error.message %>)</span> d--- <b> </b> PULL_REQUESTS <span class="error">(<%= plugins.followup.error.message %>)</span>
<% } else { -%> <% } else { -%>
dr-x <b><%= `${computed.plugins.followup.issues.count}`.padStart(5) %></b> ISSUES dr-x <b><%= `${plugins.followup.issues.count}`.padStart(5) %></b> ISSUES
-r-- <b><%= `${computed.plugins.followup.issues.open}`.padStart(5) %></b> ├── open -r-- <b><%= `${plugins.followup.issues.open}`.padStart(5) %></b> ├── open
-r-- <b><%= `${computed.plugins.followup.issues.closed}`.padStart(5) %></b> └── closed -r-- <b><%= `${plugins.followup.issues.closed}`.padStart(5) %></b> └── closed
dr-x <b><%= `${computed.plugins.followup.issues.count}`.padStart(5) %></b> PULL_REQUESTS dr-x <b><%= `${plugins.followup.issues.count}`.padStart(5) %></b> PULL_REQUESTS
-r-- <b><%= `${computed.plugins.followup.pr.open}`.padStart(5) %></b> ├── open -r-- <b><%= `${plugins.followup.pr.open}`.padStart(5) %></b> ├── open
-r-- <b><%= `${computed.plugins.followup.pr.merged}`.padStart(5) %></b> └── merged -r-- <b><%= `${plugins.followup.pr.merged}`.padStart(5) %></b> └── merged
<% }} -%> <% }} -%>
<% if (computed.licenses.favorite.length) { -%> <% if (computed.licenses.favorite.length) { -%>
dr-x LICENSE dr-x LICENSE
-r-- └── <%= computed.licenses.favorite %> -r-- └── <%= computed.licenses.favorite %>
<% } -%> <% } -%>
<% if (computed.plugins.lines) { if (computed.plugins.lines.error) { %> <% if (plugins.lines) { if (plugins.lines.error) { %>
<span class="diff error">@@ <%= computed.plugins.lines.error.message %> @@</span><% } else { %> <span class="diff error">@@ <%= plugins.lines.error.message %> @@</span><% } else { %>
<span class="diff">@@ -<%= computed.plugins.lines.deleted %> +<%= computed.plugins.lines.added %> @@</span> <span class="diff">@@ -<%= plugins.lines.deleted %> +<%= plugins.lines.added %> @@</span>
<% }} -%> <% }} -%>
</div><% } -%> </div><% } -%>
<%# ============================================================= -%> <%# ============================================================= -%>
<% if (computed.plugins.languages) { %> <% if (plugins.languages) { %>
<div class="stdin"><%- meta.$ %> locale</div><%# -%> <div class="stdin"><%- meta.$ %> locale</div><%# -%>
<div class="stdout"><%# -%> <div class="stdout"><%# -%>
<% if (computed.plugins.languages.error) { -%> <% if (plugins.languages.error) { -%>
<span class="error"><%= computed.plugins.languages.error.message %></span><%# -%> <span class="error"><%= plugins.languages.error.message %></span><%# -%>
<% } else { for (const {name, value} of computed.plugins.languages.favorites) { -%> <% } else { for (const {name, value} of plugins.languages.favorites) { -%>
<b><%= name.toLocaleUpperCase().padEnd(12) %></b> [<%= "#".repeat(Math.ceil(100*value/5)).padEnd(20) %>] <%= (100*value).toFixed(2).padEnd(5) %>% <b><%= name.toLocaleUpperCase().padEnd(12) %></b> [<%= "#".repeat(Math.ceil(100*value/5)).padEnd(20) %>] <%= (100*value).toFixed(2).padEnd(5) %>%
<% }} -%> <% }} -%>
</div><% } -%> </div><% } -%>
<%# ============================================================= -%> <%# ============================================================= -%>
<% if (computed.plugins.pagespeed) { %> <% if (plugins.pagespeed) { %>
<div class="stdin"><%- meta.$ %> curl -I <%= user.websiteUrl %></div><%# -%> <div class="stdin"><%- meta.$ %> curl -I <%= user.websiteUrl %></div><%# -%>
<div class="stdout"><%# -%> <div class="stdout"><%# -%>
<% if (computed.plugins.pagespeed.error) { -%> <% if (plugins.pagespeed.error) { -%>
<span class="error"><%= computed.plugins.pagespeed.error.message %></span><% } else { -%> <span class="error"><%= plugins.pagespeed.error.message %></span><% } else { -%>
<b>User-Agent</b>: Google PageSpeed API <b>User-Agent</b>: Google PageSpeed API
<b>Location</b>: <%= user.websiteUrl %> <b>Location</b>: <%= user.websiteUrl %>
<% for (const {score, title} of computed.plugins.pagespeed.scores) { -%> <% for (const {score, title} of plugins.pagespeed.scores) { -%>
<b><%= `X-${title.replace(/ /g, "-")}` %></b>: <%= !Number.isNaN(score) ? Math.round(score*100) : "-" %>% <b><%= `X-${title.replace(/ /g, "-")}` %></b>: <%= !Number.isNaN(score) ? Math.round(score*100) : "-" %>%
<% }} -%> <% }} -%>
</div><% } -%> </div><% } -%>

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -5,10 +5,13 @@
import ncc from "@vercel/ncc" import ncc from "@vercel/ncc"
import minify from "babel-minify" import minify from "babel-minify"
import colors from "colors" import colors from "colors"
import ejs from "ejs"
//Initialization //Initialization
const __dirname = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "..") const __dirname = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "..")
const __action = path.join(__dirname, "action") const __action = path.join(__dirname, "action")
const __workflows = path.join(__dirname, ".github/workflows")
const __utils = path.join(__dirname, "utils")
const __src = path.join(__dirname, "src") const __src = path.join(__dirname, "src")
const __plugins = path.join(__src, "plugins") const __plugins = path.join(__src, "plugins")
const __templates = path.join(__src, "templates") const __templates = path.join(__src, "templates")
@@ -57,6 +60,48 @@
} }
//Workflow
{
//Build
const code = await ejs.renderFile(path.join(__utils, "workflow.yml"), {
releases:["master", "latest"],
templates:(await fs.promises.readdir(__templates)).filter(name => !/.*[.]mjs$/.test(name)).sort(),
testcase(context = {}) {
return [`with:`, ...Object.entries({
token:"${{ secrets.METRICS_TOKEN }}",
dryrun:true,
repositories:1,
template:"${{ matrix.template }}",
base:"",
plugins_errors_fatal:true,
...context
}).map(([key, value]) => `${" ".repeat(5)}${key}: ${
typeof value === "boolean" ? (value ? "yes" : "no") :
typeof value === "string" ? (!value ? `""` : value) :
value
}`)].join("\n")
},
}, {async:true})
console.log(`Generated workflow`.grey)
//Save build
if (actions.includes("build")) {
fs.promises.writeFile(path.join(__workflows, "workflow.yml"), code)
console.log(`Generated workflow saved to ${path.join(__workflows, "dist/index.js")}`.green)
}
//Check build
if (actions.includes("check")) {
const status = `${await fs.promises.readFile(path.join(__workflows, "workflow.yml"))}` === code
if (status)
console.log(`Workflow is up-to-date`.grey)
else {
console.log(`Workflow is outdated`.red)
errors.push(`Workflow is outdated, run "npm run build" to fix it`)
}
}
}
//Action //Action
{ {
//Build //Build

185
utils/workflow.yml Normal file
View File

@@ -0,0 +1,185 @@
name: Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
uses: actions/setup-node@v1
with:
node-version: 15.x
- name: Install
run: npm ci
- name: Build
run: npm run build
- name: Test
run: npm test
analyze:
runs-on: ubuntu-latest
needs: <%- JSON.stringify(releases.map(release => `test@${release}`)) %>
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
uses: github/codeql-action/init@v1
with:
languages: javascript
config-file: ./.github/config/codeql.yml
- name: Analyze
uses: github/codeql-action/analyze@v1
# Tests cases below are auto generated through `npm run build`
# Edit utils/workflow.yml instead if you need to update workflow
<% for (const release of releases) { %>
test@<%- release %>:
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
template: <%- JSON.stringify(templates) %>
steps:
- name: ${{ matrix.template }} > Base
uses: lowlighter/metrics@<%- release %>
<%- testcase({
base: "header, activity, community, repositories, metadata",
}) %>
- name: ${{ matrix.template }} > Plugin > PageSpeed
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_pagespeed: true,
plugin_pagespeed_token: "${{ secrets.PAGESPEED_TOKEN }}",
}) %>
- name: ${{ matrix.template }} > Plugin > PageSpeed (detailed)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_pagespeed: true,
plugin_pagespeed_detailed: true,
plugin_pagespeed_token: "${{ secrets.PAGESPEED_TOKEN }}",
}) %>
- name: ${{ matrix.template }} > Plugin > Music (playlist - apple)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_music: true,
plugin_music_playlist: "${{ secrets.MUSIC_PLAYLIST_APPLE }}",
}) %>
- name: ${{ matrix.template }} > Plugin > Music (playlist - spotify)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_music: true,
plugin_music_playlist: "${{ secrets.MUSIC_PLAYLIST_SPOTIFY }}",
}) %>
- name: ${{ matrix.template }} > Plugin > Music (recent - spotify)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_music: true,
plugin_music_provider: "spotify",
plugin_music_token: "${{ secrets.SPOTIFY_TOKENS }}",
}) %>
- name: ${{ matrix.template }} > Plugin > Posts (dev.to)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_posts: true,
plugin_posts_source: "dev.to",
}) %>
- name: ${{ matrix.template }} > Plugin > Isocalendar
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_isocalendar: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Isocalendar (full year)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_isocalendar: true,
plugin_isocalendar_duration: "full-year",
}) %>
- name: ${{ matrix.template }} > Plugin > Habits
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_habits: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Languages
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_languages: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Follow-up
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_followup: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Lines
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_lines: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Traffic
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_traffic: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Gists
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_gists: true,
}) %>
- name: ${{ matrix.template }} > Plugin > Topics (stars)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_topics: true,
plugin_topics_sort: "stars",
}) %>
- name: ${{ matrix.template }} > Plugin > Topics (activity)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_topics: true,
plugin_topics_sort: "activity",
}) %>
- name: ${{ matrix.template }} > Plugin > Topics (starred)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_topics: true,
plugin_topics_sort: "starred",
}) %>
- name: ${{ matrix.template }} > Plugin > Topics (random)
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_topics: true,
plugin_topics_sort: "random",
}) %>
- name: ${{ matrix.template }} > Plugin > Projects
uses: lowlighter/metrics@<%- release %>
<%- testcase({
plugin_projects: true,
plugin_projects_limit: 2,
}) %>
<% } -%>