Mdbook Embedify
This is a mdbook preprocessor plugin that allows you to embed apps to your book, like youtube, codepen, giscus and many other apps.
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.
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" %}
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.
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.
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
Option | Description | Required | Default |
---|---|---|---|
id | Gist ID | Yes | - - |
Example
{% embed gist id="76cf171d1bdd7da41d4ca96b908eb57a" %}
Vimeo
Vimeo is a video hosting platform that allows you to upload and share videos.
Options
Option | Description | Required | Default |
---|---|---|---|
id | Video ID | Yes | - - |
loading | Supports lazy and eager | No | lazy |
Example
{% embed vimeo id="914391191" loading="lazy" %}
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
Option | Description | Required | Default |
---|---|---|---|
repo | Repository | Yes | - - |
repo-id | Repository ID | Yes | - - |
category | Category | Yes | - - |
category-id | Category ID | Yes | - - |
reactions-enabled | Enable reactions | No | 1 |
theme | Supports book, light and dark | No | book |
lang | Localization language | No | en |
loading | Supports lazy and eager | No | lazy |
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.
Youtube
YouTube is a popular online video sharing and social media platform.
Options
Option | Description | Required | Default |
---|---|---|---|
id | Video ID | Yes | - - |
loading | Supports lazy and eager | No | lazy |
Example
{% embed youtube id="DyTCOwB0DVw" loading="lazy" %}
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
Option | Description | Required | Default |
---|---|---|---|
user | username | Yes | - - |
slug | Project slug | Yes | - - |
height | Iframe height | No | 600 |
theme | Supports light and dark | No | dark |
loading | Supports lazy and eager | No | lazy |
Example
{% embed codepen user="MR-Addict" slug="NWBOqKw" height="600" theme="dark" loading="lazy" %}
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
Option | Description | Required | Default |
---|---|---|---|
id | Project ID | Yes | - - |
theme | Supports light and dark | No | dark |
loading | Supports lazy and eager | No | lazy |
Example
{% embed stackblitz id="vitejs-vite-y8mdxg" theme="light" loading="lazy" %}
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
Option | Description | Required | Default |
---|---|---|---|
id | Project ID | Yes | - - |
theme | Supports light and dark | No | dark |
loading | Supports lazy and eager | No | lazy |
Example
{% embed codesandbox id="ke8wx" theme="light" loading="lazy" %}
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
Option | Description | Required | Default |
---|---|---|---|
id | Video ID | Yes | - - |
loading | Supports lazy and eager | No | lazy |
Example
{% embed bilibili id="BV1uT4y1P7CX" loading="lazy" %}
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.
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
Option | Description | Required | Default |
---|---|---|---|
message | Footer message, markdown supported | Yes | - - |
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)"
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
Option | Description | Required | Default |
---|---|---|---|
file | File to include, relative to book root directory | Yes | - - |
lang | This will override the automatically detected language | No | - - |
range | Range of lines to include, e.g. 1-10 or 1- or -10 | No | - - |
type | Include type, cloud be raw or codeblock | No | codeblock |
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 thecodeblock
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)
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.
Announcement Banner
Announcement banner allows you put important messages at the top of the page. It supports markdown syntax too.
Options
Option | Description | Required | Default |
---|---|---|---|
id | Announcement id | Yes | - - |
message | Announcement message, markdown supported | Yes | - - |
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.
Development Guide
This guide provides an overview of how to develop custom embed applications for mdBook.
- Testing Guide - Learn how to write and run tests
- Template System - Create custom embed applications
- Language Matching - Understand file language detection
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:
Module | Coverage |
---|---|
Book Testing | Real book building and validation |
Parser Testing | Placeholder & embed syntax parsing |
Language Detection | File 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
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 File | App Name | Usage |
---|---|---|
canvas.html | canvas | {% embed canvas %} |
my-widget.html | my-widget | {% embed my-widget %} |
youtube.html | youtube | {% 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
Type | Syntax | Purpose | Example |
---|---|---|---|
Placeholder | {% key=default %} | Variable substitution | {% height=400 %} |
Processor | {% processor(key=default) %} | Content transformation | {% markdown(content) %} |
Placeholder Examples
Syntax | Behavior | Use Case |
---|---|---|
{% height %} | Required - User must provide value | Mandatory configuration |
{% height=400 %} | Optional - Uses default if not provided | Optional configuration |
{% markdown(message) %} | Processed - Content transformed by processor | Dynamic content rendering |
Available Processors
Processor | Purpose | Input | Output |
---|---|---|---|
markdown | Renders markdown to HTML | Markdown text | HTML 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
- Fork the mdbook-embedify repository
- Add your template to src/assets/templates
- Submit a pull request with documentation
- Include examples and usage instructions
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:
Priority | Method | Example | Description |
---|---|---|---|
1st (Highest) | Exact filename | Dockerfile → dockerfile | Perfect filename matches |
2nd | File extension | script.js → javascript | Extension-based detection |
3rd (Lowest) | Wildcard pattern | Dockerfile.prod → dockerfile | Flexible 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"]
}
Property | Type | Purpose | Example |
---|---|---|---|
name | String | Language identifier for syntax highlighting | "javascript" |
extensions | Array | File extensions (with dots) | [".js", ".jsx"] |
filenames | Array | Exact filenames and wildcard patterns | ["Dockerfile", "Makefile.*", "*.config.js"] |
Wildcard Pattern Syntax
Supported Wildcards
Wildcard | Regex | Description | Example Pattern | Matches |
---|---|---|---|---|
* | .* | Zero or more characters | Dockerfile.* | Dockerfile.base , Dockerfile.production |
? | . | Exactly one character | test?.txt | test1.txt , testa.txt |
Examples
🐳 Dockerfile Variants
Filename | Result | Reason |
---|---|---|
Dockerfile | dockerfile | ✅ Exact match (non-wildcard entry) |
Dockerfile.base | dockerfile | 🔍 Pattern: Dockerfile.* (wildcard entry) |
Dockerfile.production | dockerfile | 🔍 Pattern: Dockerfile.* (wildcard entry) |
dockerfile.dev | dockerfile | 🔍 Pattern: dockerfile.* (wildcard entry) |
web.dockerfile | dockerfile | 🔍 Pattern: *.dockerfile (wildcard entry) |
api.dockerfile | dockerfile | 🔍 Pattern: *.dockerfile (wildcard entry) |
Dockerfile.js | javascript | 📁 Extension: .js (overrides pattern) |
🔨 Makefile Variants
Filename | Result | Reason |
---|---|---|
Makefile | makefile | ✅ Exact match (non-wildcard entry) |
Makefile.local | makefile | 🔍 Pattern: Makefile.* (wildcard entry) |
Makefile.am | makefile | ✅ Exact match (non-wildcard entry) |
custom.makefile | makefile | 📁 Extension: .makefile |
build.mk | makefile | 📁 Extension: .mk |
🐚 Shell Configuration Files
Filename | Result | Reason |
---|---|---|
.bashrc | shell | ✅ Exact match (non-wildcard entry) |
.zshrc | shell | ✅ Exact match (non-wildcard entry) |
custom.bashrc | shell | 🔍 Pattern: *.bashrc (wildcard entry) |
my.profile | shell | 🔍 Pattern: *.profile (wildcard entry) |
script.sh | shell | 📁 Extension: .sh |
📦 Configuration Files
Filename | Result | Reason |
---|---|---|
package.json | json | 📁 Extension: .json |
tsconfig.json | json | 📁 Extension: .json |
webpack.config.js | javascript | 📁 Extension: .js |
.eslintrc.json | json | 📁 Extension: .json |
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
andrange
options for more flexible content inclusion - Better handling of markdown files with automatic code block wrapping
- Wildcard matching support for include files
- Added
-
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
andrange
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: