Skip to content

feat(astro): support lessons without parts or chapters #374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 15, 2024

Conversation

AriPerkkio
Copy link
Member

@AriPerkkio AriPerkkio commented Oct 14, 2024

Adds support for defining lessons without chapters or parts.

src/content/tutorial
│
├── meta.md # Tutorial metadata
│
└── lesson-1 # Lesson in root! No part or chapter.
   ├── content.md
   ├── _files
   └── _solution
src/content/tutorial
│
├── meta.md # Tutorial metadata
│
└── part-1
    └── lesson-1 # Lesson in part! No chapter.
        ├── content.md
        ├── _files
        └── _solution

Custom order can be defined using lessons in metadata:

---
type: 'tutorial'
lessons: ['lesson-one', 'lesson-two']
---
---
type: 'part'
lessons: ['lesson-one', 'lesson-two']
---

Mixing structures is not supported and an error is thrown when these are not followed:

  • A tutorial can have one-or-many part's or one-or-many lesson's
  • A part can have one-or-many chapter's or one-or-many lesson's

In practice:

src/content/tutorial
├── meta.md # Tutorial
├── lesson-1 # Lesson
└── part-1 # Part

> Error: Cannot mix lessons and parts in a tutorial. Either remove the parts or move root level lessons into a part.

src/content/tutorial
├── meta.md # Tutorial
└── part-1 # Part
    ├── lesson-1 # Lesson
    └── chapter-1 # Chapter

> Error: Cannot mix lessons and chapters in a part. Either remove the chapter from 1-part or move the lessons into a chapter.

However you can have multiple part's, where some contain just chapter's and some contain just lesson's:

src/content/tutorial
├── meta.md # Tutorial
│
├── part-1 # Part with lessons
│   └── lesson-1 # Lesson
│
└── part-2 # Part with chapters
    └── chapter-1 # Chapter
tk-mixed-hierarchy.webm

This comment was marked as outdated.

@AriPerkkio AriPerkkio force-pushed the feat/flat-tutorial-structure branch 8 times, most recently from 977e911 to 8854d0b Compare October 16, 2024 15:18
@AriPerkkio

This comment was marked as outdated.

@AriPerkkio

This comment was marked as outdated.

@AriPerkkio AriPerkkio force-pushed the feat/flat-tutorial-structure branch 2 times, most recently from 5d0cef6 to 1c0694e Compare October 18, 2024 11:54
@AriPerkkio AriPerkkio force-pushed the feat/flat-tutorial-structure branch 4 times, most recently from 518887e to e76ce9a Compare October 18, 2024 13:30
Comment on lines +10 to +13
"dev:lessons-in-root": "astro dev --config ./configs/lessons-in-root.ts",
"preview:lessons-in-root": "astro build --config ./configs/lessons-in-root.ts && astro preview --config ./configs/lessons-in-root.ts",
"dev:lessons-in-part": "astro dev --config ./configs/lessons-in-part.ts",
"preview:lessons-in-part": "astro build --config ./configs/lessons-in-part.ts && astro preview --config ./configs/lessons-in-part.ts",
Copy link
Member Author

@AriPerkkio AriPerkkio Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning to create scripts/start.mjs that can be called like node scripts/start.mjs --dev lessons-in-root to reduce these verbose scripts. But that will be added in follow-up PR.

@AriPerkkio AriPerkkio force-pushed the feat/flat-tutorial-structure branch from e76ce9a to 8b73cc8 Compare October 18, 2024 13:40
@AriPerkkio

This comment was marked as outdated.

@AriPerkkio AriPerkkio force-pushed the feat/flat-tutorial-structure branch from 8b73cc8 to 109f309 Compare October 18, 2024 13:53
@AriPerkkio AriPerkkio force-pushed the feat/flat-tutorial-structure branch from 109f309 to e65eee1 Compare October 21, 2024 06:43
@AriPerkkio

This comment was marked as outdated.

@AriPerkkio AriPerkkio marked this pull request as ready for review October 22, 2024 06:36
@AriPerkkio AriPerkkio requested review from sulco and Nemikolh October 22, 2024 06:36
Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic work on this @AriPerkkio ! 🎉

Can't wait to get this landed 😃

I finished a first pass, I'll try to do another pass later this week 🤞

await expect(page.getByText('Lesson in part without chapter')).toBeVisible();

// navigation select can take a while to hydrate on page load, click until responsive
await expect(async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting, what does this expect call do (compared to having them in the parent function)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The button can become visible before it has been hydrated. Clicking it doesn't do anything. So here if the last await expect(page.locator('[data-state="open"]', { has: button })).toBeVisible({ timeout: 50 }) fails, the whole callback inside expect(callback).toPass() will be retried -> button is clicked again.

This hydration issue might be related to running <root>/e2e in dev mode only. I'll try in follow-up PR that if we switch to vite build --watch & vite preview, would this issue disappear.

Comment on lines +217 to +237
if (partId) {
if (!tutorial.parts[partId]) {
throw new Error(`Could not find part '${partId}'`);
}

lesson.part = {
id: partId,
title: tutorial.parts[partId].data.title,
};
}

_tutorial.parts[partId].chapters[chapterId].lessons[lessonId] = lesson;
if (partId && chapterId) {
if (!tutorial.parts[partId].chapters[chapterId]) {
throw new Error(`Could not find chapter '${chapterId}'`);
}

lesson.chapter = {
id: chapterId,
title: tutorial.parts[partId].chapters[chapterId].data.title,
};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should do this in a second pass in case parts, chapters and lessons are not in order.

It's also something that could have been an issue with the previous logic though so maybe we don't need to care about this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point they should be ordered:

const collection = sortCollection(await getCollection('tutorial'));
const { tutorial, tutorialMetaData } = await parseCollection(collection);

function sortCollection(collection: CollectionEntryTutorial[]) {
return collection.sort((a, b) => {
const depthA = a.id.split('/').length;
const depthB = b.id.split('/').length;
return depthA - depthB;
});
}

But yes, it's not visible from this function only. Should we move the sortCollection function call inside this function, so that we can be sure it's always sorted before looping it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I missed that, no all good this function is internal to this module 👍

Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work on this @AriPerkkio! 🎉

Super impressed with how much cleaner the code is and overall this is a really high quality PR 💪

@AriPerkkio
Copy link
Member Author

Thanks for review @Nemikolh, let's get this merged! 💯

@AriPerkkio AriPerkkio merged commit 8c44cbe into stackblitz:main Nov 15, 2024
11 checks passed
@AriPerkkio AriPerkkio deleted the feat/flat-tutorial-structure branch November 15, 2024 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Parts of only one lesson
2 participants