Skip to content

Commit e65eee1

Browse files
committed
feat(astro): support lessons without parts or chapters
1 parent 06bd4e7 commit e65eee1

17 files changed

+824
-503
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: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
"title": "The first chapter in part 1",
1717
"type": "chapter"
1818
},
19-
"slug": "chapter-slug",
20-
"firstLessonId": "1-first"
19+
"slug": "chapter-slug"
2120
}
22-
},
23-
"firstChapterId": "1-chapter"
21+
}
2422
},
2523
"2-part": {
2624
"id": "2-part",
@@ -38,11 +36,9 @@
3836
"title": "The first chapter in part 1",
3937
"type": "chapter"
4038
},
41-
"slug": "chapter-slug",
42-
"firstLessonId": "1-second"
39+
"slug": "chapter-slug"
4340
}
44-
},
45-
"firstChapterId": "2-chapter"
41+
}
4642
},
4743
"3-part": {
4844
"id": "3-part",
@@ -60,11 +56,9 @@
6056
"title": "The first chapter in part 1",
6157
"type": "chapter"
6258
},
63-
"slug": "chapter-slug",
64-
"firstLessonId": "1-third"
59+
"slug": "chapter-slug"
6560
}
66-
},
67-
"firstChapterId": "3-chapter"
61+
}
6862
}
6963
},
7064
"lessons": [
@@ -81,14 +75,6 @@
8175
"id": "1-first",
8276
"filepath": "1-part/1-chapter/1-first/content.md",
8377
"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-
},
9278
"Markdown": "Markdown for tutorial",
9379
"slug": "lesson-slug",
9480
"files": [
@@ -99,6 +85,14 @@
9985
"1-part-1-chapter-1-first-solution.json",
10086
[]
10187
],
88+
"part": {
89+
"id": "1-part",
90+
"title": "Basics"
91+
},
92+
"chapter": {
93+
"id": "1-chapter",
94+
"title": "The first chapter in part 1"
95+
},
10296
"next": {
10397
"title": "Welcome to TutorialKit",
10498
"href": "/part-slug/chapter-slug/lesson-slug"
@@ -116,15 +110,7 @@
116110
},
117111
"id": "1-second",
118112
"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-
},
113+
"order": 1,
128114
"Markdown": "Markdown for tutorial",
129115
"slug": "lesson-slug",
130116
"files": [
@@ -135,6 +121,14 @@
135121
"2-part-2-chapter-1-second-solution.json",
136122
[]
137123
],
124+
"part": {
125+
"id": "2-part",
126+
"title": "Basics"
127+
},
128+
"chapter": {
129+
"id": "2-chapter",
130+
"title": "The first chapter in part 1"
131+
},
138132
"prev": {
139133
"title": "Welcome to TutorialKit",
140134
"href": "/part-slug/chapter-slug/lesson-slug"
@@ -156,15 +150,7 @@
156150
},
157151
"id": "1-third",
158152
"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-
},
153+
"order": 2,
168154
"Markdown": "Markdown for tutorial",
169155
"slug": "lesson-slug",
170156
"files": [
@@ -175,11 +161,18 @@
175161
"3-part-3-chapter-1-third-solution.json",
176162
[]
177163
],
164+
"part": {
165+
"id": "3-part",
166+
"title": "Basics"
167+
},
168+
"chapter": {
169+
"id": "3-chapter",
170+
"title": "The first chapter in part 1"
171+
},
178172
"prev": {
179173
"title": "Welcome to TutorialKit",
180174
"href": "/part-slug/chapter-slug/lesson-slug"
181175
}
182176
}
183-
],
184-
"firstPartId": "1-part"
177+
]
185178
}
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: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
"title": "The first chapter in part 1",
1717
"type": "chapter"
1818
},
19-
"slug": "chapter-slug",
20-
"firstLessonId": "1-lesson"
19+
"slug": "chapter-slug"
2120
}
22-
},
23-
"firstChapterId": "1-chapter"
21+
}
2422
}
2523
},
2624
"lessons": [
@@ -37,14 +35,6 @@
3735
"id": "1-lesson",
3836
"filepath": "1-part/1-chapter/1-lesson/content.md",
3937
"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-
},
4838
"Markdown": "Markdown for tutorial",
4939
"slug": "lesson-slug",
5040
"files": [
@@ -54,8 +44,15 @@
5444
"solution": [
5545
"1-part-1-chapter-1-lesson-solution.json",
5646
[]
57-
]
47+
],
48+
"part": {
49+
"id": "1-part",
50+
"title": "Basics"
51+
},
52+
"chapter": {
53+
"id": "1-chapter",
54+
"title": "The first chapter in part 1"
55+
}
5856
}
59-
],
60-
"firstPartId": "1-part"
57+
]
6158
}

0 commit comments

Comments
 (0)