Skip to content

Commit 29eee41

Browse files
authored
Merge pull request #91 from glaucocustodio/add-tabnews
add TabNews
2 parents 2f2dcf6 + 10866a9 commit 29eee41

File tree

7 files changed

+199
-2
lines changed

7 files changed

+199
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@ Devo currently supports:
3737
- [Designer News](https://www.designernews.co/)
3838
- [DEV Community](https://dev.to/)
3939
- [Lobsters](https://lobste.rs/)
40+
- [TabNews](https://www.tabnews.com.br/)
4041

4142
### Adding a new platform
4243
Adding a new platform is super easy. All you need to do is:
4344
- add a body component that will be displayed in the cards.
4445
- export the body component from the [`src/components/bodies.js`](./src/components/bodies.js) file.
4546
- add the details for the platform to the [`src/settings.js`](./src/settings.js) file.
47+
- add the state to the [`src/store.js`](.src/store.js) file.
4648

4749
You can check the [HackerNews component](./src/components/HackerNews/Body.vue) to see how easy it is to add a new platform. Feel free to submit pull requests or ask questions regarding adding a new platform, any kind of input is appreciated.
4850

src/components/TabNews/Body.vue

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<template>
2+
<div class="tn-list">
3+
<row v-for="(item, index) in lines" :key="index" :item="item"></row>
4+
</div>
5+
</template>
6+
7+
<script>
8+
import { mapState } from 'vuex';
9+
import Row from '@/components/TabNews/Row.vue';
10+
11+
export default {
12+
name: 'Body',
13+
components: { Row },
14+
computed: {
15+
...mapState({
16+
lines: state => state.tabnews.data,
17+
}),
18+
},
19+
};
20+
</script>
21+
22+
<style>
23+
.tn-list > :last-child {
24+
border: none;
25+
}
26+
</style>

src/components/TabNews/Row.vue

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<template>
2+
<div class="tn-item">
3+
<div class="title-row">
4+
<div class="title">
5+
<a :href="itemLink" :title="item.title">{{ item.title }}</a>
6+
</div>
7+
<div class="site-string">
8+
<a :href="siteStringLink"> ({{ siteStringLink }}) </a>
9+
</div>
10+
</div>
11+
<div class="meta-data">
12+
{{ tabcoinsVerbose }} by
13+
<a class="user-link" :href="userLink"> {{ item.owner_username }}</a> |
14+
{{ relativeDate }} |
15+
<a class="thread-link" :href="itemLink"> {{commentsVerbose}}</a>
16+
</div>
17+
</div>
18+
</template>
19+
20+
<script>
21+
export default {
22+
name: 'Row',
23+
props: {
24+
item: {
25+
required: true,
26+
},
27+
},
28+
data() {
29+
return {
30+
baseUrl: 'https://tabnews.com.br',
31+
};
32+
},
33+
34+
computed: {
35+
userLink() {
36+
return `${this.baseUrl}/${this.item.owner_username}`;
37+
},
38+
siteStringLink() {
39+
return this.baseUrl.replace('https://', '');
40+
},
41+
itemLink() {
42+
return `${this.baseUrl}/${this.item.owner_username}/${this.item.slug}`;
43+
},
44+
tabcoinsVerbose() {
45+
if (this.item.tabcoins === 0 || this.item.tabcoins > 1) {
46+
return `${this.item.tabcoins} tabcoins`;
47+
}
48+
return `${this.item.tabcoins} tabcoin`;
49+
},
50+
commentsVerbose() {
51+
if (this.item.children_deep_count === 0 || this.item.children_deep_count > 1) {
52+
return `${this.item.children_deep_count} comments`;
53+
}
54+
return `${this.item.children_deep_count} comment`;
55+
},
56+
relativeDate() {
57+
return this.timeSince(new Date(this.item.published_at));
58+
},
59+
},
60+
methods: {
61+
timeSince(date) {
62+
const seconds = Math.floor((new Date() - date) / 1000);
63+
let interval = Math.floor(seconds / 31536000);
64+
65+
if (interval > 1) {
66+
return `${interval} years`;
67+
}
68+
69+
interval = Math.floor(seconds / 2592000);
70+
if (interval > 1) {
71+
return `${interval} months`;
72+
}
73+
74+
interval = Math.floor(seconds / 86400);
75+
if (interval >= 1) {
76+
return interval + (interval === 1 ? ' day' : ' days');
77+
}
78+
79+
interval = Math.floor(seconds / 3600);
80+
if (interval >= 1) {
81+
return interval + (interval === 1 ? ' hour' : ' hours');
82+
}
83+
84+
interval = Math.floor(seconds / 60);
85+
if (interval >= 1) {
86+
return interval + (interval === 1 ? 'minute' : ' minutes');
87+
}
88+
89+
return `${Math.floor(seconds)} seconds`;
90+
},
91+
},
92+
};
93+
</script>
94+
95+
<style>
96+
.tn-item {
97+
font-size: 16px;
98+
padding: 8px 0;
99+
text-align: left;
100+
border-bottom: 1px solid #dfe3e8a8;
101+
margin: 0;
102+
}
103+
104+
.night-mode .tn-item {
105+
border-bottom: 1px solid #dfe3e82d;
106+
}
107+
108+
.tn-item a {
109+
text-decoration: none;
110+
color: inherit;
111+
}
112+
113+
.tn-item a:hover {
114+
text-decoration: underline;
115+
text-decoration-line: underline;
116+
text-decoration-style: initial;
117+
text-decoration-color: initial;
118+
}
119+
120+
.tn-item .title {
121+
white-space: nowrap;
122+
overflow: hidden;
123+
display: inline-block;
124+
text-overflow: ellipsis;
125+
}
126+
127+
.tn-item .title-row {
128+
margin-bottom: 2px;
129+
max-width: 100%;
130+
display: flex;
131+
}
132+
133+
.tn-item .site-string {
134+
color: rgb(130, 130, 130);
135+
font-size: 10.667px;
136+
display: inline-block;
137+
white-space: nowrap;
138+
margin-top: 3px;
139+
padding-left: 4px;
140+
}
141+
142+
.meta-data {
143+
color: rgb(130, 130, 130);
144+
font-size: 9.33333px;
145+
}
146+
</style>

src/components/bodies.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export { default as ProductHuntBody } from './ProductHunt/Body.vue';
1818
export { default as DesignerNewsBody } from './DesignerNews/Body.vue';
1919
export { default as DevtoBody } from './Devto/Body.vue';
2020
export { default as LobstersBody } from './Lobsters/Body.vue';
21+
export { default as TabNewsBody } from './TabNews/Body.vue';

src/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import { library } from '@fortawesome/fontawesome-svg-core';
33
import { faGithub, faHackerNewsSquare, faProductHunt, faDev } from '@fortawesome/free-brands-svg-icons';
44
import {
55
faSyncAlt, faCodeBranch, faStar, faChevronUp, faComment, faExternalLinkAlt, faSun, faMoon,
6-
faCheck, faCaretUp, faCaretDown, faNewspaper, faHeart, faAnchor, faThLarge,
6+
faCheck, faCaretUp, faCaretDown, faNewspaper, faHeart, faAnchor, faThLarge, faFolder,
77
} from '@fortawesome/free-solid-svg-icons';
88
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
99
import App from './App.vue';
1010
import store from './store';
1111

1212
library.add([faGithub, faHackerNewsSquare, faProductHunt, faSyncAlt,
1313
faCodeBranch, faStar, faChevronUp, faComment, faExternalLinkAlt, faSun, faMoon, faCheck, faCaretUp, faCaretDown,
14-
faNewspaper, faDev, faHeart, faAnchor, faThLarge]);
14+
faNewspaper, faDev, faHeart, faAnchor, faThLarge, faFolder]);
1515
Vue.component('font-awesome-icon', FontAwesomeIcon);
1616

1717
Vue.config.productionTip = false;

src/settings.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,23 @@ export default {
115115
loadingColor: 'ec8f8f',
116116
},
117117
},
118+
tabnews: {
119+
dataUrl: 'https://www.tabnews.com.br/api/v1/contents?page=1&per_page=20&strategy=relevant',
120+
title: 'TabNews',
121+
icon: ['fa', 'folder'],
122+
titleFontColor: 'ffffff',
123+
titleBackgroundColor: '24292f',
124+
loadingColor: '9e271b',
125+
126+
externalLink: 'https://www.tabnews.com.br',
127+
bodyComponentName: 'TabNewsBody',
128+
129+
nightMode: {
130+
titleBackgroundColor: DEFAULT_NIGHTMODE_BACKGROUND,
131+
titleFontColor: '8eb5e3',
132+
loadingColor: '8eb5e3',
133+
},
134+
},
118135
},
119136
layouts: [
120137
{

src/store.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ export default new Vuex.Store({
9595
cache: 5 * 60000,
9696
data: [],
9797
},
98+
tabnews: {
99+
updated_at: 0,
100+
cache: 5 * 60000,
101+
data: [],
102+
},
98103
},
99104
mutations: {
100105
set24HourFormat(state, is24HourFormat) {

0 commit comments

Comments
 (0)