Skip to content

Commit fa66157

Browse files
authored
feat(plugins/calendar): add new plugin (lowlighter#1013) [skip ci]
1 parent 9d1083f commit fa66157

File tree

9 files changed

+198
-0
lines changed

9 files changed

+198
-0
lines changed

source/plugins/calendar/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!--header-->
2+
<!--/header-->
3+
4+
## ➡️ Available options
5+
6+
<!--options-->
7+
<!--/options-->
8+
9+
## ℹ️ Examples workflows
10+
11+
<!--examples-->
12+
<!--/examples-->
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
- name: Current year calendar
2+
uses: lowlighter/metrics@latest
3+
with:
4+
filename: metrics.plugin.calendar.svg
5+
token: ${{ secrets.METRICS_TOKEN }}
6+
base: ""
7+
plugin_calendar: yes
8+
9+
- name: Full history calendar
10+
uses: lowlighter/metrics@latest
11+
with:
12+
filename: metrics.plugin.calendar.full.svg
13+
token: ${{ secrets.METRICS_TOKEN }}
14+
base: ""
15+
plugin_calendar: yes
16+
plugin_calendar_limit: 0

source/plugins/calendar/index.mjs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//Setup
2+
export default async function({login, q, data, imports, graphql, queries, account}, {enabled = false} = {}) {
3+
//Plugin execution
4+
try {
5+
//Check if plugin is enabled and requirements are met
6+
if ((!enabled)||(!q.calendar))
7+
return null
8+
9+
//Load inputs
10+
let {limit} = imports.metadata.plugins.calendar.inputs({data, account, q})
11+
12+
//Compute boundaries
13+
const end = new Date().getFullYear()
14+
const start = new Date(limit ? end-limit+1 : data.user.createdAt, 0).getFullYear()
15+
16+
//Load contribution calendar
17+
console.debug(`metrics/compute/${login}/plugins > calendar > processing years ${start} to ${end}`)
18+
const calendar = {years:[]}
19+
for (let year = start; year <= end; year++) {
20+
console.debug(`metrics/compute/${login}/plugins > calendar > processing year ${year}`)
21+
const weeks = []
22+
const newyear = new Date(year, 0, 1)
23+
const endyear = (year === end) ? new Date() : new Date(year, 11, 31)
24+
for (let from = new Date(newyear); from < endyear;) {
25+
//Set date range and ensure we start on sundays
26+
let to = new Date(from)
27+
to.setUTCHours(+4 * 7 * 24)
28+
if (to.getUTCDay())
29+
to.setUTCHours(-to.getUTCDay() * 24)
30+
if (to > endyear)
31+
to = endyear
32+
33+
//Ensure that date ranges are not overlapping by setting it to previous day at 23:59:59.999
34+
const dto = new Date(to)
35+
dto.setUTCHours(-1)
36+
dto.setUTCMinutes(59)
37+
dto.setUTCSeconds(59)
38+
dto.setUTCMilliseconds(999)
39+
//Fetch data from api
40+
console.debug(`metrics/compute/${login}/plugins > calendar > loading calendar from "${from.toISOString()}" to "${dto.toISOString()}"`)
41+
const {user:{calendar:{contributionCalendar}}} = await graphql(queries.isocalendar.calendar({login, from:from.toISOString(), to:dto.toISOString()}))
42+
weeks.push(...contributionCalendar.weeks)
43+
//Set next date range start
44+
from = new Date(to)
45+
}
46+
calendar.years.unshift({year, weeks})
47+
}
48+
49+
//Results
50+
return calendar
51+
}
52+
//Handle errors
53+
catch (error) {
54+
throw {error:{message:"An error occured", instance:error}}
55+
}
56+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: "📆 Calendar"
2+
category: github
3+
description: This plugin displays your commit calendar across several years
4+
examples:
5+
+current year: https://github.com/lowlighter/metrics/blob/examples/metrics.plugin.calendar.svg
6+
full history: https://github.com/lowlighter/metrics/blob/examples/metrics.plugin.calendar.full.svg
7+
supports:
8+
- user
9+
scopes:
10+
- public_access
11+
inputs:
12+
13+
plugin_calendar:
14+
description: Enable calendar plugin
15+
type: boolean
16+
default: no
17+
18+
plugin_calendar_limit:
19+
description: Years to display
20+
type: number
21+
default: 1
22+
zero: disable
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
query CalendarDefault {
2+
user(login: "$login") {
3+
calendar:contributionsCollection(from: "$from", to: "$to") {
4+
contributionCalendar {
5+
weeks {
6+
contributionDays {
7+
contributionCount
8+
color
9+
date
10+
}
11+
}
12+
}
13+
}
14+
}
15+
}

source/templates/classic/partials/_.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"rss",
2020
"tweets",
2121
"isocalendar",
22+
"calendar",
2223
"stars",
2324
"starlists",
2425
"stargazers",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<% if (plugins.calendar) { %>
2+
<section>
3+
<h2 class="field">
4+
<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>
5+
Contributions calendar
6+
</h2>
7+
<div class="row">
8+
<section>
9+
<% if (plugins.calendar.error) { %>
10+
<div class="field error">
11+
<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>
12+
<%= plugins.calendar.error.message %>
13+
</div>
14+
<% } else { %>
15+
<svg class="calendar" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0,0 795,<%= 130 * plugins.calendar.years.length %>">
16+
<% for (const [r, {year, weeks}] of Object.entries(plugins.calendar.years)) { %>
17+
<g transform="translate(0, <%= 14 + r * 130 %>)">
18+
<text x="0" y="0"><%= year %></text>
19+
<% for (const [x, week] of Object.entries(weeks)) { %>
20+
<g transform="translate(<%= x*15 %>, 0)">
21+
<% for (const [y, {color}] of Object.entries(week.contributionDays)) { %>
22+
<rect class="day" x="0" y="<%= 4 + (x == 0)*(7-week.contributionDays.length)*15 + y*15 %>" width="11" height="11" fill="<%= color %>" rx="2" ry="2" />
23+
<% } %>
24+
</g>
25+
<% } %>
26+
</g>
27+
<% } %>
28+
</svg>
29+
<% } %>
30+
</section>
31+
</div>
32+
</section>
33+
<% } %>

source/templates/classic/style.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,17 @@
838838
max-width: 900px;
839839
}
840840

841+
/* Calendar */
842+
svg.calendar {
843+
margin-left: 13px;
844+
margin-top: 4px;
845+
}
846+
847+
svg.calendar text {
848+
font-size: 18px;
849+
fill: currentColor;
850+
}
851+
841852
/* People */
842853
.people {
843854
padding: 0 10px;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**Mocked data */
2+
export default function({faker, query, login = faker.internet.userName()}) {
3+
console.debug("metrics/compute/mocks > mocking graphql api result > calendar/default")
4+
//Generate calendar
5+
const date = new Date(query.match(/from: "(?<date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)"/)?.groups?.date)
6+
const to = new Date(query.match(/to: "(?<date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)"/)?.groups?.date)
7+
const weeks = []
8+
let contributionDays = []
9+
for (; date <= to; date.setDate(date.getDate() + 1)) {
10+
//Create new week on sunday
11+
if (date.getDay() === 0) {
12+
weeks.push({contributionDays})
13+
contributionDays = []
14+
}
15+
//Random contributions
16+
const contributionCount = Math.min(10, Math.max(0, faker.datatype.number(14) - 4))
17+
contributionDays.push({
18+
contributionCount,
19+
color: ["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"][Math.ceil(contributionCount / 10 / 0.25)],
20+
date: date.toISOString().substring(0, 10),
21+
})
22+
}
23+
return ({
24+
user: {
25+
calendar: {
26+
contributionCalendar: {
27+
weeks,
28+
},
29+
},
30+
},
31+
})
32+
}

0 commit comments

Comments
 (0)