Until a better timeline shows up

Incrementally developing this idea as needs arise…

In case it helps anyone, and following the above example, this code splits the timeline into custom year sections with formatted headers based on start and end years, and allows multiple event icons.

It also adds a dropdown category filter at the top of the timeline. It’s then possible to display only events of a specific tag (thanks for @mr_abomination for help on replacing an existing dataview table).

// Map of tags to icons
const categories = {
  '#historic': '📅',
  '#johnson': '🔺',
  '#ussr': '🔹',
  '#nixon': '🔸',
}

// Timeline section headers (start and end years)
const sections = [
  ['0', '1900'],
  ['1900', '1930'],
  ['1930', '1940'],
  ['1940', '1950'],
  ['1950', '2025'],
]

// Dropdown filter element
const selectElement = dv.el('select')

// Return file link with icon if size is larger than threshold
const getEventLink = (e) =>
  e.file.size > 150
    ? '<span class="more-text">' + e.file.link + '</span>'
    : e.file.link

// Return tags in event as string of icons
const getEventIcon = (e) => {
  let output = ''
  for (const [tag, icon] of Object.entries(categories)) {
    if (e.file.tags.includes(tag)) {
      output += icon
    }
  }
  return output
}

// Main table render loop
const renderTable = () => {
  // Remove previous tables and headers
  // (required when changing filter)
  this.container
    .querySelectorAll('.table-view-table')
    .forEach((e) => e.parentNode.remove())

  this.container.querySelectorAll('h1').forEach((e) => e.remove())

  // Loop over sections, returning header and table
  for (const section of sections) {
    // Output h1 header, skipping "0" (zero start year)
    section[0] == '0' ? null : dv.header(1, section[0])

    // Get events in section year span,
    // filtering by dropdown category unless it's 'all'
    const events = dv
      .pages('"events"')
      .where(
        (e) =>
          String(e.date) >= section[0] &&
          String(e.date) < section[1] &&
          (e.file.tags.includes(selectElement.value) ||
            selectElement.value === 'all')
      )

    // Render the table if the section contains events
    if (events.length) {
      dv.table(
        ['', 'Date', 'Event'],
        events
          .sort((e) => String(e.date))
          .map((e) => [getEventIcon(e), e.date, getEventLink(e)])
      )
    }
  }
}

// Build the select dropdown element
selectElement.appendChild(dv.el('option', 'all'))
for (const key of Object.keys(categories)) {
  const option = dv.el('option', key)
  selectElement.appendChild(option)
}

// Build the containing div for the filter
const dropdown = dv.el('div', 'Category:', { cls: 'timeline-filter' })
dropdown.appendChild(selectElement)

// Add event listener to select element
selectElement.onchange = renderTable

// Render dropdown and tables
dropdown
renderTable()
2 Likes