mirror of
https://github.com/Lissy93/dashy.git
synced 2025-07-23 05:35:07 +02:00
✨ Adds current Eth gas price widget
This commit is contained in:
parent
65ffa0efc4
commit
7b030d8e5b
@ -21,6 +21,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
|
|||||||
- [Public Holidays](#public-holidays)
|
- [Public Holidays](#public-holidays)
|
||||||
- [TFL Status](#tfl-status)
|
- [TFL Status](#tfl-status)
|
||||||
- [Stock Price History](#stock-price-history)
|
- [Stock Price History](#stock-price-history)
|
||||||
|
- [ETH Gas Prices](#eth-gas-prices)
|
||||||
- [Joke of the Day](#joke)
|
- [Joke of the Day](#joke)
|
||||||
- [XKCD Comics](#xkcd-comics)
|
- [XKCD Comics](#xkcd-comics)
|
||||||
- [News Headlines](#news-headlines)
|
- [News Headlines](#news-headlines)
|
||||||
@ -129,7 +130,7 @@ Displays the weather (temperature and conditions) for the next few days for a gi
|
|||||||
|
|
||||||
**Field** | **Type** | **Required** | **Description**
|
**Field** | **Type** | **Required** | **Description**
|
||||||
--- | --- | --- | ---
|
--- | --- | --- | ---
|
||||||
**`apiKey`** | `string` | Required | Your OpenWeatherMap API key. You can get one for free at [openweathermap.org](https://openweathermap.org/)
|
**`apiKey`** | `string` | Required | Your OpenWeatherMap API key. You can get one at [openweathermap.org](https://openweathermap.org/) or for free via the [OWM Student Plan](https://home.openweathermap.org/students)
|
||||||
**`city`** | `string` | Required | A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
|
**`city`** | `string` | Required | A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
|
||||||
**`numDays`** | `number` | _Optional_ | The number of days to display of forecast info to display. Defaults to `4`, max `16` days
|
**`numDays`** | `number` | _Optional_ | The number of days to display of forecast info to display. Defaults to `4`, max `16` days
|
||||||
**`units`** | `string` | _Optional_ | The units to use for displaying data, can be either `metric` or `imperial`. Defaults to `metric`
|
**`units`** | `string` | _Optional_ | The units to use for displaying data, can be either `metric` or `imperial`. Defaults to `metric`
|
||||||
@ -526,6 +527,31 @@ Shows recent price history for a given publicly-traded stock or share
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### ETH Gas Prices
|
||||||
|
|
||||||
|
Renders the current Gas cost of transactions on the Ethereum network (in both GWEI and USD), along with recent historical prices. Useful for spotting a good time to transact. Uses data from [ethgas.watch](https://ethgas.watch/)
|
||||||
|
|
||||||
|
<p align="center"><img width="400" src="https://i.ibb.co/LhHfQyp/eth-gas-prices.png" /></p>
|
||||||
|
|
||||||
|
##### Options
|
||||||
|
|
||||||
|
_No config options._
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- type: eth-gas-prices
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Info
|
||||||
|
- **CORS**: 🟢 Enabled
|
||||||
|
- **Auth**: 🟢 Not Required
|
||||||
|
- **Price**: 🟢 Free
|
||||||
|
- **Host**: Managed Instance or Self-Hosted (see [wslyvh/ethgaswatch](https://github.com/wslyvh/ethgaswatch))
|
||||||
|
- **Privacy**: ⚫ No Policy Available
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Joke
|
### Joke
|
||||||
|
|
||||||
Renders a programming or generic joke. Data is fetched from the [JokesAPI](https://github.com/Sv443/JokeAPI) by @Sv443. All fields are optional.
|
Renders a programming or generic joke. Data is fetched from the [JokesAPI](https://github.com/Sv443/JokeAPI) by @Sv443. All fields are optional.
|
||||||
|
228
src/components/Widgets/EthGasPrices.vue
Normal file
228
src/components/Widgets/EthGasPrices.vue
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
<template>
|
||||||
|
<div class="eth-gas-wrapper" v-if="gasCosts">
|
||||||
|
<!-- Current Prices -->
|
||||||
|
<p class="current-label">Current Gas Prices</p>
|
||||||
|
<div v-for="gasCost in gasCosts" :key="gasCost.name" class="gas-row">
|
||||||
|
<p class="time-name">{{ gasCost.name }}</p>
|
||||||
|
<div class="cost">
|
||||||
|
<span class="usd">${{ gasCost.usd }}</span>
|
||||||
|
<span class="gwei">{{ gasCost.gwei }} GWEI</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Current ETH Price -->
|
||||||
|
<div class="current-price">
|
||||||
|
<span class="label">Current ETH Price:</span>
|
||||||
|
<span class="price">{{ gasInfo.ethPrice }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- Historical Chart -->
|
||||||
|
<p class="time-frame-label">Historical Gas Prices</p>
|
||||||
|
<div class="time-frame-selector">
|
||||||
|
<span
|
||||||
|
v-for="time in timeOptions"
|
||||||
|
:key="time.value"
|
||||||
|
@click="updateTimeFrame(time.value)"
|
||||||
|
:class="time.value === selectedTimeFrame ? 'selected' : ''"
|
||||||
|
>
|
||||||
|
{{ time.label }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div :id="chartId"></div>
|
||||||
|
<!-- Meta Info -->
|
||||||
|
<div v-if="gasInfo" class="gas-info">
|
||||||
|
<p>Last Updated: {{ gasInfo.lastUpdated }}</p>
|
||||||
|
<div class="sources">
|
||||||
|
Sources:
|
||||||
|
<a
|
||||||
|
v-for="source in gasInfo.sources"
|
||||||
|
:key="source.name"
|
||||||
|
:href="source.source"
|
||||||
|
v-tooltip="tooltip(`Average: ${source.standard || '[UNKNOWN]'} GWEI`)"
|
||||||
|
>{{ source.name }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import WidgetMixin from '@/mixins/WidgetMixin';
|
||||||
|
import ChartingMixin from '@/mixins/ChartingMixin';
|
||||||
|
import { widgetApiEndpoints } from '@/utils/defaults';
|
||||||
|
import { timestampToTime, roundPrice, putCommasInBigNum } from '@/utils/MiscHelpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [WidgetMixin, ChartingMixin],
|
||||||
|
computed: {
|
||||||
|
numHours() {
|
||||||
|
return this.options.numHours || 24;
|
||||||
|
},
|
||||||
|
endpoint() {
|
||||||
|
const numHours = this.selectedTimeFrame || this.numHours;
|
||||||
|
return `${widgetApiEndpoints.ethGasHistory}?hours=${numHours}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gasInfo: null,
|
||||||
|
gasCosts: null,
|
||||||
|
timeOptions: [
|
||||||
|
{ label: '6 hours', value: 6 },
|
||||||
|
{ label: '1 Day', value: 24 },
|
||||||
|
{ label: '1 Week', value: 168 },
|
||||||
|
{ label: '2 Weeks', value: 220 },
|
||||||
|
],
|
||||||
|
selectedTimeFrame: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* Make GET request to CoinGecko API endpoint */
|
||||||
|
fetchData() {
|
||||||
|
this.makeRequest(widgetApiEndpoints.ethGasPrices).then(this.processPriceInfo);
|
||||||
|
this.makeRequest(this.endpoint).then(this.processHistoryData);
|
||||||
|
},
|
||||||
|
processPriceInfo(data) {
|
||||||
|
this.gasCosts = [
|
||||||
|
{ name: 'Slow', gwei: data.slow.gwei, usd: data.slow.usd },
|
||||||
|
{ name: 'Normal', gwei: data.normal.gwei, usd: data.normal.usd },
|
||||||
|
{ name: 'Fast', gwei: data.fast.gwei, usd: data.fast.usd },
|
||||||
|
{ name: 'Instant', gwei: data.instant.gwei, usd: data.instant.usd },
|
||||||
|
];
|
||||||
|
const sources = [];
|
||||||
|
data.sources.forEach((sourceInfo) => {
|
||||||
|
const { name, source, standard } = sourceInfo;
|
||||||
|
sources.push({ name, source, standard });
|
||||||
|
});
|
||||||
|
this.gasInfo = {
|
||||||
|
lastUpdated: timestampToTime(data.lastUpdated),
|
||||||
|
ethPrice: `$${putCommasInBigNum(roundPrice(data.ethPrice))}`,
|
||||||
|
sources,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processHistoryData(data) {
|
||||||
|
const chartData = {
|
||||||
|
labels: data.labels,
|
||||||
|
datasets: [
|
||||||
|
{ name: 'Slow', type: 'bar', values: data.slow },
|
||||||
|
{ name: 'Normal', type: 'bar', values: data.normal },
|
||||||
|
{ name: 'Fast', type: 'bar', values: data.fast },
|
||||||
|
{ name: 'Instant', type: 'bar', values: data.instant },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return new this.Chart(`#${this.chartId}`, {
|
||||||
|
title: 'Historical Transaction Costs',
|
||||||
|
data: chartData,
|
||||||
|
type: 'axis-mixed',
|
||||||
|
height: this.chartHeight,
|
||||||
|
colors: ['#ef476f', '#ffd166', '#118ab2', '#06d6a0'],
|
||||||
|
truncateLegends: true,
|
||||||
|
lineOptions: {
|
||||||
|
hideDots: 1,
|
||||||
|
},
|
||||||
|
axisOptions: {
|
||||||
|
xIsSeries: true,
|
||||||
|
xAxisMode: 'tick',
|
||||||
|
},
|
||||||
|
tooltipOptions: {
|
||||||
|
formatTooltipY: d => `${d} GWEI`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateTimeFrame(newNumHours) {
|
||||||
|
this.startLoading();
|
||||||
|
this.selectedTimeFrame = newNumHours;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.selectedTimeFrame = this.numHours;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.eth-gas-wrapper {
|
||||||
|
p.current-label {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
}
|
||||||
|
.gas-row {
|
||||||
|
display: flex;
|
||||||
|
vertical-align: middle;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
p.time-name {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
.cost {
|
||||||
|
display: flex;
|
||||||
|
min-width: 10rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
span {
|
||||||
|
font-family: var(--font-monospace);
|
||||||
|
margin: 0.5rem;
|
||||||
|
&.usd {
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:last-child) { border-bottom: 1px dashed var(--widget-text-color); }
|
||||||
|
}
|
||||||
|
.current-price {
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
margin: 1rem 0 0.5rem;
|
||||||
|
span.label {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
span.price {
|
||||||
|
font-family: var(--font-monospace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.gas-info {
|
||||||
|
p, .sources {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
font-family: var(--font-monospace);
|
||||||
|
}
|
||||||
|
.sources a {
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
margin: 0 0.15rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.time-frame-label {
|
||||||
|
display: inline-block;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
margin: 1rem 0.5rem 0.25rem 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.time-frame-selector {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 0 0.25rem;
|
||||||
|
max-width: 20rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
color: var(--widget-text-color);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
span {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.1rem 0.25rem;
|
||||||
|
margin: 0 0.15rem;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
&.selected {
|
||||||
|
background: var(--widget-text-color);
|
||||||
|
color: var(--widget-background-color);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
border: 1px solid var(--widget-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -67,6 +67,13 @@
|
|||||||
@error="handleError"
|
@error="handleError"
|
||||||
:ref="widgetRef"
|
:ref="widgetRef"
|
||||||
/>
|
/>
|
||||||
|
<EthGasPrices
|
||||||
|
v-else-if="widgetType === 'eth-gas-prices'"
|
||||||
|
:options="widgetOptions"
|
||||||
|
@loading="setLoaderState"
|
||||||
|
@error="handleError"
|
||||||
|
:ref="widgetRef"
|
||||||
|
/>
|
||||||
<ExchangeRates
|
<ExchangeRates
|
||||||
v-else-if="widgetType === 'exchange-rates'"
|
v-else-if="widgetType === 'exchange-rates'"
|
||||||
:options="widgetOptions"
|
:options="widgetOptions"
|
||||||
@ -272,6 +279,7 @@ export default {
|
|||||||
CryptoWatchList: () => import('@/components/Widgets/CryptoWatchList.vue'),
|
CryptoWatchList: () => import('@/components/Widgets/CryptoWatchList.vue'),
|
||||||
CveVulnerabilities: () => import('@/components/Widgets/CveVulnerabilities.vue'),
|
CveVulnerabilities: () => import('@/components/Widgets/CveVulnerabilities.vue'),
|
||||||
EmbedWidget: () => import('@/components/Widgets/EmbedWidget.vue'),
|
EmbedWidget: () => import('@/components/Widgets/EmbedWidget.vue'),
|
||||||
|
EthGasPrices: () => import('@/components/Widgets/EthGasPrices.vue'),
|
||||||
ExchangeRates: () => import('@/components/Widgets/ExchangeRates.vue'),
|
ExchangeRates: () => import('@/components/Widgets/ExchangeRates.vue'),
|
||||||
Flights: () => import('@/components/Widgets/Flights.vue'),
|
Flights: () => import('@/components/Widgets/Flights.vue'),
|
||||||
GitHubTrending: () => import('@/components/Widgets/GitHubTrending.vue'),
|
GitHubTrending: () => import('@/components/Widgets/GitHubTrending.vue'),
|
||||||
|
@ -213,6 +213,8 @@ module.exports = {
|
|||||||
cryptoPrices: 'https://api.coingecko.com/api/v3/coins/',
|
cryptoPrices: 'https://api.coingecko.com/api/v3/coins/',
|
||||||
cryptoWatchList: 'https://api.coingecko.com/api/v3/coins/markets/',
|
cryptoWatchList: 'https://api.coingecko.com/api/v3/coins/markets/',
|
||||||
cveVulnerabilities: 'https://www.cvedetails.com/json-feed.php',
|
cveVulnerabilities: 'https://www.cvedetails.com/json-feed.php',
|
||||||
|
ethGasPrices: 'https://ethgas.watch/api/gas',
|
||||||
|
ethGasHistory: 'https://ethgas.watch/api/gas/trend',
|
||||||
exchangeRates: 'https://v6.exchangerate-api.com/v6/',
|
exchangeRates: 'https://v6.exchangerate-api.com/v6/',
|
||||||
flights: 'https://aerodatabox.p.rapidapi.com/flights/airports/icao/',
|
flights: 'https://aerodatabox.p.rapidapi.com/flights/airports/icao/',
|
||||||
githubTrending: 'https://gh-trending-repos.herokuapp.com/',
|
githubTrending: 'https://gh-trending-repos.herokuapp.com/',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user