0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Wired up in-memory onboarding step completion (#19940)

ref https://linear.app/tryghost/issue/IPC-92/add-logic-for-completing-steps

- added in-memory step completion to `onboarding` service
- wired up the onboarding checklist to mark steps as completed when clicked
- extracted re-used step template and logic into components/helpers
This commit is contained in:
Kevin Ansfield 2024-03-27 18:27:43 +00:00 committed by GitHub
parent 919ec733e7
commit 90d8b41f63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 105 additions and 85 deletions

View file

@ -11,67 +11,48 @@
<div> <div>
{{!-- Step 1 --}} {{!-- Step 1 --}}
<div class="gh-onboarding-item gh-onboarding-item--completed"> <div class="gh-onboarding-item gh-onboarding-item--completed">
<div class="gh-onboarding-item-content"> <Dashboard::Onboarding::Step
{{svg-jar "rocket" }} @icon="rocket"
<div class="gh-onboarding-item-details"> @title="Start a new Ghost publication"
<span class="gh-onboarding-item-title">Start a new Ghost publication</span> @complete={{true}}
</div> />
</div>
<div class="gh-onboarding-item-checkmark">
{{svg-jar "check-circle-simple" }}
</div>
</div> </div>
{{!-- Step 2 --}} {{!-- Step 2 --}}
<LinkTo @route="settings-x.settings-x" @model="design/edit?ref=setup" class="gh-onboarding-item gh-onboarding-item--next"> <LinkTo @route="settings-x.settings-x" @model="design/edit?ref=setup" class="gh-onboarding-item {{onboarding-step-class "customize-design"}}" {{on "click" (fn this.onboarding.markStepCompleted "customize-design")}}>
<div class="gh-onboarding-item-content"> <Dashboard::Onboarding::Step
{{svg-jar "brush" }} @icon="brush"
<div class="gh-onboarding-item-details"> @title="Customize your publication"
<span class="gh-onboarding-item-title">Customize your publication</span> @description="Match the look and feel to your style and make it yours."
<span class="gh-onboarding-item-description">Match the look and feel to your style and make it yours.</span> @complete={{is-onboarding-step-completed "customize-design"}}
</div> />
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
</LinkTo> </LinkTo>
{{!-- Step 3 --}} {{!-- Step 3 --}}
<LinkTo @route="lexical-editor.new" @model="post" class="gh-onboarding-item"> <LinkTo @route="lexical-editor.new" @model="post" class="gh-onboarding-item {{onboarding-step-class "first-post"}}" {{on "click" (fn this.onboarding.markStepCompleted "first-post")}}>
<div class="gh-onboarding-item-content"> <Dashboard::Onboarding::Step
{{svg-jar "writing" }} @icon="writing"
<div class="gh-onboarding-item-details"> @title="Create your first post"
<span class="gh-onboarding-item-title">Create your first post</span> @description="Explore the editor and tell your story."
<span class="gh-onboarding-item-description">Explore the editor and tell your story.</span> @complete={{is-onboarding-step-completed "first-post"}}
</div> />
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
</LinkTo> </LinkTo>
{{!-- Step 4 --}} {{!-- Step 4 --}}
<LinkTo @route="members" class="gh-onboarding-item"> <LinkTo @route="members" class="gh-onboarding-item {{onboarding-step-class "build-audience"}}" {{on "click" (fn this.onboarding.markStepCompleted "build-audience")}}>
<div class="gh-onboarding-item-content"> <Dashboard::Onboarding::Step
{{svg-jar "member-add" }} @icon="member-add"
<div class="gh-onboarding-item-details"> @title="Build your audience"
<span class="gh-onboarding-item-title">Build your audience</span> @description="Add members and grow your readership."
<span class="gh-onboarding-item-description">Add members and grow your readership.</span> @complete={{is-onboarding-step-completed "build-audience"}}
</div> />
</div>
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
</LinkTo> </LinkTo>
{{!-- Step 5 --}} {{!-- Step 5 --}}
<div role="button" {{on "click" (toggle-action "showShareModal" this)}} class="gh-onboarding-item"> <div role="button" {{on "click" (toggle-action "showShareModal" this)}} class="gh-onboarding-item {{onboarding-step-class "share-publication"}}">
<div class="gh-onboarding-item-content"> <Dashboard::Onboarding::Step
{{svg-jar "megaphone" }} @icon="megaphone"
<div class="gh-onboarding-item-details"> @title="Share your publication"
<span class="gh-onboarding-item-title">Share your publication</span> @description="Share your publication on social media."
<span class="gh-onboarding-item-description">Share your publication on social media.</span> @complete={{is-onboarding-step-completed "share-publication"}}
</div> role="presentation"
</div> />
<div class="gh-onboarding-item-action">
{{svg-jar "arrow-right-tail" }}
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,45 +1,16 @@
import Component from '@glimmer/component'; import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject} from 'ghost-admin/decorators/inject'; import {inject} from 'ghost-admin/decorators/inject';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking'; import {tracked} from '@glimmer/tracking';
export default class OnboardingChecklist extends Component { export default class OnboardingChecklist extends Component {
@service onboarding;
@inject config; @inject config;
@tracked customizePublication = false;
@tracked createPost = false;
@tracked buildAudience = false;
@tracked tellWorld = false;
@tracked showMemberTierModal = false; @tracked showMemberTierModal = false;
get siteUrl() { get siteUrl() {
return this.config.blogTitle; return this.config.blogTitle;
} }
@action
completeStep(step) {
this.completed = !this.completed;
switch (step) {
case 'customizePublication':
this.customizePublication = !this.customizePublication;
break;
case 'createPost':
this.createPost = !this.createPost;
break;
case 'buildAudience':
this.buildAudience = !this.buildAudience;
break;
case 'tellWorld':
this.tellWorld = !this.tellWorld;
break;
default:
break;
}
}
@action
closeModal() {
this.closeModal();
}
} }

View file

@ -0,0 +1,16 @@
<div class="gh-onboarding-item-content">
{{svg-jar @icon}}
<div class="gh-onboarding-item-details">
<span class="gh-onboarding-item-title">{{@title}}</span>
{{#if @description}}
<span class="gh-onboarding-item-description">{{@description}}</span>
{{/if}}
</div>
</div>
<div class={{if @complete "gh-onboarding-item-checkmark" "gh-onboarding-item-action"}}>
{{#if @complete}}
{{svg-jar "check-circle-simple"}}
{{else}}
{{svg-jar "arrow-right-tail"}}
{{/if}}
</div>

View file

@ -0,0 +1,10 @@
import Helper from '@ember/component/helper';
import {inject as service} from '@ember/service';
export default class IsOnboardingStepCompleted extends Helper {
@service onboarding;
compute([step]) {
return this.onboarding.isStepCompleted(step);
}
}

View file

@ -0,0 +1,16 @@
import Helper from '@ember/component/helper';
import {inject as service} from '@ember/service';
export default class OnboardingStepClasses extends Helper {
@service onboarding;
compute([step]) {
if (this.onboarding.isStepCompleted(step)) {
return 'gh-onboarding-item--completed';
}
if (this.onboarding.nextStep === step) {
return 'gh-onboarding-item--next';
}
}
}

View file

@ -1,11 +1,37 @@
import Service, {inject as service} from '@ember/service'; import Service, {inject as service} from '@ember/service';
import {TrackedSet} from 'tracked-built-ins';
import {action} from '@ember/object';
import {tracked} from '@glimmer/tracking';
export default class OnboardingService extends Service { export default class OnboardingService extends Service {
@service feature; @service feature;
@service session; @service session;
@tracked _completedSteps = new TrackedSet();
ONBOARDING_STEPS = [
'customize-design',
'first-post',
'build-audience',
'share-publication'
];
get isChecklistShown() { get isChecklistShown() {
return this.feature.onboardingChecklist return this.feature.onboardingChecklist
&& this.session.user.isOwnerOnly; && this.session.user.isOwnerOnly;
} }
get nextStep() {
return this.ONBOARDING_STEPS.find(step => !this.isStepCompleted(step));
}
@action
isStepCompleted(step) {
return this._completedSteps.has(step);
}
@action
markStepCompleted(step) {
this._completedSteps.add(step);
}
} }