README.md
October 13, 2025 ยท View on GitHub
Preview

Configuration
- type: custom-api
title: NBA Today
url: "https://site.api.espn.com/apis/site/v2/sports/basketball/nba/scoreboard"
cache: 15s
template: |
{{ $events := .JSON.Array "events" }}
{{ if eq (len $events) 0 }}
<div>No games scheduled today.</div>
{{ else }}
{{ $wid := printf "nba-%d" now.UnixNano }}
<div id="{{ $wid }}" style="position:relative;padding-bottom:{{ if gt (len $events) 6 }}25px{{ else }}0px{{ end }};">
<input type="checkbox" id="{{ $wid }}-cb" style="display:none"/>
<ul class="visible" style="list-style:none;padding:0;margin:0;">
{{ $count := 0 }}
{{ range $i, $g := $events }}
{{ $phase := $g.String "competitions.0.status.type.state" }}
{{ if and (lt $count 6) (eq $phase "in") }}
{{ template "nba-game" $g }}
{{ $count = add $count 1 }}
{{ end }}
{{ end }}
{{ range $i, $g := $events }}
{{ $phase := $g.String "competitions.0.status.type.state" }}
{{ if and (lt $count 6) (eq $phase "pre") }}
{{ template "nba-game" $g }}
{{ $count = add $count 1 }}
{{ end }}
{{ end }}
{{ range $i, $g := $events }}
{{ $phase := $g.String "competitions.0.status.type.state" }}
{{ if and (lt $count 6) (and (ne $phase "in") (ne $phase "pre")) }}
{{ template "nba-game" $g }}
{{ $count = add $count 1 }}
{{ end }}
{{ end }}
</ul>
<ul class="all" style="list-style:none;padding:0;margin:0;display:none">
{{ range $i, $g := $events }}
{{ if eq ($g.String "competitions.0.status.type.state") "in" }}
{{ template "nba-game" $g }}
{{ end }}
{{ end }}
{{ range $i, $g := $events }}
{{ if eq ($g.String "competitions.0.status.type.state") "pre" }}
{{ template "nba-game" $g }}
{{ end }}
{{ end }}
{{ range $i, $g := $events }}
{{ $phase := $g.String "competitions.0.status.type.state" }}
{{ if and (ne $phase "in") (ne $phase "pre") }}
{{ template "nba-game" $g }}
{{ end }}
{{ end }}
</ul>
{{ if gt (len $events) 6 }}
<label for="{{ $wid }}-cb" style="position:absolute;bottom:0px;right:0;cursor:pointer;color:var(--glance-accent-color);font-size:16px;padding:5px;">
<span style="display:inline-block;transition:transform .2s;font-size:20px;">▾</span>
</label>
{{ end }}
<style>
#{{ $wid }} .nba-row:last-child { margin-bottom:0; }
#{{ $wid }}-cb:not(:checked) ~ .all { display:none!important }
#{{ $wid }}-cb:checked ~ .visible { display:none!important }
#{{ $wid }}-cb:checked ~ .all { display:block!important }
#{{ $wid }}-cb:checked ~ label span { transform:rotate(180deg)!important }
</style>
</div>
{{ end }}
{{ define "nba-game" }}
{{ $state := .String "competitions.0.status.type.name" }}
{{ $home := index (.Array "competitions.0.competitors") 0 }}
{{ $away := index (.Array "competitions.0.competitors") 1 }}
{{ $awayRecords := $away.Array "records" }}
{{ $homeRecords := $home.Array "records" }}
{{ $awayRec := "" }}
{{ if gt (len $awayRecords) 0 }}{{ $awayRec = (index $awayRecords 0).String "summary" }}{{ end }}
{{ $homeRec := "" }}
{{ if gt (len $homeRecords) 0 }}{{ $homeRec = (index $homeRecords 0).String "summary" }}{{ end }}
{{ $awayLogo := $away.String "team.logo" }}
{{ $homeLogo := $home.String "team.logo" }}
{{ $fallbackLogo := "https://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nba.png" }}
{{ $statusText := .String "competitions.0.status.type.shortDetail" }}
{{ $statusFont := "0.7em" }}
{{ if eq $state "STATUS_IN_PROGRESS" }}{{ $statusFont = "0.8em" }}{{ end }}
{{ if eq $state "STATUS_SCHEDULED" }}{{ $statusFont = "0.8em" }}{{ end }}
{{ if eq $statusText "Final" }}{{ $statusFont = "0.8em" }}{{ end }}
{{ $awayAbbr := $away.String "team.abbreviation" }}
{{ if or (eq (len $awayAbbr) 0) (gt (len $awayAbbr) 3) }}
{{ $awayAbbr = printf "%.3s" ($away.String "team.displayName") }}
{{ end }}
{{ $homeAbbr := $home.String "team.abbreviation" }}
{{ if or (eq (len $homeAbbr) 0) (gt (len $homeAbbr) 3) }}
{{ $homeAbbr = printf "%.3s" ($home.String "team.displayName") }}
{{ end }}
<li class="nba-row" style="display:flex;flex-direction:column;gap:4px;padding:10px 0;border-bottom:1px solid var(--glance-divider);" {{ if ne $state "STATUS_SCHEDULED" }}title="{{ $awayAbbr }} Box:{{ range $j,$ls := $away.Array "linescores" }}{{ if eq $j 0 }} Q1: {{ else if eq $j 1 }} Q2: {{ else if eq $j 2 }} Q3: {{ else if eq $j 3 }} Q4: {{ else }} OT: {{ end }}{{ $ls.String "value" }}{{ end }} {{ $homeAbbr }} Box:{{ range $j,$ls := $home.Array "linescores" }}{{ if eq $j 0 }} Q1: {{ else if eq $j 1 }} Q2: {{ else if eq $j 2 }} Q3: {{ else if eq $j 3 }} Q4: {{ else }} OT: {{ end }}{{ $ls.String "value" }}{{ end }}"{{ end }}>
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0;">
<div style="display:flex;align-items:flex-start;gap:6px;min-width:0;">
{{ if $awayLogo }}
<img src="{{ $awayLogo }}" alt="{{ $awayAbbr }}" style="width:34px;height:34px;border-radius:50%;flex-shrink:0;"/>
{{ else }}
<img src="{{ $fallbackLogo }}" alt="{{ $awayAbbr }}" style="width:34px;height:34px;border-radius:50%;flex-shrink:0;"/>
{{ end }}
<div style="display:flex;flex-direction:column;gap:2px;min-width:0;">
<div style="display:flex;align-items:baseline;gap:6px;min-width:0;">
<span style="font-weight:700;letter-spacing:0.08em;white-space:nowrap;text-transform:uppercase;">{{ $awayAbbr }}</span>
</div>
{{ if $awayRec }}<span style="font-size:0.7em;color:var(--glance-muted-text);white-space:nowrap;">({{ $awayRec }})</span>{{ end }}
</div>
</div>
<div style="flex:1;display:flex;align-items:center;justify-content:center;gap:10px;white-space:nowrap;letter-spacing:0.05em;min-width:0;">
{{ if ne $state "STATUS_SCHEDULED" }}
<span style="font-size:1em;font-weight:700;font-variant-numeric:tabular-nums;color:var(--glance-heading-text);">{{ $away.String "score" }}</span>
{{ end }}
<span style="font-size:{{ $statusFont }};font-weight:500;">
{{ if eq $state "STATUS_IN_PROGRESS" }}
{{ $period := .String "competitions.0.status.period" }}
{{ if eq $period "1" }}1st{{ else if eq $period "2" }}2nd{{ else if eq $period "3" }}3rd{{ else if eq $period "4" }}4th{{ else }}OT{{ end }} {{ .String "competitions.0.status.displayClock" }}
{{ else if eq $state "STATUS_SCHEDULED" }}
{{ $tipStr := .String "competitions.0.date" }}
{{ if $tipStr }}
{{ $tip := ($tipStr | parseTime "2006-01-02T15:04Z") }}
{{ $local := $tip.In now.Location }}
{{ $hour := $local.Hour }}
{{ $minute := $local.Minute }}
{{ $ampm := "AM" }}
{{ if ge $hour 12 }}{{ $ampm = "PM" }}{{ end }}
{{ $hour12 := $hour }}
{{ if eq $hour 0 }}
{{ $hour12 = 12 }}
{{ else if gt $hour 12 }}
{{ $hour12 = add $hour -12 }}
{{ end }}
{{- printf "%d:%02d %s EDT" $hour12 $minute $ampm -}}
{{ else }}
{{ $statusText }}
{{ end }}
{{ else }}
{{ $statusText }}
{{ end }}
</span>
{{ if ne $state "STATUS_SCHEDULED" }}
<span style="font-size:1em;font-weight:700;font-variant-numeric:tabular-nums;color:var(--glance-heading-text);">{{ $home.String "score" }}</span>
{{ end }}
{{ if .Exists "competitions.0.series" }}
<span style="font-size:0.7em;color:var(--glance-muted-text);">{{ .String "competitions.0.series.summary" }}</span>
{{ end }}
</div>
<div style="display:flex;align-items:flex-start;gap:6px;justify-content:flex-end;min-width:0;">
<div style="display:flex;flex-direction:column;gap:2px;align-items:flex-end;min-width:0;">
<div style="display:flex;align-items:baseline;gap:6px;min-width:0;">
<span style="font-weight:700;letter-spacing:0.08em;white-space:nowrap;text-transform:uppercase;">{{ $homeAbbr }}</span>
</div>
{{ if $homeRec }}<span style="font-size:0.7em;color:var(--glance-muted-text);white-space:nowrap;">({{ $homeRec }})</span>{{ end }}
</div>
{{ if $homeLogo }}
<img src="{{ $homeLogo }}" alt="{{ $homeAbbr }}" style="width:34px;height:34px;border-radius:50%;flex-shrink:0;"/>
{{ else }}
<img src="{{ $fallbackLogo }}" alt="{{ $homeAbbr }}" style="width:34px;height:34px;border-radius:50%;flex-shrink:0;"/>
{{ end }}
</div>
</div>
</li>
{{ end }}