From 2db66de5d992d80b586275d8f6345de2129e1bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delorme?= Date: Sat, 28 Feb 2026 23:59:01 +0100 Subject: [PATCH] feat(alerts): add GitHub-style alerts support with styled blockquotes --- src/docs/user-guide-en.md | 37 ++++++++++++ src/main/java/ui/PreviewPanel.java | 95 ++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/src/docs/user-guide-en.md b/src/docs/user-guide-en.md index 18a4cf8..d22a1cd 100644 --- a/src/docs/user-guide-en.md +++ b/src/docs/user-guide-en.md @@ -51,6 +51,7 @@ MarkNote is a cross-platform Markdown editor designed for writers, developers, a - **Code Block Copy Button** - One-click copy for code blocks in preview - **Markdown Tables** - Full GFM table support with styled rendering - **Task Lists** - GitHub-style checkboxes (`[ ]` / `[x]`) rendered in preview +- **GitHub Alerts** - Styled blockquotes for `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, `[!CAUTION]` - **PlantUML Diagrams** - Render PlantUML diagrams directly in the preview; switch between the **online PlantUML server** (default) or a **local `plantuml.jar`** configured in Options → Tools; local rendering is asynchronous (per-block background threads) and shows a ⚙ spinning gear icon in the status bar during generation - **Mermaid Diagrams** - Render Mermaid flowcharts, sequences, and more in the preview (theme auto-matches app theme) - **Math Equations** - LaTeX/MathML support via KaTeX (`$...$` inline, `$$...$$` block) @@ -763,6 +764,9 @@ MarkNote supports standard Markdown syntax plus extensions: > Blockquotes +> [!NOTE] +> GitHub-style alerts + --- Horizontal rules --- @@ -822,6 +826,39 @@ In the preview, these render as: > **Note:** Checkboxes in the preview are read-only (disabled). To change the state, edit the Markdown source directly. +### GitHub Alerts + +MarkNote supports GitHub-style alerts (also known as admonitions) for highlighting important information in blockquotes: + +```markdown +> [!NOTE] +> Useful information that users should know. + +> [!TIP] +> Helpful advice for doing things better or more easily. + +> [!IMPORTANT] +> Key information users need to know. + +> [!WARNING] +> Urgent info that needs immediate user attention. + +> [!CAUTION] +> Advises about risks or negative outcomes. +``` + +These render as styled boxes with colored borders and icons: + +| Alert Type | Color | Use Case | +|------------|-------|----------| +| **Note** | Blue | General information | +| **Tip** | Green | Helpful hints and best practices | +| **Important** | Purple | Critical information | +| **Warning** | Yellow | Potential issues or caveats | +| **Caution** | Red | Dangerous actions or irreversible operations | + +> **Tip:** GitHub Alerts work great for documentation, tutorials, and user guides where you need to draw attention to specific information. + ### PlantUML Diagrams Embed PlantUML diagrams directly in your Markdown using fenced code blocks: diff --git a/src/main/java/ui/PreviewPanel.java b/src/main/java/ui/PreviewPanel.java index ec4246b..9093680 100644 --- a/src/main/java/ui/PreviewPanel.java +++ b/src/main/java/ui/PreviewPanel.java @@ -247,6 +247,9 @@ private void updatePreview(String markdown, boolean addToHistory) { // ── Checkboxes : convertir [ ] et [x] en éléments checkbox HTML html = processCheckboxes(html); + // ── GitHub Alerts : convertir les blockquotes [!NOTE], [!WARNING], etc. + html = processGitHubAlerts(html); + // ── Images : injecter les attributs width/height if (!imageSizes.isEmpty()) { html = applyImageSizes(html, imageSizes); @@ -333,6 +336,21 @@ private void updatePreview(String markdown, boolean addToHistory) { pre:hover .copy-btn { opacity: 1; } pre .copy-btn:hover { background: rgba(128,128,128,0.35); } pre .copy-btn.copied { background: rgba(76,175,80,0.3); border-color: rgba(76,175,80,0.5); } + /* GitHub-style Alerts */ + .markdown-alert { padding: 0.8em 1em; margin: 1em 0; border-left: 4px solid; border-radius: 6px; } + .markdown-alert-title { display: flex; align-items: center; font-weight: 600; margin-bottom: 0.4em; } + .markdown-alert-title svg { margin-right: 0.5em; } + .markdown-alert p { margin: 0.3em 0; } + .markdown-alert-note { background: rgba(9, 105, 218, 0.1); border-color: #0969da; } + .markdown-alert-note .markdown-alert-title { color: #0969da; } + .markdown-alert-tip { background: rgba(26, 127, 55, 0.1); border-color: #1a7f37; } + .markdown-alert-tip .markdown-alert-title { color: #1a7f37; } + .markdown-alert-important { background: rgba(130, 80, 223, 0.1); border-color: #8250df; } + .markdown-alert-important .markdown-alert-title { color: #8250df; } + .markdown-alert-warning { background: rgba(154, 103, 0, 0.1); border-color: #9a6700; } + .markdown-alert-warning .markdown-alert-title { color: #9a6700; } + .markdown-alert-caution { background: rgba(207, 34, 46, 0.1); border-color: #cf222e; } + .markdown-alert-caution .markdown-alert-title { color: #cf222e; } %s%s @@ -431,6 +449,83 @@ private String processCheckboxes(String html) { return html; } + /** Pattern pour détecter les blockquotes GitHub Alerts. */ + private static final Pattern GITHUB_ALERT_PATTERN = Pattern.compile( + "
\\s*

\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]\\s*(.*?)

(.*?)
", + Pattern.DOTALL | Pattern.CASE_INSENSITIVE); + + /** Icônes SVG pour les alertes GitHub. */ + private static final Map ALERT_ICONS = Map.of( + "NOTE", "", + "TIP", "", + "IMPORTANT", "", + "WARNING", "", + "CAUTION", "" + ); + + /** Labels traduits pour les alertes GitHub. */ + private static final Map ALERT_LABELS = Map.of( + "NOTE", "Note", + "TIP", "Tip", + "IMPORTANT", "Important", + "WARNING", "Warning", + "CAUTION", "Caution" + ); + + /** + * Convertit les blockquotes GitHub Alerts en éléments stylisés. + * + *

Patterns reconnus :

+ *
    + *
  • {@code > [!NOTE]} → bloc note bleu
  • + *
  • {@code > [!TIP]} → bloc tip vert
  • + *
  • {@code > [!IMPORTANT]} → bloc important violet
  • + *
  • {@code > [!WARNING]} → bloc warning jaune
  • + *
  • {@code > [!CAUTION]} → bloc caution rouge
  • + *
+ * + * @param html le HTML généré par Flexmark + * @return le HTML avec les alertes converties + */ + private String processGitHubAlerts(String html) { + Matcher m = GITHUB_ALERT_PATTERN.matcher(html); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + String type = m.group(1).toUpperCase(); + String firstLineContent = m.group(2).trim(); + String restContent = m.group(3).trim(); + + String icon = ALERT_ICONS.getOrDefault(type, ""); + String label = ALERT_LABELS.getOrDefault(type, type); + String cssClass = "markdown-alert markdown-alert-" + type.toLowerCase(); + + StringBuilder replacement = new StringBuilder(); + replacement.append("
") + .append("

") + .append(icon).append(label).append("

"); + + // Ajouter le contenu de la première ligne s'il existe + if (!firstLineContent.isEmpty()) { + // Nettoyer les
ou
en début de contenu + firstLineContent = firstLineContent.replaceFirst("^\\s*", ""); + if (!firstLineContent.isEmpty()) { + replacement.append("

").append(firstLineContent).append("

"); + } + } + + // Ajouter le reste du contenu (autres paragraphes) + if (!restContent.isEmpty()) { + replacement.append(restContent); + } + + replacement.append("
"); + + m.appendReplacement(sb, Matcher.quoteReplacement(replacement.toString())); + } + m.appendTail(sb); + return sb.toString(); + } + /** * Remplace les blocs {@code
...}
      * par des balises {@code } (serveur en ligne) ou par des placeholders