Skip to content

Content creation

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

For instance, a Vite tutorial might be structured like this:

- Part 1: Basics of Vite
- Chapter 1: Introduction
- Lesson 1: Welcome!
- Lesson 2: Why Vite?
- …
- Chapter 2: Your first Vite project
- Part 2: Vite CLI
- …

This structure is reflected in the directory structure of your TutorialKit project. When you open the project in the code editor and navigate to the src/content/tutorial directory, you will see a several numbered folders. These represent the parts of your tutorial.

  • Directorysrc
    • Directorycontent
      • Directorytutorial
        • Directory1-basics
          • Directory1-introduction/
          • Directory2-your-first-vite-project/
        • Directory2-vite-cli/
        • meta.md
    • config.ts
    • Directorytemplates/

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.

You can also omit parts or chapters such that you only have lessons or only lessons and parts. Here are a few examples:

- Lesson 1: Getting started
- Lesson 2: Adding pages
- Part 1: Introduction
- Lesson 1: What is Vite?
- Lesson 2: Installing
- …
- Part 2: Project structure
- …

A lesson content file

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:

---
type: lesson
title: Welcome to TutorialKit
# ...
---
# Kitchen Sink [Heading 1]
Lorem ipsum dolor
<!-- ... -->

This is a Markdown file with a frontmatter block at the top (marked by a single --- line at the beginning of the file and another --- line to close the block).

The frontmatter block contains metadata about the lesson, such as the title, description, and other properties that will allow you to configure this specific lesson.

Everything below the frontmatter block is the lesson content itself. You can write your lesson content in Markdown format, using headings, lists, images, and other Markdown features. You can also use the MDX format by changing the file extension from the default .md to .mdx.

Try changing the content of the content.md file and see the changes reflected in the browser.

Adding a lesson

To add a new lesson, create a new folder inside the chapter folder. Name it with a number that is not yet used in the chapter. For example, if the last lesson in the chapter is 1-welcome, you can name the new lesson folder 2-why-vite.

The numbers you prefix the lesson folders with are used to order the lessons in the tutorial.

You might notice that the name of the lesson folder is also used in the URL segment of the lesson in the tutorial app. For example, the URL of the lesson 1-welcome will look something like localhost:4321/1-basics/1-introduction/1-welcome. You can change that by modifying the slug property in the lesson’s frontmatter block:

---
title: Welcome!
slug: hello-world
---

This will change the URL of the lesson to localhost:4321/1-basics/1-introduction/hello-world.

A lesson code

Beside the content.md file in a lesson’s directory, you will find two folders:

  • _files
  • _solution

The _files folder contains any code files that are part of the lesson. For example, if the lesson revolves around React components, you might have a Button.jsx file there. The content of this file will be displayed in the tutorial app’s code editor and will be run in its preview. You can place any number of files in this folder.

The _solution folder contains the code for the lesson in its solved state. This is the code that the user will see when they click the “Solve” button in the tutorial app. The folder usually contains the same files as the _files folder, but with the code filled in. It may also include additional files.

Code templates

For the code to run in the preview, it must be an actual, working application, including a dev server and any necessary configuration files. Usually, it’s not practical to include this kind of boilerplate files in a lesson content (and copy it for every further lesson!). Instead, you can use the template feature of TutorialKit to provide a base project that will be used for all lessons.

To display the code in the preview of a lesson, TutorialKit will use the template project and apply the content of the _files (or _solution) folder on top of it.

You can find the default template in the src/templates/default directory. This is a Vite project which is a great starting point for a vanilla JavaScript app. Note, that when you navigate to that folder and run npm run dev inside, it will be a fully working Vite project.

You can modify this template to fit your needs, or create a new one from scratch. You can also have multiple templates and switch between them for different parts of your tutorial. To do that, you need to specify the template name in the lesson’s, chapter’s, or part’s front matter block:

---
title: Advanced Topics
template: my-advanced-template
---

This declaration will make TutorialKit use the src/templates/my-advanced-template directory as the base for the lesson.

If you start having a lot of templates and they all share some files, you can create a shared template that they all extend. This way, you can keep the shared files in one place and avoid duplication. To do that, you need to specify the extends property in the template’s .tk-config.json file:

{
"extends": "../shared-template"
}

This will make the template inherit all files from the shared-template directory. You can then override any file in the template by placing a file with the same name in the template’s directory. Here’s an example of how you can structure your templates:

src/templates
├── shared-template
│ ├── index.js
│ ├── index.html
│ └── package.json
└── first-template
│ │ # Contains { "extends": "../shared-template" }
│ │ # Inherits all files from "shared-template"
│ ├── .tk-config.json
│ │
│ │ # Only available in first-template
│ └── main.js
└── second-template
│ # Contains { "extends": "../shared-template" }
│ # Inherits all files from "shared-template"
├── .tk-config.json
│ # Overrides "index.js" from "shared-template"
└── index.js

Markdown and MDX Support

TutorialKit comes with built-in support for both Markdown and MDX, powered by Astro. This means you can leverage all Markdown and MDX features when creating lesson content. To explore the full capabilities, check out Astro’s Markdown support and MDX support documentation for more details.

Callouts

Callouts are visual elements designed to highlight specific information or provide additional context within a document or user interface. They are ideal for drawing attention to important tips, warnings, and other key messages.

You can create callouts using the following types: tip, info, warn, danger and success.

:::info
Some info with some markdown `syntax` and a [`link`](https://tutorialkit.dev/).
Here's a normal [link](https://tutorialkit.dev/).
:::

Content

To customize the styles of a callout, check out the theming reference.

Code blocks

TutorialKit offers a comprehensive set of code block features powered by Expressive Code. It includes all core features, along with optional plugins like collapsible sections and line numbers. For a full overview, check out the Expressive Code documentation.

content.md
```js title="code.js" ins={4} del={5} {6} "greeting"
const greeting = 'Hello, World!';
// This is a comment
const added = 'This line was added';
const removed = 'This line was removed';
const highlighted = 'This line is highlighted';
```
code.js
const greeting = 'Hello, World!';
// This is a comment
const added = 'This line was added';
const removed = 'This line was removed';
const highlighted = 'This line is highlighted';

Useful Expressive Code Attributes

  • title - Sets the title of the code block.
  • frame - Defines the frame of the code block. Options: "code", "terminal", "none", "auto".
  • showLineNumbers - Displays line numbers. You can combine this with startLineNumber=# to begin numbering from a specific line.
  • wrap - Controls word wrapping. Use preserveIndent and preserveIndent=false to adjust indentation handling.
Marking Lines
  • {x} - Marks specific lines. For example, {6,10-18} will mark lines 6 and 10 through 18.
  • ins - Marks inserted lines. Example: ins={6,10-18}.
  • del - Marks deleted lines. Example: del={6,10-18}.
  • {"Label":x} - Assigns a label to a line or range of lines. Works with mark, ins, and del. Example: {"Label1":5} del={"Label2":7-8} ins={"Label3":10-12}. If the label is long, consider placing an empty line in the code for better readability.
  • collapse={X-Y} - Collapses the specified lines. Example: collapse={1-5,12-14}.
Marking Text

You can highlight text using strings or regular expressions. For example:

content.md
```jsx title="code.js" "hello" /ye[sp]/ add=/add[12]/ del=/remove[12]/
console.log(
'Hello, the words yes and yep will be marked. Also add1, add2, remove1, remove2',
)
```
code.js
console.log(
'Hello, the words yes and yep will be marked. Also add1, add2, remove1, remove2',
)

Importing files

In addition to Expressive Code features, you can import files from your code template _files and _solution folders using the file or solution shortcodes. These shortcodes insert the content of the specified file directly into your lesson content.

  • file shortcode is used to reference files from the lesson _files or code template folder.
  • solution shortcode is used to reference files from the lesson _solution folder.

For example, the following code will insert the content of the box.css file from the _files folder:

```file:/box.css
```
.box {
width: 100px;
height: 100px;
background-color: red;
}