Skip to content

Commit e76ce9a

Browse files
committed
feat(astro): support lessons without parts or chapters
1 parent ad6ad6b commit e76ce9a

17 files changed

+818
-486
lines changed

docs/tutorialkit.dev/src/content/docs/guides/creating-content.mdx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ title: Content creation
33
description: 'Creating content in TutorialKit.'
44
---
55
import { FileTree } from '@astrojs/starlight/components';
6+
import { Tabs, TabItem } from '@astrojs/starlight/components';
67

78
From an information architecture perspective, tutorial content is divided into **parts**, which are further divided into **chapters**, each consisting of **lessons**.
89

@@ -36,6 +37,64 @@ This structure is reflected in the directory structure of your TutorialKit proje
3637

3738
Navigate into one of these folders to see another folder that represents a **chapter**. Inside the chapter folder, you will find one or more **lesson** folders.
3839

40+
You can also omit parts and chapters, if your tutorial doesn't need that deep hierarchy.
41+
42+
<Tabs>
43+
<TabItem label="Structure">
44+
```plaintext
45+
- Lesson 1: Getting started
46+
- Lesson 2: Adding pages
47+
```
48+
</TabItem>
49+
50+
<TabItem label="File tree">
51+
<FileTree>
52+
- src
53+
- content
54+
- tutorial
55+
- getting-started
56+
- _files/
57+
- _solution/
58+
- content.md
59+
- adding-pages/
60+
- meta.md
61+
- config.ts
62+
- templates/
63+
</FileTree>
64+
</TabItem>
65+
</Tabs>
66+
67+
<Tabs>
68+
<TabItem label="Structure">
69+
```plaintext
70+
- Part 1: Introduction
71+
- Lesson 1: What is Vite?
72+
- Lesson 2: Installing
73+
- …
74+
- Part 2: Project structure
75+
- …
76+
```
77+
</TabItem>
78+
79+
<TabItem label="File tree">
80+
<FileTree>
81+
- src
82+
- content
83+
- tutorial
84+
- introduction/
85+
- what-is-vite/
86+
- _files/
87+
- _solution/
88+
- content.md
89+
- installing/
90+
- project-structure/
91+
- meta.md
92+
- config.ts
93+
- templates/
94+
</FileTree>
95+
</TabItem>
96+
</Tabs>
97+
3998
## A lesson content file
4099

41100
Navigate to the `src/content/tutorial/1-basics/1-introduction/1-welcome` folder and open the `content.md` in your editor. You will see a file structured like this:

packages/astro/src/default/pages/index.astro

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,13 @@ import { joinPaths } from '../utils/url';
44
55
const tutorial = await getTutorial();
66
7-
const part = tutorial.parts[tutorial.firstPartId!];
8-
const chapter = part.chapters[part.firstChapterId!];
9-
const lesson = tutorial.lessons.find((l) => l.id === chapter.firstLessonId)!;
7+
const lesson = tutorial.lessons[0];
8+
const part = lesson.part && tutorial.parts[lesson.part.id];
9+
const chapter = lesson.chapter && part?.chapters[lesson.chapter.id];
1010
11-
if (!lesson) {
12-
throw new Error(
13-
`Unable to find lesson for ${JSON.stringify(
14-
{
15-
partId: tutorial.firstPartId || null,
16-
chapterId: part.firstChapterId || null,
17-
lessonId: chapter.firstLessonId || null,
18-
},
19-
null,
20-
2,
21-
)}`,
22-
);
23-
}
11+
const slug = [part?.slug, chapter?.slug, lesson.slug].filter(Boolean).join('/');
2412
25-
const redirect = joinPaths(import.meta.env.BASE_URL, `/${part.slug}/${chapter.slug}/${lesson.slug}`);
13+
const redirect = joinPaths(import.meta.env.BASE_URL, `/${slug}`);
2614
---
2715

2816
<!doctype html>

packages/astro/src/default/utils/__snapshots__/multiple-parts.json

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
"slug": "chapter-slug",
2020
"firstLessonId": "1-first"
2121
}
22-
},
23-
"firstChapterId": "1-chapter"
22+
}
2423
},
2524
"2-part": {
2625
"id": "2-part",
@@ -41,8 +40,7 @@
4140
"slug": "chapter-slug",
4241
"firstLessonId": "1-second"
4342
}
44-
},
45-
"firstChapterId": "2-chapter"
43+
}
4644
},
4745
"3-part": {
4846
"id": "3-part",
@@ -63,8 +61,7 @@
6361
"slug": "chapter-slug",
6462
"firstLessonId": "1-third"
6563
}
66-
},
67-
"firstChapterId": "3-chapter"
64+
}
6865
}
6966
},
7067
"lessons": [
@@ -81,14 +78,6 @@
8178
"id": "1-first",
8279
"filepath": "1-part/1-chapter/1-first/content.md",
8380
"order": 0,
84-
"part": {
85-
"id": "1-part",
86-
"title": "Basics"
87-
},
88-
"chapter": {
89-
"id": "1-chapter",
90-
"title": "The first chapter in part 1"
91-
},
9281
"Markdown": "Markdown for tutorial",
9382
"slug": "lesson-slug",
9483
"files": [
@@ -99,6 +88,14 @@
9988
"1-part-1-chapter-1-first-solution.json",
10089
[]
10190
],
91+
"part": {
92+
"id": "1-part",
93+
"title": "Basics"
94+
},
95+
"chapter": {
96+
"id": "1-chapter",
97+
"title": "The first chapter in part 1"
98+
},
10299
"next": {
103100
"title": "Welcome to TutorialKit",
104101
"href": "/part-slug/chapter-slug/lesson-slug"
@@ -116,15 +113,7 @@
116113
},
117114
"id": "1-second",
118115
"filepath": "2-part/2-chapter/1-second/content.md",
119-
"order": 0,
120-
"part": {
121-
"id": "2-part",
122-
"title": "Basics"
123-
},
124-
"chapter": {
125-
"id": "2-chapter",
126-
"title": "The first chapter in part 1"
127-
},
116+
"order": 1,
128117
"Markdown": "Markdown for tutorial",
129118
"slug": "lesson-slug",
130119
"files": [
@@ -135,6 +124,14 @@
135124
"2-part-2-chapter-1-second-solution.json",
136125
[]
137126
],
127+
"part": {
128+
"id": "2-part",
129+
"title": "Basics"
130+
},
131+
"chapter": {
132+
"id": "2-chapter",
133+
"title": "The first chapter in part 1"
134+
},
138135
"prev": {
139136
"title": "Welcome to TutorialKit",
140137
"href": "/part-slug/chapter-slug/lesson-slug"
@@ -156,15 +153,7 @@
156153
},
157154
"id": "1-third",
158155
"filepath": "3-part/3-chapter/1-third/content.md",
159-
"order": 0,
160-
"part": {
161-
"id": "3-part",
162-
"title": "Basics"
163-
},
164-
"chapter": {
165-
"id": "3-chapter",
166-
"title": "The first chapter in part 1"
167-
},
156+
"order": 2,
168157
"Markdown": "Markdown for tutorial",
169158
"slug": "lesson-slug",
170159
"files": [
@@ -175,11 +164,18 @@
175164
"3-part-3-chapter-1-third-solution.json",
176165
[]
177166
],
167+
"part": {
168+
"id": "3-part",
169+
"title": "Basics"
170+
},
171+
"chapter": {
172+
"id": "3-chapter",
173+
"title": "The first chapter in part 1"
174+
},
178175
"prev": {
179176
"title": "Welcome to TutorialKit",
180177
"href": "/part-slug/chapter-slug/lesson-slug"
181178
}
182179
}
183-
],
184-
"firstPartId": "1-part"
180+
]
185181
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"parts": {},
3+
"lessons": [
4+
{
5+
"data": {
6+
"type": "lesson",
7+
"title": "Welcome to TutorialKit",
8+
"template": "default",
9+
"i18n": {
10+
"mocked": "default localization"
11+
},
12+
"openInStackBlitz": true
13+
},
14+
"id": "1-lesson",
15+
"filepath": "1-lesson/content.md",
16+
"order": 0,
17+
"Markdown": "Markdown for tutorial",
18+
"slug": "lesson-slug",
19+
"files": [
20+
"1-lesson-files.json",
21+
[]
22+
],
23+
"solution": [
24+
"1-lesson-solution.json",
25+
[]
26+
]
27+
}
28+
]
29+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"parts": {
3+
"1-part": {
4+
"id": "1-part",
5+
"order": 0,
6+
"data": {
7+
"type": "part",
8+
"title": "Basics"
9+
},
10+
"slug": "part-slug",
11+
"chapters": {}
12+
}
13+
},
14+
"lessons": [
15+
{
16+
"data": {
17+
"type": "lesson",
18+
"title": "Welcome to TutorialKit",
19+
"template": "default",
20+
"i18n": {
21+
"mocked": "default localization"
22+
},
23+
"openInStackBlitz": true
24+
},
25+
"id": "1-lesson",
26+
"filepath": "1-part/1-lesson/content.md",
27+
"order": 0,
28+
"Markdown": "Markdown for tutorial",
29+
"slug": "lesson-slug",
30+
"files": [
31+
"1-part-1-lesson-files.json",
32+
[]
33+
],
34+
"solution": [
35+
"1-part-1-lesson-solution.json",
36+
[]
37+
],
38+
"part": {
39+
"id": "1-part",
40+
"title": "Basics"
41+
}
42+
}
43+
]
44+
}

packages/astro/src/default/utils/__snapshots__/single-part-chapter-and-lesson.json

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
"slug": "chapter-slug",
2020
"firstLessonId": "1-lesson"
2121
}
22-
},
23-
"firstChapterId": "1-chapter"
22+
}
2423
}
2524
},
2625
"lessons": [
@@ -37,14 +36,6 @@
3736
"id": "1-lesson",
3837
"filepath": "1-part/1-chapter/1-lesson/content.md",
3938
"order": 0,
40-
"part": {
41-
"id": "1-part",
42-
"title": "Basics"
43-
},
44-
"chapter": {
45-
"id": "1-chapter",
46-
"title": "The first chapter in part 1"
47-
},
4839
"Markdown": "Markdown for tutorial",
4940
"slug": "lesson-slug",
5041
"files": [
@@ -54,8 +45,15 @@
5445
"solution": [
5546
"1-part-1-chapter-1-lesson-solution.json",
5647
[]
57-
]
48+
],
49+
"part": {
50+
"id": "1-part",
51+
"title": "Basics"
52+
},
53+
"chapter": {
54+
"id": "1-chapter",
55+
"title": "The first chapter in part 1"
56+
}
5857
}
59-
],
60-
"firstPartId": "1-part"
58+
]
6159
}

0 commit comments

Comments
 (0)