mirror of
https://github.com/Lissy93/dashy.git
synced 2024-12-25 09:56:15 +03: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.
|
||||
|
||||
> ℹ️ **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
|
||||
- [General Widgets](#general-widgets)
|
||||
- [Clock](#clock)
|
||||
@ -13,6 +17,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
|
||||
- [XKCD Comics](#xkcd-comics)
|
||||
- [Code Stats](#code-stats)
|
||||
- [Vulnerability Feed](#vulnerability-feed)
|
||||
- [Sports Scores](#sports-scores)
|
||||
- [Public Holidays](#public-holidays)
|
||||
- [TFL Status](#tfl-status)
|
||||
- [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)
|
||||
- [HTML Embed Widget](#html-embedded-widget)
|
||||
- [API Response](#api-response)
|
||||
- [Prometheus Data](#prometheus-data)
|
||||
- [Data Feed](#data-feed)
|
||||
- [Usage & Customizations](#usage--customizations)
|
||||
- [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)
|
||||
- [Widget UI Options](#widget-ui-options)
|
||||
- [Building a Widget](#build-your-own-widget)
|
||||
- [Requesting a Widget](#requesting-a-widget)
|
||||
|
||||
## General Widgets
|
||||
|
||||
### 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>
|
||||
|
||||
@ -150,7 +157,7 @@ Displays the weather (temperature and conditions) for the next few days for a gi
|
||||
|
||||
### 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>
|
||||
|
||||
@ -265,7 +272,7 @@ Display news and updates from any RSS-enabled service.
|
||||
|
||||
### 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>
|
||||
|
||||
@ -328,7 +335,7 @@ Display your coding summary. [Code::Stats](https://codestats.net/) is a free and
|
||||
|
||||
### 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>
|
||||
|
||||
@ -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
|
||||
|
||||
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
|
||||
|
||||
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>
|
||||
|
||||
@ -517,7 +557,7 @@ Shows recent price history for a given publicly-traded stock or share
|
||||
|
||||
### 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>
|
||||
|
||||
@ -645,7 +685,7 @@ _No config options._
|
||||
|
||||
### 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>
|
||||
|
||||
@ -1079,7 +1119,17 @@ Or
|
||||
|
||||
### 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.
|
||||
|
||||
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"
|
||||
:ref="widgetRef"
|
||||
/>
|
||||
<SportsScores
|
||||
v-else-if="widgetType === 'sports-scores'"
|
||||
:options="widgetOptions"
|
||||
@loading="setLoaderState"
|
||||
@error="handleError"
|
||||
:ref="widgetRef"
|
||||
/>
|
||||
<StatPing
|
||||
v-else-if="widgetType === 'stat-ping'"
|
||||
:options="widgetOptions"
|
||||
@ -282,6 +289,7 @@ export default {
|
||||
PublicHolidays: () => import('@/components/Widgets/PublicHolidays.vue'),
|
||||
PublicIp: () => import('@/components/Widgets/PublicIp.vue'),
|
||||
RssFeed: () => import('@/components/Widgets/RssFeed.vue'),
|
||||
SportsScores: () => import('@/components/Widgets/SportsScores.vue'),
|
||||
StatPing: () => import('@/components/Widgets/StatPing.vue'),
|
||||
StockPriceChart: () => import('@/components/Widgets/StockPriceChart.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}`;
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
export const putCommasInBigNum = (bigNum) => {
|
||||
const strNum = Number.isNaN(bigNum) ? bigNum : String(bigNum);
|
||||
|
@ -222,6 +222,7 @@ module.exports = {
|
||||
publicIp: 'http://ip-api.com/json',
|
||||
readMeStats: 'https://github-readme-stats.vercel.app/api',
|
||||
rssToJson: 'https://api.rss2json.com/v1/api.json',
|
||||
sportsScores: 'https://www.thesportsdb.com/api/v1/json',
|
||||
stockPriceChart: 'https://www.alphavantage.co/query',
|
||||
tflStatus: 'https://api.tfl.gov.uk/line/mode/tube/status',
|
||||
weather: 'https://api.openweathermap.org/data/2.5/weather',
|
||||
|
Loading…
Reference in New Issue
Block a user