mirror of https://github.com/Lissy93/dashy.git
✨ 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)
|
||||
- [TFL Status](#tfl-status)
|
||||
- [Stock Price History](#stock-price-history)
|
||||
- [ETH Gas Prices](#eth-gas-prices)
|
||||
- [Joke of the Day](#joke)
|
||||
- [XKCD Comics](#xkcd-comics)
|
||||
- [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**
|
||||
--- | --- | --- | ---
|
||||
**`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
|
||||
**`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`
|
||||
|
@ -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
|
||||
|
||||
Renders a programming or generic joke. Data is fetched from the [JokesAPI](https://github.com/Sv443/JokeAPI) by @Sv443. All fields are optional.
|
||||
|
|
|
@ -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"
|
||||
:ref="widgetRef"
|
||||
/>
|
||||
<EthGasPrices
|
||||
v-else-if="widgetType === 'eth-gas-prices'"
|
||||
:options="widgetOptions"
|
||||
@loading="setLoaderState"
|
||||
@error="handleError"
|
||||
:ref="widgetRef"
|
||||
/>
|
||||
<ExchangeRates
|
||||
v-else-if="widgetType === 'exchange-rates'"
|
||||
:options="widgetOptions"
|
||||
|
@ -272,6 +279,7 @@ export default {
|
|||
CryptoWatchList: () => import('@/components/Widgets/CryptoWatchList.vue'),
|
||||
CveVulnerabilities: () => import('@/components/Widgets/CveVulnerabilities.vue'),
|
||||
EmbedWidget: () => import('@/components/Widgets/EmbedWidget.vue'),
|
||||
EthGasPrices: () => import('@/components/Widgets/EthGasPrices.vue'),
|
||||
ExchangeRates: () => import('@/components/Widgets/ExchangeRates.vue'),
|
||||
Flights: () => import('@/components/Widgets/Flights.vue'),
|
||||
GitHubTrending: () => import('@/components/Widgets/GitHubTrending.vue'),
|
||||
|
|
|
@ -213,6 +213,8 @@ module.exports = {
|
|||
cryptoPrices: 'https://api.coingecko.com/api/v3/coins/',
|
||||
cryptoWatchList: 'https://api.coingecko.com/api/v3/coins/markets/',
|
||||
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/',
|
||||
flights: 'https://aerodatabox.p.rapidapi.com/flights/airports/icao/',
|
||||
githubTrending: 'https://gh-trending-repos.herokuapp.com/',
|
||||
|
|
Loading…
Reference in New Issue