From 8bece7d9573fd7855799a79166c2c028746d4d33 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 27 Jul 2022 15:18:58 -0500 Subject: [PATCH] tour: add new tour component --- CHANGELOG.md | 1 + package.json | 1 + src/activities/Activities.test.tsx | 3 +- src/activities/Activities.tsx | 20 +- src/activities/hooks.ts | 22 ++ src/app/App.tsx | 2 + src/components/Button.tsx | 4 + src/explorer/Explorer.tsx | 6 +- src/reducers.ts | 2 + src/settings/Settings.tsx | 2 + src/toolbar/Toolbar.tsx | 11 +- src/toolbar/buttons/tour/TourButton.test.tsx | 23 ++ src/toolbar/buttons/tour/TourButton.tsx | 29 ++ src/toolbar/buttons/tour/i18n.ts | 12 + src/toolbar/buttons/tour/icon.svg | 1 + src/toolbar/buttons/tour/translations/en.json | 4 + src/tour/Tour.tsx | 255 ++++++++++++++++++ src/tour/actions.ts | 4 + src/tour/i18n.ts | 12 + src/tour/reducers.ts | 6 + src/tour/redux/tour.ts | 28 ++ src/tour/translations/en.json | 33 +++ yarn.lock | 93 ++++++- 23 files changed, 552 insertions(+), 22 deletions(-) create mode 100644 src/activities/hooks.ts create mode 100644 src/toolbar/buttons/tour/TourButton.test.tsx create mode 100644 src/toolbar/buttons/tour/TourButton.tsx create mode 100644 src/toolbar/buttons/tour/i18n.ts create mode 100644 src/toolbar/buttons/tour/icon.svg create mode 100644 src/toolbar/buttons/tour/translations/en.json create mode 100644 src/tour/Tour.tsx create mode 100644 src/tour/actions.ts create mode 100644 src/tour/i18n.ts create mode 100644 src/tour/reducers.ts create mode 100644 src/tour/redux/tour.ts create mode 100644 src/tour/translations/en.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f1aa2e3..d823ff4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Added better error message when no files to backup ([support#681]). - Added multi-step firmware flashing dialog. - Added support for flashing firmware via USB DFU. +- Added an interactive introductory tour of the app. ### Fixed - Fixed deleting files that are not open in the editor. diff --git a/package.json b/package.json index 9f41c77a..657e0607 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "react-dev-utils": "^12.0.1", "react-dom": "^16.13.1", "react-dropzone": "^14.2.2", + "react-joyride": "^2.5.0", "react-monaco-editor": "^0.49.0", "react-popper": "^2.3.0", "react-redux": "^8.0.2", diff --git a/src/activities/Activities.test.tsx b/src/activities/Activities.test.tsx index d5f0c0dd..315fbeb0 100644 --- a/src/activities/Activities.test.tsx +++ b/src/activities/Activities.test.tsx @@ -4,7 +4,8 @@ import { cleanup } from '@testing-library/react'; import React from 'react'; import { testRender } from '../../test'; -import Activities, { Activity } from './Activities'; +import Activities from './Activities'; +import { Activity } from './hooks'; afterEach(() => { cleanup(); diff --git a/src/activities/Activities.tsx b/src/activities/Activities.tsx index 7eb27f31..9eb60787 100644 --- a/src/activities/Activities.tsx +++ b/src/activities/Activities.tsx @@ -4,32 +4,18 @@ import './activities.scss'; import { Icon, Tab, Tabs } from '@blueprintjs/core'; import React, { useCallback, useEffect, useRef } from 'react'; -import { useLocalStorage } from 'usehooks-ts'; import Explorer from '../explorer/Explorer'; import Settings from '../settings/Settings'; +import { Activity, useActivitiesSelectedActivity } from './hooks'; import { useI18n } from './i18n'; -/** Indicates the selected activity. */ -export enum Activity { - /** No activity is selected. */ - None = 'activity.none', - /** The explorer activity is selected. */ - Explorer = 'activity.explorer', - /** The settings activity is selected. */ - Settings = 'activity.settings', -} - /** * React component that acts as a tab control to select activities. */ const Activities: React.VoidFunctionComponent = () => { + const [selectedActivity, setSelectedActivity] = useActivitiesSelectedActivity(); const i18n = useI18n(); - const [selectedActivity, setSelectedActivity] = useLocalStorage( - 'activities.selectedActivity', - Activity.Explorer, - ); - const handleAction = useCallback( (newActivity: Activity) => { // if activity is already selected, select none @@ -110,6 +96,7 @@ const Activities: React.VoidFunctionComponent = () => { ref={tabsRef} > { onMouseDown={(e) => e.stopPropagation()} /> { @@ -196,6 +197,7 @@ const App: React.VFC = () => { + ); }; diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 63b13b21..7bf1235d 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -8,6 +8,8 @@ import React, { useRef } from 'react'; import { FocusRing, useButton } from 'react-aria'; type ButtonProps = { + /** Optional DOM ID for the button. */ + id?: string; /** The label for the button. */ label: string; /** If true, the label will not be visible (will use aria-label instead). */ @@ -28,6 +30,7 @@ type ButtonProps = { /** Similar to Blueprint.js button with better accessibility. */ export const Button: React.VoidFunctionComponent = ({ + id, label, hideLabel, description, @@ -59,6 +62,7 @@ export const Button: React.VoidFunctionComponent = ({ {/* useButton() breaks the native browser :focus-visible :-/ */}