Skip to content

Commit ada7404

Browse files
committed
fix: feedback for the run this tutorial button
1 parent 3ede641 commit ada7404

File tree

7 files changed

+36
-34
lines changed

7 files changed

+36
-34
lines changed

packages/astro/src/default/components/webcontainer.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// must be imported first
22
import { useAuth } from './setup.js';
33

4-
import { safeBoot, TutorialStore, webContainerBootStatus } from '@tutorialkit/runtime';
4+
import { safeBoot, TutorialStore } from '@tutorialkit/runtime';
55
import { auth, WebContainer } from '@webcontainer/api';
66
import { joinPaths } from '../utils/url.js';
77

@@ -39,10 +39,6 @@ export function logout() {
3939
auth.logout({ ignoreRevokeError: true });
4040
}
4141

42-
export function forceBoot() {
43-
webContainerBootStatus().unblock();
44-
}
45-
4642
export const webcontainerContext: WebContainerContext = {
4743
useAuth,
4844
loggedIn: () => auth.loggedIn(),

packages/astro/src/default/utils/content.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export async function getTutorial(): Promise<Tutorial> {
4343
{
4444
partTemplate: 'Part ${index}: ${title}',
4545
noPreviewNorStepsText: 'No preview to run nor steps to show',
46-
startWebContainerText: 'Start WebContainer',
46+
startWebContainerText: 'Run this tutorial',
4747
} satisfies Lesson['data']['i18n'],
4848
tutorialMetaData.i18n,
4949
);

packages/components/react/src/BootScreen.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { useStore } from '@nanostores/react';
2-
import { webContainerBootStatus } from '@tutorialkit/runtime';
32
import type { Step, TutorialStore } from '@tutorialkit/runtime';
43
import { classNames } from './utils/classnames.js';
54

@@ -11,12 +10,12 @@ interface Props {
1110
export function BootScreen({ className, tutorialStore }: Props) {
1211
const steps = useStore(tutorialStore.steps);
1312
const { startWebContainerText, noPreviewNorStepsText } = tutorialStore.lesson?.data.i18n ?? {};
14-
const bootStatus = webContainerBootStatus();
13+
const bootStatus = useStore(tutorialStore.bootStatus);
1514

1615
return (
1716
<div className={classNames('flex-grow w-full flex justify-center items-center text-sm', className)}>
18-
{bootStatus.blocked ? (
19-
<Button onClick={bootStatus.unblock}>{startWebContainerText}</Button>
17+
{bootStatus === 'blocked' ? (
18+
<Button onClick={() => tutorialStore.unblockBoot()}>{startWebContainerText}</Button>
2019
) : steps ? (
2120
<ul className="space-y-1">
2221
{steps.map((step, index) => (

packages/runtime/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { LessonFilesFetcher } from './lesson-files.js';
22
export { TutorialRunner } from './tutorial-runner.js';
33
export type { Command, Commands, PreviewInfo, Step, Steps } from './webcontainer/index.js';
4-
export { safeBoot, webContainerBootStatus } from './webcontainer/index.js';
4+
export { safeBoot } from './webcontainer/index.js';
55
export { TutorialStore } from './store/index.js';

packages/runtime/src/store/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { LessonFilesFetcher } from '../lesson-files.js';
55
import { newTask, type Task } from '../tasks.js';
66
import { TutorialRunner } from '../tutorial-runner.js';
77
import type { ITerminal } from '../utils/terminal.js';
8+
import { bootStatus, unblockBoot, type BootStatus } from '../webcontainer/on-demand-boot.js';
89
import type { PreviewInfo } from '../webcontainer/preview-info.js';
910
import { StepsController } from '../webcontainer/steps.js';
1011
import type { TerminalConfig } from '../webcontainer/terminal-config.js';
@@ -198,6 +199,10 @@ export class TutorialStore {
198199
return this._editorStore.currentDocument;
199200
}
200201

202+
get bootStatus(): ReadableAtom<BootStatus> {
203+
return bootStatus;
204+
}
205+
201206
get documents(): ReadableAtom<EditorDocuments> {
202207
return this._editorStore.documents;
203208
}
@@ -263,6 +268,10 @@ export class TutorialStore {
263268
return !!this._lesson && Object.keys(this._lesson.solution[1]).length >= 1;
264269
}
265270

271+
unblockBoot() {
272+
unblockBoot();
273+
}
274+
266275
reset() {
267276
const isReady = this.lessonFullyLoaded.value;
268277

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export { Command, Commands } from './command.js';
2+
export { safeBoot } from './on-demand-boot.js';
23
export { PreviewInfo } from './preview-info.js';
3-
export { type Step, type Steps, StepsController } from './steps.js';
4-
export { safeBoot, webContainerBootStatus } from './on-demand-boot.js';
4+
export { StepsController, type Step, type Steps } from './steps.js';

packages/runtime/src/webcontainer/on-demand-boot.ts

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,39 @@
88
* to move forward with the boot.
99
*/
1010
import { WebContainer, type BootOptions } from '@webcontainer/api';
11+
import { atom, type ReadableAtom } from 'nanostores';
1112
import { withResolvers } from '../utils/promises.js';
1213

13-
let blocked: undefined | boolean;
14+
export type BootStatus = 'unknown' | 'blocked' | 'booting' | 'booted';
1415

16+
const localBootStatus = atom<BootStatus>('unknown');
1517
const blockingStatus = withResolvers<void>();
1618

19+
export const bootStatus: ReadableAtom<BootStatus> = localBootStatus;
20+
1721
export async function safeBoot(options: BootOptions) {
18-
if (typeof blocked === 'undefined') {
19-
blocked = isRestricted();
22+
if (localBootStatus.get() === 'unknown') {
23+
localBootStatus.set(isRestricted() ? 'blocked' : 'booting');
2024
}
2125

22-
if (blocked) {
26+
if (localBootStatus.get() === 'blocked') {
2327
await blockingStatus.promise;
28+
29+
localBootStatus.set('booting');
2430
}
2531

26-
return WebContainer.boot(options);
32+
return WebContainer.boot(options).then((webcontainer) => {
33+
localBootStatus.set('booted');
34+
return webcontainer;
35+
});
2736
}
2837

29-
interface BootStatus {
30-
readonly blocked: boolean | undefined;
31-
unblock(): void;
32-
}
38+
export function unblockBoot() {
39+
if (localBootStatus.get() !== 'blocked') {
40+
return;
41+
}
3342

34-
export function webContainerBootStatus(): BootStatus {
35-
return {
36-
blocked,
37-
unblock() {
38-
if (blocked === false) {
39-
return;
40-
}
41-
42-
blocked = false;
43-
blockingStatus.resolve();
44-
},
45-
};
43+
blockingStatus.resolve();
4644
}
4745

4846
function isRestricted() {

0 commit comments

Comments
 (0)