From 9bfaf2840cffe35d689bd115a308d21961ab082a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 21 Jul 2024 12:45:05 +0200 Subject: Add `Link` support to `rich_text` widget --- widget/src/markdown.rs | 68 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 27 deletions(-) (limited to 'widget/src/markdown.rs') diff --git a/widget/src/markdown.rs b/widget/src/markdown.rs index de691a4d..dc207a34 100644 --- a/widget/src/markdown.rs +++ b/widget/src/markdown.rs @@ -14,13 +14,13 @@ use crate::{column, container, rich_text, row, span, text}; #[derive(Debug, Clone)] pub enum Item { /// A heading. - Heading(Vec>), + Heading(Vec>), /// A paragraph. - Paragraph(Vec>), + Paragraph(Vec>), /// A code block. /// /// You can enable the `highlighter` feature for syntax highligting. - CodeBlock(Vec>), + CodeBlock(Vec>), /// A list. List { /// The first number of the list, if it is ordered. @@ -46,7 +46,7 @@ pub fn parse( let mut emphasis = false; let mut metadata = false; let mut table = false; - let mut link = false; + let mut link = None; let mut lists = Vec::new(); #[cfg(feature = "highlighter")] @@ -93,8 +93,10 @@ pub fn parse( emphasis = true; None } - pulldown_cmark::Tag::Link { .. } if !metadata && !table => { - link = true; + pulldown_cmark::Tag::Link { dest_url, .. } + if !metadata && !table => + { + link = Some(dest_url); None } pulldown_cmark::Tag::List(first_item) if !metadata && !table => { @@ -150,7 +152,7 @@ pub fn parse( None } pulldown_cmark::TagEnd::Link if !metadata && !table => { - link = false; + link = None; None } pulldown_cmark::TagEnd::Paragraph if !metadata && !table => { @@ -245,7 +247,11 @@ pub fn parse( span }; - let span = span.color_maybe(link.then_some(palette.primary)); + let span = if let Some(link) = link.as_ref() { + span.color(palette.primary).link(link.to_string()) + } else { + span + }; spans.push(span); @@ -272,40 +278,48 @@ pub fn parse( /// You can obtain the items with [`parse`]. pub fn view<'a, Message, Renderer>( items: impl IntoIterator, + on_link_click: impl Fn(String) -> Message + Copy + 'a, ) -> Element<'a, Message, Theme, Renderer> where Message: 'a, Renderer: core::text::Renderer + 'a, { let blocks = items.into_iter().enumerate().map(|(i, item)| match item { - Item::Heading(heading) => container(rich_text(heading)) - .padding(padding::top(if i > 0 { 8 } else { 0 })) - .into(), - Item::Paragraph(paragraph) => rich_text(paragraph).into(), - Item::List { start: None, items } => column( - items - .iter() - .map(|items| row!["•", view(items)].spacing(10).into()), - ) - .spacing(10) - .into(), + Item::Heading(heading) => { + container(rich_text(heading).on_link_click(on_link_click)) + .padding(padding::top(if i > 0 { 8 } else { 0 })) + .into() + } + Item::Paragraph(paragraph) => { + rich_text(paragraph).on_link_click(on_link_click).into() + } + Item::List { start: None, items } => { + column(items.iter().map(|items| { + row!["•", view(items, on_link_click)].spacing(10).into() + })) + .spacing(10) + .into() + } Item::List { start: Some(start), items, } => column(items.iter().enumerate().map(|(i, items)| { - row![text!("{}.", i as u64 + *start), view(items)] + row![text!("{}.", i as u64 + *start), view(items, on_link_click)] .spacing(10) .into() })) .spacing(10) .into(), - Item::CodeBlock(code) => { - container(rich_text(code).font(Font::MONOSPACE).size(12)) - .width(Length::Fill) - .padding(10) - .style(container::rounded_box) - .into() - } + Item::CodeBlock(code) => container( + rich_text(code) + .font(Font::MONOSPACE) + .size(12) + .on_link_click(on_link_click), + ) + .width(Length::Fill) + .padding(10) + .style(container::rounded_box) + .into(), }); Element::new(column(blocks).width(Length::Fill).spacing(16)) -- cgit