Adding a GitHub Contribution Calendar to your Svelte App
Tags: svelte, github, showdev, beginners
Published: 2023-04-16 03:57:14

Showcasing your GitHub activities in the personal site is a great way to demonstrate one's enthusiasm and determination to your works. This short article aims at introducing [`activity-calendar-widget`](https://github.com/patrick-kw-chiu/activity-calendar-widget) that can be embedded in your **Svelte App**! In fact, `activity-calendar-widget` also provides native components in framework e.g. [React](https://stackblitz.com/edit/react-ts-pjkx7k), [Vue](https://stackblitz.com/edit/vue-at6pyy), [Solid](https://stackblitz.com/edit/solidjs-templates-mjote1) and [Qwik](https://stackblitz.com/edit/qwik-starter-due4dq) as well, but we will focus on the usage in a **Svelte App** here.

## Installation

`npm i activity-calendar-widget`

## Basic Example

```JSX
<script>
  import ActivityCalendarWidget from 'activity-calendar-widget/svelte'
</script>

<div>
  <ActivityCalendarWidget daysToRender={150} />
</div>

<style>
  img { width: 82px }
</style>
```

{% embed https://stackblitz.com/edit/vitejs-vite-2rrlhd?embed=1&file=src/App.svelte&view=preview %}

Since we are working on a Svelte codebase, we `import ActivityCalendarWidget from 'activity-calendar-widget/svelte'` (**notice** the subdirectory `/svelte` at the end). After that, we can embed the `<ActivityCalendarWidget />` into our Svelte App. And duh! We have an (empty) GitHub Contribution Calendar!

> In the basic example, we also pass `daysToRender={150}` to the component. If we remove the `props`, by default it will at least render 365 days and try to fill out all the empty day box in the leftmost (oldest) column.

It's a shame to see an empty GitHub Contribution Calendar! Let's walkthrough 2 options in our hands - getting the **public** activity data using the official [GitHub events API](https://docs.github.com/en/rest/activity/events?apiVersion=2022-11-28#list-public-events-for-a-user), or getting the exact data in your profile's contributions with  [GitHub contributions API](https://github.com/grubersjoe/github-contributions-api) created by [@grubersjoe](https://github.com/grubersjoe). It is a handy API which scrapes the data from your profile.

## Usage with the official [GitHub events API](https://docs.github.com/en/rest/activity/events?apiVersion=2022-11-28#list-public-events-for-a-user)

```JSX
<script>
  import ActivityCalendarWidget from 'activity-calendar-widget/svelte'

  let data = []

  const loadGithubActivity = async () => {
    // 1. Call Github events API
    const githubId = 'patrick-kw-chiu';
    const githubApi = `https://api.github.com/users/${githubId}/events`;
    const response = await fetch(githubApi);
    const payload = await response.json();

    // 2. Report error if there's
    if (payload?.message) {
      return;
    }

    // 3. Construct the data array which expects obj with 2 keys
    // date: 'yyyy-MM-dd'
    // activities: array of anything
    let eventObj = {};
    payload.forEach((event) => {
      const date = event.created_at.slice(0, 10);
      if (!eventObj[date]) {
        eventObj[date] = [event];
      } else {
        eventObj[date] = [...eventObj[date], event];
      }
    });
    const newData = Object.entries(eventObj).map((entry) => {
      return {
        date: entry[0],
        activities: entry[1],
      };
    });
    data = newData
  }
  loadGithubActivity()
</script>

<div>
  <ActivityCalendarWidget
    daysToRender={150}
    data={data}
    levelColorMode={'dark'}
  />
</div>

<style>
  img { width: 82px }
</style>
```

To do so, first we `GET` the activities data from `https://api.github.com/users/${githubId}/events` where `githubId` is your GitHub ID.

Next, we construct a `data` array with 2 keys - `date` and `activities`, while `date` is having the `yyyy-MM-dd` format and `activities` is an array of `any`thing. Note that the length of the `activities` array will be the count. Also, we can pass an optional `clickHandler` to retrieve the detail of the `activities`. We will demo it in the last section.

Lastly, we pass the data array to the widget like `<ActivityCalendarWidget data={data} />`. We should see something like:

![Svelte-ActivityCalendarWidget-dark-mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ifok7bched1rkvjcfq7.png)

## Usage with the [GitHub contributions API](https://github.com/grubersjoe/github-contributions-api) from [@grubersjoe](https://github.com/grubersjoe)

```JSX
<script>
  import ActivityCalendarWidget from 'activity-calendar-widget/svelte'

  let data = []

  const loadGithubActivity = async () => {
    // 1. Call Github events API
    const githubId = 'patrick-kw-chiu';
    const githubApi = `https://github-contributions-api.jogruber.de/v4/${githubId}`;
    const response = await fetch(githubApi);
    const payload = await response.json();

    // 2. Report error if there's
    if (!payload?.contributions) {
      return;
    }

    // 3. Construct the data array which expects obj with 2 keys
    // date: 'yyyy-MM-dd'
    // activities: array of anything
    const newData = payload.contributions.map((contribution) => {
      return {
        date: contribution.date,
        activities: new Array(contribution.count).fill(0),
      }
    });
    data = newData
  }
  loadGithubActivity()
</script>

<div>
  <ActivityCalendarWidget
    daysToRender={150}
    data={data}
    levelColorMode={'dark'}
  />
</div>

<style>
  img { width: 82px }
</style>
```

It is basically very similar to the official GitHub events API. The difference are that

1. [GitHub contributions API](https://github.com/grubersjoe/github-contributions-api) reflects the exact contributions view from your profile, which is good

2. GitHub contributions API returns the contributions / activities like below, which might not include the full detail of the activity (if you need it)
```json
{
  "contributions": [
    {
      "date": "2020-01-01",
      "count": 0,
      "level": 0
    },
    ...
  ]
}
```

## Customize the activities calendar with other options and try out `clickHandler`

```JSX
<script>
  const clickHandler = (dt) => console.log(dt)
</script>

<ActivityCalendarWidget
  daysToRender={150}
  data={data}
  levelColorMode={'dark'}
  levelColors={[
    '#021f1f', '#055e5e', '#068f8f', '#06d1d1', '#07ffff'
  ]}
  weekdayLabel={{
    1: '月曜日',
    3: '水曜日',
    5: '金曜日'
  }}
  clickHandler={clickHandler}
/>
```

{% embed https://stackblitz.com/edit/vitejs-vite-r7rxjt?ctl=1&embed=1&file=src/App.svelte&view=preview %}

![Customized Activity Calendar Widget](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhyq4zw2l2i2wpq1b20c.png)

We can customize the activities calendar widget by passing various props. In the sample above, we pass the `levelColors` array to change it to a teal-ish color and customize the `weekdayLabel` to some Japanese characters. Visit the [API doc](https://github.com/patrick-kw-chiu/activity-calendar-widget#api) for all the supported options!

Lastly, if we click the teal-ish date box, we should see the log as below, since we pass a `clickHandler` to the widget. It includes the activities detail of the clicked `date`, as well as other info e.g. `year`, `month` and `day`.

![Activity Calendar Widget click handler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sqpymrbxshqrbnwdek3c.png)

---

## Behind the scene

Activity Calendar Widget is built with [Mitosis](https://github.com/BuilderIO/mitosis) (with a little modifications), which aims to "Write components once, compile to every framework". That's why there are also native [React](https://stackblitz.com/edit/react-ts-pjkx7k) components, [Vue](https://stackblitz.com/edit/vue-at6pyy), [Solid](https://stackblitz.com/edit/solidjs-templates-mjote1) and [Qwik](https://stackblitz.com/edit/qwik-starter-due4dq) as well. Interested to learn more? Here is a [walkthrough of building a "simplied" Activity Calendar Widget with Mitosis.js](https://medium.com/@patrick-kw-chiu/write-components-once-compile-to-every-framework-with-mitosis-9330411d21e4).

Credits: The API of Activity Calendar Widget is highly influenced by [React Activity Calendar](https://github.com/grubersjoe/react-activity-calendar). React Activity Calendar is a great component library, which provides more granular options in certain areas.

---

Thanks for reading! Want to Connect?

Visit me at [LinkedIn](https://www.linkedin.com/in/patrick-chiu/) | [GitHub](https://github.com/patrick-kw-chiu) | [Twitter](https://twitter.com/patrickkwchiu)