(core) Enable auto triggering of Welcome Tour, and various improvements.

Summary:
- Add showGristTour preference, and trigger tour automatically.
- Tour is only triggered for new and anonymous users on a personal org, with
  edit permission.

- Automatically open the right panel at tour start.
- Don't show tours on mobile, since that's not ready (popups are cut off
  and can't be dismissed)
- Cancel previous tour if a new one is somehow started.
- Remove #repeat- trigger hash tags from the URL when the tour starts.
- Ensure Help Center popup is positioned even when left panel is collapsed.
- Polish up the content of the last two cards in the tour.

Test Plan: Added test case for triggering and opening right panel.

Reviewers: alexmojaki, paulfitz

Reviewed By: alexmojaki

Differential Revision: https://phab.getgrist.com/D2955
This commit is contained in:
Dmitry S
2021-07-30 11:16:33 -04:00
parent 73c4efa315
commit 1605e18f66
12 changed files with 120 additions and 35 deletions

View File

@@ -30,17 +30,17 @@ export function createHelpTools(appModel: AppModel, spacer = true): DomContents
spacer ? cssSpacer() : null,
cssPageEntry(
cssPageLink(cssPageIcon('Feedback'),
cssLinkText('Give Feedback', dom.cls('tour-feedback')),
cssLinkText('Give Feedback'),
dom.on('click', () => beaconOpenMessage({appModel})),
),
dom.hide(isEfcr),
testId('left-feedback'),
),
cssPageEntry(
cssPageLink(cssPageIcon('Help'), {href: commonUrls.help, target: '_blank'}, cssLinkText(
'Help Center',
cssPageLink(cssPageIcon('Help'), {href: commonUrls.help, target: '_blank'},
cssLinkText('Help Center'),
dom.cls('tour-help-center')
)),
),
dom.hide(isEfcr),
),
];

View File

@@ -22,7 +22,7 @@
* the caller. Pass an `onFinishCB` to handle when a user dimiss the popups.
*/
import { Disposable, dom, DomElementArg, makeTestId, styled, svg } from "grainjs";
import { Disposable, dom, DomElementArg, Holder, makeTestId, styled, svg } from "grainjs";
import { createPopper, Placement } from '@popperjs/core';
import { FocusLayer } from 'app/client/lib/FocusLayer';
import * as Mousetrap from 'app/client/lib/Mousetrap';
@@ -71,8 +71,12 @@ export interface IOnBoardingMsg {
urlState?: IGristUrlState;
}
// There should only be one tour at a time. Use a holder to dispose the previous tour when
// starting a new one.
const tourSingleton = Holder.create<OnBoardingPopupsCtl>(null);
export function startOnBoarding(messages: IOnBoardingMsg[], onFinishCB: () => void) {
const ctl = new OnBoardingPopupsCtl(messages, onFinishCB);
const ctl = OnBoardingPopupsCtl.create(tourSingleton, messages, onFinishCB);
ctl.start().catch(reportError);
}

View File

@@ -183,7 +183,7 @@ export class RightPanel extends Disposable {
private _buildFieldContent(owner: MultiHolder) {
const fieldBuilder = owner.autoDispose(ko.computed(() => {
const vsi = this._gristDoc.viewModel.activeSection().viewInstance();
const vsi = this._gristDoc.viewModel.activeSection?.().viewInstance();
return vsi && vsi.activeFieldBuilder();
}));
@@ -197,7 +197,7 @@ export class RightPanel extends Disposable {
// build cursor position observable
const cursor = owner.autoDispose(ko.computed(() => {
const vsi = this._gristDoc.viewModel.activeSection().viewInstance();
const vsi = this._gristDoc.viewModel.activeSection?.().viewInstance();
return vsi?.cursor.currentPosition() ?? {};
}));

View File

@@ -1,6 +1,9 @@
import * as commands from 'app/client/components/commands';
import { urlState } from 'app/client/models/gristUrlState';
import { IOnBoardingMsg, startOnBoarding } from "app/client/ui/OnBoardingPopups";
import { colors } from 'app/client/ui2018/cssVars';
import { icon } from "app/client/ui2018/icons";
import { cssLink } from "app/client/ui2018/links";
import { dom, styled } from "grainjs";
export const welcomeTour: IOnBoardingMsg[] = [
@@ -58,30 +61,30 @@ export const welcomeTour: IOnBoardingMsg[] = [
},
{
selector: '.tour-help-center',
title: 'Keep learning',
title: 'Flying higher',
body: () => [
dom('p', 'Unlock Grist\'s hidden power. Dive into our documentation, videos, ',
'and tutorials to take your spreadsheet-database to the next level. '),
],
placement: 'right',
},
{
selector: '.tour-feedback',
title: 'Give feedback',
body: () => [
dom('p', 'Use ', Key('Give Feedback'), ' button (', Icon('Feedback'), ') for issues or questions. '),
dom('p', 'Use ', Key(GreyIcon('Help'), 'Help Center'), ' for documentation, videos, and tutorials.'),
dom('p', 'Use ', Key(GreyIcon('Feedback'), 'Give Feedback'), ' for issues or questions.'),
],
placement: 'right',
},
{
selector: '.tour-welcome',
title: 'Welcome to Grist!',
body: () => [
dom('p', 'Browse our ',
cssLink({target: '_blank', href: urlState().makeUrl({homePage: "templates"})},
'template library', cssInlineIcon('FieldLink')),
"to discover what's possible and get inspired."
),
],
showHasModal: true,
}
];
export function startWelcomeTour(onFinishCB: () => void) {
commands.allCommands.fieldTabOpen.run();
startOnBoarding(welcomeTour, onFinishCB);
}
@@ -95,7 +98,8 @@ const KeyStrong = styled(KeyContent, `
font-weight: 700;
`);
const Key = styled('code', `
const Key = styled('div', `
display: inline-block;
padding: 2px 5px;
border-radius: 4px;
margin: 0px 2px;
@@ -110,3 +114,12 @@ const Key = styled('code', `
const Icon = styled(icon, `
--icon-color: ${colors.lightGreen};
`);
const GreyIcon = styled(icon, `
--icon-color: ${colors.slate};
margin-right: 8px;
`);
const cssInlineIcon = styled(icon, `
margin: -3px 8px 0 4px;
`);