sphinx-timeline#

A sphinx extension to create timelines.

A scrolling horizontal timeline is created for HTML output, and other formats degrade gracefully to a simple ordered list.

  1. Mon 4th Feb 2030

    6th event

    Description …

  2. Tue 4th Feb 2020

    5th event

    Description …

  3. Wed 3rd Feb 2010

    4th event

    Description …

  4. Thu 3rd Feb 2000

    3rd event

    Description …

  5. Sat 3rd Feb 1990

    2nd event

    Description …

  6. Sun 3rd Feb 1980

    1st event

    Description …

Quick-start#

Install sphinx-timeline with pip install sphinx-timeline, then add sphinx_timeline to your conf.py file’s extensions variable:

extensions = ["sphinx_timeline"]

Now add a timeline directive to your document:

.. timeline::

   - start: 1980-02-03
     name: 1st event
   - start: 1990-02-03
     name: 2nd event
   - start: 2000-02-03
     name: 3rd event
   ---
   **{{dtrange}}**

   *{{e.name}}*

   Description ...

Usage#

A timeline contains two critical pieces:

  1. A list of events (in the form of a YAML list, JSON list, or CSV).

    • Each event must have at least start key, in ISO 8601 date(time) format, which can also have a suffix time zone in parenthesise, e.g. 2020-02-03 12:34:56 (Europe/Zurich).

    • Each event can have an optional duration key, to specify the delta from the start. This is in the format e.g. 30 minutes 4 hours 1 day 2 months 3 years. All units are optional and can be in any order, e.g. 4 hours 30 minutes is the same as 30 minutes 4 hours 0 day 0 months 0 years.

  2. A template for the event items content (in the form of a Jinja2 template)

Each can be supplied via an external file, or directly in the directive content. If both are in the directive content, then they are split by a line with ---.

For example, to use external files:

.. timeline::
   :events: /path/to/events.yaml
   :template: /path/to/template.txt

If a path starts with /, then it is relative to the Sphinx source directory, otherwise it is relative to the current document.

Jinja templates#

The template is a Jinja2 template, which is rendered for each event. The event dictionary is available as the e variable, and the following additional variables are available:

dtrange

The event’s start and duration formatted as a date range, e.g. Wed 3rd Feb 2021, 10:00 PM - 11:01 PM (UTC). If the event has no duration, then only the start is used. This can also be parsed arguments to control the formatting

.. timeline::
    :style: none

    - start: 2022-02-03 22:00
    - start: 2021-02-03 22:00
      duration: 1 hour 30 minutes
    - start: 2020-02-03
      duration: 1 day
    ---
    - {{dtrange}}
    - {{dtrange(day_name=False)}}
    - {{dtrange(short_date=True)}}
    - {{dtrange(clock12=True)}}
    - {{dtrange(abbr=False)}}
    • Thu 3rd Feb 2022, 10:00 PM (UTC)

    • 3rd Feb 2022, 10:00 PM (UTC)

    • Thu 03/02/2022, 10:00 PM (UTC)

    • Thu 3rd Feb 2022, 10:00 PM (UTC)

    • Thursday 3rd February 2022, 10:00 PM (UTC)

    • Wed 3rd Feb 2021, 10:00 PM - 11:30 PM (CET)

    • 3rd Feb 2021, 10:00 PM - 11:30 PM (CET)

    • Wed 03/02/2021, 10:00 PM - 11:30 PM (CET)

    • Wed 3rd Feb 2021, 10:00 PM - 11:30 PM (CET)

    • Wednesday 3rd February 2021, 10:00 PM - 11:30 PM (CET)

    • Mon 3rd - Tue 4th Feb 2020

    • 3rd - 4th Feb 2020

    • Mon 03/02/2020 - Tue 04/02/2020

    • Mon 3rd - Tue 4th Feb 2020

    • Monday 3rd - Tuesday 4th February 2020

dt

The same as dtrange, but duration is not included.

Directive options#

events

Path to the timeline data file, otherwise the data is read from the content. If the path starts with /, then it is relative to the Sphinx source directory, otherwise it is relative to the current document.

events-format

The format of the events. Can be json, yaml, or csv. Defaults to yaml.

template

Path to the template file, otherwise the template is read from the content. If the path starts with /, then it is relative to the Sphinx source directory, otherwise it is relative to the current document.

max-items

The maximum number of items to show. Defaults to all.

reversed

Whether to reverse the order of the item sorting.

style

The style of the timeline. Can be default or none.

height

The height of the timeline (for default style). Defaults to 300px.

width-item

The width of each item (for default style). Defaults to 280px.

class

Classes to add to the timeline list.

class-item

Classes to add to each item.

Customise HTML output#

CSS Variables#

The following CSS variables can be used to customize the appearance of the timeline:

:root {
    --tl-height: 300px;
    --tl-item-outline-color: black;
    --tl-item-outline-width: 1px;
    --tl-item-border-radius: 10px;
    --tl-item-padding: 15px;
    --tl-item-width: 280px;
    --tl-item-gap-x: 8px;
    --tl-item-gap-y: 16px;
    --tl-item-tail-height: 10px;
    --tl-item-tail-color: #383838;
    --tl-item-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    --tl-line-color: #686868;
    --tl-line-width: 3px;
    --tl-dot-color: black;
    --tl-dot-diameter: 12px;
}

For example, for furo and pydata-sphinx-theme, which have dark/light themes, you can add the following to your conf.py:

html_static_path = ["_static"]
html_css_files = ["custom.css"]

Then create the CSS _static/custom.css:

body[data-theme="dark"] {
    --tl-dot-color: #9a9a9a;
    --tl-item-outline-color: #383838;
    --tl-item-tail-color: #747474;
    --tl-item-shadow: 0 4px 8px 0 rgba(100, 100, 100, 0.2), 0 6px 10px 0 rgba(100, 100, 100, 0.19);
}

@media (prefers-color-scheme: dark) {
    body:not([data-theme="light"]) {
        --tl-dot-color: #9a9a9a;
        --tl-item-outline-color: #383838;
        --tl-item-tail-color: #747474;
        --tl-item-shadow: 0 4px 8px 0 rgba(100, 100, 100, 0.2), 0 6px 10px 0 rgba(100, 100, 100, 0.19);
    }
}

Data attributes#

On the containing div for each event, the data-dt data attribute is added, which contains the event’s start data/time in ISO format. JavaScript (if enabled) will also run, to add dt-future or dt-past class to each div, depending on whether the event is in the future or past. This means that you can use CSS selectors to style events based on their date/time.

For example, to highlight future events, you can add the following to your conf.py:

html_static_path = ["_static"]
html_css_files = ["custom.css"]

Then add to the CSS _static/custom.css:

ol.timeline-default>li.timeline>div.tl-item.dt-future {
    outline-color: green;
}