Skip to content

Commit 4ffe4be

Browse files
committed
Add tutorial wrapper and better router
1 parent 090bb42 commit 4ffe4be

File tree

5 files changed

+144
-109
lines changed

5 files changed

+144
-109
lines changed
Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,29 @@
11
<script lang="ts">
2-
import { skipAllTodos } from '$lib/tutorialUtils'
2+
import TutorialRouter from './tutorials/TutorialRouter.svelte'
33
import BackgroundRunnablesTutorial from './tutorials/app/BackgroundRunnablesTutorial.svelte'
44
import ConnectionTutorial from './tutorials/app/ConnectionTutorial.svelte'
5-
import { getTutorialIndex } from '$lib/tutorials/config'
65
7-
let backgroundRunnablesTutorial: BackgroundRunnablesTutorial | undefined = $state(undefined)
8-
let connectionTutorial: ConnectionTutorial | undefined = $state(undefined)
9-
10-
// Map tutorial IDs to their component instances
11-
const tutorialInstances = new Map<
12-
string,
13-
{ runTutorial: (options?: number) => void } | undefined
14-
>()
15-
16-
// Update map when instances change
17-
$effect(() => {
18-
tutorialInstances.set('backgroundrunnables', backgroundRunnablesTutorial)
19-
tutorialInstances.set('connection', connectionTutorial)
20-
})
6+
let tutorialRouter: TutorialRouter | undefined = $state(undefined)
217
228
export function runTutorialById(id: string, options?: { skipStepsCount?: number }) {
23-
const instance = tutorialInstances.get(id)
24-
if (instance) {
25-
if (options?.skipStepsCount !== undefined) {
26-
instance.runTutorial(options.skipStepsCount)
27-
} else {
28-
instance.runTutorial()
29-
}
30-
} else {
31-
console.warn(`Tutorial instance not found for id: ${id}`)
32-
}
33-
}
34-
35-
function skipAll() {
36-
skipAllTodos()
9+
tutorialRouter?.runTutorialById(id, options)
3710
}
3811
</script>
3912

40-
<BackgroundRunnablesTutorial
41-
bind:this={backgroundRunnablesTutorial}
42-
on:error
43-
on:skipAll={skipAll}
44-
on:reload
45-
index={getTutorialIndex('backgroundrunnables')}
46-
name="backgroundrunnables"
47-
/>
48-
49-
<ConnectionTutorial
50-
bind:this={connectionTutorial}
51-
on:error
52-
on:skipAll={skipAll}
53-
on:reload
54-
index={getTutorialIndex('connection')}
55-
name="connection"
13+
<TutorialRouter
14+
bind:this={tutorialRouter}
15+
tutorials={[
16+
{
17+
id: 'backgroundrunnables',
18+
component: BackgroundRunnablesTutorial,
19+
name: 'backgroundrunnables',
20+
supportsSkipSteps: true
21+
},
22+
{
23+
id: 'connection',
24+
component: ConnectionTutorial,
25+
name: 'connection',
26+
supportsSkipSteps: true
27+
}
28+
]}
5629
/>
Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,25 @@
11
<script lang="ts">
2-
import { skipAllTodos } from '$lib/tutorialUtils'
2+
import TutorialRouter from './tutorials/TutorialRouter.svelte'
33
import FlowBuilderLiveTutorial from './tutorials/FlowBuilderLiveTutorial.svelte'
44
import TroubleshootFlowTutorial from './tutorials/TroubleshootFlowTutorial.svelte'
5-
import { getTutorialIndex } from '$lib/tutorials/config'
65
7-
let flowBuilderLiveTutorial: FlowBuilderLiveTutorial | undefined = $state(undefined)
8-
let troubleshootFlowTutorial: TroubleshootFlowTutorial | undefined = $state(undefined)
9-
10-
// Map tutorial IDs to their component instances
11-
const tutorialInstances = new Map<string, { runTutorial: () => void } | undefined>()
12-
13-
// Update map when instances change
14-
$effect(() => {
15-
tutorialInstances.set('flow-live-tutorial', flowBuilderLiveTutorial)
16-
tutorialInstances.set('troubleshoot-flow', troubleshootFlowTutorial)
17-
})
6+
let tutorialRouter: TutorialRouter | undefined = $state(undefined)
187
198
export function runTutorialById(id: string) {
20-
const instance = tutorialInstances.get(id)
21-
if (instance) {
22-
instance.runTutorial()
23-
} else {
24-
console.warn(`Tutorial instance not found for id: ${id}`)
25-
}
26-
}
27-
28-
function skipAll() {
29-
skipAllTodos()
9+
tutorialRouter?.runTutorialById(id)
3010
}
3111
</script>
3212

33-
<FlowBuilderLiveTutorial
34-
bind:this={flowBuilderLiveTutorial}
35-
index={getTutorialIndex('flow-live-tutorial')}
36-
on:error
37-
on:skipAll={skipAll}
38-
on:reload
39-
/>
40-
<TroubleshootFlowTutorial
41-
bind:this={troubleshootFlowTutorial}
42-
index={getTutorialIndex('troubleshoot-flow')}
43-
on:error
44-
on:skipAll={skipAll}
45-
on:reload
13+
<TutorialRouter
14+
bind:this={tutorialRouter}
15+
tutorials={[
16+
{
17+
id: 'flow-live-tutorial',
18+
component: FlowBuilderLiveTutorial
19+
},
20+
{
21+
id: 'troubleshoot-flow',
22+
component: TroubleshootFlowTutorial
23+
}
24+
]}
4625
/>
Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
11
<script lang="ts">
2+
import TutorialRouter from './tutorials/TutorialRouter.svelte'
23
import WorkspaceOnboardingTutorial from './tutorials/workspace/WorkspaceOnboardingTutorial.svelte'
3-
import { skipAllTodos } from '$lib/tutorialUtils'
4-
import { getTutorialIndex } from '$lib/tutorials/config'
54
6-
let workspaceOnboardingTutorial: WorkspaceOnboardingTutorial | undefined = $state(undefined)
7-
8-
// Map tutorial IDs to their component instances
9-
const tutorialInstances = new Map<string, { runTutorial: () => void } | undefined>()
10-
11-
// Update map when instance changes
12-
$effect(() => {
13-
tutorialInstances.set('workspace-onboarding', workspaceOnboardingTutorial)
14-
})
5+
let tutorialRouter: TutorialRouter | undefined = $state(undefined)
156
167
export function runTutorialById(id: string) {
17-
const instance = tutorialInstances.get(id)
18-
if (instance) {
19-
instance.runTutorial()
20-
} else {
21-
console.warn(`Tutorial instance not found for id: ${id}`)
22-
}
23-
}
24-
25-
function skipAll() {
26-
skipAllTodos()
8+
tutorialRouter?.runTutorialById(id)
279
}
2810
</script>
2911

30-
<WorkspaceOnboardingTutorial
31-
bind:this={workspaceOnboardingTutorial}
32-
index={getTutorialIndex('workspace-onboarding')}
33-
on:skipAll={skipAll}
34-
on:error
35-
on:reload
12+
<TutorialRouter
13+
bind:this={tutorialRouter}
14+
tutorials={[
15+
{
16+
id: 'workspace-onboarding',
17+
component: WorkspaceOnboardingTutorial
18+
}
19+
]}
3620
/>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<script lang="ts">
2+
import { skipAllTodos } from '$lib/tutorialUtils'
3+
import TutorialWrapper from './TutorialWrapper.svelte'
4+
5+
interface TutorialDefinition {
6+
id: string
7+
component: any // Svelte component type - using any to avoid complex type issues
8+
name?: string // Optional name prop (used by some tutorials like AppTutorials)
9+
supportsSkipSteps?: boolean // Whether runTutorial accepts skipStepsCount parameter
10+
}
11+
12+
interface Props {
13+
tutorials: TutorialDefinition[]
14+
}
15+
16+
let { tutorials }: Props = $props()
17+
18+
// Map tutorial IDs to their component instances
19+
const tutorialInstances = new Map<
20+
string,
21+
{ runTutorial: (options?: number) => void } | { runTutorial: () => void } | undefined
22+
>()
23+
24+
function skipAll() {
25+
skipAllTodos()
26+
}
27+
28+
// Helper function to register a tutorial instance
29+
function registerInstance(id: string, instance: any) {
30+
tutorialInstances.set(id, instance)
31+
}
32+
33+
// Export function to run tutorial by ID
34+
export function runTutorialById(id: string, options?: { skipStepsCount?: number }) {
35+
const instance = tutorialInstances.get(id)
36+
if (!instance) {
37+
console.warn(`Tutorial instance not found for id: ${id}`)
38+
return
39+
}
40+
41+
// Check if this tutorial supports skipStepsCount
42+
const tutorial = tutorials.find((t) => t.id === id)
43+
if (tutorial?.supportsSkipSteps && options?.skipStepsCount !== undefined) {
44+
// Type assertion needed because TypeScript can't narrow the union type
45+
;(instance as { runTutorial: (options?: number) => void }).runTutorial(options.skipStepsCount)
46+
} else {
47+
// Call runTutorial without parameters
48+
if ('runTutorial' in instance && typeof instance.runTutorial === 'function') {
49+
instance.runTutorial()
50+
}
51+
}
52+
}
53+
</script>
54+
55+
{#each tutorials as tutorial}
56+
<TutorialWrapper
57+
id={tutorial.id}
58+
component={tutorial.component}
59+
name={tutorial.name}
60+
onInstanceReady={registerInstance}
61+
onSkipAll={skipAll}
62+
/>
63+
{/each}
64+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script lang="ts">
2+
import { getTutorialIndex } from '$lib/tutorials/config'
3+
4+
interface Props {
5+
id: string
6+
component: any // Svelte component type - using any to avoid complex type issues
7+
name?: string
8+
onInstanceReady: (id: string, instance: any) => void
9+
onSkipAll: () => void
10+
}
11+
12+
let { id, component: Component, name, onInstanceReady, onSkipAll }: Props = $props()
13+
14+
let instance: any = $state(undefined)
15+
const index = getTutorialIndex(id)
16+
17+
$effect(() => {
18+
if (instance) {
19+
onInstanceReady(id, instance)
20+
}
21+
})
22+
</script>
23+
24+
{#if Component}
25+
{@const Comp = Component}
26+
<Comp
27+
bind:this={instance}
28+
{index}
29+
{...(name ? { name } : {})}
30+
on:error
31+
on:skipAll={onSkipAll}
32+
on:reload
33+
/>
34+
{/if}
35+

0 commit comments

Comments
 (0)