feat: remove title bar if title empty

This commit is contained in:
Tom Milligan
2022-02-21 18:26:33 +00:00
committed by Tom Milligan
parent d851076cbc
commit 0b50fd68ba
6 changed files with 82 additions and 39 deletions

View File

@@ -5,6 +5,7 @@
### Added ### Added
- Additional classnames can be specified using `directive.classname` syntax - Additional classnames can be specified using `directive.classname` syntax
- Support removing the title bar entirely
### Fixed ### Fixed

View File

@@ -3,8 +3,7 @@
[![Latest version](https://img.shields.io/crates/v/mdbook-admonish.svg)](https://crates.io/crates/mdbook-admonish) [![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) [![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, 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.
based on the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/reference/admonitions/) implementation.
It turns this: It turns this:
@@ -64,6 +63,16 @@ The following steps can lead to irrecoverable data corruption.
![Data Loss](img/data-loss.png) ![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 #### Nested Markdown/HTML
Markdown and HTML can be used in the inner content, as you'd expect: Markdown and HTML can be used in the inner content, as you'd expect:
@@ -77,8 +86,7 @@ accomplished with the <span style="color: hotpink">dereference operator</span>,
![Complex Message](img/complex-message.png) ![Complex Message](img/complex-message.png)
If you have code blocks you want to include in the content, 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):
use [tildes for the outer code fence](https://spec.commonmark.org/0.30/#fenced-code-blocks):
```` ````
~~~admonish bug ~~~admonish bug
@@ -146,9 +154,7 @@ mdbook path/to/book
### Updates ### Updates
**Please note**, when updating your version of `mdbook-admonish`, updated styles **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.
will not be applied unless you rerun `mdbook-admonish install` to update the additional
CSS files in your book.
## Development ## Development

BIN
img/no-title-bar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -16,4 +16,9 @@
<p>Simples</p> <p>Simples</p>
</div> </div>
</div> </div>
<div class="admonition warning">
<div>
<p>No title, only body</p>
</div>
</div>

View File

@@ -9,3 +9,7 @@ It verifies that `mdbook` post-processes our generated HTML in the way we expect
```admonish ```admonish
Simples Simples
``` ```
```admonish warning ""
No title, only body
```

View File

@@ -101,45 +101,37 @@ struct AdmonitionInfoRaw<'a> {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
struct AdmonitionInfo<'a> { struct AdmonitionInfo<'a> {
directive: Directive, directive: Directive,
title: Cow<'a, str>, title: Option<String>,
additional_classnames: Option<Vec<&'a str>>, additional_classnames: Option<Vec<&'a str>>,
} }
impl<'a> Default for AdmonitionInfo<'a> { impl<'a> From<AdmonitionInfoRaw<'a>> for AdmonitionInfo<'a> {
fn default() -> Self { fn from(other: AdmonitionInfoRaw<'a>) -> Self {
Self {
directive: Directive::Note,
title: Cow::Borrowed("Note"),
additional_classnames: None,
}
}
}
impl<'a> TryFrom<AdmonitionInfoRaw<'a>> for AdmonitionInfo<'a> {
type Error = ();
fn try_from(other: AdmonitionInfoRaw<'a>) -> Result<Self, ()> {
let AdmonitionInfoRaw { let AdmonitionInfoRaw {
directive, directive: raw_directive,
title, title,
additional_classnames, additional_classnames,
} = other; } = other;
let title = title let (directive, title) = match (Directive::from_str(raw_directive), title) {
.map(Cow::Owned) (Ok(directive), None) => (directive, ucfirst(raw_directive)),
.unwrap_or_else(|| Cow::Owned(ucfirst(directive))); (Err(_), None) => (Directive::Note, "Note".to_owned()),
let directive = Directive::from_str(directive)?; (Ok(directive), Some(title)) => (directive, title),
Ok(Self { (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, directive,
title, title,
additional_classnames, additional_classnames,
}) }
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
struct Admonition<'a> { struct Admonition<'a> {
directive: Directive, directive: Directive,
title: Cow<'a, str>, title: Option<String>,
content: &'a str, content: &'a str,
additional_classnames: Option<Vec<&'a str>>, additional_classnames: Option<Vec<&'a str>>,
} }
@@ -164,6 +156,20 @@ impl<'a> Admonition<'a> {
let title = &self.title; let title = &self.title;
let content = &self.content; let content = &self.content;
let title_html = title
.as_ref()
.map(|title| {
Cow::Owned(format!(
r#"<div class="admonition-title">
{title}
</div>
"#
))
})
.unwrap_or(Cow::Borrowed(""));
if let Some(additional_classnames) = &self.additional_classnames { if let Some(additional_classnames) = &self.additional_classnames {
let mut buffer = additional_class.into_owned(); let mut buffer = additional_class.into_owned();
for additional_classname in additional_classnames { for additional_classname in additional_classnames {
@@ -180,12 +186,7 @@ impl<'a> Admonition<'a> {
// rendered as markdown paragraphs. // rendered as markdown paragraphs.
format!( format!(
r#"<div class="admonition {additional_class}"> r#"<div class="admonition {additional_class}">
<div class="admonition-title"> {title_html}<div>
{title}
</div>
<div>
{content} {content}
@@ -201,7 +202,7 @@ const ADMONISH_BLOCK_KEYWORD: &str = "admonish";
/// - `None` if this is not an `admonish` block. /// - `None` if this is not an `admonish` block.
/// - `Some(AdmonitionInfoRaw)` if this is an `admonish` block /// - `Some(AdmonitionInfoRaw)` if this is an `admonish` block
fn parse_info_string(info_string: &str) -> Option<AdmonitionInfoRaw> { fn parse_info_string(info_string: &str) -> Option<AdmonitionInfoRaw> {
// 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 { let directive_title = if info_string == ADMONISH_BLOCK_KEYWORD {
"" ""
} else { } else {
@@ -230,7 +231,12 @@ fn parse_info_string(info_string: &str) -> Option<AdmonitionInfoRaw> {
None => (directive, None), None => (directive, None),
Some((directive, additional_classnames)) => ( Some((directive, additional_classnames)) => (
directive, 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`. /// If the code block is not an admonition, return `None`.
fn parse_admonition<'a>(info_string: &'a str, content: &'a str) -> Option<Admonition<'a>> { fn parse_admonition<'a>(info_string: &'a str, content: &'a str) -> Option<Admonition<'a>> {
let info = parse_info_string(info_string)?; 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); let body = extract_admonish_body(content);
Some(Admonition::new(info, body)) Some(Admonition::new(info, body))
} }
@@ -629,6 +635,27 @@ Developers don't want you to know this one weird tip!
Will have bonus classnames Will have bonus classnames
</div>
</div>
"#;
assert_eq!(expected, preprocess(content).unwrap());
}
#[test]
fn block_with_empty_additional_classnames_title_content() {
let content = r#"
```admonish .... ""
```
"#;
let expected = r#"
<div class="admonition note">
<div>
</div> </div>
</div> </div>
"#; "#;