diff --git a/components/config/src/config/markup.rs b/components/config/src/config/markup.rs index 9ea5b2337..8008c872e 100644 --- a/components/config/src/config/markup.rs +++ b/components/config/src/config/markup.rs @@ -36,6 +36,8 @@ pub struct Markdown { pub highlight_themes_css: Vec, /// Whether to render emoji aliases (e.g.: :smile: => 😄) in the markdown files pub render_emoji: bool, + /// CSS class to add to external links + pub external_links_class: Option, /// Whether external links are to be opened in a new tab /// If this is true, a `rel="noopener"` will always automatically be added for security reasons pub external_links_target_blank: bool, @@ -168,6 +170,7 @@ impl Markdown { self.external_links_target_blank || self.external_links_no_follow || self.external_links_no_referrer + || self.external_links_class.is_some() } pub fn construct_external_link_tag(&self, url: &str, title: &str) -> String { @@ -175,6 +178,11 @@ impl Markdown { let mut target = "".to_owned(); let title = if title.is_empty() { "".to_owned() } else { format!("title=\"{}\" ", title) }; + let class = self + .external_links_class + .as_ref() + .map_or("".to_owned(), |c| format!("class=\"{}\" ", c)); + if self.external_links_target_blank { // Security risk otherwise rel_opts.push("noopener"); @@ -192,7 +200,7 @@ impl Markdown { format!("rel=\"{}\" ", rel_opts.join(" ")) }; - format!("", rel, target, title, url) + format!("", class, rel, target, title, url) } } @@ -204,6 +212,7 @@ impl Default for Markdown { highlight_theme: DEFAULT_HIGHLIGHT_THEME.to_owned(), highlight_themes_css: Vec::new(), render_emoji: false, + external_links_class: None, external_links_target_blank: false, external_links_no_follow: false, external_links_no_referrer: false, diff --git a/components/markdown/tests/markdown.rs b/components/markdown/tests/markdown.rs index e8cdcd42c..9fbddb706 100644 --- a/components/markdown/tests/markdown.rs +++ b/components/markdown/tests/markdown.rs @@ -133,6 +133,32 @@ fn can_use_smart_punctuation() { insta::assert_snapshot!(body); } +#[test] +fn can_use_external_links_class() { + let mut config = Config::default_for_test(); + + // external link class only + config.markdown.external_links_class = Some("external".to_string()); + let body = common::render_with_config("", config.clone()).unwrap().body; + insta::assert_snapshot!(body); + + // internal link (should not add class) + let body = + common::render_with_config("[about](@/pages/about.md)", config.clone()).unwrap().body; + insta::assert_snapshot!(body); + + // reset class, set target blank only + config.markdown.external_links_class = None; + config.markdown.external_links_target_blank = true; + let body = common::render_with_config("", config.clone()).unwrap().body; + insta::assert_snapshot!(body); + + // both class and target blank + config.markdown.external_links_class = Some("external".to_string()); + let body = common::render_with_config("", config).unwrap().body; + insta::assert_snapshot!(body); +} + #[test] fn can_use_external_links_options() { let mut config = Config::default_for_test(); diff --git a/components/markdown/tests/snapshots/markdown__can_use_external_links_class-2.snap b/components/markdown/tests/snapshots/markdown__can_use_external_links_class-2.snap new file mode 100644 index 000000000..1d1e334d5 --- /dev/null +++ b/components/markdown/tests/snapshots/markdown__can_use_external_links_class-2.snap @@ -0,0 +1,6 @@ +--- +source: components/markdown/tests/markdown.rs +expression: body +snapshot_kind: text +--- +

about

diff --git a/components/markdown/tests/snapshots/markdown__can_use_external_links_class-3.snap b/components/markdown/tests/snapshots/markdown__can_use_external_links_class-3.snap new file mode 100644 index 000000000..16af5ca41 --- /dev/null +++ b/components/markdown/tests/snapshots/markdown__can_use_external_links_class-3.snap @@ -0,0 +1,6 @@ +--- +source: components/markdown/tests/markdown.rs +expression: body +snapshot_kind: text +--- +

https://google.com

diff --git a/components/markdown/tests/snapshots/markdown__can_use_external_links_class-4.snap b/components/markdown/tests/snapshots/markdown__can_use_external_links_class-4.snap new file mode 100644 index 000000000..da6b5de88 --- /dev/null +++ b/components/markdown/tests/snapshots/markdown__can_use_external_links_class-4.snap @@ -0,0 +1,6 @@ +--- +source: components/markdown/tests/markdown.rs +expression: body +snapshot_kind: text +--- +

https://google.com

diff --git a/components/markdown/tests/snapshots/markdown__can_use_external_links_class.snap b/components/markdown/tests/snapshots/markdown__can_use_external_links_class.snap new file mode 100644 index 000000000..ab22c3f7f --- /dev/null +++ b/components/markdown/tests/snapshots/markdown__can_use_external_links_class.snap @@ -0,0 +1,6 @@ +--- +source: components/markdown/tests/markdown.rs +expression: body +snapshot_kind: text +--- +

https://google.com

diff --git a/docs/content/documentation/getting-started/configuration.md b/docs/content/documentation/getting-started/configuration.md index 0591b021d..5b83712db 100644 --- a/docs/content/documentation/getting-started/configuration.md +++ b/docs/content/documentation/getting-started/configuration.md @@ -128,6 +128,9 @@ highlight_theme = "base16-ocean-dark" # Unicode emoji equivalent in the rendered Markdown files. (e.g.: :smile: => 😄) render_emoji = false +# CSS class to add to external links (e.g. "external-link") +external_links_class = + # Whether external links are to be opened in a new tab # If this is true, a `rel="noopener"` will always automatically be added for security reasons external_links_target_blank = false