markdown: Change the copy icon to a check once copied (#25970)

This PR makes it so the copy icon on code blocks will change to a check
once the code block has been copied.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-03-03 19:14:26 -05:00 committed by GitHub
parent e7b3b8bf03
commit fc5ff318e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,6 @@
pub mod parser; pub mod parser;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::iter; use std::iter;
use std::mem; use std::mem;
use std::ops::Range; use std::ops::Range;
@ -72,6 +72,7 @@ pub struct Markdown {
fallback_code_block_language: Option<String>, fallback_code_block_language: Option<String>,
open_url: Option<Box<dyn Fn(SharedString, &mut Window, &mut App)>>, open_url: Option<Box<dyn Fn(SharedString, &mut Window, &mut App)>>,
options: Options, options: Options,
copied_code_blocks: HashSet<ElementId>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -108,6 +109,7 @@ impl Markdown {
copy_code_block_buttons: true, copy_code_block_buttons: true,
}, },
open_url: None, open_url: None,
copied_code_blocks: HashSet::new(),
}; };
this.parse(cx); this.parse(cx);
this this
@ -142,6 +144,7 @@ impl Markdown {
copy_code_block_buttons: true, copy_code_block_buttons: true,
}, },
open_url: None, open_url: None,
copied_code_blocks: HashSet::new(),
}; };
this.parse(cx); this.parse(cx);
this this
@ -749,23 +752,37 @@ impl Element for MarkdownElement {
builder.modify_current_div(|el| { builder.modify_current_div(|el| {
let id = let id =
ElementId::NamedInteger("copy-markdown-code".into(), range.end); ElementId::NamedInteger("copy-markdown-code".into(), range.end);
let was_copied =
self.markdown.read(cx).copied_code_blocks.contains(&id);
let copy_button = div().absolute().top_1().right_1().w_5().child( let copy_button = div().absolute().top_1().right_1().w_5().child(
IconButton::new(id, IconName::Copy) IconButton::new(
.icon_color(Color::Muted) id.clone(),
.shape(ui::IconButtonShape::Square) if was_copied {
.tooltip(Tooltip::text("Copy Code Block")) IconName::Check
.on_click({ } else {
let code = without_fences( IconName::Copy
parsed_markdown.source()[range.clone()].trim(), },
) )
.to_string(); .icon_color(Color::Muted)
.shape(ui::IconButtonShape::Square)
.tooltip(Tooltip::text("Copy Code"))
.on_click({
let id = id.clone();
let markdown = self.markdown.clone();
let code = without_fences(
parsed_markdown.source()[range.clone()].trim(),
)
.to_string();
move |_event, _window, cx| {
markdown.update(cx, |this, cx| {
this.copied_code_blocks.insert(id.clone());
move |_, _, cx| {
cx.write_to_clipboard(ClipboardItem::new_string( cx.write_to_clipboard(ClipboardItem::new_string(
code.clone(), code.clone(),
)) ));
} });
}), }
}),
); );
el.child(copy_button) el.child(copy_button)