-
Notifications
You must be signed in to change notification settings - Fork 1
feat(tour) designed tour of the board UI, created tour context & card step component. #81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c3b02fa
e527f55
7a78241
fd7efa1
43179bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { Button, useTheme } from '@material-ui/core'; | ||
| import Tour from 'reactour'; | ||
| import { useTour } from '../../context'; | ||
|
|
||
| export const TourGuide = (): JSX.Element => { | ||
| const theme = useTheme(); | ||
| const { isTourMode, tourSteps, tourModeEndHandler } = useTour(); | ||
| return ( | ||
| <Tour | ||
| accentColor={theme.palette.primary.main} | ||
| isOpen={isTourMode} | ||
| steps={tourSteps} | ||
| onRequestClose={tourModeEndHandler} | ||
| onAfterOpen={() => (document.body.style.overflowY = 'hidden')} | ||
| rounded={5} | ||
| maskSpace={12} | ||
| disableInteraction | ||
| closeWithMask={false} | ||
| lastStepNextButton={ | ||
| <Button variant="contained" color="primary"> | ||
| Get Started | ||
| </Button> | ||
| } | ||
| /> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import { makeStyles } from '@material-ui/core/styles'; | ||
|
|
||
| export const stepStyles = makeStyles((theme) => ({ | ||
| divider: { | ||
| marginBottom: theme.spacing(2), | ||
| }, | ||
| })); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { Box, Divider, Typography } from '@material-ui/core'; | ||
| import { ReactourStep } from 'reactour'; | ||
| import { stepStyles } from './stepStyles'; | ||
|
|
||
| interface CardStepProps { | ||
| heading: string; | ||
| description: string; | ||
| } | ||
|
|
||
| const CardStep = ({ heading, description }: CardStepProps): JSX.Element => { | ||
| const classes = stepStyles(); | ||
|
|
||
| return ( | ||
| <Box> | ||
| <Typography variant="h4" color="primary" gutterBottom> | ||
| {heading} | ||
| </Typography> | ||
| <Divider light className={classes.divider} /> | ||
| <Typography variant="body1">{description}</Typography> | ||
| </Box> | ||
| ); | ||
| }; | ||
|
|
||
| export const steps: ReactourStep[] = [ | ||
| { | ||
| selector: '[data-tour="column-step"]', | ||
| content: ( | ||
| <CardStep | ||
| heading="Column" | ||
| description="Columns help organize your cards to keep track of what needs to be done, what's happening and what's finished." | ||
| /> | ||
| ), | ||
| }, | ||
| { | ||
| selector: '[data-tour="card-step"]', | ||
| content: <CardStep heading="Card" description="These are tasks that you can assign yourself to do." />, | ||
| }, | ||
| { | ||
| selector: '[data-tour="card-form-step"]', | ||
| content: <CardStep heading="Adding a card" description="Click here to add a new card to the column." />, | ||
| }, | ||
| { | ||
| selector: '[data-tour="add-board-step"]', | ||
| content: ( | ||
| <CardStep heading="Creating a board" description="Creating a new board allows for further organization." /> | ||
| ), | ||
| }, | ||
| { | ||
| selector: '[data-tour="show-boards-step"]', | ||
| content: ( | ||
| <CardStep heading="View all boards" description="View all your created boards and navigate through them here" /> | ||
| ), | ||
| }, | ||
| ]; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import { useContext, useState, createContext, PropsWithChildren, useEffect } from 'react'; | ||
| import { ReactourStep } from 'reactour'; | ||
| import ITourContext from '../interface/TourContext'; | ||
|
|
||
| export const TourContext = createContext<ITourContext>({} as ITourContext); | ||
|
|
||
| interface TourProviderProps { | ||
| steps: ReactourStep[]; | ||
| } | ||
|
|
||
| export const TourProvider = ({ steps, children }: PropsWithChildren<TourProviderProps>): JSX.Element => { | ||
| const [isTourMode, setIsTourMode] = useState<boolean>(false); | ||
| const [hasSeenTour, setHasSeenTour] = useState<boolean>(false); | ||
| const [tourSteps] = useState<ReactourStep[]>(steps || []); | ||
|
|
||
| useEffect(() => { | ||
| const hasSeenTour = localStorage.getItem('hasSeenTour'); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this project, just utilizing localStorage works however how it works currently is pretty static to only the tour of the board. For extending this and working with showcasing other features (i.e., teams UI), the implementation would have to be touched up. However, the TourProvider is flexible with updating the steps so just some tweaking for a better tour system. |
||
| if (!hasSeenTour) { | ||
| setIsTourMode(true); | ||
| } | ||
| }); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forgot to add in the empty dependency array so it runs on just render as opposed to right now which is running on render then on every update. |
||
|
|
||
| const tourModeEndHandler = (): void => { | ||
| localStorage.setItem('hasSeenTour', 'true'); | ||
| setIsTourMode(false); | ||
| setHasSeenTour(true); | ||
| }; | ||
|
|
||
| return ( | ||
| <TourContext.Provider | ||
| value={{ | ||
| isTourMode, | ||
| hasSeenTour, | ||
| tourSteps, | ||
| tourModeEndHandler, | ||
| }} | ||
| > | ||
| {children} | ||
| </TourContext.Provider> | ||
| ); | ||
| }; | ||
|
|
||
| export function useTour(): ITourContext { | ||
| const ctx = useContext(TourContext); | ||
| if (!ctx) throw new Error('useTour must be used within TourProvider'); | ||
| return ctx; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { ReactourStep } from 'reactour'; | ||
|
|
||
| export default interface ITourContext { | ||
| isTourMode: boolean; | ||
| hasSeenTour: boolean; | ||
| tourSteps: ReactourStep[]; | ||
| tourModeEndHandler: () => void; | ||
| } |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no step for adding a column, I will add that in as it's a pretty hidden feature and probably best to highlight it.