Skip to content

Commit 8f8a375

Browse files
committed
Merge branch 'feat/search-bar' into develop
2 parents d97d865 + 96fd8ba commit 8f8a375

7 files changed

Lines changed: 125 additions & 8 deletions

File tree

src/App.css

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ a {
9494
.extras {
9595

9696
flex-direction: row;
97-
margin-left: auto;
9897
margin-right: 16px;
9998
align-content: center;
10099

@@ -418,7 +417,6 @@ a {
418417
align-self: flex-start;
419418
display: flex;
420419
flex-direction: row;
421-
margin-top: 6px;
422420
flex-wrap: wrap;
423421
gap: 4px;
424422
}
@@ -694,6 +692,27 @@ Producthunt item
694692
background-color: var(--tooltip-accent-color);
695693
}
696694

695+
.searchBar {
696+
position: relative;
697+
margin: 0 auto;
698+
margin-top: 6px;
699+
}
700+
.searchBarIcon {
701+
position: absolute;
702+
height: 46px;
703+
margin: 0 16px;
704+
}
705+
.searchBarInput {
706+
border-radius: 50px;
707+
color: var(--primary-text-color);
708+
border:1px solid var(--card-border-color);
709+
box-shadow: 0 0 20px var(--card-border-color);
710+
height: 42px;
711+
padding:0 32px 0 48px;
712+
width:580px;
713+
background-color: var(--card-header-background-color);
714+
}
715+
697716
.tooltipLoading {
698717
display: flex;
699718
justify-content: center;
@@ -800,9 +819,15 @@ Producthunt item
800819
width: 0px;
801820
background: transparent;
802821
}
822+
.searchBar {
823+
display: none;
824+
}
803825
.slogan {
804826
display: none;
805827
}
828+
.tags {
829+
margin-top: 6px;
830+
}
806831
.changelogButton {
807832
display: none;
808833
}

src/App.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ function App() {
3535
theme: getOSMode(),
3636
openLinksNewTab: true,
3737
listingMode: 'normal',
38+
searchEngine: 'Google',
3839
cards: [
3940
{ id: 0, name: 'github' },
4041
{ id: 1, name: 'hackernews' },

src/Constants.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,32 @@ export const SUPPORTED_CARDS = [
109109
},
110110
]
111111

112+
export const SUPPORTED_SEARCH_ENGINES = [
113+
{
114+
label: 'Google',
115+
url: 'https://google.com/search?q=',
116+
},
117+
{
118+
label: 'DuckDuckGo',
119+
url: 'https://duckduckgo.com?q=',
120+
},
121+
{
122+
label: 'Bing',
123+
url: 'https://bing.com/search?q=',
124+
},
125+
{
126+
label: 'Yahoo',
127+
url: 'https://search.yahoo.com/search?p=',
128+
},
129+
{
130+
label: 'Baidu',
131+
url: 'https://baidu.com/s?wd=',
132+
},
133+
{
134+
label: 'Yandex',
135+
url: 'https://yandex.ru/search/?text=',
136+
},
137+
]
112138
export const LS_PREFERENCES_KEY = 'hackerTabPrefs'
113139
export const LS_ANALYTICS_ID_KEY = 'hackerTabAnalyticsId'
114140

src/components/Header.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,43 @@ import { CgTab } from 'react-icons/cg';
44
import { BsFillBookmarksFill } from "react-icons/bs"
55
import { ReactComponent as HackertabLogo } from '../logo.svg';
66
import UserTags from "./UserTags";
7-
import { APP } from '../Constants';
8-
import SettingsModal from "../settings/SettingsModal";
7+
import { SUPPORTED_SEARCH_ENGINES } from '../Constants'
8+
import SettingsModal from '../settings/SettingsModal'
99
import { BsMoon } from 'react-icons/bs'
1010
import { IoMdSunny } from 'react-icons/io'
11-
import { trackThemeChange } from '../utils/Analytics'
11+
import { trackThemeChange, trackSearch } from '../utils/Analytics'
1212
import Changelog from './Changelog'
13+
import { GoSearch } from 'react-icons/go'
1314

15+
function SearchBar({ state }) {
16+
const keywordsInputRef = React.useRef(null)
17+
const userSearchEngine = SUPPORTED_SEARCH_ENGINES.find(
18+
(engine) => engine.label == state.searchEngine
19+
)
20+
21+
const handleSubmit = (e) => {
22+
e.preventDefault()
23+
const keywords = e.target.children[1].value
24+
trackSearch(userSearchEngine.label)
25+
window.open(`${userSearchEngine.url}${keywords}`, '_self')
26+
}
27+
28+
useEffect(() => {
29+
keywordsInputRef.current.focus()
30+
}, [])
31+
32+
return (
33+
<form className="searchBar" onSubmit={handleSubmit}>
34+
<GoSearch className="searchBarIcon" size={20} />
35+
<input
36+
ref={keywordsInputRef}
37+
type="text"
38+
className="searchBarInput"
39+
placeholder={`Search on ${userSearchEngine.label}`}
40+
/>
41+
</form>
42+
)
43+
}
1444
function Header({ state, dispatcher, showSideBar, setShowSideBar, showSettings, setShowSettings }) {
1545
const [themeIcon, setThemeIcon] = useState(<BsMoon />)
1646
const isFirstRun = useRef(true)
@@ -68,7 +98,7 @@ function Header({ state, dispatcher, showSideBar, setShowSideBar, showSettings,
6898
<HackertabLogo className="logoText" />
6999
<Changelog />
70100
</span>
71-
<div className="slogan">{APP.slogan}</div>
101+
<SearchBar state={state} />
72102
<div className="extras">
73103
<button className="extraBtn" onClick={onSettingsClick}>
74104
<BsFillGearFill />

src/preferences/AppReducer.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ const AppReducer = (state, action) => {
5151
(bm) => bm.source !== value.source || bm.url !== value.url
5252
)
5353
break
54+
case 'setSearchEngine':
55+
newState = { ...newState, searchEngine: value.label }
56+
break
5457
default:
5558
throw new Error()
5659
}
@@ -63,6 +66,7 @@ const AppReducer = (state, action) => {
6366
listingMode: newState.listingMode,
6467
changelogMeta: newState.changelogMeta,
6568
userBookmarks: newState.userBookmarks,
69+
searchEngine: newState.searchEngine,
6670
}
6771
AppStorage.setItem(LS_PREFERENCES_KEY, storageData)
6872
return newState

src/settings/SettingsModal.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import '../App.css';
88
import './settings.css';
99
import PreferencesContext from '../preferences/PreferencesContext';
1010
import ConfigurationContext from '../configuration/ConfigurationContext';
11-
import { SUPPORTED_CARDS, APP } from '../Constants'
11+
import { SUPPORTED_CARDS, SUPPORTED_SEARCH_ENGINES, APP } from '../Constants'
1212
import {
1313
trackAddLanguage,
1414
trackRemoveLanguage,
@@ -21,7 +21,8 @@ import {
2121
function SettingsModal({ showSettings, setShowSettings }) {
2222
const { supportedTags } = useContext(ConfigurationContext)
2323
const preferences = useContext(PreferencesContext)
24-
const { dispatcher, cards, userSelectedTags, openLinksNewTab, listingMode, theme } = preferences
24+
const { dispatcher, cards, userSelectedTags, openLinksNewTab, listingMode, theme, searchEngine } =
25+
preferences
2526
const [selectedCards, setSelectedCards] = useState(cards)
2627

2728
const handleCloseModal = () => {
@@ -64,6 +65,10 @@ function SettingsModal({ showSettings, setShowSettings }) {
6465
dispatcher({ type: 'setCards', value: newCards })
6566
}
6667

68+
const onSearchEngineSelectChange = (value) => {
69+
dispatcher({ type: 'setSearchEngine', value })
70+
}
71+
6772
const onOpenLinksNewTabChange = (e) => {
6873
const checked = e.target.checked
6974
trackOpenLinksNewTab(checked)
@@ -162,6 +167,27 @@ function SettingsModal({ showSettings, setShowSettings }) {
162167
/>
163168
</div>
164169
</div>
170+
171+
<div className="settingRow">
172+
<p className="settingTitle">Favorite search engine</p>
173+
<div className="settingContent">
174+
<Select
175+
options={SUPPORTED_SEARCH_ENGINES}
176+
value={SUPPORTED_SEARCH_ENGINES.find((e) => e.label == searchEngine)}
177+
isMulti={false}
178+
isClearable={false}
179+
isSearchable={false}
180+
classNamePrefix={'hackertab'}
181+
onChange={onSearchEngineSelectChange}
182+
/>
183+
<p className="settingHint">
184+
Missing a search engine? create an issue{' '}
185+
<a href="#" onClick={(e) => window.open(APP.supportLink, '_blank')}>
186+
here
187+
</a>
188+
</p>
189+
</div>
190+
</div>
165191
</div>
166192
</ReactModal>
167193
)

src/utils/Analytics.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ const trackPageScroll = (direction) => {
55
trackEvent('Pages', 'Scroll', direction)
66
}
77

8+
const trackSearch = (searchEngine) => {
9+
trackEvent('Search', 'Submit', searchEngine)
10+
}
11+
812
const trackPageView = (pageName) => {
913
trackEvent('Pages', 'Open', pageName)
1014
}
@@ -123,4 +127,5 @@ export {
123127
trackReposDateRangeChange,
124128
trackListingModeChange,
125129
trackPageScroll,
130+
trackSearch,
126131
}

0 commit comments

Comments
 (0)