Created
February 25, 2025 15:06
-
-
Save glorat/1ced5ecc887d8ee006b90055210a05e0 to your computer and use it in GitHub Desktop.
Shepherd.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as ShepherdNamespace from 'shepherd.js' | |
import 'shepherd.js/dist/css/shepherd.css' | |
// Create a singleton instance of Shepherd.Tour | |
class TourService { | |
private static instance: TourService | |
private tour: ShepherdNamespace.Tour | |
private matterIdStep?: ShepherdNamespace.Step | |
private constructor() { | |
const Shepherd = (ShepherdNamespace as any).default | |
this.tour = new Shepherd.Tour({ | |
useModalOverlay: true, | |
defaultStepOptions: { | |
classes: 'shepherd-theme-default', | |
scrollTo: true, | |
cancelIcon: { | |
enabled: true, | |
}, | |
}, | |
}) | |
} | |
public static getInstance(): TourService { | |
if (!TourService.instance) { | |
TourService.instance = new TourService() | |
} | |
return TourService.instance | |
} | |
private resetTour(): void { | |
this.tour.complete() | |
this.tour.steps.length = 0 | |
this.matterIdStep = undefined | |
} | |
public advanceMatterIdStep(value: string): void { | |
if (this.matterIdStep?.isOpen() && value.toLowerCase() === 'sample') { | |
this.tour.next() | |
} | |
} | |
public async startOnboardingTour(): Promise<void> { | |
this.resetTour() | |
this.tour.addStep({ | |
id: 'welcome', | |
text: "Welcome to BriefTech! Let's create your first workspace to get started.", | |
buttons: [ | |
{ | |
text: 'Next', | |
action: () => this.tour.next(), | |
}, | |
], | |
}) | |
this.matterIdStep = this.tour.addStep({ | |
id: 'enter-matter-id', | |
text: 'Enter "sample" as your Matter Reference to create a sample workspace.', | |
attachTo: { | |
element: '[data-testid="matter-reference-input"]', | |
on: 'bottom', | |
}, | |
buttons: [], | |
}) as ShepherdNamespace.Step | |
this.tour.addStep({ | |
id: 'create-workspace', | |
text: 'Great! Now click "Create Matter" to set up your workspace.', | |
attachTo: { | |
element: 'button[type="submit"]', | |
on: 'bottom', | |
}, | |
advanceOn: { | |
selector: 'button[type="submit"]', | |
event: 'click', | |
}, | |
buttons: [], | |
}) | |
this.tour.addStep({ | |
id: 'workspace-initializing', | |
beforeShowPromise: () => | |
waitForElement('[data-testid="multi-file-empty-manager"]'), | |
text: 'Your workspace is setup', | |
buttons: [ | |
{ | |
text: 'Next', | |
action: () => this.tour.next(), | |
}, | |
], | |
}) | |
this.tour.addStep({ | |
id: 'load-samples', | |
text: "To get started quickly, let's load some sample files into your workspace.", | |
attachTo: { | |
element: '[data-testid="load-samples-btn"]', | |
on: 'bottom', | |
}, | |
advanceOn: { | |
selector: '[data-testid="load-samples-btn"]', | |
event: 'click', | |
}, | |
buttons: [], | |
}) | |
this.tour.addStep({ | |
id: 'samples-loading', | |
beforeShowPromise: () => waitForElement('[data-testid="file-table"]'), | |
text: 'Your samples are loading here', | |
buttons: [ | |
{ | |
text: 'Finish', | |
action: () => this.tour.complete(), | |
}, | |
], | |
}) | |
console.log('Starting shepherding of user') | |
await this.tour.start() | |
} | |
public advanceToInitializingStep(): void { | |
const currentStep = this.tour.steps.find((step) => step.isOpen()) | |
if (currentStep?.id === 'create-workspace') { | |
this.tour.next() | |
} | |
} | |
} | |
function waitForElement(selector: string, timeout = 5000): Promise<void> { | |
return new Promise<void>((resolve, reject) => { | |
const startTime = Date.now() | |
const checkExist = setInterval(() => { | |
if (document.querySelector(selector)) { | |
clearInterval(checkExist) | |
resolve() | |
} else if (Date.now() - startTime > timeout) { | |
clearInterval(checkExist) | |
reject(`Element ${selector} not found within timeout`) | |
} | |
}, 200) | |
}) | |
} | |
// Export a singleton instance | |
export const tourService = TourService.getInstance() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment