Skip to content

Commit 3319614

Browse files
committed
feat: add CardsNumberSettings and LayoutSettings components for user preferences
1 parent 3b7c63a commit 3319614

4 files changed

Lines changed: 149 additions & 49 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { ChipsSet } from 'src/components/Elements'
2+
import { identifyUserMaxVisibleCards, trackMaxVisibleCardsChange } from 'src/lib/analytics'
3+
import { useUserPreferences } from 'src/stores/preferences'
4+
import { Option } from 'src/types'
5+
6+
export const CardsNumberSettings = () => {
7+
const { maxVisibleCards, setMaxVisibleCards, layout } = useUserPreferences()
8+
9+
const onMaxVisibleCardsChange = (selectedChips: Option[]) => {
10+
if (selectedChips.length) {
11+
const maxVisibleCards = parseInt(selectedChips[0].value)
12+
setMaxVisibleCards(maxVisibleCards)
13+
identifyUserMaxVisibleCards(maxVisibleCards)
14+
trackMaxVisibleCardsChange(maxVisibleCards)
15+
}
16+
}
17+
18+
if (layout === 'grid') {
19+
return null // Hide this setting in grid layout
20+
}
21+
22+
return (
23+
<div className="settingRow">
24+
<p className="settingTitle">Max number of cards to display</p>
25+
<div className="settingContent">
26+
<ChipsSet
27+
className={'noMargin alternative-color'}
28+
canSelectMultiple={false}
29+
options={[
30+
{
31+
label: '3 cards',
32+
value: '3',
33+
},
34+
{
35+
label: '4 cards',
36+
value: '4',
37+
},
38+
{
39+
label: '5 cards',
40+
value: '5',
41+
},
42+
{
43+
label: '6 cards',
44+
value: '6',
45+
},
46+
]}
47+
defaultValues={[maxVisibleCards.toString()]}
48+
onChange={(_, selectedChips) => {
49+
onMaxVisibleCardsChange(selectedChips)
50+
}}
51+
/>
52+
53+
<p className="settingHint">
54+
To ensure a seamless experience, we may adjust the selected number to align with the
55+
resolution of your screen.
56+
</p>
57+
</div>
58+
</div>
59+
)
60+
}

src/features/settings/components/GeneralSettings/GeneralSettings.tsx

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
import React from 'react'
22
import Toggle from 'react-toggle'
33
import 'react-toggle/style.css'
4-
import { ChipsSet } from 'src/components/Elements'
54
import { Footer } from 'src/components/Layout'
65
import { SettingsContentLayout } from 'src/components/Layout/SettingsContentLayout'
76
import {
87
identifyUserLinksInNewTab,
98
identifyUserListingMode,
10-
identifyUserMaxVisibleCards,
119
identifyUserTheme,
1210
trackListingModeSelect,
13-
trackMaxVisibleCardsChange,
1411
trackTabTarget,
1512
trackThemeSelect,
1613
} from 'src/lib/analytics'
1714
import { useUserPreferences } from 'src/stores/preferences'
18-
import { Option } from 'src/types'
1915
import { DeleteAccount } from '../UserSettings/DeleteAccount'
2016
import { UserInfo } from '../UserSettings/UserInfo'
17+
import { CardsNumberSettings } from './CardsNumberSettings'
2118
import { DNDSettings } from './DNDSettings'
2219
import './generalSettings.css'
20+
import { LayoutSettings } from './LayoutSettings'
2321

2422
export const GeneralSettings = () => {
2523
const {
@@ -54,15 +52,6 @@ export const GeneralSettings = () => {
5452
identifyUserTheme(newTheme)
5553
}
5654

57-
const onMaxVisibleCardsChange = (selectedChips: Option[]) => {
58-
if (selectedChips.length) {
59-
const maxVisibleCards = parseInt(selectedChips[0].value)
60-
setMaxVisibleCards(maxVisibleCards)
61-
identifyUserMaxVisibleCards(maxVisibleCards)
62-
trackMaxVisibleCardsChange(maxVisibleCards)
63-
}
64-
}
65-
6655
return (
6756
<SettingsContentLayout
6857
title="General Settings"
@@ -71,42 +60,8 @@ export const GeneralSettings = () => {
7160
}>
7261
<div>
7362
<UserInfo />
74-
<div className="settingRow">
75-
<p className="settingTitle">Max number of cards to display</p>
76-
<div className="settingContent">
77-
<ChipsSet
78-
className={'noMargin alternative-color'}
79-
canSelectMultiple={false}
80-
options={[
81-
{
82-
label: '3 cards',
83-
value: '3',
84-
},
85-
{
86-
label: '4 cards',
87-
value: '4',
88-
},
89-
{
90-
label: '5 cards',
91-
value: '5',
92-
},
93-
{
94-
label: '6 cards',
95-
value: '6',
96-
},
97-
]}
98-
defaultValues={[maxVisibleCards.toString()]}
99-
onChange={(_, selectedChips) => {
100-
onMaxVisibleCardsChange(selectedChips)
101-
}}
102-
/>
103-
104-
<p className="settingHint">
105-
To ensure a seamless experience, we may adjust the selected number to align with the
106-
resolution of your screen.
107-
</p>
108-
</div>
109-
</div>
63+
<LayoutSettings />
64+
<CardsNumberSettings />
11065

11166
<div className="settingRow">
11267
<p className="settingTitle">Dark Mode</p>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { IoGridSharp } from 'react-icons/io5'
2+
import { TfiLayoutColumn4Alt } from 'react-icons/tfi'
3+
import Select, {
4+
GroupBase,
5+
OptionProps,
6+
SingleValue,
7+
SingleValueProps,
8+
components,
9+
} from 'react-select'
10+
import { useUserPreferences } from 'src/stores/preferences'
11+
import { Layout } from 'src/types'
12+
13+
type LayoutOption = {
14+
label: string
15+
value: Layout
16+
icon: React.ReactNode
17+
}
18+
19+
const Layouts: LayoutOption[] = [
20+
{ value: 'grid', label: 'Grid', icon: <IoGridSharp /> },
21+
{ value: 'cards', label: 'Cards', icon: <TfiLayoutColumn4Alt /> },
22+
]
23+
24+
const IconOption = (props: OptionProps<LayoutOption, false, GroupBase<LayoutOption>>) => (
25+
<components.Option {...props}>
26+
<div className="optionIcon">
27+
{props.data.icon}
28+
{props.data.label}
29+
</div>
30+
</components.Option>
31+
)
32+
33+
const SingleIconOption = (
34+
props: SingleValueProps<LayoutOption, false, GroupBase<LayoutOption>>
35+
) => (
36+
<components.SingleValue {...props}>
37+
<div className="optionIcon">
38+
{props.data.icon}
39+
{props.data.label}
40+
</div>
41+
</components.SingleValue>
42+
)
43+
44+
export const LayoutSettings = () => {
45+
const { layout, setLayout } = useUserPreferences()
46+
47+
const onPeriodSelect = (selectedOption: SingleValue<LayoutOption>) => {
48+
if (!selectedOption) {
49+
return
50+
}
51+
52+
setLayout(selectedOption.value)
53+
}
54+
55+
const getDefaultValue = (): LayoutOption | undefined => {
56+
return Layouts.find((e) => e.value === layout)
57+
}
58+
59+
return (
60+
<div className="settingRow">
61+
<p className="settingTitle">Layout Style</p>
62+
<div className="settingContent">
63+
<div className="form">
64+
<div style={{ flex: 1 }}>
65+
<Select
66+
options={Layouts}
67+
components={{ Option: IconOption, SingleValue: SingleIconOption }}
68+
isMulti={false}
69+
isClearable={false}
70+
isSearchable={false}
71+
defaultValue={getDefaultValue()}
72+
classNamePrefix={'hackertab'}
73+
onChange={onPeriodSelect}
74+
/>
75+
</div>
76+
</div>
77+
</div>
78+
</div>
79+
)
80+
}

src/features/settings/components/GeneralSettings/generalSettings.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
align-items: center;
1313
justify-content: space-between;
1414
}
15+
.settingRow .optionIcon {
16+
display: flex;
17+
align-items: center;
18+
column-gap: 8px;
19+
}
1520
.settingRow:not(:last-child) {
1621
border-bottom: 1px solid var(--card-content-divider);
1722
}

0 commit comments

Comments
 (0)