Skip to content

Commit

Permalink
feat: optimise project structure and add new footer local app
Browse files Browse the repository at this point in the history
  • Loading branch information
MR-Addict committed Feb 13, 2024
1 parent 4e08b2f commit 6cfeab2
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 70 deletions.
7 changes: 2 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions example/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ command = "target/release/mdbook-embedify"

scroll-to-top.enable = true

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

announcement-banner.enable = true
announcement-banner.id = "0.2.4"
announcement-banner.theme = "default"
Expand Down
6 changes: 6 additions & 0 deletions example/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Summary

# Basics

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

# Apps

- [Third Party Apps](third-party/intro.md)
- [Gist](third-party/gist.md)
- [Giscus](third-party/giscus.md)
Expand All @@ -13,5 +18,6 @@
- [Codesandbox](third-party/codesandbox.md)
- [Bilibili](third-party/bilibili.md)
- [Local Apps](local/intro.md)
- [Footer](local/footer.md)
- [Scroll to Top](local/scroll-to-top.md)
- [Announcement Banner](local/announcement-banner.md)
3 changes: 3 additions & 0 deletions example/src/global-embedding.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Below is a full list of apps that support global configuration:
[preprocessor.embedify]
scroll-to-top.enable = true

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

announcement-banner.enable = true
announcement-banner.id = "0.2.4"
announcement-banner.theme = "default"
Expand Down
2 changes: 1 addition & 1 deletion example/src/local/announcement-banner.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Announcement Banner

Announcement banner allows you put important messages at the top of the page. It supports **markdown** syntax so that you can easily customize the message.
Announcement banner allows you put important messages at the top of the page. It supports **markdown** syntax too.

## Options

Expand Down
29 changes: 29 additions & 0 deletions example/src/local/footer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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 ignore begin -->

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

<!-- embed ignore end -->

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:

```toml
[preprocessor.embedify]
footer.enable = true
footer.message = "Copyright © 2024 • Created with ❤️ by [MR-Addict](https://github.com/MR-Addict)"
```
1 change: 1 addition & 0 deletions example/src/local/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ Local apps are apps hosted on your local book, so it is not necessary to have in

Below are all supported local apps and its detailed options.

- [Footer](footer.md)
- [Scroll To Top](scroll-to-top.md)
- [Announcement Banner](announcement-banner.md)
16 changes: 16 additions & 0 deletions src/cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use mdbook::Config;

pub fn get_config_bool(config: &Config, key: &str) -> bool {
config
.get(format!("preprocessor.embedify.{}", key).as_str())
.and_then(|v| v.as_bool())
.unwrap_or(false)
}

pub fn get_config_string(config: &Config, key: &str, default: &str) -> String {
config
.get(format!("preprocessor.embedify.{}", key).as_str())
.and_then(|v| v.as_str())
.unwrap_or(default)
.to_string()
}
48 changes: 48 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use clap::{Arg, Command};
use mdbook::preprocess::Preprocessor;
use std::{
io::{self, IsTerminal},
process,
};

pub struct Cli {
pub cmd: Command,
}

impl Cli {
pub fn new() -> Self {
let cmd = Command::new("mdbook-embedify")
.version(env!("CARGO_PKG_VERSION"))
.about("A mdbook embed preprocessor that embeds app to your book")
.subcommand(
Command::new("supports")
.arg(Arg::new("renderer").required(true))
.about("Check whether a renderer is supported by this preprocessor"),
);

let matches = cmd.clone().get_matches();
if !matches.args_present() {
if io::stdin().is_terminal() {
cmd.clone().print_help().unwrap();
process::exit(1);
}
}

Self { cmd }
}

pub fn reply_supports(&self, pre: &dyn Preprocessor) {
let matches = self.cmd.clone().get_matches();
if let Some(sub_args) = matches.subcommand_matches("supports") {
// get the renderer
let renderer = sub_args.get_one::<String>("renderer").unwrap();

// signal whether the renderer is supported by exiting with 1 or 0.
if pre.supports_renderer(renderer) {
process::exit(0);
} else {
process::exit(1);
}
}
}
}
46 changes: 32 additions & 14 deletions src/embed.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::cfg;
use crate::utils;

use mdbook::{
book::Book,
errors::Error,
Expand All @@ -17,6 +19,7 @@ impl Embed {

fn render_general_embeds(content: String) -> String {
let mut content = content;

// create a regex to match <!-- embed ignore begin -->...<!-- embed ignore end -->
let re_ignore =
Regex::new(r"(?s)<!-- embed ignore begin -->(.*)<!-- embed ignore end -->").unwrap();
Expand All @@ -35,7 +38,7 @@ fn render_general_embeds(content: String) -> String {
let re_embed = Regex::new(r"\{% embed ([\w-]+)(.*) %\}").unwrap();
content = re_embed
.replace_all(&content, |caps: &regex::Captures| {
// parse app and options str
// parse app and options
let app = caps.get(1).map_or("", |m| m.as_str());
let options_str = caps.get(2).map_or("", |m| m.as_str());

Expand All @@ -57,9 +60,9 @@ fn render_general_embeds(content: String) -> String {

fn render_announcement_banner(config: &Config) -> String {
// get the config
let id = utils::get_config_string(config, "announcement-banner.id", "");
let theme = utils::get_config_string(config, "announcement-banner.theme", "default");
let message = utils::get_config_string(config, "announcement-banner.message", "");
let id = cfg::get_config_string(config, "announcement-banner.id", "");
let theme = cfg::get_config_string(config, "announcement-banner.theme", "default");
let message = cfg::get_config_string(config, "announcement-banner.message", "");

// render the template
let options = vec![
Expand All @@ -72,13 +75,13 @@ fn render_announcement_banner(config: &Config) -> String {

fn render_giscus(config: &Config) -> String {
// get the config
let repo = utils::get_config_string(config, "giscus.repo", "");
let repo_id = utils::get_config_string(config, "giscus.repo-id", "");
let category = utils::get_config_string(config, "giscus.category", "");
let category_id = utils::get_config_string(config, "giscus.category-id", "");
let reactions_enabled = utils::get_config_string(config, "giscus.reactions-enabled", "1");
let theme = utils::get_config_string(config, "giscus.theme", "light");
let lang = utils::get_config_string(config, "giscus.lang", "en");
let repo = cfg::get_config_string(config, "giscus.repo", "");
let repo_id = cfg::get_config_string(config, "giscus.repo-id", "");
let category = cfg::get_config_string(config, "giscus.category", "");
let category_id = cfg::get_config_string(config, "giscus.category-id", "");
let reactions_enabled = cfg::get_config_string(config, "giscus.reactions-enabled", "1");
let theme = cfg::get_config_string(config, "giscus.theme", "light");
let lang = cfg::get_config_string(config, "giscus.lang", "en");

// render the template
let options = vec![
Expand All @@ -93,6 +96,15 @@ fn render_giscus(config: &Config) -> String {
utils::render_template("giscus", &options)
}

fn render_footer(config: &Config) -> String {
// get the config
let message = cfg::get_config_string(config, "footer.message", "");

// render the template
let options = vec![("message".to_string(), message)];
utils::render_template("footer", &options)
}

impl Preprocessor for Embed {
fn name(&self) -> &str {
"mdbook-embedify"
Expand All @@ -101,9 +113,10 @@ impl Preprocessor for Embed {
fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> {
let config = &ctx.config;

let scroll_to_top = utils::get_config_bool(config, "scroll-to-top.enable");
let announcement_banner = utils::get_config_bool(config, "announcement-banner.enable");
let giscus = utils::get_config_bool(config, "giscus.enable");
let footer = cfg::get_config_bool(config, "footer.enable");
let giscus = cfg::get_config_bool(config, "giscus.enable");
let scroll_to_top = cfg::get_config_bool(config, "scroll-to-top.enable");
let announcement_banner = cfg::get_config_bool(config, "announcement-banner.enable");

book.for_each_mut(|item| {
if let mdbook::book::BookItem::Chapter(chapter) = item {
Expand All @@ -126,6 +139,11 @@ impl Preprocessor for Embed {
let template = render_giscus(config);
chapter.content.push_str(&template);
}
// render the global footer
if footer {
let template = render_footer(config);
chapter.content.push_str(&template);
}
}
});

Expand Down
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
mod cfg;
mod cli;
mod embed;
mod utils;

use crate::embed::Embed;
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
use std::io;

fn main() {
let cli = cli::Cli::new();
let embed = Embed::new();

// reply --supports command line argument
utils::reply_supports(&embed);
cli.reply_supports(&embed);

let (ctx, book) = CmdPreprocessor::parse_input(io::stdin()).unwrap();
let result = embed.run(&ctx, book).unwrap();
Expand Down
54 changes: 5 additions & 49 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
use clap::{Arg, Command};
use mdbook::{preprocess::Preprocessor, Config};
use pulldown_cmark;
use regex::Regex;
use rust_embed::RustEmbed;
use std::process;

#[derive(RustEmbed)]
#[folder = "templates"]
struct Assets;

pub fn get_config_bool(config: &Config, key: &str) -> bool {
config
.get(format!("preprocessor.embedify.{}", key).as_str())
.and_then(|v| v.as_bool())
.unwrap_or(false)
}

pub fn get_config_string(config: &Config, key: &str, default: &str) -> String {
config
.get(format!("preprocessor.embedify.{}", key).as_str())
.and_then(|v| v.as_str())
.unwrap_or(default)
.to_string()
pub fn render_markdown_processor(content: String) -> String {
let mut html = String::new();
let parser = pulldown_cmark::Parser::new(&content);
pulldown_cmark::html::push_html(&mut html, parser);
html.into()
}

pub fn parse_options(options_str: &str) -> Vec<(String, String)> {
Expand All @@ -37,13 +26,6 @@ pub fn parse_options(options_str: &str) -> Vec<(String, String)> {
options
}

pub fn render_markdown_processor(content: String) -> String {
let mut html = String::new();
let parser = pulldown_cmark::Parser::new(&content);
pulldown_cmark::html::push_html(&mut html, parser);
html.into()
}

pub fn render_template(app: &str, placeholders: &[(String, String)]) -> String {
let path = format!("{}.html", app);
// check if app is supported
Expand Down Expand Up @@ -87,29 +69,3 @@ pub fn render_template(app: &str, placeholders: &[(String, String)]) -> String {
// return the result
result.to_string()
}

pub fn reply_supports(pre: &dyn Preprocessor) {
// Handle support for the --supports command line argument
let matches = Command::new("mdbook-embedify")
.about("A mdbook embed preprocessor that embeds app to your book")
.version(env!("CARGO_PKG_VERSION"))
.subcommand(
Command::new("supports")
.arg(Arg::new("renderer").required(true))
.about("Check whether a renderer is supported by this preprocessor"),
)
.get_matches();

if let Some(sub_args) = matches.subcommand_matches("supports") {
let renderer = sub_args
.get_one::<String>("renderer")
.expect("Required argument");

// Signal whether the renderer is supported by exiting with 1 or 0.
if pre.supports_renderer(renderer) {
process::exit(0);
} else {
process::exit(1);
}
}
}
15 changes: 15 additions & 0 deletions templates/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<style>
footer {
text-align: center;
margin-top: 5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
footer p {
margin: 0;
}
</style>

<footer>{% markdown(message) %}</footer>

0 comments on commit 6cfeab2

Please sign in to comment.