Skip to content

patrick-kw-chiu/activity-calendar-widget

Repository files navigation

Activity Calendar Widget

Interactive code demo (React)

Stackblitz link

Screen.Recording.2024-08-10.at.1.28.15.AM.mp4

A "GitHub Contribution/Activity" like calendar widget, that can be used as native components of React, Vue, Svelte, Solid and Qwik. You can used it with the GitHub activity API or to display any activity data.

About

Activity Calendar Widget is built with Mitosis (with a little modifications), which aims to "Write components once, compile to every framework". Interested to learn more? Here is a walkthrough of building a "simplied" Activity Calendar Widget.

Credits: The API of Activity Calendar Widget is highly influenced by React Activity Calendar. React Activity Calendar is a great component library, which provides more granular options in certain areas.

Installation

npm i activity-calendar-widget

It can then be imported in various frameworks like...

// React
import ActivityCalendarWidget from 'activity-calendar-widget/react';

// Vue
import ActivityCalendarWidget from 'activity-calendar-widget/vue';

// Svelte
import ActivityCalendarWidget from 'activity-calendar-widget/svelte';

// Solid
import ActivityCalendarWidget from 'activity-calendar-widget/solid';

// Qwik
import ActivityCalendarWidget from 'activity-calendar-widget/qwik';

Basic Usage

<ActivityCalendarWidget
  daysToRender={150}
  data={[
    { date: '2023-04-05', activities: [{}, {}, {}, {}] },
    { date: '2023-04-07', activities: [{}] },
    { date: '2023-04-08', activities: [{}, {}, {}] },
  ]}
/>

API

Props

Props name Type Default Description
data array of Data [] The activity data array. It accepts the date and activities fields.
clickHandler Function
(dateInfo: DateInfo) => {}
undefined The activity data array. It accepts the date and activities fields.
daysToRender number 365 (+ 0 to 6 days more). See more the description When daysToRender isn't specified, at least 365 days from today will be rendered, while the leftmost (oldest) column will also be filled up entirely.

When daysToRender is specified, activity-calendar-widget will render the exact number of daysToRender from today.
mode string 'day' Options: 'day' / 'week' / 'month'.

Note: Only day is supported currently. See roadmap for more info.
showSummary boolean true If set to true, a summary of "26 activities in this period" will be displayed in the bottom left of the component.
summaryText string '{{count}} activities in this period' The customized summary text with placeholder {{count}}
showLevels boolean true If set to true, a level legend will be displayed in the bottom right of the component.
levelColorMode string 'light' Options: 'light' / 'dark'. It changes the color palette of the level legend, like the screenshots at the top.

If levelColorMode is used together with levelColors, levelColorMode will be ignored and ONLY levelColor will be used.
levelColors array of string undefined If levelColors is used together with levelColorMode, levelColorMode will be ignored and ONLY levelColor will be used. E.g. ['white', 'rgba(0, 0, 0, 0.2'), '#a6a6a6']
levelLabelLess string 'Less' The "Less" label of the level legend
levelLabelMore string 'More' The "More" label of the level legend
showTooltip boolean true If set to true, when users hover the date box, a tooltip of "2 activities on Apr 11, 2023" will be displayed.
tooltipBgColor string 'rgba(0, 0, 0, 0.8)' The tooltip background color
tooltipTextColor string '#e4e8ec' The tooltip text color
weekStart number 0 Options: 0 / 1 / 2 / 3 / 4 / 5 / 6

The week start with:
0: Sun
1: Mon
2: Tue
3: Wed
4: Thu
5: Fri
6: Sat
showWeekdayLabels boolean true If set to true, the left weekday labels will be displayed.
weekdayLabel WeekdayLabel {} By default, the widget only displays Mon, Wed and Fri. If the allowed keys in weekdayLabel is provided e.g. { 0: '日曜日' }, the week value will be overwritten.

Note: To provide custom value for Sunday, provide value to 0 e.g. { 0: '日曜日' }.
showMonthLabels boolean true If set to true, the top month labels will be displayed.
monthLabel MonthLabel {} By default, all months will be displayed. If the allowed keys in monthLabel is provided e.g. { 1: '1월' }, the month value will be overwritten.

Event Handlers

clickHandler(dateInfo: DateInfo)

DateInfo

Fields Type Format Description
id string yyyy-MM-dd The date being clicked
year number yyyy The year of the date box being clicked
month number MM The month of the date box being clicked
day number dd The day of the date box being clicked
dayOfWeek number 0-6 The day of week of the date box being clicked

0: Sun
1: Mon
2: Tue
3: Wed
4: Thu
5: Fri
6: Sat
dayDiffFromToday number >= 0 Numebrs of days from today
activities array of any [] Each item inside the activities array will count as 1 activity. The format is arbitary here. You can pass { "type": "PushEvent" } or 'PullRequestEvent' or anything.
level number >= 0 If no custom levelColors is passed, level will be 0-4. 0 means no activities and 4 means the tier of having the most activities.

If custom levelColors is passed, level will be 0 to length of levelColors - 1.

Usage

<ActivityCalendarWidget
  clickHandler={(dateInfo) => console.log({ dateInfo })}
/>

DateInfo Example

{
    "id": "2023-04-16",
    "year": 2023,
    "month": 4,
    "day": 16,
    "dayOfWeek": 0,
    "dayDiffFromToday": 0,
    "activities": [
        ...
    ],
    "level": 2
}

Types

Data

Field Type Format Description
date string yyyy-MM-dd The date which contains 0 or more activities.
E.g. '2023-04-05'
activities array of any [] Each item inside the activities array will count as 1 activity. The format is arbitary here. You can pass { "type": "PushEvent" } or 'PullRequestEvent' or anything.

If you pass a clickHandler and you clicked the date box, the clickHandler callback will be executed with the activities.

Example

[
  { date: '2023-04-05', activities: [{}, {}, {}, {}] },
  { date: '2023-04-07', activities: [{}] },
  { date: '2023-04-08', activities: [{}, {}, {}] }
]

WeekdayLabel

type WeekdayKey = 0 | 1 | 2 | 3 | 4 | 5 | 6;
export type WeekdayLabel = Record<WeekdayKey, string>;

Example:

{
  0: '日曜日',
  1: '月曜日',
  2: '火曜日',
  3: '水曜日',
  4: '木曜日',
  5: '金曜日',
  6: '土曜日',
}

MonthLabel

type MonthKey = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
export type MonthLabel = Record<MonthKey, string>;

Example:

{
  1: '1월',
  2: '2월',
  3: '3월',
  // ...
  10: '10월',
  11: '11월',
  12: '12월',
}

Roadmap

  • Support mode={'month'}

Screenshot 2023-04-13 at 1 13 47 AM

  • Support mode={'week'}

Screenshot 2023-04-13 at 1 12 12 AM

Development

  1. (One off) Install dependencies of the Mitosis component and the test app
npm install

cd test-app
npm install
  1. In the root directory, watch and re-build changes in /src.
npm run start
  1. In another terminal, run the test-app (an Astro app that have react, solid, svelte and vue baked in)
cd test-app
npm run start