Skip to content

Commit 175af96

Browse files
committed
feat: add sidebar tour functionality and update tour steps
1 parent bc16b42 commit 175af96

File tree

8 files changed

+204
-22
lines changed

8 files changed

+204
-22
lines changed

public/locales/en/tour.json

+11
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@
1515
},
1616
"next": "Next",
1717
"prev": "Prev",
18+
"sidebar": {
19+
"discord": "Join our Discord community to get help, share experiences, and stay updated.",
20+
"docs": "Access documentation and guides to help you get the most out of HyperPlay.",
21+
"downloads": "Check the status of your downloads, updates, and installations in the Download Manager.",
22+
"finish": "That's it! Now you know how to navigate through HyperPlay using the sidebar.",
23+
"library": "This is your Library where all your games are displayed. Click here to access your game collection.",
24+
"quests": "Complete quests to earn rewards. Participate in challenges and boost your gaming experience.",
25+
"settings": "Configure your app settings, manage accounts, and customize your HyperPlay experience.",
26+
"store": "This is the Store navigation. Access the HyperPlay Store, Epic Games, and GOG stores to browse and purchase games.",
27+
"x": "Follow us on X (formerly Twitter) for news, updates, and announcements."
28+
},
1829
"start_tour": "Start guided tour"
1930
}
2031
}

src/frontend/components/TourGuide/TourContext.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type TourState = {
55
currentTour: string | null
66
completedTours: string[]
77
activateLibraryTour: () => void
8+
activateSidebarTour: () => void
89
deactivateTour: () => void
910
markTourAsComplete: (tourId: string) => void
1011
isTourCompleted: (tourId: string) => boolean
@@ -15,6 +16,7 @@ const initialState: TourState = {
1516
currentTour: null,
1617
completedTours: [],
1718
activateLibraryTour: () => {},
19+
activateSidebarTour: () => {},
1820
deactivateTour: () => {},
1921
markTourAsComplete: () => {},
2022
isTourCompleted: () => false
@@ -40,6 +42,11 @@ export const TourProvider: React.FC<TourProviderProps> = ({ children }) => {
4042
setIsTourActive(true)
4143
}
4244

45+
const activateSidebarTour = () => {
46+
setCurrentTour('sidebar')
47+
setIsTourActive(true)
48+
}
49+
4350
const deactivateTour = () => {
4451
setIsTourActive(false)
4552
setCurrentTour(null)
@@ -64,6 +71,7 @@ export const TourProvider: React.FC<TourProviderProps> = ({ children }) => {
6471
currentTour,
6572
completedTours,
6673
activateLibraryTour,
74+
activateSidebarTour,
6775
deactivateTour,
6876
markTourAsComplete,
6977
isTourCompleted

src/frontend/components/TourGuide/TourGuide.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Steps } from 'intro.js-react'
33
import 'intro.js/introjs.css'
44
import { useTranslation } from 'react-i18next'
55
import { useTourGuide } from './TourContext'
6-
import { libraryTourSteps, TourStep } from './TourSteps'
6+
import { libraryTourSteps, sidebarTourSteps, TourStep } from './TourSteps'
77
import './TourGuide.scss'
88

99
export const TourGuide: React.FC = () => {
@@ -22,6 +22,9 @@ export const TourGuide: React.FC = () => {
2222
case 'library':
2323
steps = libraryTourSteps(t)
2424
break
25+
case 'sidebar':
26+
steps = sidebarTourSteps(t)
27+
break
2528
// Add more tour types here as needed
2629
default:
2730
steps = []

src/frontend/components/TourGuide/TourSteps.ts

+84
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,87 @@ export const libraryTourSteps = (t: TFunction<'tour'>): TourStep[] => [
8383
position: 'center'
8484
}
8585
]
86+
87+
// Sidebar tour steps
88+
export const sidebarTourSteps = (t: TFunction): TourStep[] => [
89+
{
90+
element: '[data-tour="sidebar-store"]',
91+
intro: t(
92+
'tour.sidebar.store',
93+
'This is the Store navigation. Access the HyperPlay Store, Epic Games, and GOG stores to browse and purchase games.'
94+
),
95+
position: 'right'
96+
},
97+
{
98+
element: '[data-tour="sidebar-library"]',
99+
intro: t(
100+
'tour.sidebar.library',
101+
'This is your Library where all your games are displayed. Click here to access your game collection.'
102+
),
103+
position: 'right'
104+
},
105+
/* {
106+
element: '[data-tour="sidebar-achievements"]',
107+
intro: t(
108+
'tour.sidebar.achievements',
109+
"Track your achievements across games. See what you've unlocked and what's still to conquer."
110+
),
111+
position: 'right'
112+
}, */
113+
{
114+
element: '[data-tour="sidebar-quests"]',
115+
intro: t(
116+
'tour.sidebar.quests',
117+
'Complete quests to earn rewards. Participate in challenges and boost your gaming experience.'
118+
),
119+
position: 'right'
120+
},
121+
{
122+
element: '[data-tour="sidebar-downloads"]',
123+
intro: t(
124+
'tour.sidebar.downloads',
125+
'Check the status of your downloads, updates, and installations in the Download Manager.'
126+
),
127+
position: 'right'
128+
},
129+
{
130+
element: '[data-tour="sidebar-settings"]',
131+
intro: t(
132+
'tour.sidebar.settings',
133+
'Configure your app settings, manage accounts, and customize your HyperPlay experience.'
134+
),
135+
position: 'right'
136+
},
137+
{
138+
element: '[data-tour="sidebar-discord"]',
139+
intro: t(
140+
'tour.sidebar.discord',
141+
'Join our Discord community to get help, share experiences, and stay updated.'
142+
),
143+
position: 'right'
144+
},
145+
{
146+
element: '[data-tour="sidebar-x"]',
147+
intro: t(
148+
'tour.sidebar.x',
149+
'Follow us on X (formerly Twitter) for news, updates, and announcements.'
150+
),
151+
position: 'right'
152+
},
153+
{
154+
element: '[data-tour="sidebar-docs"]',
155+
intro: t(
156+
'tour.sidebar.docs',
157+
'Access documentation and guides to help you get the most out of HyperPlay.'
158+
),
159+
position: 'right'
160+
},
161+
{
162+
element: '.SidebarLinks',
163+
intro: t(
164+
'tour.sidebar.finish',
165+
"That's it! Now you know how to navigate through HyperPlay using the sidebar."
166+
),
167+
position: 'right'
168+
}
169+
]

src/frontend/components/TourGuide/TourTriggerButton.tsx

+25-9
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,52 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
55
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'
66
import { useTourGuide } from './TourContext'
77

8+
export type TourType = 'library' | 'sidebar'
9+
810
interface TourTriggerButtonProps {
9-
tourId?: string // If not provided, uses the 'library' tour by default
11+
tourId?: TourType
1012
className?: string
13+
buttonType?: 'primary' | 'secondary' | 'tertiary'
14+
showIcon?: boolean
15+
showText?: boolean
1116
}
1217

1318
export const TourTriggerButton: React.FC<TourTriggerButtonProps> = ({
1419
tourId = 'library',
15-
className = ''
20+
className = '',
21+
buttonType = 'tertiary',
22+
showIcon = true,
23+
showText = true
1624
}) => {
1725
const { t } = useTranslation('tour')
18-
const { activateLibraryTour } = useTourGuide()
26+
const { activateLibraryTour, activateSidebarTour } = useTourGuide()
1927

2028
const handleClick = () => {
21-
if (tourId === 'library') {
22-
activateLibraryTour()
29+
switch (tourId) {
30+
case 'library':
31+
activateLibraryTour()
32+
break
33+
case 'sidebar':
34+
activateSidebarTour()
35+
break
36+
default:
37+
activateLibraryTour()
2338
}
24-
// Add additional tour activation functions as needed
2539
}
2640

2741
return (
2842
<Button
29-
type="tertiary"
43+
type={buttonType}
3044
className={className}
3145
onClick={handleClick}
3246
title={t('tour.start_tour', 'Start guided tour')}
3347
leftIcon={
34-
<FontAwesomeIcon icon={faQuestionCircle} height={14} width={14} />
48+
showIcon ? (
49+
<FontAwesomeIcon icon={faQuestionCircle} height={14} width={14} />
50+
) : undefined
3551
}
3652
>
37-
{t('tour.help', 'Help')}
53+
{showText && t('tour.help', 'Help')}
3854
</Button>
3955
)
4056
}

src/frontend/components/UI/Sidebar/components/SidebarLinks/index.tsx

+24-10
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export default observer(function SidebarLinks() {
7676
return (
7777
<>
7878
<div className="SidebarLinks Sidebar__section">
79-
<div className="sidebarLinkGradientWrapper">
79+
<div className="sidebarLinkGradientWrapper" data-tour="sidebar-store">
8080
<Tooltip {...tooltipProps} label={t('sidebar.store', 'Store')}>
8181
<NavLink
8282
className={({ isActive }) =>
@@ -98,7 +98,7 @@ export default observer(function SidebarLinks() {
9898
</NavLink>
9999
</Tooltip>
100100
</div>
101-
<div className="sidebarLinkGradientWrapper">
101+
<div className="sidebarLinkGradientWrapper" data-tour="sidebar-library">
102102
<Tooltip {...tooltipProps} label={t('sidebar.library', 'Library')}>
103103
<NavLink
104104
className={({ isActive }) =>
@@ -118,7 +118,10 @@ export default observer(function SidebarLinks() {
118118
</Tooltip>
119119
</div>
120120
{SHOW_ACHIEVEMENTS && (
121-
<div className="sidebarLinkGradientWrapper">
121+
<div
122+
className="sidebarLinkGradientWrapper"
123+
data-tour="sidebar-achievements"
124+
>
122125
<Tooltip
123126
{...tooltipProps}
124127
label={t('sidebar.achievements', 'Achievements')}
@@ -140,7 +143,10 @@ export default observer(function SidebarLinks() {
140143
</div>
141144
)}
142145
{SHOW_QUESTS ? (
143-
<div className="sidebarLinkGradientWrapper">
146+
<div
147+
className="sidebarLinkGradientWrapper"
148+
data-tour="sidebar-quests"
149+
>
144150
<Tooltip {...tooltipProps} label={t('sidebar.quests', 'Quests')}>
145151
<NavLink
146152
data-testid="quests"
@@ -159,7 +165,10 @@ export default observer(function SidebarLinks() {
159165
</Tooltip>
160166
</div>
161167
) : null}
162-
<div className="sidebarLinkGradientWrapper">
168+
<div
169+
className="sidebarLinkGradientWrapper"
170+
data-tour="sidebar-downloads"
171+
>
163172
<Tooltip
164173
{...tooltipProps}
165174
label={t('sidebar.downloadManager', 'Download Manager')}
@@ -174,7 +183,10 @@ export default observer(function SidebarLinks() {
174183
</NavLink>
175184
</Tooltip>
176185
</div>
177-
<div className="sidebarLinkGradientWrapper">
186+
<div
187+
className="sidebarLinkGradientWrapper"
188+
data-tour="sidebar-settings"
189+
>
178190
<Tooltip {...tooltipProps} label={t('sidebar.settings', 'Settings')}>
179191
<NavLink
180192
data-testid="settings"
@@ -194,10 +206,11 @@ export default observer(function SidebarLinks() {
194206
</div>
195207
</div>
196208

197-
<div className=" SidebarLinks Sidebar__section">
209+
<div className="SidebarLinks Sidebar__section">
198210
<div
199211
className="sidebarLinkGradientWrapper"
200212
onClick={() => handleExternalLink(window.api.openDiscordLink)}
213+
data-tour="sidebar-discord"
201214
>
202215
<Tooltip {...tooltipProps} label="Discord">
203216
<div className="Sidebar__item">
@@ -208,8 +221,9 @@ export default observer(function SidebarLinks() {
208221
</Tooltip>
209222
</div>
210223
<div
211-
className="sidebarLinkGradientWrapper "
224+
className="sidebarLinkGradientWrapper"
212225
onClick={() => handleExternalLink(window.api.openTwitterLink)}
226+
data-tour="sidebar-x"
213227
>
214228
<Tooltip {...tooltipProps} label="X">
215229
<div className="Sidebar__item">
@@ -219,7 +233,7 @@ export default observer(function SidebarLinks() {
219233
</div>
220234
</Tooltip>
221235
</div>
222-
<div className="sidebarLinkGradientWrapper">
236+
<div className="sidebarLinkGradientWrapper" data-tour="sidebar-docs">
223237
<Tooltip {...tooltipProps} label={t('sidebar.docs', 'Docs')}>
224238
<NavLink
225239
data-testid="Docs"
@@ -232,7 +246,7 @@ export default observer(function SidebarLinks() {
232246
</NavLink>
233247
</Tooltip>
234248
</div>
235-
<div className="sidebarLinkGradientWrapper">
249+
<div className="sidebarLinkGradientWrapper" data-tour="sidebar-quit">
236250
{(isFullscreen || activeController) && <QuitButton />}
237251
</div>
238252
</div>

src/frontend/components/UI/Sidebar/index.module.scss

+34
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,37 @@
2525
.Sidebar::-webkit-scrollbar {
2626
width: 0px;
2727
}
28+
29+
.sidebarContent {
30+
display: flex;
31+
flex-direction: column;
32+
width: 100%;
33+
height: 100%;
34+
justify-content: space-between;
35+
}
36+
37+
.sidebarTourButtonWrapper {
38+
display: flex;
39+
justify-content: center;
40+
margin-top: auto;
41+
padding: var(--space-sm) 0;
42+
}
43+
44+
.sidebarTourButton {
45+
margin-top: var(--space-md);
46+
background-color: var(--transparent);
47+
color: var(--text-default);
48+
font-weight: 500;
49+
text-align: center;
50+
transition: background-color 0.2s, color 0.2s;
51+
52+
svg {
53+
width: 24px;
54+
height: 24px;
55+
}
56+
57+
&:hover {
58+
background-color: var(--primary);
59+
color: var(--text-title);
60+
}
61+
}

src/frontend/components/UI/Sidebar/index.tsx

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import React from 'react'
22
import SidebarLinks from './components/SidebarLinks'
3+
import TourTriggerButton from 'frontend/components/TourGuide/TourTriggerButton'
34
import './index.scss'
45
import styles from './index.module.scss'
56

67
const Sidebar = () => {
78
return (
8-
<aside className={`${styles.Sidebar}`}>
9-
<SidebarLinks />
9+
<aside className={`${styles.Sidebar}`} data-tour="sidebar-container">
10+
<div className={styles.sidebarContent}>
11+
<SidebarLinks />
12+
<div className={styles.sidebarTourButtonWrapper}>
13+
<TourTriggerButton
14+
tourId="sidebar"
15+
className={styles.sidebarTourButton}
16+
buttonType="secondary"
17+
showIcon={true}
18+
showText={false}
19+
/>
20+
</div>
21+
</div>
1022
</aside>
1123
)
1224
}

0 commit comments

Comments
 (0)