Skip to content

Commit 1fd7e6b

Browse files
authored
🔀 Merge pull request #1194 from josuablejeru/feature/hackernews-widget
hackernews widget
2 parents 3c25fb8 + 040b472 commit 1fd7e6b

File tree

4 files changed

+138
-10
lines changed

4 files changed

+138
-10
lines changed

docs/widgets.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
3535
- [GitHub Trending](#github-trending)
3636
- [GitHub Profile Stats](#github-profile-stats)
3737
- [Healthchecks Status](#healthchecks-status)
38+
- [Hackernews Trending](#hackernews-trending)
3839
- [Mvg Departure](#mvg-departure)
3940
- [Mvg Connection](#mvg-connection)
4041
- [Custom search](#custom-search)
@@ -1182,6 +1183,27 @@ Display status of one or more HealthChecks project(s). Works with healthcheck.io
11821183

11831184
---
11841185

1186+
### Hackernews Trending
1187+
1188+
Display new and trending Posts from Hackernews
1189+
1190+
#### Options
1191+
**Field** | **Type** | **Required** | **Description**
1192+
--- | --- | --- | ---
1193+
**`stories`** | `string` | _Optional_ | HN Stories to display defaults to `topstories`. Options are: `beststories`, `topstories` or `newstories`
1194+
**`limit`** | `int` | _Optional_ | The size of the list of Posts to show.
1195+
1196+
##### Example
1197+
1198+
```yaml
1199+
- type: hackernews-trending
1200+
options:
1201+
stories: newstories
1202+
limit: 10
1203+
```
1204+
1205+
---
1206+
11851207
### MVG Departure
11861208

11871209
Display departure time of a MVG (Münchner Verkehrs Gesellschaft) station.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<template>
2+
<div class="hackernews-wrapper">
3+
<!-- Hackernews Trending Posts-->
4+
<div class="posts-wrapper" v-if="trendingPosts">
5+
<div class="post-row" v-for="(trendingPosts, index) in trendingPosts" :key="index">
6+
<a class="post-top" :href="trendingPosts.originURL">
7+
<div class="post-title-wrap">
8+
<p class="post-title">{{ trendingPosts.title }}</p>
9+
<p class="post-date">
10+
{{ formatDate(trendingPosts.time) }}
11+
</p>
12+
<p class="post-score" v-if="trendingPosts.score">score: {{ trendingPosts.score }}</p>
13+
</div>
14+
</a>
15+
</div>
16+
</div>
17+
</div>
18+
</template>
19+
20+
<script>
21+
// import axios from 'axios';
22+
import WidgetMixin from '@/mixins/WidgetMixin';
23+
import { widgetApiEndpoints } from '@/utils/defaults';
24+
25+
export default {
26+
mixins: [WidgetMixin],
27+
data() {
28+
return {
29+
trendingPosts: null,
30+
};
31+
},
32+
computed: {
33+
stories() {
34+
// This can be `beststories`, `topstories` or newstories
35+
// TODO: display error message if another string not matching the keywords was insert
36+
return this.options.stories || 'topstories';
37+
},
38+
limit() {
39+
return this.options.limit || 10;
40+
},
41+
endpoint() {
42+
return `${widgetApiEndpoints.hackernewsTrending}/${this.stories}.json`;
43+
},
44+
},
45+
methods: {
46+
fetchData() {
47+
this.makeRequest(this.endpoint).then(this.fetchPostDetails);
48+
},
49+
async fetchPostDetails(data) {
50+
const topPosts = data.slice(0, this.limit);
51+
const allData = topPosts.map((post) => {
52+
const url = `${widgetApiEndpoints.hackernewsTrending}/item/${post}.json`;
53+
return this.makeRequest(url);
54+
});
55+
Promise.all(allData).then((resolvedPostValues) => {
56+
this.trendingPosts = resolvedPostValues.map((element, index) => {
57+
const trendingPost = { ...element, originURL: `https://news.ycombinator.com/item?id=${topPosts.at(index)}` };
58+
return trendingPost;
59+
});
60+
});
61+
},
62+
formatDate(unixTime) {
63+
const date = new Date(unixTime * 1000);
64+
// Then specify how you want your dates to be formatted
65+
return new Intl.DateTimeFormat('default', { dateStyle: 'long' }).format(date);
66+
},
67+
},
68+
};
69+
</script>
70+
71+
<style scoped lang="scss">
72+
.hackernews-wrapper {
73+
.meta-container {
74+
display: flex;
75+
align-items: center;
76+
text-decoration: none;
77+
margin: 0.25rem 0 0.5rem 0;
78+
}
79+
80+
.post-row {
81+
border-top: 1px dashed var(--widget-text-color);
82+
padding: 0.5rem 0 0.25rem 0;
83+
.post-top {
84+
display: flex;
85+
align-items: center;
86+
text-decoration: none;
87+
p.post-title {
88+
margin: 0;
89+
font-size: 1rem;
90+
font-weight: bold;
91+
color: var(--widget-text-color);
92+
}
93+
p.post-date {
94+
font-size: 0.8rem;
95+
margin: 0;
96+
opacity: var(--dimming-factor);
97+
color: var(--widget-text-color);
98+
}
99+
p.post-score {
100+
font-size: 0.8rem;
101+
margin: 0;
102+
opacity: var(--dimming-factor);
103+
color: var(--widget-text-color);
104+
}
105+
}
106+
}
107+
}
108+
</style>

src/components/Widgets/WidgetBase.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const COMPAT = {
7979
'gl-system-load': 'GlSystemLoad',
8080
'gl-cpu-temp': 'GlCpuTemp',
8181
'health-checks': 'HealthChecks',
82+
'hackernews-trending': 'HackernewsTrending',
8283
'gluetun-status': 'GluetunStatus',
8384
iframe: 'IframeWidget',
8485
image: 'ImageWidget',

src/utils/defaults.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,7 @@ module.exports = {
107107
footer: true,
108108
},
109109
/* A list of route names that page furniture (header, footer, etc) should be hidden on */
110-
hideFurnitureOn: [
111-
'minimal',
112-
'login',
113-
'download',
114-
],
110+
hideFurnitureOn: ['minimal', 'login', 'download'],
115111
/* Key names for local storage identifiers */
116112
localStorageKeys: {
117113
LANGUAGE: 'language',
@@ -166,9 +162,7 @@ module.exports = {
166162
/* Amount of time to show splash screen, when enabled, in milliseconds */
167163
splashScreenTime: 1000,
168164
/* Page meta-data, rendered in the header of each view */
169-
metaTagData: [
170-
{ name: 'description', content: 'A simple static homepage for you\'re server' },
171-
],
165+
metaTagData: [{ name: 'description', content: "A simple static homepage for you're server" }],
172166
/* Default option for Toast messages */
173167
toastedOptions: {
174168
position: 'bottom-center',
@@ -212,8 +206,10 @@ module.exports = {
212206
generativeFallback: 'https://evatar.io/{icon}',
213207
localPath: './item-icons',
214208
faviconName: 'favicon.ico',
215-
homeLabIcons: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/master/png/{icon}.png',
216-
homeLabIconsFallback: 'https://raw.githubusercontent.com/NX211/homer-icons/master/png/{icon}.png',
209+
homeLabIcons:
210+
'https://raw.githubusercontent.com/walkxcode/dashboard-icons/master/png/{icon}.png',
211+
homeLabIconsFallback:
212+
'https://raw.githubusercontent.com/NX211/homer-icons/master/png/{icon}.png',
217213
},
218214
/* API endpoints for widgets that need to fetch external data */
219215
widgetApiEndpoints: {
@@ -231,6 +227,7 @@ module.exports = {
231227
exchangeRates: 'https://v6.exchangerate-api.com/v6/',
232228
flights: 'https://aerodatabox.p.rapidapi.com/flights/airports/icao/',
233229
githubTrending: 'https://gh-trending-repos.herokuapp.com/',
230+
hackernewsTrending: 'https://hacker-news.firebaseio.com/v0',
234231
healthChecks: 'https://healthchecks.io/api/v1/checks',
235232
holidays: 'https://kayaposoft.com/enrico/json/v2.0/?action=getHolidaysForDateRange',
236233
jokes: 'https://v2.jokeapi.dev/joke/',

0 commit comments

Comments
 (0)