Skip to content

Commit e8085f6

Browse files
committed
improve the rss feed setting
1 parent 2cffb6e commit e8085f6

6 files changed

Lines changed: 163 additions & 91 deletions

File tree

src/assets/variables.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ html.dark {
8484
--tab-neutral-button-text: #a2a7ad;
8585
--tab-positive-button-background: #0366d6;
8686
--tab-positive-button-text: white;
87+
88+
--settings-input-background-color: #0d1116;
89+
--settings-input-border-color: #3a4553;
90+
--settings-input-border-focus-color: #6b7b90;
91+
--settings-input-placeholder-color: #42474e;
92+
--settings-input-text-color: #fff
8793
}
8894

8995
html.light {
@@ -160,4 +166,11 @@ html.light {
160166
--tab-neutral-button-text: #3c5065;
161167
--tab-positive-button-background: #0366d6;
162168
--tab-positive-button-text: white;
169+
170+
--settings-input-background-color: #ffffff;
171+
--settings-input-border-color: #e9ebec;
172+
--settings-input-border-focus-color: #c4d6df;
173+
--settings-input-placeholder-color: #97a6ad;
174+
--settings-input-text-color: #253b53
175+
163176
}

src/features/cards/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from "./api/getRssFeed"
12
export * from "./components/conferencesCard"
23
export * from './components/customRssCard'
34
export * from './components/devtoCard'

src/features/settings/components/RSSInput.tsx

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { useState } from 'react'
2+
import BeatLoader from 'react-spinners/BeatLoader'
3+
import { getRssUrlFeed } from 'src/features/cards'
4+
import { identifyUserCards, trackRssSourceAdd } from 'src/lib/analytics'
5+
import { SelectedCard } from 'src/types'
6+
import { isValidURL } from 'src/utils/UrlUtils'
7+
8+
import { BsRssFill } from 'react-icons/bs'
9+
import { useUserPreferences } from 'src/stores/preferences'
10+
import { SupportedCardType } from 'src/types'
11+
12+
type RssSettingProps = {
13+
setSelectedCards: (cards: SelectedCard[]) => void
14+
}
15+
16+
export const RssSetting = ({ setSelectedCards }: RssSettingProps) => {
17+
const { cards, setCards, userCustomCards, setUserCustomCards } = useUserPreferences()
18+
19+
const [rssUrl, setRssUrl] = useState<string | undefined>()
20+
const [rssInputError, setRssInputError] = useState<string | undefined>()
21+
const [isRssInputLoading, setIsRssInputLoading] = useState<boolean>(false)
22+
23+
const onRssAddClick = async () => {
24+
if (!rssUrl) {
25+
setRssInputError('Please provide an RSS Feed URL')
26+
return
27+
}
28+
29+
if (!isValidURL(rssUrl)) {
30+
setRssInputError('Invalid RSS Feed URL. Please check and try again')
31+
return
32+
}
33+
34+
setIsRssInputLoading(true)
35+
36+
try {
37+
const info = await getRssUrlFeed(rssUrl)
38+
let value = info.title.toLowerCase()
39+
40+
if (userCustomCards.some((card) => card.link === info.link)) {
41+
throw Error('RSS Feed already exists', { cause: 'EXISTS' })
42+
}
43+
44+
let customCard: SupportedCardType = {
45+
feedUrl: rssUrl.replace('https:', 'http:'),
46+
label: info.title,
47+
value,
48+
analyticsTag: value,
49+
link: info.link,
50+
type: 'rss',
51+
icon: info.icon,
52+
}
53+
setUserCustomCards([...userCustomCards, customCard])
54+
const newCards = [
55+
...cards,
56+
{ id: cards.length, name: customCard.value, type: customCard.type },
57+
]
58+
setCards(newCards)
59+
setSelectedCards(newCards)
60+
identifyUserCards(newCards.map((card) => card.name))
61+
trackRssSourceAdd(customCard.value)
62+
setRssUrl('')
63+
} catch (_) {
64+
setRssInputError('Error occured. Please check and try again.')
65+
} finally {
66+
setIsRssInputLoading(false)
67+
}
68+
}
69+
70+
return (
71+
<div className="settingRow">
72+
<p className="settingTitle">Add New Source</p>
73+
<div className="settingContent">
74+
<div className="form">
75+
<input
76+
type="text"
77+
value={rssUrl}
78+
onChange={(e) => setRssUrl(e.target.value)}
79+
placeholder="https://url.com/rss/feed"
80+
/>
81+
{isRssInputLoading ? (
82+
<BeatLoader color={'#A9B2BD'} loading={isRssInputLoading} size={6} />
83+
) : (
84+
<div>
85+
<button className="rssButton" onClick={onRssAddClick}>
86+
<BsRssFill /> Add Rss Feed
87+
</button>
88+
</div>
89+
)}
90+
</div>
91+
{rssInputError && (
92+
<div className="settingHint">
93+
<p>{rssInputError}</p>
94+
</div>
95+
)}
96+
</div>
97+
</div>
98+
)
99+
}

src/features/settings/components/SettingsModal.tsx

Lines changed: 3 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ import React, { useState } from 'react'
22
import { VscClose } from 'react-icons/vsc'
33
import ReactModal from 'react-modal'
44
import Select, { ActionMeta, MultiValue, SingleValue } from 'react-select'
5-
import BeatLoader from 'react-spinners/BeatLoader'
65
import Toggle from 'react-toggle'
76
import 'react-toggle/style.css'
87
import { SUPPORTED_CARDS, SUPPORTED_SEARCH_ENGINES, supportLink } from 'src/config'
9-
import { getRssUrlFeed } from 'src/features/cards/api/getRssFeed'
108
import { Tag, useRemoteConfigStore } from 'src/features/remoteConfig'
119
import {
1210
identifyUserCards,
@@ -18,16 +16,15 @@ import {
1816
trackLanguageAdd,
1917
trackLanguageRemove,
2018
trackListingModeSelect,
21-
trackRssSourceAdd,
2219
trackSearchEngineSelect,
2320
trackSourceAdd,
2421
trackSourceRemove,
2522
trackTabTarget,
2623
trackThemeSelect,
2724
} from 'src/lib/analytics'
2825
import { useUserPreferences } from 'src/stores/preferences'
29-
import { SearchEngineType, SelectedCard, SupportedCardType } from 'src/types'
30-
import { isValidURL } from 'src/utils/UrlUtils'
26+
import { SearchEngineType, SelectedCard } from 'src/types'
27+
import { RssSetting } from './RssSetting'
3128
import './settings.css'
3229

3330
type SettingsModalProps = {
@@ -61,10 +58,6 @@ export const SettingsModal = ({ showSettings, setShowSettings }: SettingsModalPr
6158
} = useUserPreferences()
6259
const [selectedCards, setSelectedCards] = useState(cards)
6360

64-
const [rssUrl, setRssUrl] = useState('')
65-
const [rssInputError, setRssInputError] = useState('')
66-
const [isRssInputLoading, setIsRssInputLoading] = useState(false)
67-
6861
const AVAILABLE_CARDS = [...SUPPORTED_CARDS, ...userCustomCards]
6962

7063
const handleCloseModal = () => {
@@ -150,53 +143,6 @@ export const SettingsModal = ({ showSettings, setShowSettings }: SettingsModalPr
150143
identifyUserTheme(newTheme)
151144
}
152145

153-
const onRssAddClick = async () => {
154-
if (!isValidURL(rssUrl)) {
155-
setRssInputError('Invalid RSS Feed URL. Please check and try again.')
156-
return
157-
}
158-
159-
// check if card exists
160-
161-
setIsRssInputLoading(true)
162-
163-
// get rssUrl Info
164-
try {
165-
const info = await getRssUrlFeed(rssUrl)
166-
let value = info.title.toLowerCase()
167-
const exists = userCustomCards.find((card) => card.link === info.link)
168-
if (exists) {
169-
throw Error('RSS Feed already exists', { cause: 'EXISTS' })
170-
}
171-
172-
let customCard: SupportedCardType = {
173-
feedUrl: rssUrl.replace('https:', 'http:'),
174-
label: info.title,
175-
value,
176-
analyticsTag: value,
177-
link: info.link,
178-
type: 'rss',
179-
icon: info.icon,
180-
}
181-
setUserCustomCards([...userCustomCards, customCard])
182-
const newCards = [
183-
...cards,
184-
{ id: cards.length, name: customCard.value, type: customCard.type },
185-
]
186-
setCards(newCards)
187-
setSelectedCards(newCards)
188-
identifyUserCards(newCards.map((card) => card.name))
189-
trackRssSourceAdd(customCard.value)
190-
setRssUrl('')
191-
} catch (err: any) {
192-
setRssInputError(
193-
err?.cause === 'EXISTS' ? err?.message : 'Error occured. Please check and try again.'
194-
)
195-
} finally {
196-
setIsRssInputLoading(false)
197-
}
198-
}
199-
200146
return (
201147
<ReactModal
202148
isOpen={showSettings}
@@ -266,39 +212,7 @@ export const SettingsModal = ({ showSettings, setShowSettings }: SettingsModalPr
266212
</div>
267213
</div>
268214

269-
<div className="settingRow">
270-
<p className="settingTitle">Add Custom Source</p>
271-
<div className="settingContent">
272-
{/* <Select
273-
menuIsOpen={false}
274-
options={[]}
275-
value={userCustomCards}
276-
onChange={onRssSelectChange}
277-
isMulti={true}
278-
isClearable={false}
279-
isSearchable={false}
280-
classNamePrefix={'hackertab'}
281-
className={'rss-sources'}
282-
/> */}
283-
<div className="rssUrlControl">
284-
<input
285-
className="rssUrlInput"
286-
value={rssUrl}
287-
onChange={(e) => setRssUrl(e.target.value)}
288-
/>
289-
{isRssInputLoading ? (
290-
<BeatLoader color={'#A9B2BD'} loading={isRssInputLoading} size={6} />
291-
) : (
292-
<button onClick={onRssAddClick}>ADD</button>
293-
)}
294-
</div>
295-
{rssInputError && (
296-
<div className="settingHint">
297-
<p>{rssInputError}</p>
298-
</div>
299-
)}
300-
</div>
301-
</div>
215+
<RssSetting setSelectedCards={setSelectedCards} />
302216

303217
<div className="settingRow">
304218
<p className="settingTitle">Dark Mode</p>

src/features/settings/components/settings.css

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,52 @@ Modal
4646
.settingRow:not(:last-child) {
4747
border-bottom: 1px solid var(--card-content-divider);
4848
}
49+
50+
.settingContent .form {
51+
display: flex;
52+
flex-direction: column;
53+
row-gap: 12px;
54+
}
55+
56+
.settingContent input[type=text] {
57+
background-color: var(--settings-input-background-color);
58+
border:1px solid var(--settings-input-border-color);
59+
border-radius: 50px;
60+
padding:6px 18px;
61+
color:var(--settings-input-text-color);
62+
font-size: 14px;
63+
}
64+
65+
.settingContent input[type=text]::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
66+
color: var(--settings-input-placeholder-color);
67+
opacity: 1;
68+
font-size: 14px;
69+
}
70+
71+
.settingContent input[type=text]:focus {
72+
border-color:var(--settings-input-border-focus-color)
73+
}
74+
75+
.settingContent button {
76+
display: flex;
77+
align-items: center;
78+
column-gap: 8px;
79+
background-color:none;
80+
border:none;
81+
border-radius: 50px;
82+
padding:6px 12px;
83+
font-size: 14px;
84+
font-weight: bold;
85+
cursor: pointer;
86+
}
87+
88+
.rssButton {
89+
background-color: #EE802F;
90+
color:white;
91+
}
92+
.rssButton:hover {
93+
opacity: 0.9;
94+
}
4995
.settingContent {
5096
width: 100%;
5197
flex: 1;
@@ -133,6 +179,7 @@ Select styles
133179
display: none;
134180
}
135181

182+
.rss-widget
136183
.rssUrlControl {
137184
margin: 6px 0;
138185
color: var(--primary-text-color);

0 commit comments

Comments
 (0)