Skip to content

goma-time-filter

Horizontal pill row of time-interval filters with a hardcoded "All" pill on the left. Pure host-fed: each interval is a { label, value } pair, where value matches the matches-aggregator topic's hoursInterval segment.

Lighter than the rest of the filter family: no WAMP transport, no sport-scoping, no API container — just a host-fed array, a selection state, and a goma:time-select event. Pair with <goma-events-horizontal> (followTimePicker: true) to drive the events feed.

Live demo

Open in the playground → — toggle Time filter in the widget rail. The playground ships a default 8-pill mock interval set (1H / 3H / 6H / 12H / Today / Tomorrow / 3 days / Week); paste your own JSON into the inspector's "Intervals JSON" field to swap.

Install

bash
npm install @gomagaming/time-filter

You also need the shared peer dependencies installed at your app level:

bash
npm install vue pinia vue-router vue-i18n @vueuse/core swiper

Element

html
<goma-time-filter id="tf"></goma-time-filter>

Configuration

The time-filter has no socketUrl / apiBaseUrl requirement — there's no WAMP transport. Only the standard locale / theme / messages knobs apply.

js
const el = document.getElementById('tf')
el.config = { locale: 'en' }   // optional; defaults to 'en'

The intervals array

Drive the widget by setting el.intervals to an array of { label, value } pairs:

js
el.intervals = [
  { label: '1H',       value: '0-1' },
  { label: '3H',       value: '0-3' },
  { label: '6H',       value: '0-6' },
  { label: '12H',      value: '0-12' },
  { label: 'Today',    value: '0-24' },
  { label: 'Tomorrow', value: '24-48' },
  { label: '3 days',   value: '0-72' },
  { label: 'Week',     value: '0-168' },
]
  • label is the visible pill text. The widget renders it verbatim — hosts pre-localise (the widget itself only localises the hardcoded "All" pill via the bundled time_filter_all_label key).
  • value is the canonical identifier. Format matches the matches-aggregator topic's hoursInterval segment: '{start}-{end}' where both are non-negative integers in hours. Use 'all' for the no-filter sentinel — but you don't need to supply that yourself, the hardcoded "All" pill already covers it.

Entries missing value are dropped silently; duplicates by value keep the first occurrence. Malformed payloads don't crash the render.

Props (HTML attributes + JS properties)

PropertyAttributeDefaultDescription
intervalsintervals[]Array of { label, value } pairs. Set via JS or as a JSON-encoded HTML attribute.
selectedTimeValueselected-time-value'all'The currently-selected interval's value field. 'all' selects the hardcoded leftmost pill. Two-way: clicks update this.
spaceBetweenspace-between8Pixel gap between pills.
showLabelsshow-labelstrueRender the label on each pill (otherwise pills shrink to icon-free dots — useful for ultra-compact layouts).

The hardcoded "All" pill

Always rendered as the leftmost pill. Clicking it emits:

js
{
  timeValue: 'all',
  timeLabel: 'All',     // locale-aware via `t('time_filter_all_label')`
  previousTimeValue: <whatever was selected>,
}

timeValue === 'all' is the canonical "no filter" sentinel — maps straight to the matches-aggregator topic's literal all hoursInterval segment.

Events

StatusEventDetailEmitted when
Canonicalready{}Widget mounted.
Canonicalgoma:error{ message, code, component? }Render error.
Canonicalgoma:time-select{ timeValue, timeLabel, previousTimeValue }User taps a time-interval pill or the "All" pill. The widget also mutates selectedTimeValue so the pill flips immediately.

Embedding examples

Vanilla HTML — drive an events-horizontal feed

html
<goma-time-filter id="times"></goma-time-filter>
<goma-events-horizontal
  id="feed"
  follow-time-picker
  topic="custom-matches-aggregator/1/all/all/all/POPULAR/LIVE/10/5"
></goma-events-horizontal>
<script type="module">
  import '@gomagaming/time-filter'
  import '@gomagaming/events-horizontal'

  const times = document.getElementById('times')
  times.intervals = [
    { label: '1H',    value: '0-1' },
    { label: 'Today', value: '0-24' },
    { label: 'Week',  value: '0-168' },
  ]
  document.getElementById('feed').config = { /* socket + REST creds */ }
</script>

Tap a pill → events-horizontal rewrites segment 3 (hoursInterval) of its topic → WAMP subscription rebinds transparently, no reconnect.

React

jsx
import '@gomagaming/time-filter'
import { useEffect, useRef } from 'react'

const INTERVALS = [
  { label: '1H',    value: '0-1' },
  { label: 'Today', value: '0-24' },
  { label: 'Week',  value: '0-168' },
]

function TimeFilter({ onSelect }) {
  const ref = useRef(null)
  useEffect(() => {
    if (!ref.current) return
    ref.current.intervals = INTERVALS
  }, [])
  return (
    <goma-time-filter ref={ref} onGoma:time-select={(e) => onSelect(e.detail)} />
  )
}

Vue 3

vue
<script setup>
import '@gomagaming/time-filter'
import { ref, onMounted } from 'vue'

const el = ref(null)
const INTERVALS = [
  { label: '1H', value: '0-1' },
  { label: 'Today', value: '0-24' },
]

onMounted(() => { el.value.intervals = INTERVALS })
</script>

<template>
  <goma-time-filter ref="el" @goma:time-select="onTimeSelect" />
</template>

Theming

Same --goma-* tokens as goma-region-filter / goma-competition-filter. Override via el.theme = { … }. Time-filter doesn't render a flag/icon ring or a live-count badge, so a slightly narrower set:

TokenElement
--goma-backgroundPrimaryRail background
--goma-backgroundCardsInactive pill background
--goma-textPrimaryInactive pill label
--goma-highlightPrimarySelected pill background
--goma-highlightPrimaryContrastSelected pill label

i18n

Three bundled keys (en / fr / pt):

KeyDefault (en)Used in
time_filter_all_labelAllThe hardcoded leftmost pill
time_filter_ariaTime filter<swiper aria-label>
time_filter_emptyNo time intervals available(Reserved — currently only the All pill renders when intervals is empty.)

Pill labels themselves are never localised by the widget — hosts pre-localise their intervals array before passing it in. This keeps the prop-shape contract minimal.

Accessibility

ElementRoleAttributes
Swiper containertablistaria-label="Time filter" (i18n key time_filter_aria)
Time pilltabtabindex="0", aria-selected, aria-label="{label}"
Error bannerrole="alert" for screen-reader announcement

Keyboard: Tab to focus pills, Enter / Space to select. :focus-visible ring uses the --goma-highlightPrimary token.

Source layout

LayerFile
Element classpackages/time-filter/src/TimeFilterElement.js
App wrapperpackages/time-filter/src/TimeFilterApp.vue
Component treepackages/time-filter/src/components/TimeFilter/{TimeList,TimeItem}.vue
Manifestpackages/time-filter/custom-elements.json

Unlike the sport / region / competition filters, there's no shared composable in @gomagaming/sports-domain — the widget is purely host-driven and has no WAMP plumbing of its own.

What's deferred

  • A future v2 surface could ship a default intervals set bundled at the locale layer (e.g. intervals: 'preset:standard' resolves to [{label: t('time_1h'), value: '0-1'}, …]). Out of scope for v1 — hosts supply their own arrays today, which gives them full control over localisation and the set of options.