Skip to content

Commit 0bbb832

Browse files
authored
Merge pull request #90 from medyo/develop
Version 1.14.0
2 parents 44b3472 + ce87671 commit 0bbb832

24 files changed

Lines changed: 592 additions & 52 deletions

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
.eslintcache
44
.env*
55
*.zip
6-
6+
.todo
77
# dependencies
88
/node_modules
99
/.pnp

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "1.1.0",
44
"private": false,
55
"dependencies": {
6+
"@amplitude/analytics-browser": "^1.5.3",
67
"@testing-library/jest-dom": "^5.11.4",
78
"@testing-library/react": "^11.1.0",
89
"@testing-library/user-event": "^12.1.10",
@@ -18,7 +19,7 @@
1819
"react-device-detect": "^1.17.0",
1920
"react-dom": "^17.0.1",
2021
"react-error-boundary": "^3.1.4",
21-
"react-icons": "^4.1.0",
22+
"react-icons": "^4.4.0",
2223
"react-markdown": "^7.0.1",
2324
"react-modal": "^3.12.1",
2425
"react-pro-sidebar": "^0.6.0",

public/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Hackertab.dev",
33
"description": "The Developer’s Homepage",
4-
"version": "1.13.0",
4+
"version": "1.14.0",
55
"manifest_version": 2,
66
"chrome_url_overrides": {
77
"newtab": "index.html"

src/App.css

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@import url('https://fonts.googleapis.com/css?family=Nunito:regular,600');
21
@import "variables.css";
32

43
html {
@@ -63,7 +62,7 @@ a {
6362
align-content: center;
6463
flex-wrap: wrap;
6564
height:86px;
66-
margin: 0 1% 12px 1%;
65+
margin: 0 1% 0px 1%;
6766
}
6867

6968
.AppFooter {
@@ -194,10 +193,10 @@ a {
194193
.blockContent {
195194
flex-grow: 1;
196195
overflow-y: auto;
197-
height: calc(80vh - 1% - 16px - 30px);
198196
display: flex;
199197
flex-direction: column;
200198
overflow-x: hidden;
199+
height: calc(80vh - 1% - 46px);
201200
}
202201

203202
.scrollable {
@@ -234,13 +233,12 @@ a {
234233
.blockHeader {
235234
text-align: center;
236235
vertical-align: baseline;
237-
background: var(--card-header-background-color);
238236
color: var(--card-header-text-color);
239237
font-weight: 400;
240238
height: 30px;
241239
font-size: 16px;
242240
padding-top: 16px;
243-
padding-bottom: 16px;
241+
padding-bottom: 8px;
244242
cursor: pointer;
245243
}
246244
.blockHeader:hover .blockHeaderLink{
@@ -269,6 +267,10 @@ a {
269267
position: relative;
270268
}
271269

270+
.blockRow:last-child {
271+
padding-bottom: 42px;
272+
273+
}
272274
/* Actions */
273275
.blockActions {
274276
position: absolute;
@@ -334,6 +336,7 @@ a {
334336
visibility: visible;
335337
}
336338

339+
/* .blockContent > div > div > div:not(:last-child), .blockRow:not(:last-child) */
337340
.blockRow:not(:last-child) {
338341
border-bottom: 1px solid var(--card-content-divider);
339342
}
@@ -345,6 +348,7 @@ a {
345348
font-size: 16px;
346349
text-decoration: none;
347350
display: flex;
351+
flex-direction: row;
348352
}
349353
.rowTitle:hover {
350354
color: var(--primary-hover-text-color);
@@ -393,10 +397,12 @@ a {
393397
.rowDescription .rowItem {
394398
font-size: 12px;
395399
}
396-
.rowDetails .hnRowItem {
400+
.rowDetails .hnRowItem {
397401
color: #F6682F
398402
}
399-
403+
.rowDetails .inRowItem {
404+
color: #4799EB
405+
}
400406
.rowDetails .redditRowItem {
401407
color: #FA481D;
402408
}
@@ -405,6 +411,12 @@ a {
405411
color: #A91916
406412
}
407413

414+
.rowDetails .mediumRowItem {
415+
color: #000000;
416+
}
417+
.dark .rowDetails .mediumRowItem {
418+
color:#FFFFFF;
419+
}
408420
.rowItemIcon {
409421
position: relative;
410422
top: 1px;
@@ -426,6 +438,7 @@ a {
426438
flex-direction: row;
427439
flex-wrap: wrap;
428440
gap: 4px;
441+
margin-top: 12px;
429442
}
430443

431444
.tag {
@@ -876,6 +889,72 @@ Producthunt item
876889
}
877890
}
878891

892+
@keyframes cardPlaceholderPulse {
893+
0% {
894+
opacity: .6;
895+
}
896+
50% {
897+
opacity: 1;
898+
}
899+
100% {
900+
opacity: .6;
901+
}
902+
}
903+
904+
.cardPlaceholder {
905+
padding: 16px 16px 24px 16px;
906+
animation-duration: 1.5s;
907+
animation-name: cardPlaceholderPulse;
908+
animation-iteration-count: infinite;
909+
}
910+
.mediaCardPlaceholder {
911+
display: flex;
912+
flex-direction: row;
913+
}
914+
915+
.cardPlaceholder .media {
916+
width: 50px;
917+
height: 50px;
918+
margin-right: 16px;
919+
background: var(--placeholder-background-color);
920+
display: inline-block;
921+
}
922+
.cardPlaceholder .cardContent {
923+
display: flex;
924+
flex-direction: column;
925+
}
926+
.cardPlaceholder .cardUpvote {
927+
margin-left: auto;
928+
background: var(--placeholder-background-color);
929+
width: 33px;
930+
height: 44px;
931+
}
932+
.cardPlaceholder .line {
933+
background: var(--placeholder-background-color);
934+
display: block;
935+
height: 17px;
936+
border-radius: 4px;
937+
}
938+
.cardPlaceholder .smallLine {
939+
margin-top: 8px;
940+
background: var(--placeholder-background-color);
941+
display: block;
942+
height: 14px;
943+
width: 90%;
944+
border-radius: 4px;
945+
}
946+
.cardPlaceholder .details {
947+
display: flex;
948+
flex-direction: row;
949+
margin-top: 10px;
950+
}
951+
.cardPlaceholder .detail {
952+
background: var(--placeholder-background-color);
953+
height: 10px;
954+
width: 73px;
955+
margin-right: 16px;
956+
border-radius: 4px;
957+
}
879958
/* Small devices (portrait tablets and large phones, 600px and up) */
880959
@media only screen and (min-width: 600px) {
881960
.block {

src/App.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect, useContext, useRef } from 'react'
1+
import React, { useState, useEffect, useContext } from 'react'
22
import './App.css'
33
import ConfigurationContext from './configuration/ConfigurationContext'
44
import Footer from './components/Footer'
@@ -10,6 +10,7 @@ import ScrollCardsNavigator from './components/ScrollCardsNavigator'
1010
import AppContentLayout from './components/AppContentLayout'
1111
import 'react-contexify/dist/ReactContexify.css'
1212
import PreferencesContext from './preferences/PreferencesContext'
13+
import { initAnalytics } from './utils/Analytics'
1314

1415
function App() {
1516
const { marketingBannerConfig = {}, feedbackWidget } = useContext(ConfigurationContext)
@@ -18,6 +19,7 @@ function App() {
1819
const { dispatcher, ...state } = useContext(PreferencesContext)
1920

2021
useEffect(() => {
22+
initAnalytics()
2123
trackPageView('home')
2224
}, [])
2325

src/Constants.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ import ProductHuntCard from './cards/ProductHuntCard'
77
import RedditCard from './cards/RedditCard'
88
import LobstersCard from './cards/LobstersCard'
99
import HashNodeCard from './cards/HashNodeCard'
10+
import IndieHackersCard from './cards/IndieHackersCard'
1011
import FreeCodeCampCard from './cards/FreeCodeCampCard'
12+
import MediumCard from './cards/MediumCard'
1113
import { SiGithub } from 'react-icons/si'
1214
import { SiYcombinator } from 'react-icons/si'
1315
import { FaDev } from 'react-icons/fa'
1416
import { SiProducthunt } from 'react-icons/si'
15-
import { FaReddit } from 'react-icons/fa'
17+
import { FaReddit, FaMediumM } from 'react-icons/fa'
1618
import { HiTicket } from 'react-icons/hi'
1719
import HashNodeIcon from './static/icon_hashnode.png'
1820
import LobstersIcon from './static/icon_lobsters.png'
1921
import { FaFreeCodeCamp } from 'react-icons/fa'
22+
import { CgIndieHackers } from 'react-icons/cg'
2023

2124
const APP = {
2225
name: 'Hackertab.dev',
@@ -31,6 +34,8 @@ const APP = {
3134
dataSourcesLink: 'https://www.hackertab.dev/data-sources',
3235
changeLogLink: 'https://api.github.com/repos/medyo/hackertab.dev/releases',
3336
}
37+
export const ANALYTICS_ENDPOINT = 'https://api.hackertab.dev/analytics'
38+
export const ANALYTICS_SDK_KEY = '9662c93f91473ba6e96711b22e0a367d'
3439

3540
export const LOCAL_CONFIGURATION = {
3641
supportedTags: [], // Loaded remotly
@@ -100,6 +105,20 @@ export const SUPPORTED_CARDS = [
100105
label: 'FreeCodeCamp',
101106
component: FreeCodeCampCard,
102107
},
108+
{
109+
value: 'indiehackers',
110+
icon: <CgIndieHackers className="blockHeaderWhite" />,
111+
analyticsTag: 'indiehackers',
112+
label: 'IndieHackers',
113+
component: IndieHackersCard,
114+
},
115+
{
116+
value: 'medium',
117+
icon: <FaMediumM />,
118+
analyticsTag: 'medium',
119+
label: 'Medium',
120+
component: MediumCard,
121+
}
103122
]
104123

105124
export const SUPPORTED_SEARCH_ENGINES = [
@@ -140,13 +159,15 @@ export const GLOBAL_TAG = {
140159
githubValues: ['global'],
141160
devtoValues: [''],
142161
hashnodeValues: ['programming'],
162+
mediumValues: ['programming'],
143163
}
144164
export const MY_LANGUAGES_TAG = {
145165
value: 'myLangs',
146166
label: 'My Languages',
147167
githubValues: ['myLangs'],
148168
devtoValues: ['myLangs'],
149169
hashnodeValues: ['myLangs'],
170+
mediumValues: ['myLangs'],
150171
}
151172
export const MAX_MERGED_ITEMS_PER_LANGUAGE = 10
152173
export { APP }

src/bookmark/BookmarksSidebar.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ function BookmarksSidebar({ showSidebar, onClose }) {
3232
const githubBookmarks = userBookmarks.filter(bm => bm.source == "github")
3333
const jobsBookmarks = userBookmarks.filter(bm => bm.source == "jobs")
3434
const newsBookmarks = userBookmarks.filter(
35-
(bm) => ['hackernews', 'devto', 'hashnode', 'lobsters', 'freecodecamp'].indexOf(bm.source) != -1
35+
(bm) =>
36+
[
37+
'hackernews',
38+
'devto',
39+
'hashnode',
40+
'lobsters',
41+
'freecodecamp',
42+
'medium',
43+
'indiehackers',
44+
].indexOf(bm.source) != -1
3645
)
3746
const conferencesBookmarks = userBookmarks.filter(bm => bm.source == "conferences")
3847
const productsBookmarks = userBookmarks.filter(bm => bm.source == "producthunt")

src/cards/IndieHackersCard.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React, { useContext } from 'react'
2+
import { VscTriangleUp } from 'react-icons/vsc'
3+
import CardComponent from '../components/CardComponent'
4+
import ListComponent from '../components/ListComponent'
5+
import indiehackersApi from '../services/indiehackers'
6+
import { BiCommentDetail } from 'react-icons/bi'
7+
import { MdAccessTime } from 'react-icons/md'
8+
import CardLink from '../components/CardLink'
9+
import CardItemWithActions from '../components/CardItemWithActions'
10+
import PreferencesContext from '../preferences/PreferencesContext'
11+
import { FaChevronUp } from 'react-icons/fa'
12+
import { format } from 'timeago.js'
13+
14+
const StoryItem = ({ item, index, analyticsTag }) => {
15+
const { listingMode } = useContext(PreferencesContext)
16+
17+
return (
18+
<CardItemWithActions
19+
source={'indiehackers'}
20+
index={index}
21+
item={item}
22+
key={index}
23+
cardItem={
24+
<>
25+
<p className="rowTitle">
26+
<CardLink link={item.url} analyticsSource={analyticsTag}>
27+
{listingMode === 'compact' && (
28+
<span className="counterWrapper">
29+
<VscTriangleUp />
30+
<span className="value">{item.score}</span>
31+
</span>
32+
)}
33+
34+
<span className="subTitle">{item.title}</span>
35+
</CardLink>
36+
</p>
37+
{listingMode === 'normal' && (
38+
<div className="rowDetails">
39+
<span className="rowItem inRowItem">
40+
<FaChevronUp className="rowItemIcon" /> {item.likes} points
41+
</span>
42+
<span className="rowItem">
43+
<MdAccessTime className="rowItemIcon" /> {format(new Date(item.published_at))}
44+
</span>
45+
<span className="rowItem">
46+
<BiCommentDetail className="rowItemIcon" /> {item.comments} comments
47+
</span>
48+
</div>
49+
)}
50+
</>
51+
}
52+
/>
53+
)
54+
}
55+
56+
function IndieHackersCard({ analyticsTag, label, icon, withAds }) {
57+
const fetchStories = async () => {
58+
return await indiehackersApi.getTopStories()
59+
}
60+
61+
const renderItem = (item, index) => (
62+
<StoryItem item={item} key={`st-${index}`} index={index} analyticsTag={analyticsTag} />
63+
)
64+
65+
return (
66+
<CardComponent
67+
icon={<span className="blockHeaderIcon">{icon}</span>}
68+
link="https://indiehackers.com/"
69+
title={label}>
70+
<ListComponent fetchData={fetchStories} renderItem={renderItem} withAds={withAds} />
71+
</CardComponent>
72+
)
73+
}
74+
75+
export default IndieHackersCard

0 commit comments

Comments
 (0)