diff --git a/CHANGELOG.md b/CHANGELOG.md index 8229d26..30499d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - Additional classnames can be specified using `directive.classname` syntax +- Support removing the title bar entirely ### Fixed diff --git a/README.md b/README.md index 8675ee2..df21535 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ [![Latest version](https://img.shields.io/crates/v/mdbook-admonish.svg)](https://crates.io/crates/mdbook-admonish) [![docs.rs](https://img.shields.io/docsrs/mdbook-admonish)](https://docs.rs/mdbook-admonish) -A preprocessor for [mdbook](https://github.com/rust-lang-nursery/mdBook) to add [Material Design](https://material.io/design) admonishments, -based on the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/reference/admonitions/) implementation. +A preprocessor for [mdbook](https://github.com/rust-lang-nursery/mdBook) to add [Material Design](https://material.io/design) admonishments, based on the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/reference/admonitions/) implementation. It turns this: @@ -64,6 +63,16 @@ The following steps can lead to irrecoverable data corruption. ![Data Loss](img/data-loss.png) +You can also remove the title bar entirely, by specifying the empty string: + +```` +```admonish success "" +This will take a while, go and grab a drink of water. +``` +```` + +![No Title Bar](img/no-title-bar.png) + #### Nested Markdown/HTML Markdown and HTML can be used in the inner content, as you'd expect: @@ -77,8 +86,7 @@ accomplished with the dereference operator, ![Complex Message](img/complex-message.png) -If you have code blocks you want to include in the content, -use [tildes for the outer code fence](https://spec.commonmark.org/0.30/#fenced-code-blocks): +If you have code blocks you want to include in the content, use [tildes for the outer code fence](https://spec.commonmark.org/0.30/#fenced-code-blocks): ```` ~~~admonish bug @@ -146,9 +154,7 @@ mdbook path/to/book ### Updates -**Please note**, when updating your version of `mdbook-admonish`, updated styles -will not be applied unless you rerun `mdbook-admonish install` to update the additional -CSS files in your book. +**Please note**, when updating your version of `mdbook-admonish`, updated styles will not be applied unless you rerun `mdbook-admonish install` to update the additional CSS files in your book. ## Development diff --git a/img/no-title-bar.png b/img/no-title-bar.png new file mode 100644 index 0000000..5bb99a1 Binary files /dev/null and b/img/no-title-bar.png differ diff --git a/integration/expected/chapter_1_main.html b/integration/expected/chapter_1_main.html index d913b1d..c2681ff 100644 --- a/integration/expected/chapter_1_main.html +++ b/integration/expected/chapter_1_main.html @@ -16,4 +16,9 @@

Simples

+
+
+

No title, only body

+
+
diff --git a/integration/src/chapter_1.md b/integration/src/chapter_1.md index 31fc2ac..79ae27b 100644 --- a/integration/src/chapter_1.md +++ b/integration/src/chapter_1.md @@ -9,3 +9,7 @@ It verifies that `mdbook` post-processes our generated HTML in the way we expect ```admonish Simples ``` + +```admonish warning "" +No title, only body +``` diff --git a/src/lib.rs b/src/lib.rs index 728e404..c73bea8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,45 +101,37 @@ struct AdmonitionInfoRaw<'a> { #[derive(Debug, PartialEq)] struct AdmonitionInfo<'a> { directive: Directive, - title: Cow<'a, str>, + title: Option, additional_classnames: Option>, } -impl<'a> Default for AdmonitionInfo<'a> { - fn default() -> Self { - Self { - directive: Directive::Note, - title: Cow::Borrowed("Note"), - additional_classnames: None, - } - } -} - -impl<'a> TryFrom> for AdmonitionInfo<'a> { - type Error = (); - - fn try_from(other: AdmonitionInfoRaw<'a>) -> Result { +impl<'a> From> for AdmonitionInfo<'a> { + fn from(other: AdmonitionInfoRaw<'a>) -> Self { let AdmonitionInfoRaw { - directive, + directive: raw_directive, title, additional_classnames, } = other; - let title = title - .map(Cow::Owned) - .unwrap_or_else(|| Cow::Owned(ucfirst(directive))); - let directive = Directive::from_str(directive)?; - Ok(Self { + let (directive, title) = match (Directive::from_str(raw_directive), title) { + (Ok(directive), None) => (directive, ucfirst(raw_directive)), + (Err(_), None) => (Directive::Note, "Note".to_owned()), + (Ok(directive), Some(title)) => (directive, title), + (Err(_), Some(title)) => (Directive::Note, title), + }; + // If the user explicitly gave no title, then disable the title bar + let title = if title.is_empty() { None } else { Some(title) }; + Self { directive, title, additional_classnames, - }) + } } } #[derive(Debug, PartialEq)] struct Admonition<'a> { directive: Directive, - title: Cow<'a, str>, + title: Option, content: &'a str, additional_classnames: Option>, } @@ -164,6 +156,20 @@ impl<'a> Admonition<'a> { let title = &self.title; let content = &self.content; + let title_html = title + .as_ref() + .map(|title| { + Cow::Owned(format!( + r#"
+ +{title} + +
+"# + )) + }) + .unwrap_or(Cow::Borrowed("")); + if let Some(additional_classnames) = &self.additional_classnames { let mut buffer = additional_class.into_owned(); for additional_classname in additional_classnames { @@ -180,12 +186,7 @@ impl<'a> Admonition<'a> { // rendered as markdown paragraphs. format!( r#"
-
- -{title} - -
-
+{title_html}
{content} @@ -201,7 +202,7 @@ const ADMONISH_BLOCK_KEYWORD: &str = "admonish"; /// - `None` if this is not an `admonish` block. /// - `Some(AdmonitionInfoRaw)` if this is an `admonish` block fn parse_info_string(info_string: &str) -> Option { - // Get the rest of the info string if this is an admonitionment + // Get the rest of the info string if this is an admonition let directive_title = if info_string == ADMONISH_BLOCK_KEYWORD { "" } else { @@ -230,7 +231,12 @@ fn parse_info_string(info_string: &str) -> Option { None => (directive, None), Some((directive, additional_classnames)) => ( directive, - Some(additional_classnames.split(CLASSNAME_SEPARATOR).collect()), + Some( + additional_classnames + .split(CLASSNAME_SEPARATOR) + .filter(|additional_classname| !additional_classname.is_empty()) + .collect(), + ), ), }; @@ -280,7 +286,7 @@ fn extract_admonish_body(content: &str) -> &str { /// If the code block is not an admonition, return `None`. fn parse_admonition<'a>(info_string: &'a str, content: &'a str) -> Option> { let info = parse_info_string(info_string)?; - let info = AdmonitionInfo::try_from(info).unwrap_or_default(); + let info = AdmonitionInfo::from(info); let body = extract_admonish_body(content); Some(Admonition::new(info, body)) } @@ -629,6 +635,27 @@ Developers don't want you to know this one weird tip! Will have bonus classnames +
+
+"#; + + assert_eq!(expected, preprocess(content).unwrap()); + } + + #[test] + fn block_with_empty_additional_classnames_title_content() { + let content = r#" +```admonish .... "" +``` +"#; + + let expected = r#" + +
+
+ + +
"#;