mirror of
https://github.com/Lissy93/dashy.git
synced 2025-07-21 12:45:16 +02:00
✨ Adds a Sports Scores widget
This commit is contained in:
parent
a6b96483eb
commit
5684bf06e8
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.
|
Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.
|
||||||
|
|
||||||
|
> ℹ️ **Note**: Widgets are still in the Alpha-phase of development.
|
||||||
|
> If you find a bug, please raise it.<br>
|
||||||
|
> Adding / editing widgets through the UI isn't yet supported, you will need to do this in the YAML config file.
|
||||||
|
|
||||||
##### Contents
|
##### Contents
|
||||||
- [General Widgets](#general-widgets)
|
- [General Widgets](#general-widgets)
|
||||||
- [Clock](#clock)
|
- [Clock](#clock)
|
||||||
@ -13,6 +17,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
|
|||||||
- [XKCD Comics](#xkcd-comics)
|
- [XKCD Comics](#xkcd-comics)
|
||||||
- [Code Stats](#code-stats)
|
- [Code Stats](#code-stats)
|
||||||
- [Vulnerability Feed](#vulnerability-feed)
|
- [Vulnerability Feed](#vulnerability-feed)
|
||||||
|
- [Sports Scores](#sports-scores)
|
||||||
- [Public Holidays](#public-holidays)
|
- [Public Holidays](#public-holidays)
|
||||||
- [TFL Status](#tfl-status)
|
- [TFL Status](#tfl-status)
|
||||||
- [Exchange Rates](#exchange-rates)
|
- [Exchange Rates](#exchange-rates)
|
||||||
@ -38,6 +43,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
|
|||||||
- [Iframe Widget](#iframe-widget)
|
- [Iframe Widget](#iframe-widget)
|
||||||
- [HTML Embed Widget](#html-embedded-widget)
|
- [HTML Embed Widget](#html-embedded-widget)
|
||||||
- [API Response](#api-response)
|
- [API Response](#api-response)
|
||||||
|
- [Prometheus Data](#prometheus-data)
|
||||||
- [Data Feed](#data-feed)
|
- [Data Feed](#data-feed)
|
||||||
- [Usage & Customizations](#usage--customizations)
|
- [Usage & Customizations](#usage--customizations)
|
||||||
- [Widget Usage Guide](#widget-usage-guide)
|
- [Widget Usage Guide](#widget-usage-guide)
|
||||||
@ -46,12 +52,13 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
|
|||||||
- [Language Translations](#language-translations)
|
- [Language Translations](#language-translations)
|
||||||
- [Widget UI Options](#widget-ui-options)
|
- [Widget UI Options](#widget-ui-options)
|
||||||
- [Building a Widget](#build-your-own-widget)
|
- [Building a Widget](#build-your-own-widget)
|
||||||
|
- [Requesting a Widget](#requesting-a-widget)
|
||||||
|
|
||||||
## General Widgets
|
## General Widgets
|
||||||
|
|
||||||
### Clock
|
### Clock
|
||||||
|
|
||||||
A simple, live-updating time and date widget with time-zone support. All options are optional.
|
A simple, live-updating time and date widget with time-zone support. All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="400" src="https://i.ibb.co/vjb4RTv/clock.png" /></p>
|
<p align="center"><img width="400" src="https://i.ibb.co/vjb4RTv/clock.png" /></p>
|
||||||
|
|
||||||
@ -150,7 +157,7 @@ Displays the weather (temperature and conditions) for the next few days for a gi
|
|||||||
|
|
||||||
### Crypto Watch List
|
### Crypto Watch List
|
||||||
|
|
||||||
Keep track of price changes of your favorite crypto assets. Data is fetched from [CoinGecko](https://www.coingecko.com/)
|
Keep track of price changes of your favorite crypto assets. Data is fetched from [CoinGecko](https://www.coingecko.com/). All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="400" src="https://i.ibb.co/WtS6jQ8/crypto-prices.png" /></p>
|
<p align="center"><img width="400" src="https://i.ibb.co/WtS6jQ8/crypto-prices.png" /></p>
|
||||||
|
|
||||||
@ -265,7 +272,7 @@ Display news and updates from any RSS-enabled service.
|
|||||||
|
|
||||||
### XKCD Comics
|
### XKCD Comics
|
||||||
|
|
||||||
Have a laugh with the daily comic from [XKCD](https://xkcd.com/). A classic webcomic website covering everything from Linux, math, romance, science and language.
|
Have a laugh with the daily comic from [XKCD](https://xkcd.com/). A classic webcomic website covering everything from Linux, math, romance, science and language. All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="400" src="https://i.ibb.co/kqV68hy/xkcd-comic.png" /></p>
|
<p align="center"><img width="400" src="https://i.ibb.co/kqV68hy/xkcd-comic.png" /></p>
|
||||||
|
|
||||||
@ -328,7 +335,7 @@ Display your coding summary. [Code::Stats](https://codestats.net/) is a free and
|
|||||||
|
|
||||||
### Vulnerability Feed
|
### Vulnerability Feed
|
||||||
|
|
||||||
Display a feed of recent vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional.
|
Keep track of recent security advisories and vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="400" src="https://i.ibb.co/DYJMpjp/vulnerability-feed.png" /></p>
|
<p align="center"><img width="400" src="https://i.ibb.co/DYJMpjp/vulnerability-feed.png" /></p>
|
||||||
|
|
||||||
@ -371,6 +378,39 @@ or
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Sports Scores
|
||||||
|
|
||||||
|
Show recent scores and upcoming matches from your favourite sports team. Data is fetched from [TheSportsDB.com](https://www.thesportsdb.com/). From the UI, you can click any other team to view their scores and upcoming games, or click a league name to see all teams.
|
||||||
|
|
||||||
|
<p align="center"><img width="400" src="https://i.ibb.co/8XhXGkN/sports-scores.png" /></p>
|
||||||
|
|
||||||
|
##### Options
|
||||||
|
|
||||||
|
**Field** | **Type** | **Required** | **Description**
|
||||||
|
--- | --- | --- | ---
|
||||||
|
**`teamId`** | `string` | __Optional__ | The ID of a team to fetch scores from. You can search for your team on the [Teams Page](https://www.thesportsdb.com/teams_main.php)
|
||||||
|
**`leagueId`** | `string` | __Optional__ | Alternatively, provide a league ID to fetch all games from. You can find the ID on the [Leagues Page](https://www.thesportsdb.com/Sport/Leagues)
|
||||||
|
**`pastOrFuture`** | `string` | __Optional__ | Set to `past` to show scores for recent games, or `future` to show upcoming games. Defaults to `past`. You can change this within the UI
|
||||||
|
**`apiKey`** | `string` | __Optional__ | Optionally specify your API key, which you can sign up for at [TheSportsDB.com](https://www.thesportsdb.com/)
|
||||||
|
**`limit`** | `number` | __Optional__ | To limit output to a certain number of matches, defaults to `15`
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- type: sports-scores
|
||||||
|
options:
|
||||||
|
teamId: 133636
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Info
|
||||||
|
- **CORS**: 🟢 Enabled
|
||||||
|
- **Auth**: 🟠 Optional
|
||||||
|
- **Price**: 🟠 Free plan (upto 30 requests / second, limited endpoints)
|
||||||
|
- **Host**: Managed Instance Only
|
||||||
|
- **Privacy**: ⚫ No Policy Available
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Public Holidays
|
### Public Holidays
|
||||||
|
|
||||||
Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from [Enrico](http://kayaposoft.com/enrico/)
|
Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from [Enrico](http://kayaposoft.com/enrico/)
|
||||||
@ -406,7 +446,7 @@ Counting down to the next day off work? This widget displays upcoming public hol
|
|||||||
|
|
||||||
### TFL Status
|
### TFL Status
|
||||||
|
|
||||||
Shows real-time tube status of the London Underground. All options are optional.
|
Shows real-time tube status of the London Underground. All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="400" src="https://i.ibb.co/LRDhXDn/tfl-status.png" /></p>
|
<p align="center"><img width="400" src="https://i.ibb.co/LRDhXDn/tfl-status.png" /></p>
|
||||||
|
|
||||||
@ -517,7 +557,7 @@ Shows recent price history for a given publicly-traded stock or share
|
|||||||
|
|
||||||
### Joke
|
### Joke
|
||||||
|
|
||||||
Renders a programming or generic joke. Data is fetched from the [JokesAPI](https://github.com/Sv443/JokeAPI) by @Sv443
|
Renders a programming or generic joke. Data is fetched from the [JokesAPI](https://github.com/Sv443/JokeAPI) by @Sv443. All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="400" src="https://i.ibb.co/sQJGkyR/joke.png" /></p>
|
<p align="center"><img width="400" src="https://i.ibb.co/sQJGkyR/joke.png" /></p>
|
||||||
|
|
||||||
@ -645,7 +685,7 @@ _No config options._
|
|||||||
|
|
||||||
### GitHub Trending
|
### GitHub Trending
|
||||||
|
|
||||||
Displays currently trending projects on GitHub. Optionally specify a language and time-frame. Data is fetched from [Lissy93/gh-trending-no-cors](https://github.com/Lissy93/gh-trending-no-cors) using the GitHub API.
|
Displays currently trending projects on GitHub. Optionally specify a language and time-frame. Data is fetched from [Lissy93/gh-trending-no-cors](https://github.com/Lissy93/gh-trending-no-cors) using the GitHub API. All fields are optional.
|
||||||
|
|
||||||
<p align="center"><img width="380" src="https://i.ibb.co/BGy7Q3g/github-trending.png" /></p>
|
<p align="center"><img width="380" src="https://i.ibb.co/BGy7Q3g/github-trending.png" /></p>
|
||||||
|
|
||||||
@ -1079,7 +1119,17 @@ Or
|
|||||||
|
|
||||||
### API Response
|
### API Response
|
||||||
|
|
||||||
Directly output plain-text response from any API-enabled service
|
Directly output plain-text response from any API-enabled service.
|
||||||
|
|
||||||
|
// Coming soon...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Prometheus Data
|
||||||
|
|
||||||
|
Display data from any service with a Prometheus exporter.
|
||||||
|
|
||||||
|
// Coming soon...
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -1185,4 +1235,23 @@ Widgets cannot currently be edited through the UI. This feature is in developmen
|
|||||||
|
|
||||||
Widgets are built in a modular fashion, making it easy for anyone to create their own custom components.
|
Widgets are built in a modular fashion, making it easy for anyone to create their own custom components.
|
||||||
|
|
||||||
For a full tutorial on creating your own widget, you can follow [this guide](https://github.com/Lissy93/dashy/blob/master/docs/development-guides.md#building-a-widget), or take a look at [here](https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e) for a code example.
|
For a full tutorial on creating your own widget, you can follow [this guide](/docs/development-guides.md#building-a-widget), or take a look at [here](https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e) for a code example.
|
||||||
|
|
||||||
|
Alternatively, for displaying simple data, you could also just use the either the [iframe](#iframe-widget), [embed](#html-embedded-widget), [Data Feed](#data-feed) or [API response](#api-response) widgets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requesting a Widget
|
||||||
|
|
||||||
|
Suggestions for widget ideas are welcome. But there is no guarantee that I will build your widget idea.
|
||||||
|
|
||||||
|
You can suggest a widget [here](https://git.io/Jygo3), please star the repo before submitting a ticket.
|
||||||
|
|
||||||
|
Please only request widgets for services that:
|
||||||
|
- Have a publicly accessible API
|
||||||
|
- Are CORS and HTTPS enabled
|
||||||
|
- Are free to use, or have a free plan
|
||||||
|
- Allow for use in their Terms of Service
|
||||||
|
- Would be useful for other users
|
||||||
|
|
||||||
|
For services that are not officially supported, it is likely still possible to display data using either the [iframe](#iframe-widget), [embed](#html-embedded-widget) or [API response](#api-response) widgets. For more advanced features, like charts and action buttons, you could also build your own widget, using [this tutorial](/docs/development-guides.md#building-a-widget), it's fairly straight forward, and you can use an [existing widget](https://github.com/Lissy93/dashy/tree/master/src/components/Widgets) (or [this example](https://git.io/JygKI)) as a template.
|
||||||
|
337
src/components/Widgets/SportsScores.vue
Normal file
337
src/components/Widgets/SportsScores.vue
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sports-scores-wrapper" v-if="matches">
|
||||||
|
<!-- Show back to original button -->
|
||||||
|
<p v-if="whatToShow === 'team' && currentTeamId !== teamId"
|
||||||
|
@click="fetchTeamScores(teamId)" class="back-to-original">
|
||||||
|
⇦ Back to Original Team
|
||||||
|
</p>
|
||||||
|
<p v-else-if="whatToShow === 'league' && leagueId && currentLeagueId !== leagueId"
|
||||||
|
@click="fetchLeagueScores(leagueId)" class="back-to-original">
|
||||||
|
⇦ Back to Original League
|
||||||
|
</p>
|
||||||
|
<!-- Show toggle switch for past and future matches -->
|
||||||
|
<div class="past-or-future">
|
||||||
|
<span
|
||||||
|
:class="`btn ${whenToShow === 'past' ? 'selected' : ''}`"
|
||||||
|
v-tooltip="tooltip('View Recent Scores')"
|
||||||
|
@click="fetchPastFutureEvents('past')"
|
||||||
|
>
|
||||||
|
Past Scores
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
:class="`btn ${whenToShow === 'future' ? 'selected' : ''}`"
|
||||||
|
v-tooltip="tooltip('View Upcoming Games')"
|
||||||
|
@click="fetchPastFutureEvents('future')"
|
||||||
|
>
|
||||||
|
Upcoming Games
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="match-row" v-for="match in matches" :key="match.id">
|
||||||
|
<!-- Banner Image -->
|
||||||
|
<div class="match-thumbnail-wrap">
|
||||||
|
<img :src="match.thumbnail" :alt="`${match.title} Banner Image`" class="match-thumbnail" />
|
||||||
|
</div>
|
||||||
|
<!-- Team Scores -->
|
||||||
|
<div class="score">
|
||||||
|
<div
|
||||||
|
:class="`score-block home ${currentTeamId !== match.home.id ? 'clickable' : ''}`"
|
||||||
|
v-tooltip="tooltip(`Click to view ${match.home.name} Scores`)"
|
||||||
|
@click="fetchTeamScores(match.home.id)"
|
||||||
|
>
|
||||||
|
<p class="team-score">{{ match.home.score }}</p>
|
||||||
|
<p class="team-name">{{ match.home.name }}</p>
|
||||||
|
<p class="team-location">Home</p>
|
||||||
|
</div>
|
||||||
|
<div class="colon">{{ match.home.score || match.away.score ? ':' : 'v' }}</div>
|
||||||
|
<div
|
||||||
|
class="score-block away clickable"
|
||||||
|
v-tooltip="tooltip(`Click to view ${match.away.name} Scores`)"
|
||||||
|
@click="fetchTeamScores(match.away.id)"
|
||||||
|
>
|
||||||
|
<p class="team-score">{{ match.away.score }}</p>
|
||||||
|
<p class="team-name">{{ match.away.name }}</p>
|
||||||
|
<p class="team-location">Away</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Match Meta Info -->
|
||||||
|
<div class="match-info">
|
||||||
|
<p class="status">{{ match.status }} </p>
|
||||||
|
<p class="league" @click="fetchLeagueScores(match.leagueId)">
|
||||||
|
{{ match.league }}, {{ match.season }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a :href="match.venue | mapsUrl">{{ match.venue }}</a>
|
||||||
|
on {{ match.date | formatDate }} ({{ match.time | formatTime }})</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
import WidgetMixin from '@/mixins/WidgetMixin';
|
||||||
|
import { timestampToDate, getPlaceUrl } from '@/utils/MiscHelpers';
|
||||||
|
import { widgetApiEndpoints } from '@/utils/defaults';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [WidgetMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentTeamId: null, // ID of the selected team
|
||||||
|
currentLeagueId: null, // ID of selected league
|
||||||
|
whenToShow: null, // Either 'past' or 'future'
|
||||||
|
whatToShow: null, // Either 'team' or 'league'
|
||||||
|
matches: null, // Array of matches returned
|
||||||
|
initiated: false, // Set to true once values set
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
teamId() {
|
||||||
|
return this.options.teamId;
|
||||||
|
},
|
||||||
|
leagueId() {
|
||||||
|
return this.options.leagueId;
|
||||||
|
},
|
||||||
|
apiKey() {
|
||||||
|
return this.options.apiKey || '50130162';
|
||||||
|
},
|
||||||
|
limit() {
|
||||||
|
return this.options.limit || 20;
|
||||||
|
},
|
||||||
|
pastOrFuture() {
|
||||||
|
return this.options.pastOrFuture || 'past';
|
||||||
|
},
|
||||||
|
endpoint() {
|
||||||
|
this.initiate();
|
||||||
|
const endpoint = widgetApiEndpoints.sportsScores;
|
||||||
|
if (this.whatToShow === 'league' && this.whenToShow === 'future') {
|
||||||
|
return `${endpoint}/${this.apiKey}/eventsnextleague.php?id=${this.currentLeagueId}`;
|
||||||
|
} else if (this.whatToShow === 'league' && this.whenToShow === 'past') {
|
||||||
|
return `${endpoint}/${this.apiKey}/eventspastleague.php?id=${this.currentLeagueId}`;
|
||||||
|
} else if (this.whatToShow === 'team' && this.whenToShow === 'future') {
|
||||||
|
return `${endpoint}/${this.apiKey}/eventsnext.php?id=${this.currentTeamId}`;
|
||||||
|
} else if (this.whatToShow === 'team' && this.whenToShow === 'past') {
|
||||||
|
return `${endpoint}/${this.apiKey}/eventslast.php?id=${this.currentTeamId}`;
|
||||||
|
} else {
|
||||||
|
this.error('Missing team or league ID');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
formatDate(dateStr) {
|
||||||
|
return timestampToDate(dateStr);
|
||||||
|
},
|
||||||
|
formatTime(timeStr) {
|
||||||
|
if (!timeStr) return '';
|
||||||
|
return timeStr.slice(0, 5);
|
||||||
|
},
|
||||||
|
mapsUrl(placeName) {
|
||||||
|
return getPlaceUrl(placeName);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initiate() {
|
||||||
|
if (!this.initiated) {
|
||||||
|
this.currentTeamId = this.teamId;
|
||||||
|
this.currentLeagueId = this.leagueId;
|
||||||
|
this.whenToShow = this.pastOrFuture;
|
||||||
|
this.whatToShow = this.teamOrLeague();
|
||||||
|
this.initiated = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchData() {
|
||||||
|
axios.get(this.endpoint)
|
||||||
|
.then((response) => {
|
||||||
|
this.processData(response.data.results || response.data.events);
|
||||||
|
})
|
||||||
|
.catch((dataFetchError) => {
|
||||||
|
this.error('Unable to fetch data', dataFetchError);
|
||||||
|
this.finishLoading();
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.finishLoading();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
processData(data) {
|
||||||
|
const matches = [];
|
||||||
|
data.forEach((match) => {
|
||||||
|
matches.push({
|
||||||
|
id: match.idEvent,
|
||||||
|
sport: match.strSport,
|
||||||
|
title: match.strEvent,
|
||||||
|
league: match.strLeague,
|
||||||
|
leagueId: match.idLeague,
|
||||||
|
season: match.strSeason,
|
||||||
|
venue: match.strVenue,
|
||||||
|
date: match.dateEvent,
|
||||||
|
time: match.strTime,
|
||||||
|
status: match.strStatus,
|
||||||
|
thumbnail: match.strThumb,
|
||||||
|
home: {
|
||||||
|
id: match.idHomeTeam,
|
||||||
|
name: match.strHomeTeam,
|
||||||
|
score: match.intHomeScore,
|
||||||
|
},
|
||||||
|
away: {
|
||||||
|
id: match.idAwayTeam,
|
||||||
|
name: match.strAwayTeam,
|
||||||
|
score: match.intAwayScore,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.matches = matches.slice(0, this.limit);
|
||||||
|
},
|
||||||
|
teamOrLeague() {
|
||||||
|
if (!this.currentTeamId && !this.currentLeagueId) {
|
||||||
|
this.error('You must specify either a teamId or leagueId');
|
||||||
|
}
|
||||||
|
if (this.currentTeamId) return 'team';
|
||||||
|
return 'league';
|
||||||
|
},
|
||||||
|
fetchTeamScores(teamId) {
|
||||||
|
if (teamId) {
|
||||||
|
this.whatToShow = 'team';
|
||||||
|
this.startLoading();
|
||||||
|
this.currentTeamId = teamId;
|
||||||
|
this.fetchData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchLeagueScores(leagueId) {
|
||||||
|
if (leagueId) {
|
||||||
|
this.whatToShow = 'league';
|
||||||
|
this.startLoading();
|
||||||
|
this.currentLeagueId = leagueId;
|
||||||
|
this.fetchData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchPastFutureEvents(pastOrFuture) {
|
||||||
|
this.startLoading();
|
||||||
|
this.whenToShow = pastOrFuture;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
tooltip(content) {
|
||||||
|
return {
|
||||||
|
content, html: true, trigger: 'hover focus', delay: 250,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.sports-scores-wrapper {
|
||||||
|
p {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
}
|
||||||
|
.match-row {
|
||||||
|
.match-thumbnail-wrap {
|
||||||
|
width: 80%;
|
||||||
|
max-height: 5rem;
|
||||||
|
display: flex;
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
margin: 1rem auto 0.5rem auto;
|
||||||
|
overflow: hidden;
|
||||||
|
img.match-thumbnail {
|
||||||
|
width: 100%;
|
||||||
|
height: fit-content;
|
||||||
|
margin-top: -13%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.score {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
.score-block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 40%;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
p.team-score {
|
||||||
|
margin: 0.25rem auto;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: var(--font-monospace);
|
||||||
|
}
|
||||||
|
p.team-name {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
p.team-location {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
}
|
||||||
|
&.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
border: 1px dashed var(--widget-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.colon {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.match-info {
|
||||||
|
background: var(--widget-accent-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
margin: 0.5rem auto 1rem auto;
|
||||||
|
p, a {
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin: 0;
|
||||||
|
&.status {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
&.league {
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px dashed var(--widget-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.back-to-original {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.1rem 0.25rem;
|
||||||
|
width: 100%;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.past-or-future {
|
||||||
|
width: 100%;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
border-bottom: 1px dashed var(--widget-text-color);
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
span.btn {
|
||||||
|
max-width: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.1rem 0.25rem;
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
&.selected {
|
||||||
|
background: var(--widget-text-color);
|
||||||
|
color: var(--widget-background-color);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -186,6 +186,13 @@
|
|||||||
@error="handleError"
|
@error="handleError"
|
||||||
:ref="widgetRef"
|
:ref="widgetRef"
|
||||||
/>
|
/>
|
||||||
|
<SportsScores
|
||||||
|
v-else-if="widgetType === 'sports-scores'"
|
||||||
|
:options="widgetOptions"
|
||||||
|
@loading="setLoaderState"
|
||||||
|
@error="handleError"
|
||||||
|
:ref="widgetRef"
|
||||||
|
/>
|
||||||
<StatPing
|
<StatPing
|
||||||
v-else-if="widgetType === 'stat-ping'"
|
v-else-if="widgetType === 'stat-ping'"
|
||||||
:options="widgetOptions"
|
:options="widgetOptions"
|
||||||
@ -282,6 +289,7 @@ export default {
|
|||||||
PublicHolidays: () => import('@/components/Widgets/PublicHolidays.vue'),
|
PublicHolidays: () => import('@/components/Widgets/PublicHolidays.vue'),
|
||||||
PublicIp: () => import('@/components/Widgets/PublicIp.vue'),
|
PublicIp: () => import('@/components/Widgets/PublicIp.vue'),
|
||||||
RssFeed: () => import('@/components/Widgets/RssFeed.vue'),
|
RssFeed: () => import('@/components/Widgets/RssFeed.vue'),
|
||||||
|
SportsScores: () => import('@/components/Widgets/SportsScores.vue'),
|
||||||
StatPing: () => import('@/components/Widgets/StatPing.vue'),
|
StatPing: () => import('@/components/Widgets/StatPing.vue'),
|
||||||
StockPriceChart: () => import('@/components/Widgets/StockPriceChart.vue'),
|
StockPriceChart: () => import('@/components/Widgets/StockPriceChart.vue'),
|
||||||
SystemInfo: () => import('@/components/Widgets/SystemInfo.vue'),
|
SystemInfo: () => import('@/components/Widgets/SystemInfo.vue'),
|
||||||
|
@ -113,6 +113,11 @@ export const getMapUrl = (location, zoom) => {
|
|||||||
return `https://www.openstreetmap.org/#map=${zoom || 10}/${location.lat}/${location.lon}`;
|
return `https://www.openstreetmap.org/#map=${zoom || 10}/${location.lat}/${location.lon}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Given a place name, return a link to Google Maps search page */
|
||||||
|
export const getPlaceUrl = (placeName) => {
|
||||||
|
return `https://www.google.com/maps/search/${encodeURIComponent(placeName)}`;
|
||||||
|
};
|
||||||
|
|
||||||
/* Given a large number, will add commas to make more readable */
|
/* Given a large number, will add commas to make more readable */
|
||||||
export const putCommasInBigNum = (bigNum) => {
|
export const putCommasInBigNum = (bigNum) => {
|
||||||
const strNum = Number.isNaN(bigNum) ? bigNum : String(bigNum);
|
const strNum = Number.isNaN(bigNum) ? bigNum : String(bigNum);
|
||||||
|
@ -222,6 +222,7 @@ module.exports = {
|
|||||||
publicIp: 'http://ip-api.com/json',
|
publicIp: 'http://ip-api.com/json',
|
||||||
readMeStats: 'https://github-readme-stats.vercel.app/api',
|
readMeStats: 'https://github-readme-stats.vercel.app/api',
|
||||||
rssToJson: 'https://api.rss2json.com/v1/api.json',
|
rssToJson: 'https://api.rss2json.com/v1/api.json',
|
||||||
|
sportsScores: 'https://www.thesportsdb.com/api/v1/json',
|
||||||
stockPriceChart: 'https://www.alphavantage.co/query',
|
stockPriceChart: 'https://www.alphavantage.co/query',
|
||||||
tflStatus: 'https://api.tfl.gov.uk/line/mode/tube/status',
|
tflStatus: 'https://api.tfl.gov.uk/line/mode/tube/status',
|
||||||
weather: 'https://api.openweathermap.org/data/2.5/weather',
|
weather: 'https://api.openweathermap.org/data/2.5/weather',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user