Use buffer size for markdown preview (#29172)
Note: This is implemented in a very hacky and one-off manner. The primary change is to pass a rem size through the markdown render tree, and scale all sizing (rems & pixels) based on the passed in rem size manually. This required copying in the `CheckBox` component from `ui::CheckBox` to make it use the manual rem scaling without modifying the `CheckBox` implementation directly as it is used elsewhere. A better solution is required, likely involving `window.with_rem_size` and/or _actual_ `em` units that allow text-size-relative scaling. Release Notes: - Made it so Markdown preview uses the _buffer_ font size instead of the _ui_ font size. --------- Co-authored-by: Ben Kunkle <ben@zed.dev> Co-authored-by: Nate Butler <nate@zed.dev>
This commit is contained in:
parent
9249919b7a
commit
38afae86a9
2 changed files with 230 additions and 27 deletions
|
@ -11,6 +11,8 @@ use gpui::{
|
||||||
list,
|
list,
|
||||||
};
|
};
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
|
use settings::Settings;
|
||||||
|
use theme::ThemeSettings;
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use workspace::item::{Item, ItemHandle};
|
use workspace::item::{Item, ItemHandle};
|
||||||
use workspace::{Pane, Workspace};
|
use workspace::{Pane, Workspace};
|
||||||
|
@ -185,6 +187,7 @@ impl MarkdownPreviewView {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let block = contents.children.get(ix).unwrap();
|
let block = contents.children.get(ix).unwrap();
|
||||||
let rendered_block = render_markdown_block(block, &mut render_cx);
|
let rendered_block = render_markdown_block(block, &mut render_cx);
|
||||||
|
|
||||||
|
@ -195,7 +198,9 @@ impl MarkdownPreviewView {
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(ix)
|
.id(ix)
|
||||||
.when(should_apply_padding, |this| this.pb_3())
|
.when(should_apply_padding, |this| {
|
||||||
|
this.pb(render_cx.scaled_rems(0.75))
|
||||||
|
})
|
||||||
.group("markdown-block")
|
.group("markdown-block")
|
||||||
.on_click(cx.listener(
|
.on_click(cx.listener(
|
||||||
move |this, event: &ClickEvent, window, cx| {
|
move |this, event: &ClickEvent, window, cx| {
|
||||||
|
@ -234,7 +239,11 @@ impl MarkdownPreviewView {
|
||||||
container.child(
|
container.child(
|
||||||
div()
|
div()
|
||||||
.relative()
|
.relative()
|
||||||
.child(div().pl_4().child(rendered_block))
|
.child(
|
||||||
|
div()
|
||||||
|
.pl(render_cx.scaled_rems(1.0))
|
||||||
|
.child(rendered_block),
|
||||||
|
)
|
||||||
.child(indicator.absolute().left_0().top_0()),
|
.child(indicator.absolute().left_0().top_0()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -504,6 +513,8 @@ impl Item for MarkdownPreviewView {
|
||||||
|
|
||||||
impl Render for MarkdownPreviewView {
|
impl Render for MarkdownPreviewView {
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let buffer_size = ThemeSettings::get_global(cx).buffer_font_size(cx);
|
||||||
|
let buffer_line_height = ThemeSettings::get_global(cx).buffer_line_height;
|
||||||
v_flex()
|
v_flex()
|
||||||
.id("MarkdownPreview")
|
.id("MarkdownPreview")
|
||||||
.key_context("MarkdownPreview")
|
.key_context("MarkdownPreview")
|
||||||
|
@ -511,6 +522,8 @@ impl Render for MarkdownPreviewView {
|
||||||
.size_full()
|
.size_full()
|
||||||
.bg(cx.theme().colors().editor_background)
|
.bg(cx.theme().colors().editor_background)
|
||||||
.p_4()
|
.p_4()
|
||||||
|
.text_size(buffer_size)
|
||||||
|
.line_height(relative(buffer_line_height.value()))
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex_grow()
|
.flex_grow()
|
||||||
|
|
|
@ -8,7 +8,7 @@ use gpui::{
|
||||||
AbsoluteLength, AnyElement, App, AppContext as _, ClipboardItem, Context, DefiniteLength, Div,
|
AbsoluteLength, AnyElement, App, AppContext as _, ClipboardItem, Context, DefiniteLength, Div,
|
||||||
Element, ElementId, Entity, HighlightStyle, Hsla, ImageSource, InteractiveText, IntoElement,
|
Element, ElementId, Entity, HighlightStyle, Hsla, ImageSource, InteractiveText, IntoElement,
|
||||||
Keystroke, Length, Modifiers, ParentElement, Render, Resource, SharedString, Styled,
|
Keystroke, Length, Modifiers, ParentElement, Render, Resource, SharedString, Styled,
|
||||||
StyledText, TextStyle, WeakEntity, Window, div, img, px, rems,
|
StyledText, TextStyle, WeakEntity, Window, div, img, rems,
|
||||||
};
|
};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -18,10 +18,10 @@ use std::{
|
||||||
};
|
};
|
||||||
use theme::{ActiveTheme, SyntaxTheme, ThemeSettings};
|
use theme::{ActiveTheme, SyntaxTheme, ThemeSettings};
|
||||||
use ui::{
|
use ui::{
|
||||||
ButtonCommon, Checkbox, Clickable, Color, FluentBuilder, IconButton, IconName, IconSize,
|
ButtonCommon, Clickable, Color, FluentBuilder, IconButton, IconName, IconSize,
|
||||||
InteractiveElement, Label, LabelCommon, LabelSize, LinkPreview, StatefulInteractiveElement,
|
InteractiveElement, Label, LabelCommon, LabelSize, LinkPreview, Pixels, Rems,
|
||||||
StyledExt, StyledImage, ToggleState, Tooltip, VisibleOnHover, h_flex, relative,
|
StatefulInteractiveElement, StyledExt, StyledImage, ToggleState, Tooltip, VisibleOnHover,
|
||||||
tooltip_container, v_flex,
|
h_flex, relative, tooltip_container, v_flex,
|
||||||
};
|
};
|
||||||
use workspace::{OpenOptions, OpenVisible, Workspace};
|
use workspace::{OpenOptions, OpenVisible, Workspace};
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ pub struct RenderContext {
|
||||||
text_style: TextStyle,
|
text_style: TextStyle,
|
||||||
border_color: Hsla,
|
border_color: Hsla,
|
||||||
text_color: Hsla,
|
text_color: Hsla,
|
||||||
|
window_rem_size: Pixels,
|
||||||
text_muted_color: Hsla,
|
text_muted_color: Hsla,
|
||||||
code_block_background_color: Hsla,
|
code_block_background_color: Hsla,
|
||||||
code_span_background_color: Hsla,
|
code_span_background_color: Hsla,
|
||||||
|
@ -56,6 +57,7 @@ impl RenderContext {
|
||||||
let buffer_font_family = settings.buffer_font.family.clone();
|
let buffer_font_family = settings.buffer_font.family.clone();
|
||||||
let mut buffer_text_style = window.text_style();
|
let mut buffer_text_style = window.text_style();
|
||||||
buffer_text_style.font_family = buffer_font_family.clone();
|
buffer_text_style.font_family = buffer_font_family.clone();
|
||||||
|
buffer_text_style.font_size = AbsoluteLength::from(settings.buffer_font_size(cx));
|
||||||
|
|
||||||
RenderContext {
|
RenderContext {
|
||||||
workspace,
|
workspace,
|
||||||
|
@ -67,6 +69,7 @@ impl RenderContext {
|
||||||
syntax_theme: theme.syntax().clone(),
|
syntax_theme: theme.syntax().clone(),
|
||||||
border_color: theme.colors().border,
|
border_color: theme.colors().border,
|
||||||
text_color: theme.colors().text,
|
text_color: theme.colors().text,
|
||||||
|
window_rem_size: window.rem_size(),
|
||||||
text_muted_color: theme.colors().text_muted,
|
text_muted_color: theme.colors().text_muted,
|
||||||
code_block_background_color: theme.colors().surface_background,
|
code_block_background_color: theme.colors().surface_background,
|
||||||
code_span_background_color: theme.colors().editor_document_highlight_read_background,
|
code_span_background_color: theme.colors().editor_document_highlight_read_background,
|
||||||
|
@ -88,6 +91,17 @@ impl RenderContext {
|
||||||
ElementId::from(SharedString::from(id))
|
ElementId::from(SharedString::from(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HACK: used to have rems relative to buffer font size, so that things scale appropriately as
|
||||||
|
/// buffer font size changes. The callees of this function should be reimplemented to use real
|
||||||
|
/// relative sizing once that is implemented in GPUI
|
||||||
|
pub fn scaled_rems(&self, rems: f32) -> Rems {
|
||||||
|
return self
|
||||||
|
.buffer_text_style
|
||||||
|
.font_size
|
||||||
|
.to_rems(self.window_rem_size)
|
||||||
|
.mul(rems);
|
||||||
|
}
|
||||||
|
|
||||||
/// This ensures that children inside of block quotes
|
/// This ensures that children inside of block quotes
|
||||||
/// have padding between them.
|
/// have padding between them.
|
||||||
///
|
///
|
||||||
|
@ -103,7 +117,7 @@ impl RenderContext {
|
||||||
/// and "And this is the next paragraph."
|
/// and "And this is the next paragraph."
|
||||||
fn with_common_p(&self, element: Div) -> Div {
|
fn with_common_p(&self, element: Div) -> Div {
|
||||||
if self.indent > 0 {
|
if self.indent > 0 {
|
||||||
element.pb_3()
|
element.pb(self.scaled_rems(0.75))
|
||||||
} else {
|
} else {
|
||||||
element
|
element
|
||||||
}
|
}
|
||||||
|
@ -141,27 +155,38 @@ pub fn render_markdown_block(block: &ParsedMarkdownElement, cx: &mut RenderConte
|
||||||
|
|
||||||
fn render_markdown_heading(parsed: &ParsedMarkdownHeading, cx: &mut RenderContext) -> AnyElement {
|
fn render_markdown_heading(parsed: &ParsedMarkdownHeading, cx: &mut RenderContext) -> AnyElement {
|
||||||
let size = match parsed.level {
|
let size = match parsed.level {
|
||||||
HeadingLevel::H1 => rems(2.),
|
HeadingLevel::H1 => 2.,
|
||||||
HeadingLevel::H2 => rems(1.5),
|
HeadingLevel::H2 => 1.5,
|
||||||
HeadingLevel::H3 => rems(1.25),
|
HeadingLevel::H3 => 1.25,
|
||||||
HeadingLevel::H4 => rems(1.),
|
HeadingLevel::H4 => 1.,
|
||||||
HeadingLevel::H5 => rems(0.875),
|
HeadingLevel::H5 => 0.875,
|
||||||
HeadingLevel::H6 => rems(0.85),
|
HeadingLevel::H6 => 0.85,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let text_size = cx.scaled_rems(size);
|
||||||
|
|
||||||
|
// was `DefiniteLength::from(text_size.mul(1.25))`
|
||||||
|
// let line_height = DefiniteLength::from(text_size.mul(1.25));
|
||||||
|
let line_height = text_size * 1.25;
|
||||||
|
|
||||||
|
// was `rems(0.15)`
|
||||||
|
// let padding_top = cx.scaled_rems(0.15);
|
||||||
|
let padding_top = rems(0.15);
|
||||||
|
|
||||||
|
// was `.pb_1()` = `rems(0.25)`
|
||||||
|
// let padding_bottom = cx.scaled_rems(0.25);
|
||||||
|
let padding_bottom = rems(0.25);
|
||||||
|
|
||||||
let color = match parsed.level {
|
let color = match parsed.level {
|
||||||
HeadingLevel::H6 => cx.text_muted_color,
|
HeadingLevel::H6 => cx.text_muted_color,
|
||||||
_ => cx.text_color,
|
_ => cx.text_color,
|
||||||
};
|
};
|
||||||
|
|
||||||
let line_height = DefiniteLength::from(size.mul(1.25));
|
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.line_height(line_height)
|
.line_height(line_height)
|
||||||
.text_size(size)
|
.text_size(text_size)
|
||||||
.text_color(color)
|
.text_color(color)
|
||||||
.pt(rems(0.15))
|
.pt(padding_top)
|
||||||
.pb_1()
|
.pb(padding_bottom)
|
||||||
.children(render_markdown_text(&parsed.contents, cx))
|
.children(render_markdown_text(&parsed.contents, cx))
|
||||||
.whitespace_normal()
|
.whitespace_normal()
|
||||||
.into_any()
|
.into_any()
|
||||||
|
@ -173,22 +198,23 @@ fn render_markdown_list_item(
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
use ParsedMarkdownListItemType::*;
|
use ParsedMarkdownListItemType::*;
|
||||||
|
|
||||||
let padding = rems((parsed.depth - 1) as f32);
|
let padding = cx.scaled_rems((parsed.depth - 1) as f32);
|
||||||
|
|
||||||
let bullet = match &parsed.item_type {
|
let bullet = match &parsed.item_type {
|
||||||
Ordered(order) => format!("{}.", order).into_any_element(),
|
Ordered(order) => format!("{}.", order).into_any_element(),
|
||||||
Unordered => "•".into_any_element(),
|
Unordered => "•".into_any_element(),
|
||||||
Task(checked, range) => div()
|
Task(checked, range) => div()
|
||||||
.id(cx.next_id(range))
|
.id(cx.next_id(range))
|
||||||
.mt(px(3.))
|
.mt(cx.scaled_rems(3.0 / 16.0))
|
||||||
.child(
|
.child(
|
||||||
Checkbox::new(
|
MarkdownCheckbox::new(
|
||||||
"checkbox",
|
"checkbox",
|
||||||
if *checked {
|
if *checked {
|
||||||
ToggleState::Selected
|
ToggleState::Selected
|
||||||
} else {
|
} else {
|
||||||
ToggleState::Unselected
|
ToggleState::Unselected
|
||||||
},
|
},
|
||||||
|
cx.clone(),
|
||||||
)
|
)
|
||||||
.when_some(
|
.when_some(
|
||||||
cx.checkbox_clicked_callback.clone(),
|
cx.checkbox_clicked_callback.clone(),
|
||||||
|
@ -216,7 +242,7 @@ fn render_markdown_list_item(
|
||||||
})
|
})
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
};
|
};
|
||||||
let bullet = div().mr_2().child(bullet);
|
let bullet = div().mr(cx.scaled_rems(0.5)).child(bullet);
|
||||||
|
|
||||||
let contents: Vec<AnyElement> = parsed
|
let contents: Vec<AnyElement> = parsed
|
||||||
.content
|
.content
|
||||||
|
@ -227,11 +253,175 @@ fn render_markdown_list_item(
|
||||||
let item = h_flex()
|
let item = h_flex()
|
||||||
.pl(DefiniteLength::Absolute(AbsoluteLength::Rems(padding)))
|
.pl(DefiniteLength::Absolute(AbsoluteLength::Rems(padding)))
|
||||||
.items_start()
|
.items_start()
|
||||||
.children(vec![bullet, div().children(contents).pr_4().w_full()]);
|
.children(vec![
|
||||||
|
bullet,
|
||||||
|
div().children(contents).pr(cx.scaled_rems(1.0)).w_full(),
|
||||||
|
]);
|
||||||
|
|
||||||
cx.with_common_p(item).into_any()
|
cx.with_common_p(item).into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # MarkdownCheckbox ///
|
||||||
|
/// HACK: Copied from `ui/src/components/toggle.rs` to deal with scaling issues in markdown preview
|
||||||
|
/// changes should be integrated into `Checkbox` in `toggle.rs` while making sure checkboxes elsewhere in the
|
||||||
|
/// app are not visually affected
|
||||||
|
#[derive(gpui::IntoElement)]
|
||||||
|
struct MarkdownCheckbox {
|
||||||
|
id: ElementId,
|
||||||
|
toggle_state: ToggleState,
|
||||||
|
disabled: bool,
|
||||||
|
placeholder: bool,
|
||||||
|
on_click: Option<Box<dyn Fn(&ToggleState, &mut Window, &mut App) + 'static>>,
|
||||||
|
filled: bool,
|
||||||
|
style: ui::ToggleStyle,
|
||||||
|
tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> gpui::AnyView>>,
|
||||||
|
label: Option<SharedString>,
|
||||||
|
render_cx: RenderContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MarkdownCheckbox {
|
||||||
|
/// Creates a new [`Checkbox`].
|
||||||
|
fn new(id: impl Into<ElementId>, checked: ToggleState, render_cx: RenderContext) -> Self {
|
||||||
|
Self {
|
||||||
|
id: id.into(),
|
||||||
|
toggle_state: checked,
|
||||||
|
disabled: false,
|
||||||
|
on_click: None,
|
||||||
|
filled: false,
|
||||||
|
style: ui::ToggleStyle::default(),
|
||||||
|
tooltip: None,
|
||||||
|
label: None,
|
||||||
|
placeholder: false,
|
||||||
|
render_cx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binds a handler to the [`Checkbox`] that will be called when clicked.
|
||||||
|
fn on_click(mut self, handler: impl Fn(&ToggleState, &mut Window, &mut App) + 'static) -> Self {
|
||||||
|
self.on_click = Some(Box::new(handler));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bg_color(&self, cx: &App) -> Hsla {
|
||||||
|
let style = self.style.clone();
|
||||||
|
match (style, self.filled) {
|
||||||
|
(ui::ToggleStyle::Ghost, false) => cx.theme().colors().ghost_element_background,
|
||||||
|
(ui::ToggleStyle::Ghost, true) => cx.theme().colors().element_background,
|
||||||
|
(ui::ToggleStyle::ElevationBased(_), false) => gpui::transparent_black(),
|
||||||
|
(ui::ToggleStyle::ElevationBased(elevation), true) => elevation.darker_bg(cx),
|
||||||
|
(ui::ToggleStyle::Custom(_), false) => gpui::transparent_black(),
|
||||||
|
(ui::ToggleStyle::Custom(color), true) => color.opacity(0.2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn border_color(&self, cx: &App) -> Hsla {
|
||||||
|
if self.disabled {
|
||||||
|
return cx.theme().colors().border_variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.style.clone() {
|
||||||
|
ui::ToggleStyle::Ghost => cx.theme().colors().border,
|
||||||
|
ui::ToggleStyle::ElevationBased(_) => cx.theme().colors().border,
|
||||||
|
ui::ToggleStyle::Custom(color) => color.opacity(0.3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl gpui::RenderOnce for MarkdownCheckbox {
|
||||||
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
let group_id = format!("checkbox_group_{:?}", self.id);
|
||||||
|
let color = if self.disabled {
|
||||||
|
Color::Disabled
|
||||||
|
} else {
|
||||||
|
Color::Selected
|
||||||
|
};
|
||||||
|
let icon_size_small = IconSize::Custom(self.render_cx.scaled_rems(14. / 16.)); // was IconSize::Small
|
||||||
|
let icon = match self.toggle_state {
|
||||||
|
ToggleState::Selected => {
|
||||||
|
if self.placeholder {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
ui::Icon::new(IconName::Check)
|
||||||
|
.size(icon_size_small)
|
||||||
|
.color(color),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToggleState::Indeterminate => Some(
|
||||||
|
ui::Icon::new(IconName::Dash)
|
||||||
|
.size(icon_size_small)
|
||||||
|
.color(color),
|
||||||
|
),
|
||||||
|
ToggleState::Unselected => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bg_color = self.bg_color(cx);
|
||||||
|
let border_color = self.border_color(cx);
|
||||||
|
let hover_border_color = border_color.alpha(0.7);
|
||||||
|
|
||||||
|
let size = self.render_cx.scaled_rems(1.25); // was Self::container_size(); (20px)
|
||||||
|
|
||||||
|
let checkbox = h_flex()
|
||||||
|
.id(self.id.clone())
|
||||||
|
.justify_center()
|
||||||
|
.items_center()
|
||||||
|
.size(size)
|
||||||
|
.group(group_id.clone())
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_none()
|
||||||
|
.justify_center()
|
||||||
|
.items_center()
|
||||||
|
.m(self.render_cx.scaled_rems(0.25)) // was .m_1
|
||||||
|
.size(self.render_cx.scaled_rems(1.0)) // was .size_4
|
||||||
|
.rounded(self.render_cx.scaled_rems(0.125)) // was .rounded_xs
|
||||||
|
.border_1()
|
||||||
|
.bg(bg_color)
|
||||||
|
.border_color(border_color)
|
||||||
|
.when(self.disabled, |this| this.cursor_not_allowed())
|
||||||
|
.when(self.disabled, |this| {
|
||||||
|
this.bg(cx.theme().colors().element_disabled.opacity(0.6))
|
||||||
|
})
|
||||||
|
.when(!self.disabled, |this| {
|
||||||
|
this.group_hover(group_id.clone(), |el| el.border_color(hover_border_color))
|
||||||
|
})
|
||||||
|
.when(self.placeholder, |this| {
|
||||||
|
this.child(
|
||||||
|
div()
|
||||||
|
.flex_none()
|
||||||
|
.rounded_full()
|
||||||
|
.bg(color.color(cx).alpha(0.5))
|
||||||
|
.size(self.render_cx.scaled_rems(0.25)), // was .size_1
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.children(icon),
|
||||||
|
);
|
||||||
|
|
||||||
|
h_flex()
|
||||||
|
.id(self.id)
|
||||||
|
.gap(ui::DynamicSpacing::Base06.rems(cx))
|
||||||
|
.child(checkbox)
|
||||||
|
.when_some(
|
||||||
|
self.on_click.filter(|_| !self.disabled),
|
||||||
|
|this, on_click| {
|
||||||
|
this.on_click(move |_, window, cx| {
|
||||||
|
on_click(&self.toggle_state.inverse(), window, cx)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// TODO: Allow label size to be different from default.
|
||||||
|
// TODO: Allow label color to be different from muted.
|
||||||
|
.when_some(self.label, |this, label| {
|
||||||
|
this.child(Label::new(label).color(Color::Muted))
|
||||||
|
})
|
||||||
|
.when_some(self.tooltip, |this, tooltip| {
|
||||||
|
this.tooltip(move |window, cx| tooltip(window, cx))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn paragraph_len(paragraphs: &MarkdownParagraph) -> usize {
|
fn paragraph_len(paragraphs: &MarkdownParagraph) -> usize {
|
||||||
paragraphs
|
paragraphs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -578,8 +768,8 @@ fn render_markdown_text(parsed_new: &MarkdownParagraph, cx: &mut RenderContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_markdown_rule(cx: &mut RenderContext) -> AnyElement {
|
fn render_markdown_rule(cx: &mut RenderContext) -> AnyElement {
|
||||||
let rule = div().w_full().h(px(2.)).bg(cx.border_color);
|
let rule = div().w_full().h(cx.scaled_rems(0.125)).bg(cx.border_color);
|
||||||
div().pt_3().pb_3().child(rule).into_any()
|
div().py(cx.scaled_rems(0.5)).child(rule).into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InteractiveMarkdownElementTooltip {
|
struct InteractiveMarkdownElementTooltip {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue