From 9e7122c143ab4b5d1c623312c60031ff653aead4 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Fri, 27 Jun 2025 01:28:59 +0800 Subject: [PATCH 1/2] Add support for rendering alerts in README --- app/styles/crate/version.module.css | 69 +++++++++++++++++++++++ crates/crates_io_markdown/lib.rs | 48 +++++++++++++++- e2e/acceptance/readme-rendering.spec.ts | 22 ++++++++ tests/acceptance/readme-rendering-test.js | 21 +++++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/app/styles/crate/version.module.css b/app/styles/crate/version.module.css index e88e9bf9451..d963c063a0d 100644 --- a/app/styles/crate/version.module.css +++ b/app/styles/crate/version.module.css @@ -152,3 +152,72 @@ border: 0; } } + +/* alerts */ +:global(.markdown-alert) { + --fg-color-note: #4494f8; + --fg-color-tip: #3fb950; + --fg-color-important: #ab7df8; + --fg-color-warning: #d29922; + --fg-color-caution: #f85149; + + padding: 0.5rem 1rem; + margin-bottom: 1rem; + color: inherit; + border-left: .25em solid var(--gray-border); + + & > :first-child { + margin-top: 0; + } + + & > :last-child { + margin-bottom: 0; + } + + :global(.markdown-alert-title) { + display: flex; + font-weight: 500; + align-items: center; + line-height: 1; + } + + &:global(.markdown-alert-note) { + border-left-color: var(--fg-color-note); + + & > :global(.markdown-alert-title) { + color: var(--fg-color-note); + } + } + + &:global(.markdown-alert-tip) { + border-left-color: var(--fg-color-tip); + + & > :global(.markdown-alert-title) { + color: var(--fg-color-tip); + } + } + + &:global(.markdown-alert-important) { + border-left-color: var(--fg-color-important); + + & > :global(.markdown-alert-title) { + color: var(--fg-color-important); + } + } + + &:global(.markdown-alert-warning) { + border-left-color: var(--fg-color-warning); + + & > :global(.markdown-alert-title) { + color: var(--fg-color-warning); + } + } + + &:global(.markdown-alert-caution) { + border-left-color: var(--fg-color-caution); + + & > :global(.markdown-alert-title) { + color: var(--fg-color-caution); + } + } +} diff --git a/crates/crates_io_markdown/lib.rs b/crates/crates_io_markdown/lib.rs index 6fae87d6c9a..d609b2a8020 100644 --- a/crates/crates_io_markdown/lib.rs +++ b/crates/crates_io_markdown/lib.rs @@ -46,6 +46,18 @@ impl<'a> MarkdownRenderer<'a> { ]), ), ("section", hashset(&["footnotes"])), + ( + "div", + hashset(&[ + "markdown-alert", + "markdown-alert-note", + "markdown-alert-tip", + "markdown-alert-important", + "markdown-alert-warning", + "markdown-alert-caution", + ]), + ), + ("p", hashset(&["markdown-alert-title"])), ]); let sanitize_url = UrlRelative::Custom(Box::new(SanitizeUrl::new(base_url, base_dir))); @@ -77,7 +89,9 @@ impl<'a> MarkdownRenderer<'a> { .build(); let extension_options = ComrakExtensionOptions::builder() + .alerts(true) .autolink(true) + .multiline_block_quotes(true) .strikethrough(true) .table(true) .tagfilter(true) @@ -429,7 +443,7 @@ mod tests { #[test] fn text_with_forbidden_class_attribute() { let text = "

Hello World!

"; - assert_snapshot!(markdown_to_html(text, None, ""), @"

Hello World!

"); + assert_snapshot!(markdown_to_html(text, None, ""), @r#"

Hello World!

"#); } #[test] @@ -684,4 +698,36 @@ There can also be some text in between! "##); } + + #[test] + fn alerts_note() { + let text = r#" +> [!note] +> Hello, world! + "#; + assert_snapshot!(markdown_to_html(text, None, ""), @r#" +
+

Note

+

Hello, world!

+
+ "#); + } + + #[test] + fn alerts_note_multiline_block_quotes() { + let text = r#" +>>> [!note] +Hello, + +world! +>>> +"#; + assert_snapshot!(markdown_to_html(text, None, ""), @r#" +
+

Note

+

Hello,

+

world!

+
+ "#); + } } diff --git a/e2e/acceptance/readme-rendering.spec.ts b/e2e/acceptance/readme-rendering.spec.ts index 40be046ed0f..1b7d928e0f4 100644 --- a/e2e/acceptance/readme-rendering.spec.ts +++ b/e2e/acceptance/readme-rendering.spec.ts @@ -2,6 +2,28 @@ import { expect, test } from '@/e2e/helper'; import { http, HttpResponse } from 'msw'; const README_HTML = ` +
+

Note

+

Useful information that users should know, even when skimming content.

+
+
+

Tip

+

Helpful advice for doing things better or more easily.

+
+
+

Important

+

Key information users need to know to achieve their goal.

+
+
+

Warning

+

Urgent info that needs immediate user attention to avoid problems.

+
+
+

Caution

+

Advises about risks or negative outcomes of certain actions.

+
+ +

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.


You may be looking for:

diff --git a/tests/acceptance/readme-rendering-test.js b/tests/acceptance/readme-rendering-test.js index a8d9de3453f..4ec5ba8194a 100644 --- a/tests/acceptance/readme-rendering-test.js +++ b/tests/acceptance/readme-rendering-test.js @@ -9,6 +9,27 @@ import { setupApplicationTest } from 'crates-io/tests/helpers'; import { visit } from '../helpers/visit-ignoring-abort'; const README_HTML = ` +
+

Note

+

Useful information that users should know, even when skimming content.

+
+
+

Tip

+

Helpful advice for doing things better or more easily.

+
+
+

Important

+

Key information users need to know to achieve their goal.

+
+
+

Warning

+

Urgent info that needs immediate user attention to avoid problems.

+
+
+

Caution

+

Advises about risks or negative outcomes of certain actions.

+
+

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.


You may be looking for:

From 26d3e61ea6fe25d3bfd16d7f79eb746a504a34f0 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Fri, 27 Jun 2025 01:49:29 +0800 Subject: [PATCH 2/2] Add support for rendering alert icon in README --- app/styles/crate/version.module.css | 33 +++++++++++++++++++++++ e2e/acceptance/readme-rendering.spec.ts | 11 ++++++++ public/assets/alert-caution.svg | 3 +++ public/assets/alert-important.svg | 3 +++ public/assets/alert-note.svg | 3 +++ public/assets/alert-tip.svg | 3 +++ public/assets/alert-warning.svg | 3 +++ tests/acceptance/readme-rendering-test.js | 12 +++++++++ 8 files changed, 71 insertions(+) create mode 100644 public/assets/alert-caution.svg create mode 100644 public/assets/alert-important.svg create mode 100644 public/assets/alert-note.svg create mode 100644 public/assets/alert-tip.svg create mode 100644 public/assets/alert-warning.svg diff --git a/app/styles/crate/version.module.css b/app/styles/crate/version.module.css index d963c063a0d..1daa2bd556d 100644 --- a/app/styles/crate/version.module.css +++ b/app/styles/crate/version.module.css @@ -181,11 +181,24 @@ line-height: 1; } + & > :global(.markdown-alert-title)::before { + content: ''; + margin-right: .5rem; + background-color: var(--gray-border); + width: 1em; + height: 1em; + } + &:global(.markdown-alert-note) { border-left-color: var(--fg-color-note); & > :global(.markdown-alert-title) { color: var(--fg-color-note); + + &:before { + mask: url("/assets/alert-note.svg"); + background-color: var(--fg-color-note); + } } } @@ -194,6 +207,11 @@ & > :global(.markdown-alert-title) { color: var(--fg-color-tip); + + &:before { + mask: url("/assets/alert-tip.svg"); + background-color: var(--fg-color-tip); + } } } @@ -202,6 +220,11 @@ & > :global(.markdown-alert-title) { color: var(--fg-color-important); + + &:before { + mask: url("/assets/alert-important.svg"); + background-color: var(--fg-color-important); + } } } @@ -210,6 +233,11 @@ & > :global(.markdown-alert-title) { color: var(--fg-color-warning); + + &:before { + mask: url("/assets/alert-warning.svg"); + background-color: var(--fg-color-warning); + } } } @@ -218,6 +246,11 @@ & > :global(.markdown-alert-title) { color: var(--fg-color-caution); + + &:before { + mask: url("/assets/alert-caution.svg"); + background-color: var(--fg-color-caution); + } } } } diff --git a/e2e/acceptance/readme-rendering.spec.ts b/e2e/acceptance/readme-rendering.spec.ts index 1b7d928e0f4..80ecf826b21 100644 --- a/e2e/acceptance/readme-rendering.spec.ts +++ b/e2e/acceptance/readme-rendering.spec.ts @@ -23,6 +23,17 @@ const README_HTML = `

Advises about risks or negative outcomes of certain actions.

+
+

Note

+
+

Important

+
+

Caution

+

Rick roll

+

Never gonna give you up

+
+
+

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.


diff --git a/public/assets/alert-caution.svg b/public/assets/alert-caution.svg new file mode 100644 index 00000000000..30336823494 --- /dev/null +++ b/public/assets/alert-caution.svg @@ -0,0 +1,3 @@ + diff --git a/public/assets/alert-important.svg b/public/assets/alert-important.svg new file mode 100644 index 00000000000..bbb6be3a8a8 --- /dev/null +++ b/public/assets/alert-important.svg @@ -0,0 +1,3 @@ + diff --git a/public/assets/alert-note.svg b/public/assets/alert-note.svg new file mode 100644 index 00000000000..1be6dc64570 --- /dev/null +++ b/public/assets/alert-note.svg @@ -0,0 +1,3 @@ + diff --git a/public/assets/alert-tip.svg b/public/assets/alert-tip.svg new file mode 100644 index 00000000000..9c381a06dee --- /dev/null +++ b/public/assets/alert-tip.svg @@ -0,0 +1,3 @@ + diff --git a/public/assets/alert-warning.svg b/public/assets/alert-warning.svg new file mode 100644 index 00000000000..176711f243d --- /dev/null +++ b/public/assets/alert-warning.svg @@ -0,0 +1,3 @@ + diff --git a/tests/acceptance/readme-rendering-test.js b/tests/acceptance/readme-rendering-test.js index 4ec5ba8194a..b39bc1182ee 100644 --- a/tests/acceptance/readme-rendering-test.js +++ b/tests/acceptance/readme-rendering-test.js @@ -30,6 +30,18 @@ const README_HTML = `

Advises about risks or negative outcomes of certain actions.

+
+

Note

+
+

Important

+
+

Caution

+

Rick roll

+

Never gonna give you up

+
+
+
+

Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.


You may be looking for: