Skip to content

MMRIZE/MMM-CalendarExt3Journal

Repository files navigation

MMM-CalendarExt3Journal

MagicMirror² module for presenting events as a daily/weekly journal with time ranges.

Screenshot

screenshot1

screenshot2

Features

  • Detailed event view by day/week with specific time ranges
  • Locale-aware calendar (date formats, first day of week, weekends)
  • Customizable events: filtering, sorting, transforming
  • Multi-instance support — no need to copy/rename the module

Install

cd ~/MagicMirror/modules
git clone https://github.com/MMRIZE/MMM-CalendarExt3Journal
cd MMM-CalendarExt3Journal
npm install --omit=dev

Note: npm install is required — it initializes the CX3_Shared submodule.

Update

cd ~/MagicMirror/modules/MMM-CalendarExt3Journal
git pull
npm install --omit=dev

If the submodule is not updated properly, run:

git submodule update --init --recursive

Config

The simplest configuration:

    {
      module: "MMM-CalendarExt3Journal",
      position: "bottom_bar",
    },

A more complete example:

    {
      module: "MMM-CalendarExt3Journal",
      position: "bottom_bar",
      config: {
        height: '50vh',
        width: '100%',
        locale: 'en-GB',
        maxLaneThreshold: 3,
        staticWeek: true,
        staticTime: true,
        hourLength: 9,
        beginHour:  8,
        calendarSet: ['us_holiday', 'EPL'],
      }
    },

The default calendar module must also be configured:

/* default/calendar module configuration */
    {
      module: "calendar",
      position: "top_left",
      config: {
        broadcastPastEvents: true, // <= IMPORTANT to see past events
        calendars: [
          {
            url: "webcal://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics",
            name: "us_holiday", // <= RECOMMENDED to assign name
            color: "red" // <= RECOMMENDED to assign color
          },
          ...
        ]
      }
    },

Config details

All the properties are omittable, and if omitted, a default value will be applied.

property default description
height '800px' The height of the module.
width '100%' The width of the module.
instanceId (auto-generated) When you want more than 1 instance of this module, each instance would need this value to distinguish each other. If you don't assign this property, the identifier of the module instance will be assigned automatically but not recommended to use it. (Hard to guess the auto-assigned value.)
calendarSet [] When you want to display only selected calendars, fulfil this array with the targeted calendar name(of the default calendar module).
e.g) calendarSet: ['us_holiday', 'office'],
[] or null will allow all the calendars.
locale (language of MM config) e.g. de or ko-KR or ja-Jpan-JP-u-ca-japanese-hc-h12. It defines how to handle and display your date-time values by the locale. When omitted, the default language config value of MM.
staticWeek false if true, the view will show 1 week's view forcely. (from the start of the week to the end of the week. Usually It will be MonSun or SunSat by locale)
If true, the dayIndex and days attributes will be ignored.
dayIndex 0 Which day starts in the view. -1 means yesterday, 2 means the next day of tomorrow. Today is 0
days 3 How many days will be shown from dayIndex. 1 means just a day.
staticTime true If true, the view will show the events from beginHour to beginHour + hourLength.
If false, the view will show the events from this hour + beginHour for hourLength.
Details are explained below later.
beginHour 8 The view frame starts from this hour (relatively or statically)
hourLength 4 How many hours the view has.
hourIndexOptions {hour: 'numeric', minute: '2-digit'} The format of hour index time. It varies by the locale and this option.
With locale:'en-GB', isplaying will be 12:00.
See options
dateHeaderOptions {day: 'numeric', weekday: 'short'} The format of each day header. It varies by the locale and this option.
With locale:'en-GB', displaying will be SUN 25.
See options
eventTimeOptions {timeStyle: 'short'} The format of each event. It varies by the locale and this option.
With locale:'en-GB', displaying will be 12:34.
See options
eventFilter callback function See the Filtering part.
eventSorter callback function See the Sorting part.
eventTransformer callback function See the Transforming part.
preProcessor callback function See the preProcessing part.
waitFetch 5000 (ms) waiting the fetching of last calendar to prevent flickering view by too frequent fetching.
refreshInterval 600000 (ms) refresh view by force if you need it.
animationSpeed 1000 (ms) Refreshing the view smoothly.
useSymbol true Whether to show font-awesome symbold instead of simple dot icon.
maxLaneThreshold 3 Maximum lane count per connected overlap group before falling back to compact offset rendering. If lane count is greater than this value, that group is shown in offset mode. 0 means always offset, very high values mean almost always lanes.
useIconify false If set true, You can use iconify-icon instead of fontawesome.
weekends (auto-filled by locale) (Array of day order). e.g. weekends: [1, 3] means Monday and Wednesday would be regarded as weekends. Usually you don't have to set this value.
Auto-filled by locale unless you set manually.
firstDayOfWeek (auto-filled by locale) Monday is the first day of the week according to the international standard ISO 8601, but in the US, Canada, Japan and some cultures, it's counted as the second day of the week. If you want to start the week from Monday, set this property to 1. If you want Sunday, set 0.
Sunday:0, Monday:1, Tuesday:2, ..., Saturday:6
Auto-filled by locale unless you set manually.
minimalDaysOfNewYear (auto-filled by locale) ISO 8601 also says each week's year is the Gregorian year in which the Thursday falls. The first week of the year, hence, always contains 4 January. However, the US (Yes, it is.) system differs from standards. In the US, containing 1 January defines the first week. In that case, set this value to 1. And under some other culture, you might need to modify this.
Auto-filled by locale unless you set manually.

Notification

Incoming Notifications

CX3J_CONFIG, payload: {config}

  • The current configuration value would be overridden by the receiving payload.
  • For example; the current config might be;
config: {
  ...
  staticTime: true,
  beginhHour: 8,
  hourLength: 8,
  calendarSet: ['office', 'family'],
  ...
}

When some external notification like below comes;

.sendNotification('CX3J_CONFIG', { calendarSet: ['EPL'], beginHour: 16 })

Then, the view will be changed with those attributes. The unmentioned values would remain as before.

CX3J_RESET

Return to the original config value .

I think these 2 notifications would be enough to control the module's view. This approach is a new way for my all CX3* modules. I'll change other CX3* modules in this way later.

Outgoing Notification

Nothing yet. (Does it need?)

Styling with CSS

You can handle almost all of the visual things with CSS. See the MMM-CalendarExt3Journal.css and override your needs into your custom.css.

  • CX3J, CX3J_{instanceId}, .bodice : The root selector. Each instance of this module will have CX3J_{instanceId} as another root selector. With this CSS selector, you can assign individual looks to each instance.
.CX3J {
  --moduleHeight: 800px;
  --moduleWidth: 100%;
  --indexWidth: 60px;
  --eventHeight: 16px;
  --borderSize: 1px;
  --mainBorderStyle: var(--borderSize) solid darkgray;
  --subBorderStyle: var(--borderSize) dotted darkslategray;
}

The most commonly used values would be defined in .CX3J selector as variables.

  • moduleHeight and -moduleWidth will be set by configuration value height and width for your convenience.

Handling Events

Each event object has this structure.

{
  "title": "Leeds United - Chelsea",
  "startDate": 1650193200000,
  "endDate": 1650199500000,
  "fullDayEvent": false,
  "class": "PUBLIC",
  "location": false,
  "geo": false,
  "description": "...",
  "today": false,
  "symbol": ["calendar-alt"],
  "calendarName": "tottenham",
  "color": "gold",
  "calendarSeq": 1, // This would be the order from `calendarSet` of configuration
  "isPassed": true,
  "isCurrent": false,
  "isFuture": false,
  "isFullday": false,
  "isMultiday": false,
  "skip": false, // If this is set, event will not be rendered. (since 1.7.0)
}

You can use these values to handle events.

Filtering

You can filter each event by its condition.

eventFilter: (ev) => {
  if (ev.isFullday) return false
  return true
}

This example shows how you can filter out 'fullday' events.

Sorting

You can sort each event by its condition. However, this module arranges events masonry with density. So displaying would not fit with your sorting intention. Anyway, try if you need it.

eventSorter: (a, b) => {
  return a.calendarSeq - b.calendarSeq
}

This example tries to sort events by calendar order in calendarSet.

Transforming

You can manipulate or change the properties of the event.

eventTransformer: (ev) => {
  if (ev.title.search('John') > -1) ev.color = 'blue'
  return ev
}

This example shows how you can transform the color of events when the event title has specific text.

preProcessing

preProcessor: (ev) => {
  if (ev.title.includes('test')) return null
  if (ev.calendarName === 'Specific calendar') ev.startDate += 2 * 60 * 60 * 1000
  return ev
}

This example shows

  1. if the title of an event has "test", drop the event off

  2. then add 2 hours to the start time of events on the specific calendar.

Unlike eventTransformer, the preProcessor would be applied to raw data format of events from the default calendar module or equivalent after receiving notification.

This is the better place to adjust the event itself to make it compatible with this module before the main logic of the module handle and regularize events.

skip to draw

If an event has .skip: true as a property, it will not be rendered. However, it remains in the data, so you can still sort, filter, or reference it.

Generally, this attribute will not derived from the original calendar provider(e.g. default calendar module). You may need to assign the value by yourself with event-handling.

Using Iconify

You can use Iconify icons instead of Font Awesome by setting useIconify: true:

// In your calendar module config
defaultSymbolClassName: '', // <-- Important to identify iconify properly.
calendars: [
  {
    color: "red",
    symbol: "flag:us-4x3",
    url: "https://ics.calendarlabs.com/76/mm3137/US_Holidays.ics"
  },
  {
    color: "red",
    symbol: "fa fa-fw fa-flag",
    url: "https://ics.calendarlabs.com/76/mm3137/US_Holidays.ics"
  },
],

Note: Set defaultSymbolClassName: '' in your calendar module config when using Iconify. If you want to use Font Awesome icons alongside Iconify, add the Font Awesome class names (e.g. fa, fas, fa-calendar-check) manually.

Known Limitations

  • The default calendar module does not emit the exact start time of multi-day full-day events that span the current moment — they always appear to start today. This module inherits that behavior.

Changelog

See CHANGELOG.md.

  • Released.

More Info.

Siblings

Author

ko-fi

About

Magic mirror module for presenting events as daily/weekly journal style.

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors