#calendar #static-website #static #ical #ics #config-file #static-site-generator

bin+lib statical

A calendar aggregator and generator to make maintaining calendars on static websites easier

2 unstable releases

0.2.0 Jan 3, 2024
0.1.0 May 26, 2022

#1174 in Web programming

BSD-3-Clause

175KB
3K SLoC

statical

A calendar aggregator and generator to make maintaining calendars on static websites easier.

Why this exists

While there is no shortage of calendaring services available, they all have drawbacks:

  • They are branded, or rather expensive with prices ranging from around $8-45 per month. While that's not terrible on the low end, if you want to add calendaring to multiple websites it adds up quickly.
  • These calendars, whether embedded or linked, call out to their servers which may not respect the privacy preferences of site visitors.
  • While self-hosted options are available, I don't want to have to setup and administer another server just to host a simple calendar. Static sites are excellent and the calendar should be static as well.

None of the available options met my needs so I decided to build my own. This project was also excellent motivation and practice for Rust software development.

Status

This program is now mostly usable for basic calendar generation functionality. It is thus now in the Beta stage of development and with a little more work can hit the version 1.0 milestone.

The documentation needs to be completed as well as adding a setup guide. The code is nearing general usability, but may still require a bit of tinkering and digging.

To make configuration easier, statical can now generate an example config file with the --generate-default-config flag.

The default templates are starting to look acceptable and we are planning a final design pass shortly. While the templates and CSS are fully customizable, the goal is for the defaults to produce a calendar with good user experience, interface and aesthetics. There is still a bit of work to be done here.

Features

  • Reads *.ics files or live calendar feeds
    • Caches live calendar feeds
    • Cache timeout is configurable (default is 1 day)
    • Allows cookies to be specified to enable downloading of calendar feeds that require login
  • Does NOT require contributors to create a new login. Just add their calendar feed to the config file.
  • Can be run manually on your personal machine or setup on a Cron job, Git hook, or Continuous Integration (CI) pipeline
  • Generates static HTML views
    • Month
    • Week
    • Day
    • Agenda
  • View customization
    • Default views are embedded in the app
    • Alternately, views can also be individually overridden and fully customized via Tera templates
    • Views are completely HTML and CSS based, no JavaScript is present
    • SASS/CSS is provided but can be edited or completely overridden
    • Calendars can be assigned custom colors. Any valid CSS color notation should work, including color names.
    • Colors are adjusted for readability via the Oklch color space. (The lightness and chroma adjustment values can be configured or adjustment can be entirely disabled.)
  • Generates calendar feeds in ICS format

Target users

Statical is built with three types of users in mind:

1. Casual CLI users

Statical should be easy enough for someone with basic CLI knowledge to install it, modify the default configuration, and have calendars that look good in minutes.

2. Advanced web designers

For those who want more control of the calendars generated:

  • Ample config options are provided
  • SASS/CSS can be customized or completely overridden
  • Views are generated via templates that can be customized or completely overridden

3. Rust programmers

If complete control is desired, this code is released under the BSD 3 clause license.

Usage

Background

Statical is intended to be used in a "Static Site Generator chain" (credit to CloudCannon for the term). Statical should run before tools like Pagefind and Jampack as its output pages will need to be indexed and optimized.

An example chain might look like the following:

  1. soupault (or your favorite static site generator)
  2. statical
  3. Pagefind (or tinysearch, stork, orama, or similar)
  4. Jampack
  5. deploy or sync your site

Configuration

Statical must have a config file is order to run. Create the example config file with the command:

statical --create-default-config

Edit the config file as necessary with your favorite text editor. Only the keys below are strictly necessary:

  • display_timezone: One of the TZ identifiers from the IANA Time Zone Database
  • default_calendar_view: one of Month, Week, Day, or Agenda
  • calendar_sources Multiple sources can be provided.
    • name: must be kebab-case
    • source: can be the URL of a calendar feed or a local *.ics file

The rest have default values that should work for most users. There are comments in the generated config file explaining the purpose of each option.

Running statical

Statical needs to be run every time there are changes to the calendar. This can be done manually or via cron job, Git hook or CI pipeline.

Statical will look in the current directory for its config file named statical.toml. Alternately, you can specify one or more config files as arguments to statical e.g.:

statical site-one/statical.toml site-two/statical.toml ...

Customization

Default assets and templates are built into statical, but can be overridden by the user if desired.

Assets

If you would like to customize the CSS run:

statical --restore-missing-assets

The assets directory will be created at the location specified in the configuration file (paths are relative to the config file itself). The default is assets.

Any missing asset files will be re-created from those built-in to statical. Assets can be edited as desired, or deleted to return to the built-in defaults. If an asset is already present with the same name as one of the defaults, it will not be overwritten.

Templates

To customize the views themselves run:

statical --restore-missing-templates

The templates directory will be created at the location specified in the configuration file (paths are relative to the config file itself). The default is templates.

Any missing template files will be re-created from those built-in to statical. Templates can be edited as desired, or deleted to return to the built-in defaults. If a template is already present with the same name as one of the defaults, it will not be overwritten.

Template Language

Statical uses Tera templates to allow customization of calendar views. For detailed information about Tera its capabilities see the Tera Documentation.

To see what data is available for use within a given template, add the following code somewhere in your template:

<pre>
  {{ __tera_context }}
</pre>

If statical does not do exactly what you need, check out these projects instead.

  • ical-merger: Merges multiple iCalendar files into one, as a web service.
  • ical-filter: HTTP daemon to normalize and filter iCalendar files
  • zerocal: A Serverless Calendar App in Rust Running on shuttle.rs by Matthias Endler

Road map and TODOs

The below got rather large and probably needs to be cleaned up and reorganized. We'll leave it here for now, but it will likely be split out into a separate doc later.

Pre-release testing fixes

  • Fix default date bug (2023-09-13)
  • Make copy stylesheet true by default (2023-09-13)
  • Embed default stylesheet in binary (2023-09-13)
  • Add --restore-missing-templates (2023-09-14)
  • Make the config generation write to file directly (2023-09-14)
  • Put sources default in that triggers help if it is not updated
  • Add initial setup option
  • Add help when command is first run (2023-09-14)
  • Add assistant to help add calendar sources?
  • Ensure that partial configuration files work i.e. those missing many keys
  • Create a list of required config keys, the minimum necessary to run statical (2023-09-15)
  • Adjust the view links for the closest time period to the current page (link to the item that is >= the current item)
  • Link day numbers

Setup and Configuration (1.0 Milestone)

  • Add toml config
  • add an option to generate example templates or provide them in the docs/repo (2023-09-04)
  • Add tera templates (2022-05-17)
  • add baseurl support (2023-09-08)
  • Default to looking for the statical.toml file in the current dir (2023-09-08)
  • Make all paths relative to the config file (2023-09-09)
  • Prompt with instructions on how to use Statical if config file is not present or provided. (2023-09-14)
  • Add --restore-missing-assets option (2023-09-14)
  • Add auto-retrieval of authentication cookies from browsers

Setup and Configuration (Future Work)

  • Allow template path config. (2023-09-14)
  • calendar colors and CSS classes (2023-09-19)
  • paths for time interval pages should be configurable?

Calendar Generation (1.0 Milestone)

  • Add call to get date of the first day of the week (2022-05-19)
  • Switch week view to BTreeMap based event lists (2023-09-02)
  • Switch day view to BTreeMap based event lists (2023-09-02)
  • Redo event grouping logic (2023-08-28)
    • Store all events in a BTreeMap (it allows efficient in-order access and thus ranges) (2023-08-28)
    • This should allow a single map to hold all events rather than the complex, nested structures we are using now (2023-08-28)
    • Retrieve events from the map on view creation, maybe group them into relevant contexts then (2023-08-28)

Styling (1.0 Milestone)

  • Add styling to hide event descriptions in the calendar view and show them on hover (2023-09-01)
  • Add weekday vs weekend classes (2023-09-08)
  • SASS processing (2023-09-19)
  • add source calendar class (2023-09-19)
  • Remove no-wrap from event header text (but keep no-wrap on duration)
  • highlight current day
  • Clean up pagination and views
  • Align pagination with grid
  • Center header
  • cleanup css
  • CSS classes for calendar colors
  • Append calendar class CSS rules to stylesheet
  • Make CCS rules have higher specificity
  • Make the calendar feed view button a drop-down menu
  • Add translucent overlay to other-month days
  • Rename the default stylesheet statical.css

Styling (Future Work)

  • add event classes
  • add event categories
  • Figure out how to layout overlapping events. CSS grid to the rescue?
  • Make overlapping events stack horizontally in the Day view on desktop (maybe week and month if space allows)
  • Add times on left side and align events in week and day view

Output pages (1.0 Milestone)

  • agenda (list of events)
  • day (2022-09-15)
  • week (2022-05-19)
  • month (2022-09-15)
  • index pages for each time interval (2022-09-15)
  • link pages with forward and back links (2022-05-19)
  • add default CSS (2022-05-19)
  • add links to switch between intervals (2022-09-15)
  • Add summary to event header (2023-09-08)
  • Store templates internally but use external versions if provided. (2023-09-08)
  • event detail
    • decide on url naming, probably not date based, maybe including calendar name
    • use unexpanded events
  • Add page map, an overview of all pages generated in the calendar (good for debugging and double checking sparse vs. dense generation)
  • Add ics feed generation
  • Add month name on fist day of month in week view (just like month view) (2023-09-09)
  • Determine which month a week "belongs to" based on which month has the most days in that week? (2023-09-09)
  • Clean up the HTML class logic in the week template, move it into the Week class when generating contexts
  • Add day strftime format?
  • Add strftime format for agenda dates?
  • Add keybindings to allow keyboard navigation of calendar
  • Allow a template based replacement of embed_page head section

JavaScript (Future Work)

  • Add JavaScript (or CSS toggle) to toggle event descriptions for mobile
  • Add JavaScript to jump to the closest date to the one selected when switching view formats
  • jump to current day
  • highlight current day
  • select day(s)
  • highlight selected day(s)
  • switch views while maintaining selected day(s)
  • add JS to toggle display of events by calendar
  • add JS to toggle display of events by category

Calendar generation (1.0 Milestone)

  • Fix agenda event collection logic
  • Fix event ordering in day view
  • Calculate beginning and end dates of each calendar, do not default to today

Calendar Generation (Future Work)

  • Loop through all months, weeks, days in the calendar ranges (dense HTML calendar generation setting)
  • add a sparse setting and decide how to handle missing intervals
  • Add a sparse flag to not render missing intervals or to put placeholders there

Calendar filtering and processing (Future Work)

  • Add HTML sanitization to calendar descriptions
  • Add support for Markdown in calendar descriptions
  • Event de-duplication
  • Event information merging
  • Information merge precedence/hierarchy
  • Add processing rules
    • Add categories
    • Add tags?
    • Hide/merge events
    • Move/copy/edit events
    • Add calendar groups
    • Calendar feed routing
  • add human date format parsing
  • support for sunrise and sunset (if event has a location, or default to calendar location?)
  • Add support for first/second/third/etc. X day of the month

Ergonomics

  • live preview server

External tool integration (Future Work)

  • pagefind integration (add indexing hints templates)
  • jampack integration?

Dependencies

~32–46MB
~791K SLoC