Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mdbook Embedify

Crates.io Crates.io

This is a mdbook preprocessor plugin that allows you to embed apps to your book, like youtube, codepen, giscus and many other apps.

Copyright © 2025 • Created with ❤️ by MR-Addict

Usage

Installation

There are two ways to install this preprocessor.

You can install it from crates.io using cargo.

cargo install mdbook-embedify

Or you can download the binary from releases page.

Then you can check your installation by running:

mdbook-embedify --version

After installation, add the following code to your book.toml file:

[preprocessor.embedify]

And that’s it! You can now use embed macro to embed apps to your book.

Syntax

The basic syntax is like this:

{% embed app options[] %}

options are key-value based array seperated by space and its value should be wrapped by quotes.

For example:

{% embed codepen user="MR-Addict" slug="NWBOqKw" height="600" theme="dark" loading="lazy" %}

See more examples at apps section.

Copyright © 2025 • Created with ❤️ by MR-Addict

Ignore Embeds

Sometimes you may want preprocessor to ignore some embeds.

There are two ways to do it:

  • Inline: You can use {% embed-ignore %} syntax to ignore the embed in the current line.
  • Block: You can use comments to wrap the content you want to ignore.

Inline Ignore

To ignore an embed in the current line, you can use the {% embed-ignore %}. The preprocessor will automatically convert it to {% embed %}:

For example:

{% embed-ignore youtube id="DyTCOwB0DVw" loading="lazy" %}

Will be replaced as:

{% embed youtube id="DyTCOwB0DVw" loading="lazy" %}

Block Ignore

To ignore a block of embeds, you can use HTML comments to wrap the content you want to ignore. The preprocessor will not render any embeds inside these comments.

  • <!-- embed ignore begin -->
  • <!-- embed ignore end -->

For example:

<!-- embed ignore begin -->
{% embed youtube id="DyTCOwB0DVw" loading="lazy" %}
<!-- embed ignore end -->

Will also be shown as:

{% embed youtube id="DyTCOwB0DVw" loading="lazy" %}

Priorities

Block ignore has higher priority than inline ignore, so if you wrap an inline ignore in a block ignore, it will keep as it is and will not be changed.

For example:

<!-- embed ignore begin -->
{% embed-ignore youtube id="DyTCOwB0DVw" loading="lazy" %}
<!-- embed ignore end -->

Will be shown as:

{% embed-ignore youtube id="DyTCOwB0DVw" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Global Embedding

Some apps allow you to automatically embed to every chapter. You can do this by modifying book.toml file to enable them.

For example:

[preprocessor.embedify]
scroll-to-top.enable = true

Attention 💥

When you do this, you don’t need to add {% embed scroll-to-top %} manually. It will be automatically added it to every chapter. If you do, it will be rendered twice.

Below is a full list of apps that support global configuration:

[preprocessor.embedify]
scroll-to-top.enable = true

footer.enable = true
footer.message = "Copyright © 2025 • Created with ❤️ by [MR-Addict](https://github.com/MR-Addict)"

announcement-banner.enable = true
announcement-banner.id = "0.2.17"
announcement-banner.message = "*New version [0.2.17](https://github.com/MR-Addict/mdbook-embedify/releases/tag/0.2.17) relased*"

giscus.enable = true
giscus.repo = "MR-Addict/mdbook-embedify"
giscus.repo-id = "R_kgDOLCxX0Q"
giscus.category = "General"
giscus.category-id = "DIC_kwDOLCxX0c4CdGx-"
giscus.reactions-enabled = "1"
giscus.theme = "book"
giscus.lang = "en"
giscus.loading = "lazy"

You can see more details about each app at its own page.

Copyright © 2025 • Created with ❤️ by MR-Addict

Third Party Apps

Third party apps are apps that are hosted on third party sites. Below are all supported third party apps and its detailed options.

Copyright © 2025 • Created with ❤️ by MR-Addict

Gist

Gist is a simple way to share snippets and pastes with others. All gists are Git repositories, so they are automatically versioned, forkable and usable from Git.

Options

OptionDescriptionRequiredDefault
idGist IDYes- -

Example

{% embed gist id="76cf171d1bdd7da41d4ca96b908eb57a" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Vimeo

Vimeo is a video hosting platform that allows you to upload and share videos.

Options

OptionDescriptionRequiredDefault
idVideo IDYes- -
loadingSupports lazy and eagerNolazy

Example

{% embed vimeo id="914391191" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Giscus

Giscus is a comments system powered by GitHub Discussions. Let visitors leave comments and reactions on your website via GitHub! Heavily inspired by utterances.

Options

OptionDescriptionRequiredDefault
repoRepositoryYes- -
repo-idRepository IDYes- -
categoryCategoryYes- -
category-idCategory IDYes- -
reactions-enabledEnable reactionsNo1
themeSupports book, light and darkNobook
langLocalization languageNoen
loadingSupports lazy and eagerNolazy

Example

{% embed giscus repo="MR-Addict/mdbook-embedify" repo-id="R_XXXXXXXXXX" category="General" category-id="DIC_XXXXXXXXXXXXXXXX" theme="book" loading="eager" %}

This book’s giscus is enabled, you can see it at the bottom of this page. And you can also have a try by commenting below.

However, you may want to enable it for the whole book. You can do this by adding below options to book.toml file after [preprocessor.embedify] section:

giscus.enable = true
giscus.repo = "MR-Addict/mdbook-embedify"
giscus.repo-id = "R_XXXXXXXXXX"
giscus.category = "General"
giscus.category-id = "DIC_XXXXXXXXXXXXXXXX"
giscus.reactions-enabled = "1"
giscus.theme = "book"
giscus.lang = "en"
giscus.loading = "eager"

Refuse to Connect

Giscus will refuse to connect if you build and preview your book with file:// protocol. The easiest solution is to use some static server so that you can preview your book with http:// protocol.

For exampe:

node.js installed

npx serve book -p 3000

Which will serve your book at http://localhost:3000.

python installed

python -m http.server --directory book 8080

Which will serve your book at http://localhost:8080.

Copyright © 2025 • Created with ❤️ by MR-Addict

Youtube

YouTube is a popular online video sharing and social media platform.

Options

OptionDescriptionRequiredDefault
idVideo IDYes- -
loadingSupports lazy and eagerNolazy

Example

{% embed youtube id="DyTCOwB0DVw" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Codepen

Codepen is a social development environment for front-end designers and developers. It’s the best place to build and deploy a website, show off your work, build test cases, and find inspiration.

Options

OptionDescriptionRequiredDefault
userusernameYes- -
slugProject slugYes- -
heightIframe heightNo600
themeSupports light and darkNodark
loadingSupports lazy and eagerNolazy

Example

{% embed codepen user="MR-Addict" slug="NWBOqKw" height="600" theme="dark" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Stackblitz

Stackblitz is an instant fullstack web IDE for the JavaScript ecosystem. It’s powered by WebContainers, the first WebAssembly-based operating system which boots the Node.js environment in milliseconds, securely within your browser tab.

Options

OptionDescriptionRequiredDefault
idProject IDYes- -
themeSupports light and darkNodark
loadingSupports lazy and eagerNolazy

Example

{% embed stackblitz id="vitejs-vite-y8mdxg" theme="light" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Codesandbox

Codesandbox is an online code editor that allows you to create and share web applications. It is particularly useful for web developers who want to work on React, Vue, Angular, or any other front-end libraries.

Options

OptionDescriptionRequiredDefault
idProject IDYes- -
themeSupports light and darkNodark
loadingSupports lazy and eagerNolazy

Example

{% embed codesandbox id="ke8wx" theme="light" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Bilibili

Bilibili is a Chinese video sharing website based in Shanghai, themed around animation, comic, and games (ACG), where users can submit, view, and add commentary subtitles on videos.

Options

OptionDescriptionRequiredDefault
idVideo IDYes- -
loadingSupports lazy and eagerNolazy

Example

{% embed bilibili id="BV1uT4y1P7CX" loading="lazy" %}

Copyright © 2025 • Created with ❤️ by MR-Addict

Local Apps

Local apps are apps hosted on your local book, so it is not necessary to have internet connection to use them.

Below are all supported local apps and its detailed options.

Copyright © 2025 • Created with ❤️ by MR-Addict

Footer

The footer app is useful for displaying copyright information, privacy policy, and other legal information. It supports markdown syntax so that you can easily customize the message.

Options

OptionDescriptionRequiredDefault
messageFooter message, markdown supportedYes- -

Example

{% embed footer message="Copyright © 2025 • Created with ❤️ by [MR-Addict](https://github.com/MR-Addict)" %}

This book’s footer is enabled, you can see it at the bottom of this page.

However, you may want to enable it for the whole book. You can do this by adding below options to book.toml file after [preprocessor.embedify] section:

footer.message = "Copyright © 2025 • Created with ❤️ by [MR-Addict](https://github.com/MR-Addict)"

Copyright © 2025 • Created with ❤️ by MR-Addict

Include

Attention 💥

Support since v0.2.12.

Language is detected by file extension, which I manually edited from linguist. If you find any issues with the language detection, please open an issue.

The include app is for including source file or wrapped it as markdown code block.

The language is automatically detected by the file name extension. You can override it by passing lang option. The file path should be relative to book root directory.

Options

OptionDescriptionRequiredDefault
fileFile to include, relative to book root directoryYes- -
langThis will override the automatically detected languageNo- -
rangeRange of lines to include, e.g. 1-10 or 1- or -10No- -
typeInclude type, cloud be raw or codeblockNocodeblock

Attention 💥

  • When range is used, it will insert the specified lines starts from 1.
  • The raw type will insert the raw file content into the markdown file directly, while the codeblock type will wrap it as a code block.

Example

{% embed include file="src/SUMMARY.md" %}

This will include the src/SUMMARY.md file and wrap it as a markdown code block which is the source code of this book’s summary.

# Summary

# Basics

- [Intro](index.md)
- [Usage](usage.md)
- [Ignore Embeds](ignore-embeds.md)
- [Global Embedding](global-embedding.md)

# Apps

- [Third Party Apps](third-party/index.md)
  - [Gist](third-party/gist.md)
  - [Vimeo](third-party/vimeo.md)
  - [Giscus](third-party/giscus.md)
  - [Youtube](third-party/youtube.md)
  - [Codepen](third-party/codepen.md)
  - [Stackblitz](third-party/stackblitz.md)
  - [Codesandbox](third-party/codesandbox.md)
  - [Bilibili](third-party/bilibili.md)
- [Local Apps](local/index.md)
  - [Footer](local/footer.md)
  - [Include](local/include.md)
  - [Scroll to Top](local/scroll-to-top.md)
  - [Announcement Banner](local/announcement-banner.md)

# Development

- [Development Guide](development/index.md)
  - [Testing Guide](development/testing.md)
  - [Template System](development/template.md)
  - [Language Matching](development/language-matching.md)

# CHANGELOG

- [CHANGELOG](CHANGELOG.md)

Copyright © 2025 • Created with ❤️ by MR-Addict

Scroll to top button

Scroll to top button allows users to quickly smoothly scroll back to the top of the page.

Options

Scroll to top button app has no options.

Example

{% embed scroll-to-top %}

Typically, we want to use it for the whole book. You can do this by adding below options to book.toml file after [preprocessor.embedify] section:

scroll-to-top.enable = true

This book uses this option. You can see it at the bottom right corner of this page. But it only shows when pages are long enough to scroll. Or you can see it my another book Notes.

Copyright © 2025 • Created with ❤️ by MR-Addict

Announcement Banner

Announcement banner allows you put important messages at the top of the page. It supports markdown syntax too.

Options

OptionDescriptionRequiredDefault
idAnnouncement idYes- -
messageAnnouncement message, markdown supportedYes- -

Example

{% embed announcement-banner id="0.2.17" message="*New version [0.2.17](https://github.com/MR-Addict/mdbook-embedify/releases/tag/0.2.17) relased*" %}

This book’s announcement banner is enabled, you can see it at the top of this page.

However, you may want to enable it for the whole book. You can do this by adding below options to book.toml file after [preprocessor.embedify] section:

announcement-banner.enable = true
announcement-banner.id = "0.2.17"
announcement-banner.message = "*New version [0.2.17](https://github.com/MR-Addict/mdbook-embedify/releases/tag/0.2.17) relased*"

Note that announcement banner id must be unique, otherwise it won’t be shown if there is another announcement banner with the same id when user closed it.

Copyright © 2025 • Created with ❤️ by MR-Addict

Development Guide

This guide provides an overview of how to develop custom embed applications for mdBook.

Copyright © 2025 • Created with ❤️ by MR-Addict

Testing Guide

Pre-requisites

Ensure you have the following installed:

Make sure you have the same mdbook version installed as the one used in the project.

You can find the version in the Cargo.toml file under the [dependencies] section.

Test Suite Overview

mdbook-embedify covering these critical modules:

ModuleCoverage
Book TestingReal book building and validation
Parser TestingPlaceholder & embed syntax parsing
Language DetectionFile extension to language mapping

Quick Commands

# Run complete test suite
cargo test

# Run specific test suites
cargo test --test book
cargo test --test parser
cargo test --test detect_lang

# Run tests quietly
cargo test -- --quiet

# Run with detailed output
cargo test -- --nocapture

# Run tests with timing information
cargo test -- --show-output

Copyright © 2025 • Created with ❤️ by MR-Addict

Template System

Attention 💥

Support since v0.2.14.

The template system allows you to create custom embed applications that aren’t supported by the built-in preprocessor. This powerful feature enables you to extend mdbook-embedify with your own interactive components and dynamic content.

Real world example 💡

You can take a looke of my notes book.

It supports caption and preview with much more complex behavior.

Dynamic vs Static Content

Custom templates act like dynamic reusable components. If you want to just copy static content, you should use the include app instead.

Creating a Custom App

Template Folder Setup

Templates must be placed in the assets/templates folder (relative to your book.toml file).

Configure the template folder (optional):

[preprocessor.embedify]
custom-templates-folder = "assets/templates"

📍 Path Requirements:

The template folder path must be relative to the book root directory (where book.toml is located).

Template File Naming

The template filename becomes the app name:

Template FileApp NameUsage
canvas.htmlcanvas{% embed canvas %}
my-widget.htmlmy-widget{% embed my-widget %}
youtube.htmlyoutube{% embed youtube %} (overrides built-in)

⚠️ Override Behavior:

If your custom app name matches a built-in app, the custom template will override the built-in functionality.

Example: Creating a Canvas App

Let’s create a canvas app - a simple drawable canvas component.

Step 1: Create the template file (assets/templates/canvas.html)

Basic HTML structure with styling:

<div class="canvas-container">
  <canvas height="400"></canvas>
</div>
<style>
  .canvas-container {
    width: 100%;
    background: white;
    border-radius: 1rem;
    border: 1px solid #ccc;

    background-size: 20px 20px;
    background-image: linear-gradient(to right, #eee 1px, transparent 1px),
      linear-gradient(to bottom, #eee 1px, transparent 1px);
  }
</style>

Add interactive JavaScript:

<script>
  document.addEventListener("DOMContentLoaded", () => {
    const container = document.querySelector(".canvas-container");
    const canvas = container.querySelector("canvas");
    const ctx = canvas.getContext("2d");
    const resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) canvas.width = entry.contentRect.width;
    });
    resizeObserver.observe(container);

    let drawing = false;
    const lastPos = { x: 0, y: 0 };

    // Draw a line from last position to current position
    function draw(x, y) {
      ctx.beginPath();
      ctx.moveTo(lastPos.x, lastPos.y);
      ctx.lineTo(x, y);
      ctx.stroke();
      lastPos.x = x;
      lastPos.y = y;
    }

    // Mouse events
    canvas.addEventListener("mousedown", (e) => {
      drawing = true;
      lastPos.x = e.offsetX;
      lastPos.y = e.offsetY;
    });

    canvas.addEventListener("mousemove", (e) => {
      if (!drawing) return;
      draw(e.offsetX, e.offsetY);
    });

    canvas.addEventListener("mouseup", () => (drawing = false));
    canvas.addEventListener("mouseout", () => (drawing = false));

    // Touch events
    canvas.addEventListener("touchstart", (e) => {
      if (e.touches.length !== 1) return;
      e.preventDefault();
      drawing = true;

      const rect = canvas.getBoundingClientRect();
      lastPos.x = e.touches[0].clientX - rect.left;
      lastPos.y = e.touches[0].clientY - rect.top;
    });

    canvas.addEventListener("touchmove", (e) => {
      if (!drawing || e.touches.length !== 1) return;
      e.preventDefault();
      const rect = canvas.getBoundingClientRect();
      const x = e.touches[0].clientX - rect.left;
      const y = e.touches[0].clientY - rect.top;
      draw(x, y);
    });

    canvas.addEventListener("touchend", () => (drawing = false));
    canvas.addEventListener("touchcancel", () => (drawing = false));
  });
</script>

CSS & JavaScript Integration 💡

You can include CSS and JavaScript directly in template files using <style> and <script> blocks.

Step 2: Add dynamic height support

Make the canvas height configurable using placeholder syntax:

<canvas height="{% height=400 %}"></canvas>

This allows users to customize the height: {% embed canvas height=600 %}

Placeholder Syntax

The template system supports two types of dynamic content:

Syntax Types

TypeSyntaxPurposeExample
Placeholder{% key=default %}Variable substitution{% height=400 %}
Processor{% processor(key=default) %}Content transformation{% markdown(content) %}

Placeholder Examples

SyntaxBehaviorUse Case
{% height %}Required - User must provide valueMandatory configuration
{% height=400 %}Optional - Uses default if not providedOptional configuration
{% markdown(message) %}Processed - Content transformed by processorDynamic content rendering

Available Processors

ProcessorPurposeInputOutput
markdownRenders markdown to HTMLMarkdown textHTML content

Example usage:

<div class="content">{% markdown(description="Description in **markdown**") %}</div>

Complete Canvas Template

Here’s the complete template file for our canvas app:

<div class="canvas-container">
  <canvas height="{% height=400 %}"></canvas>
</div>
<style>
  .canvas-container {
    width: 100%;
    background: white;
    border-radius: 1rem;
    border: 1px solid #ccc;

    background-size: 20px 20px;
    background-image: linear-gradient(to right, #eee 1px, transparent 1px),
      linear-gradient(to bottom, #eee 1px, transparent 1px);
  }
</style>
<script>
  document.addEventListener("DOMContentLoaded", () => {
    const container = document.querySelector(".canvas-container");
    const canvas = container.querySelector("canvas");
    const ctx = canvas.getContext("2d");
    const resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) canvas.width = entry.contentRect.width;
    });
    resizeObserver.observe(container);

    let drawing = false;
    const lastPos = { x: 0, y: 0 };

    // Draw a line from last position to current position
    function draw(x, y) {
      ctx.beginPath();
      ctx.moveTo(lastPos.x, lastPos.y);
      ctx.lineTo(x, y);
      ctx.stroke();
      lastPos.x = x;
      lastPos.y = y;
    }

    // Mouse events
    canvas.addEventListener("mousedown", (e) => {
      drawing = true;
      lastPos.x = e.offsetX;
      lastPos.y = e.offsetY;
    });

    canvas.addEventListener("mousemove", (e) => {
      if (!drawing) return;
      draw(e.offsetX, e.offsetY);
    });

    canvas.addEventListener("mouseup", () => (drawing = false));
    canvas.addEventListener("mouseout", () => (drawing = false));

    // Touch events
    canvas.addEventListener("touchstart", (e) => {
      if (e.touches.length !== 1) return;
      e.preventDefault();
      drawing = true;

      const rect = canvas.getBoundingClientRect();
      lastPos.x = e.touches[0].clientX - rect.left;
      lastPos.y = e.touches[0].clientY - rect.top;
    });

    canvas.addEventListener("touchmove", (e) => {
      if (!drawing || e.touches.length !== 1) return;
      e.preventDefault();
      const rect = canvas.getBoundingClientRect();
      const x = e.touches[0].clientX - rect.left;
      const y = e.touches[0].clientY - rect.top;
      draw(x, y);
    });

    canvas.addEventListener("touchend", () => (drawing = false));
    canvas.addEventListener("touchcancel", () => (drawing = false));
  });
</script>

Using Your Custom App

Basic Usage

After creating the template file, use your app in your book:

{% embed canvas height=400 %}

With Default Values

Since height has a default value of 400, you can omit it:

{% embed canvas %}

Interactive Example

Test the canvas app by drawing on it:

Contributing Templates

Want to share your custom templates with the community?

For Personal Use

  • Keep templates in your assets/templates/ folder
  • Customize as needed for your specific use case

For Community Contribution

Copyright © 2025 • Created with ❤️ by MR-Addict

Language Matching System

Attention 💥

Support since v0.2.17.

The language detection system is used for include app to provide accurate syntax highlighting based on file paths.

Overview

The language detection system intelligently identifies programming languages from file paths using a sophisticated three-tier matching system with clear precedence rules:

PriorityMethodExampleDescription
1st (Highest)Exact filenameDockerfiledockerfilePerfect filename matches
2ndFile extensionscript.jsjavascriptExtension-based detection
3rd (Lowest)Wildcard patternDockerfile.proddockerfileFlexible pattern matching

Configuration System

Configuration Location

Language definitions are stored in src/assets/config/languages.json. Each language entry supports multiple matching strategies.

Language Definition Structure

{
  "name": "dockerfile",
  "extensions": [".dockerfile"],
  "filenames": ["Dockerfile", "dockerfile", "Containerfile", "Dockerfile.*", "dockerfile.*", "*.dockerfile"]
}
PropertyTypePurposeExample
nameStringLanguage identifier for syntax highlighting"javascript"
extensionsArrayFile extensions (with dots)[".js", ".jsx"]
filenamesArrayExact filenames and wildcard patterns["Dockerfile", "Makefile.*", "*.config.js"]

Wildcard Pattern Syntax

Supported Wildcards

WildcardRegexDescriptionExample PatternMatches
*.*Zero or more charactersDockerfile.*Dockerfile.base, Dockerfile.production
?.Exactly one charactertest?.txttest1.txt, testa.txt

Examples

🐳 Dockerfile Variants

FilenameResultReason
Dockerfiledockerfile✅ Exact match (non-wildcard entry)
Dockerfile.basedockerfile🔍 Pattern: Dockerfile.* (wildcard entry)
Dockerfile.productiondockerfile🔍 Pattern: Dockerfile.* (wildcard entry)
dockerfile.devdockerfile🔍 Pattern: dockerfile.* (wildcard entry)
web.dockerfiledockerfile🔍 Pattern: *.dockerfile (wildcard entry)
api.dockerfiledockerfile🔍 Pattern: *.dockerfile (wildcard entry)
Dockerfile.jsjavascript📁 Extension: .js (overrides pattern)

🔨 Makefile Variants

FilenameResultReason
Makefilemakefile✅ Exact match (non-wildcard entry)
Makefile.localmakefile🔍 Pattern: Makefile.* (wildcard entry)
Makefile.ammakefile✅ Exact match (non-wildcard entry)
custom.makefilemakefile📁 Extension: .makefile
build.mkmakefile📁 Extension: .mk

🐚 Shell Configuration Files

FilenameResultReason
.bashrcshell✅ Exact match (non-wildcard entry)
.zshrcshell✅ Exact match (non-wildcard entry)
custom.bashrcshell🔍 Pattern: *.bashrc (wildcard entry)
my.profileshell🔍 Pattern: *.profile (wildcard entry)
script.shshell📁 Extension: .sh

📦 Configuration Files

FilenameResultReason
package.jsonjson📁 Extension: .json
tsconfig.jsonjson📁 Extension: .json
webpack.config.jsjavascript📁 Extension: .js
.eslintrc.jsonjson📁 Extension: .json

Copyright © 2025 • Created with ❤️ by MR-Addict

Changelog

This page tracks all notable changes to mdbook-embedify. The format is based on Keep a Changelog.

[0.2.17] - 2025-01-05 🎉

✨ New Features

  • Embed Ignore Functionality: You can now prevent specific embed blocks from being processed using embed-ignore

    {% embed-ignore codepen user="example" slug="demo" %}
    

    This is perfect for documentation where you want to show embed syntax without processing it.

  • Comprehensive Testing Suite: Added robust testing framework including:

    • Book integration tests that validate entire mdbook builds
    • Parser testing for embed syntax validation
    • Language detection testing
    • Automated comparison of generated vs expected output
  • Enhanced Language Detection: Major improvements to file extension mapping:

    • Support for wildcard matching in filename patterns
    • Multi-dot file extensions (.spec.ts, .test.js, etc.)
    • More accurate language detection using consolidated patterns
  • Development Documentation: Added comprehensive guides for contributors and developers

🔧 Improvements

  • Include App Enhancements:

    • Added type and range options for more flexible content inclusion
    • Better handling of markdown files with automatic code block wrapping
    • Wildcard matching support for include files
  • Custom Template Support: Configure custom templates folder for your specific needs

  • Better Error Reporting: Enhanced error messages throughout the system

🐛 Bug Fixes

  • Improved mdbook installation process with existing installation checks
  • Fixed language detection issues with complex file extensions
  • Resolved regex handling problems
  • Better handling of draft chapters
  • Fixed various CI/CD workflow issues

🔧 Technical Improvements

  • Rewritten parser using Rust Pest for better performance
  • Enhanced HTML minification process
  • Canvas template improvements with dynamic height and touch support

[0.2.16] - 2024-12-XX

✨ New Features

  • Advanced Language Detection: Integrated hyperpolyglot for improved language detection accuracy
  • Version number display in documentation interface

[0.2.15] - 2024-12-XX

✨ New Features

  • Enhanced canvas template with dynamic height and touch support

🔧 Improvements

  • HTML minification now removes style and script comments for cleaner output

[0.2.14] - 2024-12-XX

✨ New Features

  • Custom Templates: Full support for custom templates in embed preprocessor
  • Canvas App Template: New interactive canvas template for dynamic content

📚 Documentation

  • Updated guides for creating new apps and using templates

[0.2.13] - 2024-12-XX

✨ New Features

  • Enhanced Include App: Added type and range options for precise content inclusion

🔧 Improvements

  • Better error reporting and validation across the board

[0.2.12] - 2024-12-XX

✨ New Features

  • Include App: Brand new functionality for embedding content from other files
  • Enhanced markdown code block support for better formatting

🐛 Bug Fixes

  • Proper handling of draft chapters in mdbook
  • Improved markdown file processing and rendering

🚀 What’s Next?

Stay tuned for upcoming features and improvements! Check our GitHub repository for the latest updates and to contribute to the project.

🤝 Contributing

Found a bug or have a feature request? We’d love to hear from you:

Copyright © 2025 • Created with ❤️ by MR-Addict