gorbie_commonmark_backend/
alerts.rs

1use crate::elements::{blockquote, newline};
2use egui::Ui;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
6pub struct Alert {
7    /// The color that will be used to put emphasis to the alert
8    pub accent_color: egui::Color32,
9    /// The icon that will be displayed
10    pub icon: char,
11    /// The identifier that will be used to look for the blockquote such as NOTE and TIP
12    pub identifier: String,
13    /// The identifier that will be shown when rendering. E.g: Note and Tip
14    pub identifier_rendered: String,
15}
16
17// Seperate function to not leak into the public API
18pub fn alert_ui(alert: &Alert, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) {
19    blockquote(ui, alert.accent_color, |ui| {
20        newline(ui);
21        ui.colored_label(alert.accent_color, alert.icon.to_string());
22        ui.add_space(3.0);
23        ui.colored_label(alert.accent_color, &alert.identifier_rendered);
24        // end line
25        newline(ui);
26        add_contents(ui);
27    })
28}
29
30#[derive(Debug, Clone)]
31pub struct AlertBundle {
32    /// the key is `[!identifier]`
33    alerts: HashMap<String, Alert>,
34}
35
36impl AlertBundle {
37    pub fn from_alerts(alerts: Vec<Alert>) -> Self {
38        let mut map = HashMap::with_capacity(alerts.len());
39        for alert in alerts {
40            // Store it the way it will be in text to make lookup easier
41            map.insert(format!("[!{}]", alert.identifier), alert);
42        }
43
44        Self { alerts: map }
45    }
46
47    pub fn into_alerts(self) -> Vec<Alert> {
48        // since the rendered field can be changed it is better to force creation of
49        // a new bundle with from_alerts after a potential modification
50
51        self.alerts.into_values().collect::<Vec<_>>()
52    }
53
54    pub fn empty() -> Self {
55        AlertBundle {
56            alerts: Default::default(),
57        }
58    }
59
60    /// github flavoured markdown alerts
61    /// `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]` and `[!CAUTION]`.
62    ///
63    /// This is used by default
64    pub fn gfm() -> Self {
65        Self::from_alerts(vec![
66            Alert {
67                accent_color: egui::Color32::from_rgb(10, 80, 210),
68                icon: '❕',
69                identifier: "NOTE".to_owned(),
70                identifier_rendered: "Note".to_owned(),
71            },
72            Alert {
73                accent_color: egui::Color32::from_rgb(0, 130, 20),
74                icon: '💡',
75                identifier: "TIP".to_owned(),
76                identifier_rendered: "Tip".to_owned(),
77            },
78            Alert {
79                accent_color: egui::Color32::from_rgb(150, 30, 140),
80                icon: '💬',
81                identifier: "IMPORTANT".to_owned(),
82                identifier_rendered: "Important".to_owned(),
83            },
84            Alert {
85                accent_color: egui::Color32::from_rgb(200, 120, 0),
86                icon: '⚠',
87                identifier: "WARNING".to_owned(),
88                identifier_rendered: "Warning".to_owned(),
89            },
90            Alert {
91                accent_color: egui::Color32::from_rgb(220, 0, 0),
92                icon: '🔴',
93                identifier: "CAUTION".to_owned(),
94                identifier_rendered: "Caution".to_owned(),
95            },
96        ])
97    }
98
99    /// See if the bundle contains no alerts
100    pub fn is_empty(&self) -> bool {
101        self.alerts.is_empty()
102    }
103}
104
105pub fn try_get_alert<'a>(bundle: &'a AlertBundle, text: &str) -> Option<&'a Alert> {
106    bundle.alerts.get(&text.to_uppercase())
107}